1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
abstract class sql_compiler { |
4
|
|
|
protected $skipDefaultOrderBy; |
5
|
|
|
protected $store; |
6
|
|
|
public $error; |
7
|
|
|
protected $join_target_properties; |
8
|
|
|
protected $offset; |
9
|
|
|
protected $limit; |
10
|
|
|
protected $cache; |
11
|
|
|
protected $path; |
12
|
|
|
protected $_SCAN_WS = array(" " => true, "\t" => true, "\n" => true ,"\r" => true); |
13
|
|
|
protected $_SCAN_AZ = array("a" => true, "A" => true, "b" => true, "B" => true, "c" => true, "C" => true, "d" => true, "D" => true, "e" => true, "E" => true, "f" => true, "F" => true, "g" => true, "G" => true, "h" => true, "H" => true, "i" => true, "I" => true, "j" => true, "J" => true, "k" => true, "K" => true, "l" => true, "L" => true, "m" => true, "M" => true, "n" => true, "N" => true, "o" => true, "O" => true, "p" => true, "P" => true, "q" => true, "Q" => true, "r" => true, "R" => true, "s" => true, "S" => true, "t" => true, "T" => true, "u" => true, "U" => true, "v" => true, "V" => true, "w" => true, "W" => true, "x" => true, "X" => true, "y" => true, "Y" => true, "z" => true, "Z" => true); |
14
|
|
|
protected $_SCAN_AZ_09 = array("a" => true, "A" => true, "b" => true, "B" => true, "c" => true, "C" => true, "d" => true, "D" => true, "e" => true, "E" => true, "f" => true, "F" => true, "g" => true, "G" => true, "h" => true, "H" => true, "i" => true, "I" => true, "j" => true, "J" => true, "k" => true, "K" => true, "l" => true, "L" => true, "m" => true, "M" => true, "n" => true, "N" => true, "o" => true, "O" => true, "p" => true, "P" => true, "q" => true, "Q" => true, "r" => true, "R" => true, "s" => true, "S" => true, "t" => true, "T" => true, "u" => true, "U" => true, "v" => true, "V" => true, "w" => true, "W" => true, "x" => true, "X" => true, "y" => true, "Y" => true, "z" => true, "Z" => true, "_" => true, "0" => true, "1" => true, "2" => true, "3" => true, "4" => true, "5" => true, "6" => true, "7" => true, "8" => true, "9" => true); |
15
|
|
|
protected $_SCAN_NUM = array("0" => true, "1" => true, "2" => true, "3" => true, "4" => true, "5" => true, "6" => true, "7" => true, "8" => true, "9" => true); |
16
|
|
|
protected $_SCAN_NUM_START = array("0" => true, "1" => true, "2" => true, "3" => true, "4" => true, "5" => true, "6" => true, "7" => true, "8" => true, "9" => true, "-" => true); |
17
|
|
|
protected $_SCAN_CMP = array("~" => array("=" => array("FIN" => true)), "=" => array("=" => array("FIN" => true), "FIN" => true, "~" => array("FIN" => true, "~" => array("FIN" => true)), "*" => array("FIN" => true, "*" => array("FIN" => true)), "/" => array("FIN" => true)), "!" => array("=" => array("FIN" => true), "~" => array("FIN" => true, "~" => array("FIN" => true)), "*" => array("FIN" => true, "*" => array("FIN" => true)), "/" => array("FIN" => true, "/" => array("FIN" => true))), "<" => array("=" => array("FIN" => true), "FIN" => true), ">" => array("=" => array("FIN" => true), "FIN" => true), "/" => array("=" => array("=" => array("FIN" => true)))); |
18
|
|
|
|
19
|
|
|
|
20
|
192 |
|
protected function parse_const(&$YYBUFFER) { |
21
|
192 |
|
$YYCURSOR = 0; |
22
|
192 |
|
while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) { |
23
|
192 |
|
$YYCURSOR++; |
24
|
144 |
|
} |
25
|
192 |
|
$value = ''; |
26
|
192 |
|
$yych = $YYBUFFER[$YYCURSOR]; |
27
|
|
|
switch (true) { |
28
|
192 |
|
case '"' === $yych: |
29
|
192 |
|
case "'" === $yych: |
30
|
190 |
|
$quote = $yych; |
31
|
190 |
|
$yych = $YYBUFFER[++$YYCURSOR]; |
32
|
190 |
|
while ($yych !== "\0" && $yych !== $quote) { |
33
|
190 |
|
if ($yych === "\\") { |
34
|
49 |
|
$yych = $YYBUFFER[++$YYCURSOR]; |
35
|
3 |
|
if ($yych !== $quote && $yych != "\\") { |
36
|
|
|
$value .= "\\"; |
37
|
|
|
} |
38
|
48 |
|
} |
39
|
190 |
|
$value .= $yych; |
40
|
190 |
|
$yych = $YYBUFFER[++$YYCURSOR]; |
41
|
142 |
|
} |
42
|
190 |
|
$YYBUFFER = substr($YYBUFFER, $YYCURSOR + 1); |
43
|
190 |
|
$node["id"] = "string"; |
|
|
|
|
44
|
190 |
|
$node["type"] = ($quote === '"') ? "double" : "single"; |
45
|
190 |
|
$node["value"] = stripslashes($value); |
46
|
190 |
|
return $node; |
47
|
|
|
break; |
48
|
2 |
|
case $this->_SCAN_NUM_START[$yych]: |
49
|
2 |
|
$value = $yych; |
50
|
2 |
|
$yych = $YYBUFFER[++$YYCURSOR]; |
51
|
2 |
|
while (isset($this->_SCAN_NUM[$yych])) { |
52
|
|
|
$value .= $yych; |
53
|
1 |
|
$yych = $YYBUFFER[++$YYCURSOR]; |
54
|
|
|
} |
55
|
2 |
|
if ($yych === '.') { |
56
|
|
|
$value .= $yych; |
57
|
|
|
$yych = $YYBUFFER[++$YYCURSOR]; |
58
|
|
|
while (isset($this->_SCAN_NUM[$yych])) { |
59
|
|
|
$value .= $yych; |
60
|
|
|
$yych = $YYBUFFER[++$YYCURSOR]; |
61
|
|
|
} |
62
|
|
|
$node["id"]="float"; |
|
|
|
|
63
|
|
|
$node["value"]=(float)$value; |
64
|
|
|
} else { |
65
|
2 |
|
$node["id"]="int"; |
|
|
|
|
66
|
2 |
|
$node["value"]=(int)$value;; |
67
|
|
|
} |
68
|
2 |
|
$YYBUFFER = substr($YYBUFFER, $YYCURSOR); |
69
|
2 |
|
return $node; |
70
|
|
|
break; |
71
|
|
|
} |
72
|
|
|
} |
73
|
|
|
|
74
|
197 |
|
protected function parse_ident(&$YYBUFFER) { |
75
|
|
|
/* parse identifier regs 1,2 and 3 |
|
|
|
|
76
|
|
|
|
77
|
|
|
reg[1]: tablename |
78
|
|
|
reg[2]: property name |
79
|
|
|
reg[3]: only used with 'my' properties |
80
|
|
|
*/ |
81
|
197 |
|
$reg_id='^[[:space:]]*(([a-z_][a-z0-9_]*)(:[a-z]+)?([.][a-z_][a-z0-9_]*)?([.][a-z_][a-z0-9_]*)?)'; |
82
|
197 |
|
$reg_id.='[[:space:]]*'; |
83
|
|
|
|
84
|
197 |
|
$YYCURSOR = 0; |
85
|
197 |
|
while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) { |
86
|
186 |
|
$YYCURSOR++; |
87
|
140 |
|
} |
88
|
197 |
|
$value = ''; |
89
|
197 |
|
$yych = $YYBUFFER[$YYCURSOR]; |
90
|
|
|
|
91
|
197 |
|
if ($this->_SCAN_AZ[$yych]) { |
92
|
196 |
|
$value .= $yych; |
93
|
196 |
|
$yych = $YYBUFFER[++$YYCURSOR]; |
94
|
196 |
|
while (isset($this->_SCAN_AZ_09[$yych])) { |
95
|
196 |
|
$value .= $yych; |
96
|
196 |
|
$yych = $YYBUFFER[++$YYCURSOR]; |
97
|
148 |
|
} |
98
|
196 |
|
$match_1 = $value; $value = ''; |
99
|
196 |
|
if ($yych === ':') { |
100
|
|
|
$yych = $YYBUFFER[++$YYCURSOR]; |
101
|
|
|
while (isset($this->_SCAN_AZ[$yych])) { |
102
|
|
|
$value .= $yych; |
103
|
|
|
$yych = $YYBUFFER[++$YYCURSOR]; |
104
|
|
|
} |
105
|
|
|
$record_id = $value; $value = ''; |
106
|
|
|
} |
107
|
196 |
View Code Duplication |
if ($yych === '.') { |
108
|
193 |
|
$yych = $YYBUFFER[++$YYCURSOR]; |
109
|
193 |
|
if ($this->_SCAN_AZ[$yych]) { |
110
|
193 |
|
$value .= $yych; |
111
|
193 |
|
$yych = $YYBUFFER[++$YYCURSOR]; |
112
|
193 |
|
while (isset($this->_SCAN_AZ_09[$yych])) { |
113
|
193 |
|
$value .= $yych; |
114
|
193 |
|
$yych = $YYBUFFER[++$YYCURSOR]; |
115
|
145 |
|
} |
116
|
145 |
|
} |
117
|
193 |
|
$match_2 = $value; $value = ''; |
118
|
145 |
|
} |
119
|
196 |
View Code Duplication |
if ($yych === '.') { |
120
|
|
|
$yych = $YYBUFFER[++$YYCURSOR]; |
121
|
|
|
if ($this->_SCAN_AZ[$yych]) { |
122
|
|
|
$value .= $yych; |
123
|
|
|
$yych = $YYBUFFER[++$YYCURSOR]; |
124
|
|
|
while (isset($this->_SCAN_AZ_09[$yych])) { |
125
|
|
|
$value .= $yych; |
126
|
|
|
$yych = $YYBUFFER[++$YYCURSOR]; |
127
|
|
|
} |
128
|
|
|
} |
129
|
|
|
$match_3 = $value; $value = ''; |
|
|
|
|
130
|
|
|
} |
131
|
|
|
|
132
|
148 |
|
} |
133
|
|
|
|
134
|
|
|
|
135
|
197 |
|
if($match_1) { |
136
|
196 |
|
if (!$match_2) { |
|
|
|
|
137
|
|
|
/* default table is 'object' */ |
138
|
51 |
|
$match_2 = $match_1; |
|
|
|
|
139
|
51 |
|
$match_1 = "object"; |
140
|
39 |
|
} |
141
|
196 |
|
$node["id"]="ident"; |
|
|
|
|
142
|
|
|
|
143
|
196 |
|
$table=$match_1; |
144
|
196 |
|
$field=$match_2; |
145
|
196 |
|
if ($table=="object") { |
146
|
|
|
switch ($field) { |
147
|
189 |
|
case "implements": |
148
|
184 |
|
$node["id"]="implements"; |
149
|
184 |
|
break; |
150
|
53 |
|
case "path": |
151
|
53 |
|
case "parent": |
152
|
53 |
|
case "priority": |
153
|
1 |
|
$node["table"]="nodes"; |
154
|
1 |
|
$node["field"]=$field; |
155
|
1 |
|
break; |
156
|
41 |
|
default: |
157
|
53 |
|
$node["table"]="objects"; |
158
|
87 |
|
$node["field"]=$field; |
159
|
41 |
|
} |
160
|
143 |
|
} else |
161
|
191 |
|
if ($table === "my") { |
162
|
|
|
$node["id"] = "custom"; |
163
|
|
|
if ($match_3) { |
164
|
|
|
$node["nls"] = $field; |
165
|
|
|
$field = $match_3; |
|
|
|
|
166
|
|
|
} |
167
|
|
|
$node["field"] = $field; |
168
|
|
|
$node["record_id"] = $record_id; |
|
|
|
|
169
|
|
|
} else { |
170
|
191 |
|
$node["id"]="property"; |
171
|
191 |
|
if ($match_3) { |
172
|
|
|
$node["nls"] = $field; |
173
|
|
|
$field = $match_3; |
174
|
|
|
} |
175
|
191 |
|
$node["table"]="prop_".$table; |
176
|
191 |
|
$node["field"]="AR_".$field; |
177
|
191 |
|
$node["record_id"] = $record_id; |
178
|
|
|
} |
179
|
148 |
|
} |
180
|
197 |
|
$YYBUFFER = substr($YYBUFFER, $YYCURSOR); |
181
|
197 |
|
return $node; |
|
|
|
|
182
|
|
|
} |
183
|
|
|
|
184
|
195 |
|
protected function parse_cmp_expr(&$YYBUFFER) { |
185
|
195 |
|
$result=$this->parse_ident($YYBUFFER); |
186
|
195 |
|
if ($result) { |
|
|
|
|
187
|
194 |
|
$YYCURSOR = 0; |
188
|
194 |
|
while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) { |
189
|
193 |
|
$YYCURSOR++; |
190
|
145 |
|
} |
191
|
194 |
|
$yych = $YYBUFFER[$YYCURSOR]; |
192
|
194 |
|
$YYCURSOR_START = $YYCURSOR; |
193
|
194 |
|
$RULES = &$this->_SCAN_CMP; |
194
|
194 |
|
while (isset($RULES[$yych])) { |
195
|
192 |
|
$RULES = &$RULES[$yych]; |
196
|
192 |
|
if (isset($RULES['FIN'])) { |
197
|
192 |
|
$YYMATCH = $YYCURSOR; |
198
|
144 |
|
} |
199
|
192 |
|
$yych = $YYBUFFER[++$YYCURSOR]; |
200
|
144 |
|
} |
201
|
194 |
|
if (isset($YYMATCH)) { |
202
|
192 |
|
$node["id"]="cmp"; |
|
|
|
|
203
|
192 |
|
$node["operator"]=substr($YYBUFFER, $YYCURSOR_START, ($YYMATCH + 1) - $YYCURSOR_START); |
204
|
192 |
|
$node["left"]=$result; |
205
|
192 |
|
$YYBUFFER = substr($YYBUFFER, $YYCURSOR); |
206
|
192 |
|
$result=$this->parse_const($YYBUFFER); |
207
|
192 |
|
if ($result) { |
208
|
192 |
|
$node["right"]=$result; |
209
|
144 |
|
} |
210
|
192 |
|
$result=$node; |
211
|
144 |
|
} else { |
212
|
2 |
|
$this->error="unknow compare-operator near '$YYBUFFER'"; |
213
|
|
|
} |
214
|
146 |
|
} |
215
|
195 |
|
return $result; |
216
|
|
|
} |
217
|
|
|
|
218
|
195 |
|
protected function parse_group_expr(&$YYBUFFER) { |
219
|
195 |
|
$YYCURSOR = 0; |
220
|
195 |
|
while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) { |
221
|
186 |
|
$YYCURSOR++; |
222
|
140 |
|
} |
223
|
195 |
|
$yych = $YYBUFFER[$YYCURSOR++]; |
224
|
195 |
|
if ($yych === '(') { |
225
|
|
|
$YYBUFFER = substr($YYBUFFER, $YYCURSOR); |
226
|
|
|
$result = $this->parse_or_expr($YYBUFFER); |
227
|
|
|
$YYCURSOR = 0; |
228
|
|
|
while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) { |
229
|
|
|
$YYCURSOR++; |
230
|
|
|
} |
231
|
|
|
$yych = $YYBUFFER[$YYCURSOR++]; |
232
|
|
|
if ($yych === ')') { |
233
|
|
|
$YYBUFFER = substr($YYBUFFER, $YYCURSOR); |
234
|
|
|
$node["id"]="group"; |
|
|
|
|
235
|
|
|
$node["left"]=$result; |
236
|
|
|
$result=$node; |
237
|
|
|
} else { |
238
|
|
|
unset($result); |
239
|
|
|
$this->error = "missing closing group sign near '$YYBUFFER'"; |
240
|
|
|
} |
241
|
|
|
} else { |
242
|
195 |
|
$result = $this->parse_cmp_expr($YYBUFFER); |
243
|
|
|
} |
244
|
195 |
|
return $result; |
245
|
|
|
} |
246
|
|
|
|
247
|
195 |
View Code Duplication |
protected function parse_and_expr(&$YYBUFFER) { |
|
|
|
|
248
|
195 |
|
$result=$this->parse_group_expr($YYBUFFER); |
249
|
195 |
|
while (is_array($result)) { |
250
|
194 |
|
$YYCURSOR = 0; |
251
|
194 |
|
while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) { |
252
|
185 |
|
$YYCURSOR++; |
253
|
139 |
|
} |
254
|
194 |
|
$ident = strtolower(substr($YYBUFFER, $YYCURSOR, 3)); |
255
|
194 |
|
if ($ident === 'and' && !isset($this->_SCAN_AZ_09[$YYBUFFER[$YYCURSOR + 3]]) ) { |
256
|
184 |
|
$YYBUFFER = substr($YYBUFFER, $YYCURSOR + 3); |
257
|
184 |
|
$right = $this->parse_group_expr($YYBUFFER); |
258
|
184 |
|
if (is_array($right)) { |
259
|
|
|
$result = array( |
260
|
184 |
|
'id' => $ident, |
261
|
184 |
|
'left' => $result, |
262
|
46 |
|
'right' => $right |
263
|
138 |
|
); |
264
|
138 |
|
} else { |
265
|
46 |
|
unset($result); |
266
|
|
|
} |
267
|
138 |
|
} else { |
268
|
194 |
|
break; |
269
|
|
|
} |
270
|
138 |
|
} |
271
|
195 |
|
return $result; |
272
|
|
|
} |
273
|
|
|
|
274
|
195 |
View Code Duplication |
protected function parse_or_expr(&$YYBUFFER) { |
|
|
|
|
275
|
195 |
|
$result=$this->parse_and_expr($YYBUFFER); |
276
|
195 |
|
while (is_array($result)) { |
277
|
194 |
|
$YYCURSOR = 0; |
278
|
194 |
|
while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) { |
279
|
49 |
|
$YYCURSOR++; |
280
|
37 |
|
} |
281
|
194 |
|
$ident = strtolower(substr($YYBUFFER, $YYCURSOR, 2)); |
282
|
194 |
|
if ($ident === 'or' && !isset($this->_SCAN_AZ_09[$YYBUFFER[$YYCURSOR + 2]]) ) { |
283
|
|
|
$YYBUFFER = substr($YYBUFFER, $YYCURSOR + 2); |
284
|
|
|
$right = $this->parse_and_expr($YYBUFFER); |
285
|
|
|
if (is_array($right)) { |
286
|
|
|
$result = array( |
287
|
|
|
'id' => $ident, |
288
|
|
|
'left' => $result, |
289
|
|
|
'right' => $right |
290
|
|
|
); |
291
|
|
|
} else { |
292
|
|
|
unset($result); |
293
|
|
|
} |
294
|
|
|
} else { |
295
|
194 |
|
break; |
296
|
|
|
} |
297
|
|
|
} |
298
|
195 |
|
return $result; |
299
|
|
|
} |
300
|
|
|
|
301
|
122 |
|
protected function parse_orderby(&$YYBUFFER) { |
302
|
50 |
|
$field = $this->parse_ident($YYBUFFER); |
303
|
|
|
|
304
|
50 |
|
$YYCURSOR = 0; |
305
|
86 |
|
while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) { |
306
|
1 |
|
$YYCURSOR++; |
307
|
1 |
|
} |
308
|
50 |
|
$value = ''; |
309
|
50 |
|
$yych = $YYBUFFER[$YYCURSOR]; |
310
|
50 |
View Code Duplication |
if ($this->_SCAN_AZ[$yych]) { |
311
|
1 |
|
$value .= $yych; |
312
|
1 |
|
$yych = $YYBUFFER[++$YYCURSOR]; |
313
|
1 |
|
while (isset($this->_SCAN_AZ[$yych])) { |
314
|
1 |
|
$value .= $yych; |
315
|
1 |
|
$yych = $YYBUFFER[++$YYCURSOR]; |
316
|
1 |
|
} |
317
|
1 |
|
$sort_type = strtoupper($value); |
318
|
1 |
|
if (!($sort_type == 'ASC' || $sort_type == 'DESC')) { // If sort type is anything else than ASC or DESC, it is not part of the order by. |
319
|
1 |
|
$sort_type = 'ASC'; |
320
|
1 |
|
$YYCURSOR = $YYCURSOR - strlen($value); |
321
|
49 |
|
$value = ''; |
|
|
|
|
322
|
1 |
|
} |
323
|
1 |
|
} else { |
324
|
49 |
|
$sort_type = 'ASC'; |
325
|
|
|
} |
326
|
50 |
|
while (is_array($field)) { |
327
|
|
|
$result = array( |
328
|
86 |
|
'id' => 'orderbyfield', |
329
|
50 |
|
'type' => $sort_type, |
330
|
50 |
|
'right' => $field, |
331
|
12 |
|
'left' => $result |
|
|
|
|
332
|
38 |
|
); |
333
|
50 |
|
while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) { |
334
|
|
|
$YYCURSOR++; |
335
|
|
|
} |
336
|
50 |
|
$yych = $YYBUFFER[$YYCURSOR]; |
337
|
50 |
|
if ($yych !== ',') { |
338
|
50 |
|
$YYBUFFER = substr($YYBUFFER, $YYCURSOR); |
339
|
50 |
|
unset($field); |
340
|
38 |
|
} else { |
341
|
1 |
|
$YYBUFFER = substr($YYBUFFER, $YYCURSOR + 1); |
342
|
1 |
|
$field = $this->parse_ident($YYBUFFER); |
343
|
1 |
|
$YYCURSOR = 0; |
344
|
1 |
|
while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) { |
345
|
48 |
|
$YYCURSOR++; |
346
|
|
|
} |
347
|
1 |
|
$value = ''; |
348
|
1 |
|
$yych = $YYBUFFER[$YYCURSOR]; |
349
|
49 |
View Code Duplication |
if ($this->_SCAN_AZ[$yych]) { |
350
|
|
|
$value .= $yych; |
351
|
|
|
$yych = $YYBUFFER[++$YYCURSOR]; |
352
|
|
|
while (isset($this->_SCAN_AZ[$yych])) { |
353
|
|
|
$value .= $yych; |
354
|
|
|
$yych = $YYBUFFER[++$YYCURSOR]; |
355
|
|
|
} |
356
|
|
|
$sort_type = strtoupper($value); |
357
|
|
|
if (!($sort_type == 'ASC' || $sort_type == 'DESC')) { // If sort type is anything else than ASC or DESC, it is not part of the order by. |
358
|
|
|
$sort_type = 'ASC'; |
359
|
|
|
$YYCURSOR = $YYCURSOR - strlen($value); |
360
|
|
|
$value = ''; |
|
|
|
|
361
|
|
|
} |
362
|
|
|
} else { |
363
|
1 |
|
$sort_type = 'ASC'; |
364
|
|
|
} |
365
|
|
|
} |
366
|
38 |
|
} |
367
|
50 |
|
return $result; |
368
|
|
|
} |
369
|
|
|
|
370
|
|
|
|
371
|
|
|
protected function parse_join_target_properties(&$query) { |
372
|
|
|
do { |
373
|
|
|
if (!preg_match('/^([a-z_][a-z0-9_]*)(:[a-z]+)?/i', $query, $regs)) { |
374
|
|
|
$this->error = "expected property name at '$query'"; |
375
|
|
|
return false; |
376
|
|
|
} |
377
|
|
|
$this->join_target_properties["prop_".$regs[1]][$regs[2]] = true; |
378
|
|
|
$query = substr($query, strlen($regs[0])); |
379
|
|
|
|
380
|
|
|
if (!preg_match('/^[[:space:]]*,[[:space:]]*/', $query, $regs)) { |
381
|
|
|
return true; |
382
|
|
|
} |
383
|
|
|
$query = substr($query, strlen($regs[0])); |
384
|
|
|
} while(1); |
385
|
|
|
} |
386
|
|
|
|
387
|
197 |
|
protected function parse_query(&$query) { |
388
|
|
|
|
389
|
197 |
|
if (!preg_match('|^[[:space:]]*order[[:space:]]*by[[:space:]]+|i', $query, $regs)) { |
390
|
195 |
|
$result=$this->parse_or_expr($query); |
391
|
147 |
|
} else { |
392
|
2 |
|
$no_selection = true; |
393
|
|
|
} |
394
|
|
|
|
395
|
|
|
/* |
|
|
|
|
396
|
|
|
$YYCURSOR = 0; |
397
|
|
|
while ($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]]) { |
398
|
|
|
$YYCURSOR++; |
399
|
|
|
} |
400
|
|
|
|
401
|
|
|
$yych = $YYBUFFER[$YYCURSOR]; |
402
|
|
|
if ($this->_SCAN_AZ[$yych]) { |
403
|
|
|
$value = $yych; |
404
|
|
|
$yych = $YYBUFFER[++$YYCURSOR]; |
405
|
|
|
while ($this->_SCAN_AZ[$yych]) { |
406
|
|
|
$value .= $yych; |
407
|
|
|
$yych = $YYBUFFER[++$YYCURSOR]; |
408
|
|
|
} |
409
|
|
|
$value = strtolower($value); |
410
|
|
|
if ($value === 'order') { |
411
|
|
|
while ($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]]) { |
412
|
|
|
$YYCURSOR++; |
413
|
|
|
} |
414
|
|
|
$yych = $YYBUFFER[$YYCURSOR]; |
415
|
|
|
if ($this->_SCAN_AZ[$yych]) { |
416
|
|
|
$value = $yych; |
417
|
|
|
$yych = $YYBUFFER[++$YYCURSOR]; |
418
|
|
|
while ($this->_SCAN_AZ[$yych]) { |
419
|
|
|
$value .= $yych; |
420
|
|
|
$yych = $YYBUFFER[++$YYCURSOR]; |
421
|
|
|
} |
422
|
|
|
$value = strtolower($value); |
423
|
|
|
if ($value === 'by') { |
424
|
|
|
$YYBUFFER = substr($YYBUFFER, $YYCURSOR; |
425
|
|
|
$result = $this->parse_or_expr($YYBUFFER); |
426
|
|
|
$YYCURSOR = 0; |
427
|
|
|
$value = ''; |
428
|
|
|
} else { |
429
|
|
|
$this->error = "syntax error near: $YYBUFFER"; |
430
|
|
|
return false; |
431
|
|
|
} |
432
|
|
|
} |
433
|
|
|
} |
434
|
|
|
} |
435
|
|
|
|
436
|
|
|
*/ |
437
|
|
|
|
438
|
197 |
|
if (preg_match('|^[[:space:]]*join[[:space:]]*target[[:space:]]*on[[:space:]]*|i', $query, $regs)) { |
439
|
|
|
$this->join_target_properties = array(); |
440
|
|
|
$query = substr($query, strlen($regs[0])); |
441
|
|
|
$this->parse_join_target_properties($query); |
442
|
|
|
} |
443
|
|
|
|
444
|
197 |
|
$matching = preg_match('|^[[:space:]]*order[[:space:]]*by[[:space:]]+|i', $query, $regs); |
445
|
197 |
|
if ( $matching || $no_selection ) { |
|
|
|
|
446
|
50 |
|
$query=substr($query, strlen($regs[0])); |
447
|
50 |
|
$node["id"]="orderby"; |
|
|
|
|
448
|
50 |
|
$node["right"]=$this->parse_orderby($query); |
449
|
50 |
|
$node["left"]=$result; |
|
|
|
|
450
|
50 |
|
$result=$node; |
451
|
38 |
|
} |
452
|
197 |
|
if (preg_match('|^[[:space:]]*limit[[:space:]]+([0-9]+)[[:space:]]*([,][[:space:]]*([0-9]+))?|i', $query, $regs)) { |
453
|
1 |
|
$query=substr($query, strlen($regs[0])); |
454
|
1 |
|
$limit_s["id"]="limit"; |
|
|
|
|
455
|
1 |
|
$limit_s["offset"]=$regs[1]; |
456
|
1 |
|
$limit_s["limit"]=$regs[3]; |
457
|
1 |
|
} else { |
458
|
196 |
|
$limit_s["id"]="limit"; |
|
|
|
|
459
|
196 |
|
$limit_s["offset"]=($this->offset) ? $this->offset : 0; |
460
|
196 |
|
$limit_s["limit"]=($this->limit) ? $this->limit : 0; |
461
|
|
|
} |
462
|
197 |
|
$limit_s["left"]=$result; |
463
|
197 |
|
$result=$limit_s; |
464
|
|
|
|
465
|
197 |
|
return $result; |
466
|
|
|
} |
467
|
|
|
|
468
|
|
|
// virtual (&private) method. To be implemented in the sql specific compiler |
469
|
|
|
protected abstract function priv_sql_compile($node) ; |
|
|
|
|
470
|
|
|
|
471
|
197 |
|
public function compile($path, $query, $limit=100, $offset=0, $layers = array()) { |
472
|
197 |
|
debug("sql_compiler::compile ($path, $query, $limit, $offset)", "store"); |
473
|
197 |
|
$this->error=""; |
474
|
197 |
|
$this->path = $path; |
475
|
|
|
|
476
|
197 |
|
$this->limit=$limit; |
477
|
197 |
|
$this->offset=$offset; |
478
|
197 |
|
$this->layers=$layers; |
|
|
|
|
479
|
|
|
|
480
|
197 |
|
$tree=$this->parse_query($query); |
481
|
|
|
|
482
|
197 |
|
if ( $this->error ) { |
483
|
2 |
|
return null; |
484
|
195 |
|
} else if ( trim($query) ) { |
485
|
|
|
// no error detected, but there is still a part of the query left |
486
|
|
|
$this->error="unkown operator near '$query'"; |
487
|
|
|
return null; |
488
|
195 |
|
} else if ( $tree ) { |
|
|
|
|
489
|
195 |
|
$compiled_query=$this->priv_sql_compile($tree); |
490
|
195 |
|
return $compiled_query; |
491
|
|
|
} else { |
492
|
|
|
return null; |
493
|
|
|
} |
494
|
|
|
|
495
|
|
|
} |
496
|
|
|
|
497
|
|
|
|
498
|
|
|
} |
499
|
|
|
|
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.
Let’s take a look at an example:
As you can see in this example, the array
$myArray
is initialized the first time when the foreach loop is entered. You can also see that the value of thebar
key is only written conditionally; thus, its value might result from a previous iteration.This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.