1 /*
2 * Copyright 2015-2018 HuntLabs.cn
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 module hunt.sql.dialect.postgresql.parser.PGLexer;
17
18 import hunt.sql.parser.CharTypes;
19 import hunt.sql.parser.Token;
20
21 import hunt.collection;
22 import hunt.sql.parser;
23 import hunt.sql.util.DBType;
24 import hunt.logging;
25
26 import std.concurrency : initOnce;
27
28 public class PGLexer : Lexer {
29
30 // public static Keywords DEFAULT_PG_KEYWORDS;
31
32 static Keywords DEFAULT_PG_KEYWORDS() {
33 __gshared Keywords inst;
34 return initOnce!inst(initKeyWords());
35 }
36
37 private static Keywords initKeyWords() {
38 Map!(string, Token) map = new HashMap!(string, Token)();
39
40 map.putAll(Keywords.DEFAULT_KEYWORDS.getKeywords());
41
42 map.put("BEGIN", Token.BEGIN);
43 map.put("CASCADE", Token.CASCADE);
44 map.put("CONTINUE", Token.CONTINUE);
45 map.put("CURRENT", Token.CURRENT);
46 map.put("FETCH", Token.FETCH);
47 map.put("FIRST", Token.FIRST);
48
49 map.put("IDENTITY", Token.IDENTITY);
50 map.put("LIMIT", Token.LIMIT);
51 map.put("NEXT", Token.NEXT);
52 map.put("NOWAIT", Token.NOWAIT);
53 map.put("OF", Token.OF);
54
55 map.put("OFFSET", Token.OFFSET);
56 map.put("ONLY", Token.ONLY);
57 map.put("RECURSIVE", Token.RECURSIVE);
58 map.put("RESTART", Token.RESTART);
59
60 map.put("RESTRICT", Token.RESTRICT);
61 map.put("RETURNING", Token.RETURNING);
62 map.put("ROW", Token.ROW);
63 map.put("ROWS", Token.ROWS);
64 map.put("SHARE", Token.SHARE);
65 map.put("SHOW", Token.SHOW);
66 map.put("START", Token.START);
67
68 map.put("USING", Token.USING);
69 map.put("WINDOW", Token.WINDOW);
70
71 map.put("TRUE", Token.TRUE);
72 map.put("FALSE", Token.FALSE);
73 map.put("ARRAY", Token.ARRAY);
74 map.put("IF", Token.IF);
75 map.put("TYPE", Token.TYPE);
76 map.put("ILIKE", Token.ILIKE);
77
78 return new Keywords(map);
79 }
80
81 public this(string input, SQLParserFeature[] features...){
82 super(input);
83 super.keywods = DEFAULT_PG_KEYWORDS;
84 super.dbType = DBType.POSTGRESQL.name;
85 foreach(SQLParserFeature feature ; features) {
86 config(feature, true);
87 }
88 }
89
90 override protected void scanString() {
91 _mark = _pos;
92 bool hasSpecial = false;
93
94 for (;;) {
95 // logDebug("ch : ",ch);
96 if (isEOF()) {
97 lexError("unclosed.str.lit");
98 return;
99 }
100
101 ch = charAt(++_pos);
102
103 if (ch == '\\') {
104 scanChar();
105 if (!hasSpecial) {
106 initBuff(bufPos);
107 arraycopy(_mark + 1, buf, 0, bufPos);
108 hasSpecial = true;
109 }
110
111 putChar('\\');
112 switch (ch) {
113 case '\0':
114 putChar('\0');
115 break;
116 case '\'':
117 putChar('\'');
118 break;
119 case '"':
120 putChar('"');
121 break;
122 case 'b':
123 putChar('\b');
124 break;
125 case 'n':
126 putChar('\n');
127 break;
128 case 'r':
129 putChar('\r');
130 break;
131 case 't':
132 putChar('\t');
133 break;
134 case '\\':
135 putChar('\\');
136 break;
137 case 'Z':
138 putChar(cast(char) 0x1A); // ctrl + Z
139 break;
140 default:
141 putChar(ch);
142 break;
143 }
144 scanChar();
145 }
146
147 if (ch == '\'') {
148 scanChar();
149 if (ch != '\'') {
150 _token = Token.LITERAL_CHARS;
151 break;
152 } else {
153 initBuff(bufPos);
154 arraycopy(_mark + 1, buf, 0, bufPos);
155 // logDebugf("bufPos :%d ,mark : %d , buf : %s",bufPos,_mark,buf);
156 hasSpecial = true;
157 putChar('\'');
158 // putChar('\'');
159 continue;
160 }
161 }
162
163 if (!hasSpecial) {
164 bufPos++;
165 continue;
166 }
167
168 if (bufPos == buf.length) {
169 putChar(ch);
170 } else {
171 buf[bufPos++] = ch;
172 }
173 }
174
175 if (!hasSpecial) {
176 _stringVal = subString(_mark + 1, bufPos);
177 } else {
178 _stringVal = cast(string)buf[0..bufPos];
179 }
180 }
181
182 override public void scanSharp() {
183 scanChar();
184 if (ch == '>') {
185 scanChar();
186 if (ch == '>') {
187 scanChar();
188 _token = Token.POUNDGTGT;
189 } else {
190 _token = Token.POUNDGT;
191 }
192 } else {
193 _token = Token.POUND;
194 }
195 }
196
197 override protected void scanVariable_at() {
198 if (ch != '@') {
199 throw new ParserException("illegal variable. " ~ info());
200 }
201
202 _mark = _pos;
203 bufPos = 1;
204 char ch;
205
206 char c1 = charAt(_pos + 1);
207 if (c1 == '@') {
208 _pos += 2;
209 _token = Token.MONKEYS_AT_AT;
210 this.ch = charAt(++_pos);
211 return;
212 } else if (c1 == '>') {
213 _pos += 2;
214 _token = Token.MONKEYS_AT_GT;
215 this.ch = charAt(++_pos);
216 return;
217 }
218
219 for (;;) {
220 ch = charAt(++_pos);
221
222 if (!CharTypes.isIdentifierChar(ch)) {
223 break;
224 }
225
226 bufPos++;
227 continue;
228 }
229
230 this.ch = charAt(_pos);
231
232 _stringVal = addSymbol();
233 _token = Token.VARIANT;
234 }
235 }