9
9
namespace SqlParser \Statements ;
10
10
11
11
use SqlParser \Statement ;
12
+ use SqlParser \Parser ;
13
+ use SqlParser \Token ;
14
+ use SqlParser \TokensList ;
12
15
use SqlParser \Components \ArrayObj ;
13
16
use SqlParser \Components \Expression ;
17
+ use SqlParser \Components \ExpressionArray ;
14
18
use SqlParser \Components \Limit ;
15
19
use SqlParser \Components \OrderKeyword ;
16
20
use SqlParser \Components \Condition ;
21
+ use SqlParser \Components \OptionsArray ;
17
22
18
23
/**
19
24
* `DELETE` statement.
24
29
* [ORDER BY ...]
25
30
* [LIMIT row_count]
26
31
*
32
+ * Multi-table syntax
33
+ *
34
+ * DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
35
+ * tbl_name[.*] [, tbl_name[.*]] ...
36
+ * FROM table_references
37
+ * [WHERE where_condition]
38
+ *
39
+ * OR
40
+ *
41
+ * DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
42
+ * FROM tbl_name[.*] [, tbl_name[.*]] ...
43
+ * USING table_references
44
+ * [WHERE where_condition]
45
+ *
46
+ *
27
47
* @category Statements
28
48
* @package SqlParser
29
49
* @subpackage Statements
@@ -44,29 +64,25 @@ class DeleteStatement extends Statement
44
64
);
45
65
46
66
/**
47
- * The clauses of this statement, in order .
67
+ * Table(s) used as sources for this statement .
48
68
*
49
- * @see Statement::$CLAUSES
69
+ * @var Expression[]
70
+ */
71
+ public $ from ;
72
+
73
+ /**
74
+ * Tables used as sources for this statement
50
75
*
51
- * @var array
76
+ * @var Expression[]
52
77
*/
53
- public static $ CLAUSES = array (
54
- 'DELETE ' => array ('DELETE ' , 2 ),
55
- // Used for options.
56
- '_OPTIONS ' => array ('_OPTIONS ' , 1 ),
57
- 'FROM ' => array ('FROM ' , 3 ),
58
- 'PARTITION ' => array ('PARTITION ' , 3 ),
59
- 'WHERE ' => array ('WHERE ' , 3 ),
60
- 'ORDER BY ' => array ('ORDER BY ' , 3 ),
61
- 'LIMIT ' => array ('LIMIT ' , 3 ),
62
- );
78
+ public $ using ;
63
79
64
80
/**
65
- * Tables used as sources for this statement.
81
+ * Columns used in this statement
66
82
*
67
83
* @var Expression[]
68
84
*/
69
- public $ from ;
85
+ public $ columns ;
70
86
71
87
/**
72
88
* Partitions used as source for this statement.
@@ -95,4 +111,220 @@ class DeleteStatement extends Statement
95
111
* @var Limit
96
112
*/
97
113
public $ limit ;
114
+
115
+
116
+ /**
117
+ * @return string
118
+ */
119
+ public function build ()
120
+ {
121
+ $ ret = 'DELETE ' . OptionsArray::build ($ this ->options );
122
+
123
+ if ($ this ->columns != NULL && count ($ this ->columns ) > 0 ) {
124
+ $ ret .= ' ' . ExpressionArray::build ($ this ->columns );
125
+ }
126
+ if ($ this ->from != NULL && count ($ this ->from ) > 0 ) {
127
+ $ ret .= ' FROM ' . ExpressionArray::build ($ this ->from );
128
+ }
129
+ if ($ this ->using != NULL && count ($ this ->using ) > 0 ) {
130
+ $ ret .= ' USING ' . ExpressionArray::build ($ this ->using );
131
+ }
132
+ if ($ this ->where != NULL && count ($ this ->where ) > 0 ) {
133
+ $ ret .= ' WHERE ' . Condition::build ($ this ->where );
134
+ }
135
+ if ($ this ->order != NULL && count ($ this ->order ) > 0 ) {
136
+ $ ret .= ' ORDER BY ' . ExpressionArray::build ($ this ->order );
137
+ }
138
+ if ($ this ->limit != NULL && count ($ this ->limit ) > 0 ) {
139
+ $ ret .= ' LIMIT ' . Limit::build ($ this ->limit );
140
+ }
141
+
142
+ return $ ret ;
143
+
144
+ }
145
+
146
+
147
+ /**
148
+ * @param Parser $parser The instance that requests parsing.
149
+ * @param TokensList $list The list of tokens to be parsed.
150
+ *
151
+ * @return void
152
+ */
153
+ public function parse (Parser $ parser , TokensList $ list )
154
+ {
155
+ ++$ list ->idx ; // Skipping `DELETE`.
156
+
157
+ // parse any options if provided
158
+ $ this ->options = OptionsArray::parse (
159
+ $ parser ,
160
+ $ list ,
161
+ static ::$ OPTIONS
162
+ );
163
+ ++$ list ->idx ;
164
+
165
+ /**
166
+ * The state of the parser.
167
+ *
168
+ * Below are the states of the parser.
169
+ *
170
+ * 0 ---------------------------------[ FROM ]----------------------------------> 2
171
+ * 0 ------------------------------[ table[.*] ]--------------------------------> 1
172
+ * 1 ---------------------------------[ FROM ]----------------------------------> 2
173
+ * 2 --------------------------------[ USING ]----------------------------------> 3
174
+ * 2 --------------------------------[ WHERE ]----------------------------------> 4
175
+ * 2 --------------------------------[ ORDER ]----------------------------------> 5
176
+ * 2 --------------------------------[ LIMIT ]----------------------------------> 6
177
+ *
178
+ * @var int $state
179
+ */
180
+ $ state = 0 ;
181
+
182
+ /**
183
+ * If the query is multi-table or not
184
+ *
185
+ * @var bool $multiTable
186
+ */
187
+ $ multiTable = false ;
188
+
189
+ for (; $ list ->idx < $ list ->count ; ++$ list ->idx ) {
190
+ /**
191
+ * Token parsed at this moment.
192
+ *
193
+ * @var Token $token
194
+ */
195
+ $ token = $ list ->tokens [$ list ->idx ];
196
+
197
+ // End of statement.
198
+ if ($ token ->type === Token::TYPE_DELIMITER ) {
199
+ break ;
200
+ }
201
+
202
+ if ($ state === 0 ) {
203
+ if ($ token ->type === Token::TYPE_KEYWORD
204
+ && $ token ->value !== 'FROM '
205
+ ) {
206
+ $ parser ->error (__ ('Unexpected keyword. ' ), $ token );
207
+ break ;
208
+ } elseif ($ token ->type === Token::TYPE_KEYWORD
209
+ && $ token ->value === 'FROM '
210
+ ) {
211
+ ++$ list ->idx ; // Skip 'FROM'
212
+ $ this ->from = ExpressionArray::parse ($ parser , $ list );
213
+ $ state = 2 ;
214
+ } else {
215
+ $ this ->columns = ExpressionArray::parse ($ parser , $ list );
216
+ $ state = 1 ;
217
+ }
218
+ } elseif ($ state === 1 ) {
219
+ if ($ token ->type === Token::TYPE_KEYWORD
220
+ && $ token ->value !== 'FROM '
221
+ ) {
222
+ $ parser ->error (__ ('Unexpected keyword. ' ), $ token );
223
+ break ;
224
+ } elseif ($ token ->type === Token::TYPE_KEYWORD
225
+ && $ token ->value === 'FROM '
226
+ ) {
227
+ ++$ list ->idx ; // Skip 'FROM'
228
+ $ this ->from = ExpressionArray::parse ($ parser , $ list );
229
+ $ state = 2 ;
230
+ } else {
231
+ $ parser ->error (__ ('Unexpected token. ' ), $ token );
232
+ break ;
233
+ }
234
+ } elseif ($ state === 2 ) {
235
+ if ($ token ->type === Token::TYPE_KEYWORD
236
+ && $ token ->value === 'USING '
237
+ ) {
238
+ ++$ list ->idx ; // Skip 'USING'
239
+ $ this ->using = ExpressionArray::parse ($ parser , $ list );
240
+ $ state = 3 ;
241
+
242
+ $ multiTable = true ;
243
+ } elseif ($ token ->type === Token::TYPE_KEYWORD
244
+ && $ token ->value === 'WHERE '
245
+ ) {
246
+ ++$ list ->idx ; // Skip 'WHERE'
247
+ $ this ->where = Condition::parse ($ parser , $ list );
248
+ $ state = 4 ;
249
+ } elseif ($ token ->type === Token::TYPE_KEYWORD
250
+ && $ token ->value === 'ORDER BY '
251
+ ) {
252
+ ++$ list ->idx ; // Skip 'ORDER BY'
253
+ $ this ->order = OrderKeyword::parse ($ parser , $ list );
254
+ $ state = 5 ;
255
+ } elseif ($ token ->type === Token::TYPE_KEYWORD
256
+ && $ token ->value === 'LIMIT '
257
+ ) {
258
+ ++$ list ->idx ; // Skip 'LIMIT'
259
+ $ this ->limit = Limit::parse ($ parser , $ list );
260
+ $ state = 6 ;
261
+ } elseif ($ token ->type === Token::TYPE_KEYWORD ) {
262
+ $ parser ->error (__ ('Unexpected keyword. ' ), $ token );
263
+ break ;
264
+ }
265
+ } elseif ($ state === 3 ) {
266
+ if ($ token ->type === Token::TYPE_KEYWORD
267
+ && $ token ->value === 'WHERE '
268
+ ) {
269
+ ++$ list ->idx ; // Skip 'WHERE'
270
+ $ this ->where = Condition::parse ($ parser , $ list );
271
+ $ state = 4 ;
272
+ } elseif ($ token ->type === Token::TYPE_KEYWORD ) {
273
+ $ parser ->error (__ ('Unexpected keyword. ' ), $ token );
274
+ break ;
275
+ } else {
276
+ $ parser ->error (__ ('Unexpected token. ' ), $ token );
277
+ break ;
278
+ }
279
+ } elseif ($ state === 4 ) {
280
+ if ($ multiTable === true
281
+ && $ token ->type === Token::TYPE_KEYWORD
282
+ ) {
283
+ $ parser ->error (
284
+ __ ('This type of clause is not valid in Multi-table queries. ' ),
285
+ $ token
286
+ );
287
+ break ;
288
+ }
289
+
290
+ if ($ token ->type === Token::TYPE_KEYWORD
291
+ && $ token ->value === 'ORDER BY '
292
+ ) {
293
+ ++$ list ->idx ; // Skip 'ORDER BY'
294
+ $ this ->order = OrderKeyword::parse ($ parser , $ list );
295
+ $ state = 5 ;
296
+ } elseif ($ token ->type === Token::TYPE_KEYWORD
297
+ && $ token ->value === 'LIMIT '
298
+ ) {
299
+ ++$ list ->idx ; // Skip 'LIMIT'
300
+ $ this ->limit = Limit::parse ($ parser , $ list );
301
+ $ state = 6 ;
302
+ } elseif ($ token ->type === Token::TYPE_KEYWORD ) {
303
+ $ parser ->error (__ ('Unexpected keyword. ' ), $ token );
304
+ break ;
305
+ }
306
+ } elseif ($ state === 5 ) {
307
+ if ($ token ->type === Token::TYPE_KEYWORD
308
+ && $ token ->value === 'LIMIT '
309
+ ) {
310
+ ++$ list ->idx ; // Skip 'LIMIT'
311
+ $ this ->limit = Limit::parse ($ parser , $ list );
312
+ $ state = 6 ;
313
+ } elseif ($ token ->type === Token::TYPE_KEYWORD ) {
314
+ $ parser ->error (__ ('Unexpected keyword. ' ), $ token );
315
+ break ;
316
+ }
317
+ }
318
+ }
319
+
320
+ if ($ state >= 2 ) {
321
+ foreach ($ this ->from as $ from_expr ) {
322
+ $ from_expr ->database = $ from_expr ->table ;
323
+ $ from_expr ->table = $ from_expr ->column ;
324
+ $ from_expr ->column = null ;
325
+ }
326
+ }
327
+
328
+ --$ list ->idx ;
329
+ }
98
330
}
0 commit comments