16
16
17
17
package io .r2dbc .postgresql ;
18
18
19
+ import io .netty .util .collection .CharObjectHashMap ;
20
+ import io .netty .util .collection .CharObjectMap ;
21
+
19
22
import java .util .ArrayList ;
20
- import java .util .Arrays ;
23
+ import java .util .LinkedList ;
21
24
import java .util .List ;
22
25
23
26
import static java .lang .Character .isWhitespace ;
29
32
*/
30
33
class PostgresqlSqlParser {
31
34
32
- private static final char [] SPECIAL_AND_OPERATOR_CHARS = {
33
- '+' , '-' , '*' , '/' , '<' , '>' , '=' , '~' , '!' , '@' , '#' , '%' , '^' , '&' , '|' , '`' , '?' ,
34
- '(' , ')' , '[' , ']' , ',' , ';' , ':' , '*' , '.' , '\'' , '"'
35
- };
35
+ private static final CharObjectMap <Object > SPECIAL_AND_OPERATOR_CHARS = new CharObjectHashMap <>();
36
36
37
37
static {
38
- Arrays .sort (SPECIAL_AND_OPERATOR_CHARS );
38
+ char [] specialCharsAndOperators = {'+' , '-' , '*' , '/' , '<' , '>' , '=' , '~' , '!' , '@' , '#' , '%' , '^' , '&' , '|' , '`' , '?' ,
39
+ '(' , ')' , '[' , ']' , ',' , ';' , ':' , '*' , '.' , '\'' , '"' };
40
+
41
+ for (char c : specialCharsAndOperators ) {
42
+ SPECIAL_AND_OPERATOR_CHARS .put (c , new Object ());
43
+ }
44
+ }
45
+
46
+ public static ParsedSql parse (String sql ) {
47
+ List <ParsedSql .Token > tokens = tokenize (sql );
48
+ List <ParsedSql .Statement > statements = new ArrayList <>();
49
+ LinkedList <Boolean > functionBodyList = null ;
50
+
51
+ List <ParsedSql .Token > currentStatementTokens = new ArrayList <>(tokens .size ());
52
+
53
+ for (int i = 0 ; i < tokens .size (); i ++) {
54
+ ParsedSql .Token current = tokens .get (i );
55
+ currentStatementTokens .add (current );
56
+
57
+ if (current .getType () == ParsedSql .TokenType .DEFAULT ) {
58
+ String currentValue = current .getValue ();
59
+
60
+ if (currentValue .equalsIgnoreCase ("BEGIN" )) {
61
+ if (functionBodyList == null ) {
62
+ functionBodyList = new LinkedList <>();
63
+ }
64
+ if (hasNextToken (tokens , i ) && peekNext (tokens , i ).getValue ().equalsIgnoreCase ("ATOMIC" )) {
65
+ functionBodyList .add (true );
66
+ } else {
67
+ functionBodyList .add (false );
68
+ }
69
+ } else if (currentValue .equalsIgnoreCase ("END" ) && functionBodyList != null && !functionBodyList .isEmpty ()) {
70
+ functionBodyList .removeLast ();
71
+ }
72
+ } else if (current .getType ().equals (ParsedSql .TokenType .STATEMENT_END )) {
73
+ boolean inFunctionBody = false ;
74
+
75
+ if (functionBodyList != null ) {
76
+ for (boolean b : functionBodyList ) {
77
+ inFunctionBody |= b ;
78
+ }
79
+ }
80
+ if (!inFunctionBody ) {
81
+ statements .add (new ParsedSql .Statement (currentStatementTokens ));
82
+ currentStatementTokens = new ArrayList <>();
83
+ }
84
+ }
85
+ }
86
+
87
+ if (!currentStatementTokens .isEmpty ()) {
88
+ statements .add (new ParsedSql .Statement (currentStatementTokens ));
89
+ }
90
+
91
+ return new ParsedSql (sql , statements );
92
+ }
93
+
94
+ private static ParsedSql .Token peekNext (List <ParsedSql .Token > tokens , int index ) {
95
+ return tokens .get (index + 1 );
96
+ }
97
+
98
+ private static boolean hasNextToken (List <ParsedSql .Token > tokens , int index ) {
99
+ return tokens .size () > index + 1 ;
100
+ }
101
+
102
+ private static char peekNext (CharSequence sequence , int index ) {
103
+ return sequence .charAt (index + 1 );
104
+ }
105
+
106
+ private static boolean hasNextToken (CharSequence sequence , int index ) {
107
+ return sequence .length () > index + 1 ;
39
108
}
40
109
41
110
private static List <ParsedSql .Token > tokenize (String sql ) {
@@ -57,12 +126,12 @@ private static List<ParsedSql.Token> tokenize(String sql) {
57
126
token = getQuotedIdentifierToken (sql , i );
58
127
break ;
59
128
case '-' : // Possible start of double-dash comment
60
- if (( i + 1 ) < sql . length () && sql . charAt ( i + 1 ) == '-' ) {
129
+ if (hasNextToken ( sql , i ) && peekNext ( sql , i ) == '-' ) {
61
130
token = getCommentToLineEndToken (sql , i );
62
131
}
63
132
break ;
64
133
case '/' : // Possible start of c-style comment
65
- if (( i + 1 ) < sql . length () && sql . charAt ( i + 1 ) == '*' ) {
134
+ if (hasNextToken ( sql , i ) && peekNext ( sql , i ) == '*' ) {
66
135
token = getBlockCommentToken (sql , i );
67
136
}
68
137
break ;
@@ -89,48 +158,6 @@ private static List<ParsedSql.Token> tokenize(String sql) {
89
158
return tokens ;
90
159
}
91
160
92
- public static ParsedSql parse (String sql ) {
93
- List <ParsedSql .Token > tokens = tokenize (sql );
94
- List <ParsedSql .Statement > statements = new ArrayList <>();
95
- List <Boolean > functionBodyList = new ArrayList <>();
96
-
97
- List <ParsedSql .Token > currentStatementTokens = new ArrayList <>();
98
- for (int i = 0 ; i < tokens .size (); i ++) {
99
- ParsedSql .Token current = tokens .get (i );
100
- currentStatementTokens .add (current );
101
-
102
- if (current .getType () == ParsedSql .TokenType .DEFAULT ) {
103
- String currentValue = current .getValue ();
104
-
105
- if (currentValue .equalsIgnoreCase ("BEGIN" )) {
106
- if (i + 1 < tokens .size () && tokens .get (i + 1 ).getValue ().equalsIgnoreCase ("ATOMIC" )) {
107
- functionBodyList .add (true );
108
- } else {
109
- functionBodyList .add (false );
110
- }
111
- } else if (currentValue .equalsIgnoreCase ("END" ) && !functionBodyList .isEmpty ()) {
112
- functionBodyList .remove (functionBodyList .size () - 1 );
113
- }
114
- } else if (current .getType ().equals (ParsedSql .TokenType .STATEMENT_END )) {
115
- boolean inFunctionBody = false ;
116
-
117
- for (boolean b : functionBodyList ) {
118
- inFunctionBody |= b ;
119
- }
120
- if (!inFunctionBody ) {
121
- statements .add (new ParsedSql .Statement (currentStatementTokens ));
122
- currentStatementTokens = new ArrayList <>();
123
- }
124
- }
125
- }
126
-
127
- if (!currentStatementTokens .isEmpty ()) {
128
- statements .add (new ParsedSql .Statement (currentStatementTokens ));
129
- }
130
-
131
- return new ParsedSql (sql , statements );
132
- }
133
-
134
161
private static ParsedSql .Token getDefaultToken (String sql , int beginIndex ) {
135
162
for (int i = beginIndex + 1 ; i < sql .length (); i ++) {
136
163
char c = sql .charAt (i );
@@ -142,7 +169,7 @@ private static ParsedSql.Token getDefaultToken(String sql, int beginIndex) {
142
169
}
143
170
144
171
private static boolean isSpecialOrOperatorChar (char c ) {
145
- return Arrays . binarySearch ( SPECIAL_AND_OPERATOR_CHARS , c ) >= 0 ;
172
+ return SPECIAL_AND_OPERATOR_CHARS . containsKey ( c ) ;
146
173
}
147
174
148
175
private static ParsedSql .Token getBlockCommentToken (String sql , int beginIndex ) {
0 commit comments