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 }