14
14
* limitations under the License.
15
15
*/
16
16
17
- package io .r2dbc .postgresql . util . sql ;
17
+ package io .r2dbc .postgresql ;
18
18
19
19
import java .util .ArrayList ;
20
20
import java .util .Arrays ;
21
21
import java .util .List ;
22
22
23
- import static java .lang .Character .isDigit ;
24
23
import static java .lang .Character .isWhitespace ;
25
- import static java .lang .Character .toLowerCase ;
26
24
27
- public class BasicPostgresqlSqlLexer {
25
+ /**
26
+ * Utility to tokenize Postgres SQL statements.
27
+ *
28
+ * @since 0.9
29
+ */
30
+ class PostgresqlSqlLexer {
28
31
29
32
private static final char [] SPECIAL_AND_OPERATOR_CHARS = {
30
33
'+' , '-' , '*' , '/' , '<' , '>' , '=' , '~' , '!' , '@' , '#' , '%' , '^' , '&' , '|' , '`' , '?' ,
@@ -36,14 +39,14 @@ public class BasicPostgresqlSqlLexer {
36
39
}
37
40
38
41
public static TokenizedSql tokenize (String sql ) {
39
- List <Token > tokens = new ArrayList <>();
40
- List <TokenizedStatement > statements = new ArrayList <>();
42
+ List <TokenizedSql . Token > tokens = new ArrayList <>();
43
+ List <TokenizedSql . TokenizedStatement > statements = new ArrayList <>();
41
44
42
45
int statementStartIndex = 0 ;
43
46
int i = 0 ;
44
47
while (i < sql .length ()) {
45
48
char c = sql .charAt (i );
46
- Token token = null ;
49
+ TokenizedSql . Token token = null ;
47
50
48
51
if (isWhitespace (c )) {
49
52
i ++;
@@ -70,25 +73,25 @@ public static TokenizedSql tokenize(String sql) {
70
73
token = getParameterOrDollarQuoteToken (sql , i );
71
74
break ;
72
75
case ';' :
73
- token = new Token (TokenType .STATEMENT_END , ";" );
76
+ token = new TokenizedSql . Token (TokenizedSql . TokenType .STATEMENT_END , ";" );
74
77
break ;
75
78
default :
76
79
break ;
77
80
}
78
81
if (token == null ) {
79
82
if (isSpecialOrOperatorChar (c )) {
80
- token = new Token (TokenType .SPECIAL_OR_OPERATOR , Character .toString (c ));//getSpecialOrOperatorToken(sql, i);
83
+ token = new TokenizedSql . Token (TokenizedSql . TokenType .SPECIAL_OR_OPERATOR , Character .toString (c ));//getSpecialOrOperatorToken(sql, i);
81
84
} else {
82
85
token = getDefaultToken (sql , i );
83
86
}
84
87
}
85
88
86
89
i += token .getValue ().length ();
87
90
88
- if (token .getType () == TokenType .STATEMENT_END ) {
91
+ if (token .getType () == TokenizedSql . TokenType .STATEMENT_END ) {
89
92
90
93
tokens .add (token );
91
- statements .add (new TokenizedStatement (sql .substring (statementStartIndex , i ), tokens ));
94
+ statements .add (new TokenizedSql . TokenizedStatement (sql .substring (statementStartIndex , i ), tokens ));
92
95
93
96
tokens = new ArrayList <>();
94
97
statementStartIndex = i + 1 ;
@@ -98,27 +101,27 @@ public static TokenizedSql tokenize(String sql) {
98
101
}
99
102
// If tokens is not empty, implicit statement end
100
103
if (!tokens .isEmpty ()) {
101
- statements .add (new TokenizedStatement (sql .substring (statementStartIndex ), tokens ));
104
+ statements .add (new TokenizedSql . TokenizedStatement (sql .substring (statementStartIndex ), tokens ));
102
105
}
103
106
104
107
return new TokenizedSql (sql , statements );
105
108
}
106
109
107
- private static Token getDefaultToken (String sql , int beginIndex ) {
110
+ private static TokenizedSql . Token getDefaultToken (String sql , int beginIndex ) {
108
111
for (int i = beginIndex + 1 ; i < sql .length (); i ++) {
109
112
char c = sql .charAt (i );
110
113
if (Character .isWhitespace (c ) || isSpecialOrOperatorChar (c )) {
111
- return new Token (TokenType .DEFAULT , sql .substring (beginIndex , i ));
114
+ return new TokenizedSql . Token (TokenizedSql . TokenType .DEFAULT , sql .substring (beginIndex , i ));
112
115
}
113
116
}
114
- return new Token (TokenType .DEFAULT , sql .substring (beginIndex ));
117
+ return new TokenizedSql . Token (TokenizedSql . TokenType .DEFAULT , sql .substring (beginIndex ));
115
118
}
116
119
117
120
private static boolean isSpecialOrOperatorChar (char c ) {
118
121
return Arrays .binarySearch (SPECIAL_AND_OPERATOR_CHARS , c ) >= 0 ;
119
122
}
120
123
121
- private static Token getBlockCommentToken (String sql , int beginIndex ) {
124
+ private static TokenizedSql . Token getBlockCommentToken (String sql , int beginIndex ) {
122
125
int depth = 1 ;
123
126
for (int i = beginIndex + 2 ; i < (sql .length () - 1 ); i ++) {
124
127
String biGraph = sql .substring (i , i + 2 );
@@ -131,78 +134,78 @@ private static Token getBlockCommentToken(String sql, int beginIndex) {
131
134
i ++;
132
135
}
133
136
if (depth == 0 ) {
134
- return new Token (TokenType .COMMENT , sql .substring (beginIndex , i + 1 ));
137
+ return new TokenizedSql . Token (TokenizedSql . TokenType .COMMENT , sql .substring (beginIndex , i + 1 ));
135
138
}
136
139
}
137
140
throw new IllegalArgumentException ("Sql cannot be parsed: unclosed block comment (comment opened at index " + beginIndex + ") in statement: " + sql );
138
141
}
139
142
140
- private static Token getCommentToLineEndToken (String sql , int beginIndex ) {
143
+ private static TokenizedSql . Token getCommentToLineEndToken (String sql , int beginIndex ) {
141
144
int lineEnding = sql .indexOf ('\n' , beginIndex );
142
145
if (lineEnding == -1 ) {
143
- return new Token (TokenType .COMMENT , sql .substring (beginIndex ));
146
+ return new TokenizedSql . Token (TokenizedSql . TokenType .COMMENT , sql .substring (beginIndex ));
144
147
} else {
145
- return new Token (TokenType .COMMENT , sql .substring (beginIndex , lineEnding ));
148
+ return new TokenizedSql . Token (TokenizedSql . TokenType .COMMENT , sql .substring (beginIndex , lineEnding ));
146
149
}
147
150
}
148
151
149
- private static Token getDollarQuoteToken (String sql , String tag , int beginIndex ) {
152
+ private static TokenizedSql . Token getDollarQuoteToken (String sql , String tag , int beginIndex ) {
150
153
int nextQuote = sql .indexOf (tag , beginIndex + tag .length ());
151
154
if (nextQuote == -1 ) {
152
155
throw new IllegalArgumentException ("Sql cannot be parsed: unclosed quote (quote opened at index " + beginIndex + ") in statement: " + sql );
153
156
} else {
154
- return new Token (TokenType .STRING_CONSTANT , sql .substring (beginIndex , nextQuote + tag .length ()));
157
+ return new TokenizedSql . Token (TokenizedSql . TokenType .STRING_CONSTANT , sql .substring (beginIndex , nextQuote + tag .length ()));
155
158
}
156
159
}
157
160
158
- private static Token getParameterToken (String sql , int beginIndex ) {
161
+ private static TokenizedSql . Token getParameterToken (String sql , int beginIndex ) {
159
162
for (int i = beginIndex + 1 ; i < sql .length (); i ++) {
160
163
char c = sql .charAt (i );
161
164
if (isWhitespace (c ) || isSpecialOrOperatorChar (c )) {
162
- return new Token (TokenType .PARAMETER , sql .substring (beginIndex , i ));
165
+ return new TokenizedSql . Token (TokenizedSql . TokenType .PARAMETER , sql .substring (beginIndex , i ));
163
166
}
164
167
if (!isAsciiDigit (c )) {
165
168
throw new IllegalArgumentException ("Sql cannot be parsed: illegal character in parameter or dollar-quote tag: " + c );
166
169
}
167
170
}
168
- return new Token (TokenType .PARAMETER , sql .substring (beginIndex ));
171
+ return new TokenizedSql . Token (TokenizedSql . TokenType .PARAMETER , sql .substring (beginIndex ));
169
172
}
170
173
171
- private static Token getParameterOrDollarQuoteToken (String sql , int beginIndex ) {
174
+ private static TokenizedSql . Token getParameterOrDollarQuoteToken (String sql , int beginIndex ) {
172
175
char firstChar = sql .charAt (beginIndex + 1 );
173
176
if (firstChar == '$' ) {
174
177
return getDollarQuoteToken (sql , "$$" , beginIndex );
175
178
} else if (isAsciiDigit (firstChar )) {
176
179
return getParameterToken (sql , beginIndex );
177
180
} else {
178
- for (int i = beginIndex + 1 ; i < sql .length (); i ++) {
179
- char c = sql .charAt (i );
180
- if (c == '$' ) {
181
- return getDollarQuoteToken (sql , sql .substring (beginIndex , i + 1 ), beginIndex );
182
- }
183
- if (!(isAsciiLetter (c ) || c == '_' || isAsciiDigit (c ))) {
184
- throw new IllegalArgumentException ("Sql cannot be parsed: illegal character in dollar-quote tag (quote opened at index " + beginIndex + ") in statement: " + sql );
185
- }
181
+ for (int i = beginIndex + 1 ; i < sql .length (); i ++) {
182
+ char c = sql .charAt (i );
183
+ if (c == '$' ) {
184
+ return getDollarQuoteToken (sql , sql .substring (beginIndex , i + 1 ), beginIndex );
185
+ }
186
+ if (!(isAsciiLetter (c ) || c == '_' || isAsciiDigit (c ))) {
187
+ throw new IllegalArgumentException ("Sql cannot be parsed: illegal character in dollar-quote tag (quote opened at index " + beginIndex + ") in statement: " + sql );
186
188
}
187
- throw new IllegalArgumentException ("Sql cannot be parsed: unclosed dollar-quote tag(quote opened at index " + beginIndex + ") in statement: " + sql );
189
+ }
190
+ throw new IllegalArgumentException ("Sql cannot be parsed: unclosed dollar-quote tag(quote opened at index " + beginIndex + ") in statement: " + sql );
188
191
}
189
192
}
190
193
191
- private static Token getStandardQuoteToken (String sql , int beginIndex ) {
194
+ private static TokenizedSql . Token getStandardQuoteToken (String sql , int beginIndex ) {
192
195
int nextQuote = sql .indexOf ('\'' , beginIndex + 1 );
193
196
if (nextQuote == -1 ) {
194
197
throw new IllegalArgumentException ("Sql cannot be parsed: unclosed quote (quote opened at index " + beginIndex + ") in statement: " + sql );
195
198
} else {
196
- return new Token (TokenType .STRING_CONSTANT , sql .substring (beginIndex , nextQuote + 1 ));
199
+ return new TokenizedSql . Token (TokenizedSql . TokenType .STRING_CONSTANT , sql .substring (beginIndex , nextQuote + 1 ));
197
200
}
198
201
}
199
202
200
- private static Token getQuotedIdentifierToken (String sql , int beginIndex ) {
203
+ private static TokenizedSql . Token getQuotedIdentifierToken (String sql , int beginIndex ) {
201
204
int nextQuote = sql .indexOf ('\"' , beginIndex + 1 );
202
205
if (nextQuote == -1 ) {
203
206
throw new IllegalArgumentException ("Sql cannot be parsed: unclosed quoted identifier (identifier opened at index " + beginIndex + ") in statement: " + sql );
204
207
} else {
205
- return new Token (TokenType .QUOTED_IDENTIFIER , sql .substring (beginIndex , nextQuote + 1 ));
208
+ return new TokenizedSql . Token (TokenizedSql . TokenType .QUOTED_IDENTIFIER , sql .substring (beginIndex , nextQuote + 1 ));
206
209
}
207
210
}
208
211
0 commit comments