250 |
kaklik |
1 |
<?php |
|
|
2 |
/* $Id: sqlparser.lib.php,v 2.47 2006/01/17 17:02:30 cybot_tm Exp $ */ |
|
|
3 |
// vim: expandtab sw=4 ts=4 sts=4: |
|
|
4 |
|
|
|
5 |
/** SQL Parser Functions for phpMyAdmin |
|
|
6 |
* |
|
|
7 |
* Copyright 2002 Robin Johnson <robbat2@users.sourceforge.net> |
|
|
8 |
* http://www.orbis-terrarum.net/?l=people.robbat2 |
|
|
9 |
* |
|
|
10 |
* These functions define an SQL parser system, capable of understanding and |
|
|
11 |
* extracting data from a MySQL type SQL query. |
|
|
12 |
* |
|
|
13 |
* The basic procedure for using the new SQL parser: |
|
|
14 |
* On any page that needs to extract data from a query or to pretty-print a |
|
|
15 |
* query, you need code like this up at the top: |
|
|
16 |
* |
|
|
17 |
* ($sql contains the query) |
|
|
18 |
* $parsed_sql = PMA_SQP_parse($sql); |
|
|
19 |
* |
|
|
20 |
* If you want to extract data from it then, you just need to run |
|
|
21 |
* $sql_info = PMA_SQP_analyze($parsed_sql); |
|
|
22 |
* |
|
|
23 |
* lem9: See comments in PMA_SQP_analyze for the returned info |
|
|
24 |
* from the analyzer. |
|
|
25 |
* |
|
|
26 |
* If you want a pretty-printed version of the query, do: |
|
|
27 |
* $string = PMA_SQP_formatHtml($parsed_sql); |
|
|
28 |
* (note that that you need to have syntax.css.php included somehow in your |
|
|
29 |
* page for it to work, I recommend '<link rel="stylesheet" type="text/css" |
|
|
30 |
* href="syntax.css.php" />' at the moment.) |
|
|
31 |
*/ |
|
|
32 |
|
|
|
33 |
|
|
|
34 |
/** |
|
|
35 |
* Minimum inclusion? (i.e. for the stylesheet builder) |
|
|
36 |
*/ |
|
|
37 |
if ( ! defined( 'PMA_MINIMUM_COMMON' ) ) { |
|
|
38 |
/** |
|
|
39 |
* Include the string library as we use it heavily |
|
|
40 |
*/ |
|
|
41 |
require_once('./libraries/string.lib.php'); |
|
|
42 |
|
|
|
43 |
/** |
|
|
44 |
* Include data for the SQL Parser |
|
|
45 |
*/ |
|
|
46 |
require_once('./libraries/sqlparser.data.php'); |
|
|
47 |
require_once('./libraries/mysql_charsets.lib.php'); |
|
|
48 |
if (!isset($mysql_charsets)) { |
|
|
49 |
$mysql_charsets = array(); |
|
|
50 |
$mysql_charsets_count = 0; |
|
|
51 |
$mysql_collations_flat = array(); |
|
|
52 |
$mysql_collations_count = 0; |
|
|
53 |
} |
|
|
54 |
|
|
|
55 |
if (!defined('DEBUG_TIMING')) { |
|
|
56 |
function PMA_SQP_arrayAdd(&$arr, $type, $data, &$arrsize) |
|
|
57 |
{ |
|
|
58 |
$arr[] = array('type' => $type, 'data' => $data); |
|
|
59 |
$arrsize++; |
|
|
60 |
} // end of the "PMA_SQP_arrayAdd()" function |
|
|
61 |
} else { |
|
|
62 |
function PMA_SQP_arrayAdd(&$arr, $type, $data, &$arrsize) |
|
|
63 |
{ |
|
|
64 |
global $timer; |
|
|
65 |
|
|
|
66 |
$t = $timer; |
|
|
67 |
$arr[] = array('type' => $type, 'data' => $data, 'time' => $t); |
|
|
68 |
$timer = microtime(); |
|
|
69 |
$arrsize++; |
|
|
70 |
} // end of the "PMA_SQP_arrayAdd()" function |
|
|
71 |
} // end if... else... |
|
|
72 |
|
|
|
73 |
|
|
|
74 |
/** |
|
|
75 |
* Reset the error variable for the SQL parser |
|
|
76 |
* |
|
|
77 |
* @access public |
|
|
78 |
*/ |
|
|
79 |
// Added, Robbat2 - 13 Janurary 2003, 2:59PM |
|
|
80 |
function PMA_SQP_resetError() |
|
|
81 |
{ |
|
|
82 |
global $SQP_errorString; |
|
|
83 |
$SQP_errorString = ''; |
|
|
84 |
unset($SQP_errorString); |
|
|
85 |
} |
|
|
86 |
|
|
|
87 |
/** |
|
|
88 |
* Get the contents of the error variable for the SQL parser |
|
|
89 |
* |
|
|
90 |
* @return string Error string from SQL parser |
|
|
91 |
* |
|
|
92 |
* @access public |
|
|
93 |
*/ |
|
|
94 |
// Added, Robbat2 - 13 Janurary 2003, 2:59PM |
|
|
95 |
function PMA_SQP_getErrorString() |
|
|
96 |
{ |
|
|
97 |
global $SQP_errorString; |
|
|
98 |
return isset($SQP_errorString) ? $SQP_errorString : ''; |
|
|
99 |
} |
|
|
100 |
|
|
|
101 |
/** |
|
|
102 |
* Check if the SQL parser hit an error |
|
|
103 |
* |
|
|
104 |
* @return boolean error state |
|
|
105 |
* |
|
|
106 |
* @access public |
|
|
107 |
*/ |
|
|
108 |
// Added, Robbat2 - 13 Janurary 2003, 2:59PM |
|
|
109 |
function PMA_SQP_isError() |
|
|
110 |
{ |
|
|
111 |
global $SQP_errorString; |
|
|
112 |
return isset($SQP_errorString) && !empty($SQP_errorString); |
|
|
113 |
} |
|
|
114 |
|
|
|
115 |
/** |
|
|
116 |
* Set an error message for the system |
|
|
117 |
* |
|
|
118 |
* @param string The error message |
|
|
119 |
* @param string The failing SQL query |
|
|
120 |
* |
|
|
121 |
* @access private |
|
|
122 |
* @scope SQL Parser internal |
|
|
123 |
*/ |
|
|
124 |
// Revised, Robbat2 - 13 Janurary 2003, 2:59PM |
|
|
125 |
function PMA_SQP_throwError($message, $sql) |
|
|
126 |
{ |
|
|
127 |
|
|
|
128 |
global $SQP_errorString; |
|
|
129 |
$SQP_errorString = '<p>'.$GLOBALS['strSQLParserUserError'] . '</p>' . "\n" |
|
|
130 |
. '<pre>' . "\n" |
|
|
131 |
. 'ERROR: ' . $message . "\n" |
|
|
132 |
. 'SQL: ' . htmlspecialchars($sql) . "\n" |
|
|
133 |
. '</pre>' . "\n"; |
|
|
134 |
|
|
|
135 |
} // end of the "PMA_SQP_throwError()" function |
|
|
136 |
|
|
|
137 |
|
|
|
138 |
/** |
|
|
139 |
* Do display the bug report |
|
|
140 |
* |
|
|
141 |
* @param string The error message |
|
|
142 |
* @param string The failing SQL query |
|
|
143 |
* |
|
|
144 |
* @access public |
|
|
145 |
*/ |
|
|
146 |
function PMA_SQP_bug($message, $sql) |
|
|
147 |
{ |
|
|
148 |
global $SQP_errorString; |
|
|
149 |
$debugstr = 'ERROR: ' . $message . "\n"; |
|
|
150 |
$debugstr .= 'CVS: $Id: sqlparser.lib.php,v 2.47 2006/01/17 17:02:30 cybot_tm Exp $' . "\n"; |
|
|
151 |
$debugstr .= 'MySQL: '.PMA_MYSQL_STR_VERSION . "\n"; |
|
|
152 |
$debugstr .= 'USR OS, AGENT, VER: ' . PMA_USR_OS . ' ' . PMA_USR_BROWSER_AGENT . ' ' . PMA_USR_BROWSER_VER . "\n"; |
|
|
153 |
$debugstr .= 'PMA: ' . PMA_VERSION . "\n"; |
|
|
154 |
$debugstr .= 'PHP VER,OS: ' . PMA_PHP_STR_VERSION . ' ' . PHP_OS . "\n"; |
|
|
155 |
$debugstr .= 'LANG: ' . $GLOBALS['lang'] . "\n"; |
|
|
156 |
$debugstr .= 'SQL: ' . htmlspecialchars($sql); |
|
|
157 |
|
|
|
158 |
$encodedstr = $debugstr; |
|
|
159 |
if (@function_exists('gzcompress')) { |
|
|
160 |
$encodedstr = gzcompress($debugstr, 9); |
|
|
161 |
} |
|
|
162 |
$encodedstr = preg_replace("/(\015\012)|(\015)|(\012)/", '<br />' . "\n", chunk_split(base64_encode($encodedstr))); |
|
|
163 |
|
|
|
164 |
$SQP_errorString .= $GLOBALS['strSQLParserBugMessage'] . '<br />' . "\n" |
|
|
165 |
. '----' . $GLOBALS['strBeginCut'] . '----' . '<br />' . "\n" |
|
|
166 |
. $encodedstr . "\n" |
|
|
167 |
. '----' . $GLOBALS['strEndCut'] . '----' . '<br />' . "\n"; |
|
|
168 |
|
|
|
169 |
$SQP_errorString .= '----' . $GLOBALS['strBeginRaw'] . '----<br />' . "\n" |
|
|
170 |
. '<pre>' . "\n" |
|
|
171 |
. $debugstr |
|
|
172 |
. '</pre>' . "\n" |
|
|
173 |
. '----' . $GLOBALS['strEndRaw'] . '----<br />' . "\n"; |
|
|
174 |
|
|
|
175 |
} // end of the "PMA_SQP_bug()" function |
|
|
176 |
|
|
|
177 |
|
|
|
178 |
/** |
|
|
179 |
* Parses the SQL queries |
|
|
180 |
* |
|
|
181 |
* @param string The SQL query list |
|
|
182 |
* |
|
|
183 |
* @return mixed Most of times, nothing... |
|
|
184 |
* |
|
|
185 |
* @global array The current PMA configuration |
|
|
186 |
* @global array MySQL column attributes |
|
|
187 |
* @global array MySQL reserved words |
|
|
188 |
* @global array MySQL column types |
|
|
189 |
* @global array MySQL function names |
|
|
190 |
* @global integer MySQL column attributes count |
|
|
191 |
* @global integer MySQL reserved words count |
|
|
192 |
* @global integer MySQL column types count |
|
|
193 |
* @global integer MySQL function names count |
|
|
194 |
* @global array List of available character sets |
|
|
195 |
* @global array List of available collations |
|
|
196 |
* @global integer Character sets count |
|
|
197 |
* @global integer Collations count |
|
|
198 |
* |
|
|
199 |
* @access public |
|
|
200 |
*/ |
|
|
201 |
function PMA_SQP_parse($sql) |
|
|
202 |
{ |
|
|
203 |
global $cfg; |
|
|
204 |
global $PMA_SQPdata_column_attrib, $PMA_SQPdata_reserved_word, $PMA_SQPdata_column_type, $PMA_SQPdata_function_name, |
|
|
205 |
$PMA_SQPdata_column_attrib_cnt, $PMA_SQPdata_reserved_word_cnt, $PMA_SQPdata_column_type_cnt, $PMA_SQPdata_function_name_cnt; |
|
|
206 |
global $mysql_charsets, $mysql_collations_flat, $mysql_charsets_count, $mysql_collations_count; |
|
|
207 |
global $PMA_SQPdata_forbidden_word, $PMA_SQPdata_forbidden_word_cnt; |
|
|
208 |
|
|
|
209 |
// rabus: Convert all line feeds to Unix style |
|
|
210 |
$sql = str_replace("\r\n", "\n", $sql); |
|
|
211 |
$sql = str_replace("\r", "\n", $sql); |
|
|
212 |
|
|
|
213 |
$len = PMA_strlen($sql); |
|
|
214 |
if ($len == 0) { |
|
|
215 |
return array(); |
|
|
216 |
} |
|
|
217 |
|
|
|
218 |
$sql_array = array(); |
|
|
219 |
$sql_array['raw'] = $sql; |
|
|
220 |
$count1 = 0; |
|
|
221 |
$count2 = 0; |
|
|
222 |
$punct_queryend = ';'; |
|
|
223 |
$punct_qualifier = '.'; |
|
|
224 |
$punct_listsep = ','; |
|
|
225 |
$punct_level_plus = '('; |
|
|
226 |
$punct_level_minus = ')'; |
|
|
227 |
$digit_floatdecimal = '.'; |
|
|
228 |
$digit_hexset = 'x'; |
|
|
229 |
$bracket_list = '()[]{}'; |
|
|
230 |
$allpunct_list = '-,;:!?/.^~\*&%+<=>|'; |
|
|
231 |
$allpunct_list_pair = array ( |
|
|
232 |
|
|
|
233 |
1 => '&&', |
|
|
234 |
2 => ':=', |
|
|
235 |
3 => '<<', |
|
|
236 |
4 => '<=', |
|
|
237 |
5 => '<=>', |
|
|
238 |
6 => '<>', |
|
|
239 |
7 => '>=', |
|
|
240 |
8 => '>>', |
|
|
241 |
9 => '||' |
|
|
242 |
); |
|
|
243 |
$allpunct_list_pair_size = 10; //count($allpunct_list_pair); |
|
|
244 |
$quote_list = '\'"`'; |
|
|
245 |
$arraysize = 0; |
|
|
246 |
|
|
|
247 |
while ($count2 < $len) { |
|
|
248 |
$c = PMA_substr($sql, $count2, 1); |
|
|
249 |
$count1 = $count2; |
|
|
250 |
|
|
|
251 |
if (($c == "\n")) { |
|
|
252 |
$count2++; |
|
|
253 |
PMA_SQP_arrayAdd($sql_array, 'white_newline', '', $arraysize); |
|
|
254 |
continue; |
|
|
255 |
} |
|
|
256 |
|
|
|
257 |
// Checks for white space |
|
|
258 |
if (PMA_STR_isSpace($c)) { |
|
|
259 |
$count2++; |
|
|
260 |
continue; |
|
|
261 |
} |
|
|
262 |
|
|
|
263 |
// Checks for comment lines. |
|
|
264 |
// MySQL style # |
|
|
265 |
// C style /* */ |
|
|
266 |
// ANSI style -- |
|
|
267 |
if (($c == '#') |
|
|
268 |
|| (($count2 + 1 < $len) && ($c == '/') && (PMA_substr($sql, $count2 + 1, 1) == '*')) |
|
|
269 |
|| (($count2 + 2 == $len) && ($c == '-') && (PMA_substr($sql, $count2 + 1, 1) == '-')) |
|
|
270 |
|| (($count2 + 2 < $len) && ($c == '-') && (PMA_substr($sql, $count2 + 1, 1) == '-') && ((PMA_substr($sql, $count2 + 2, 1) <= ' ')))) { |
|
|
271 |
$count2++; |
|
|
272 |
$pos = 0; |
|
|
273 |
$type = 'bad'; |
|
|
274 |
switch ($c) { |
|
|
275 |
case '#': |
|
|
276 |
$type = 'mysql'; |
|
|
277 |
case '-': |
|
|
278 |
$type = 'ansi'; |
|
|
279 |
$pos = $GLOBALS['PMA_strpos']($sql, "\n", $count2); |
|
|
280 |
break; |
|
|
281 |
case '/': |
|
|
282 |
$type = 'c'; |
|
|
283 |
$pos = $GLOBALS['PMA_strpos']($sql, '*/', $count2); |
|
|
284 |
$pos += 2; |
|
|
285 |
break; |
|
|
286 |
default: |
|
|
287 |
break; |
|
|
288 |
} // end switch |
|
|
289 |
$count2 = ($pos < $count2) ? $len : $pos; |
|
|
290 |
$str = PMA_substr($sql, $count1, $count2 - $count1); |
|
|
291 |
PMA_SQP_arrayAdd($sql_array, 'comment_' . $type, $str, $arraysize); |
|
|
292 |
continue; |
|
|
293 |
} // end if |
|
|
294 |
|
|
|
295 |
// Checks for something inside quotation marks |
|
|
296 |
if (PMA_STR_strInStr($c, $quote_list)) { |
|
|
297 |
$startquotepos = $count2; |
|
|
298 |
$quotetype = $c; |
|
|
299 |
$count2++; |
|
|
300 |
$escaped = FALSE; |
|
|
301 |
$escaped_escaped = FALSE; |
|
|
302 |
$pos = $count2; |
|
|
303 |
$oldpos = 0; |
|
|
304 |
do { |
|
|
305 |
$oldpos = $pos; |
|
|
306 |
$pos = $GLOBALS['PMA_strpos'](' ' . $sql, $quotetype, $oldpos + 1) - 1; |
|
|
307 |
// ($pos === FALSE) |
|
|
308 |
if ($pos < 0) { |
|
|
309 |
$debugstr = $GLOBALS['strSQPBugUnclosedQuote'] . ' @ ' . $startquotepos. "\n" |
|
|
310 |
. 'STR: ' . htmlspecialchars($quotetype); |
|
|
311 |
PMA_SQP_throwError($debugstr, $sql); |
|
|
312 |
return $sql; |
|
|
313 |
} |
|
|
314 |
|
|
|
315 |
// If the quote is the first character, it can't be |
|
|
316 |
// escaped, so don't do the rest of the code |
|
|
317 |
if ($pos == 0) { |
|
|
318 |
break; |
|
|
319 |
} |
|
|
320 |
|
|
|
321 |
// Checks for MySQL escaping using a \ |
|
|
322 |
// And checks for ANSI escaping using the $quotetype character |
|
|
323 |
if (($pos < $len) && PMA_STR_charIsEscaped($sql, $pos)) { |
|
|
324 |
$pos ++; |
|
|
325 |
continue; |
|
|
326 |
} elseif (($pos + 1 < $len) && (PMA_substr($sql, $pos, 1) == $quotetype) && (PMA_substr($sql, $pos + 1, 1) == $quotetype)) { |
|
|
327 |
$pos = $pos + 2; |
|
|
328 |
continue; |
|
|
329 |
} else { |
|
|
330 |
break; |
|
|
331 |
} |
|
|
332 |
} while ($len > $pos); // end do |
|
|
333 |
|
|
|
334 |
$count2 = $pos; |
|
|
335 |
$count2++; |
|
|
336 |
$type = 'quote_'; |
|
|
337 |
switch ($quotetype) { |
|
|
338 |
case '\'': |
|
|
339 |
$type .= 'single'; |
|
|
340 |
break; |
|
|
341 |
case '"': |
|
|
342 |
$type .= 'double'; |
|
|
343 |
break; |
|
|
344 |
case '`': |
|
|
345 |
$type .= 'backtick'; |
|
|
346 |
break; |
|
|
347 |
default: |
|
|
348 |
break; |
|
|
349 |
} // end switch |
|
|
350 |
$data = PMA_substr($sql, $count1, $count2 - $count1); |
|
|
351 |
PMA_SQP_arrayAdd($sql_array, $type, $data, $arraysize); |
|
|
352 |
continue; |
|
|
353 |
} |
|
|
354 |
|
|
|
355 |
// Checks for brackets |
|
|
356 |
if (PMA_STR_strInStr($c, $bracket_list)) { |
|
|
357 |
// All bracket tokens are only one item long |
|
|
358 |
$count2++; |
|
|
359 |
$type_type = ''; |
|
|
360 |
if (PMA_STR_strInStr($c, '([{')) { |
|
|
361 |
$type_type = 'open'; |
|
|
362 |
} else { |
|
|
363 |
$type_type = 'close'; |
|
|
364 |
} |
|
|
365 |
|
|
|
366 |
$type_style = ''; |
|
|
367 |
if (PMA_STR_strInStr($c, '()')) { |
|
|
368 |
$type_style = 'round'; |
|
|
369 |
} elseif (PMA_STR_strInStr($c, '[]')) { |
|
|
370 |
$type_style = 'square'; |
|
|
371 |
} else { |
|
|
372 |
$type_style = 'curly'; |
|
|
373 |
} |
|
|
374 |
|
|
|
375 |
$type = 'punct_bracket_' . $type_type . '_' . $type_style; |
|
|
376 |
PMA_SQP_arrayAdd($sql_array, $type, $c, $arraysize); |
|
|
377 |
continue; |
|
|
378 |
} |
|
|
379 |
|
|
|
380 |
// Checks for identifier (alpha or numeric) |
|
|
381 |
if (PMA_STR_isSqlIdentifier($c, FALSE) || ($c == '@') || ($c == '.' && PMA_STR_isDigit(PMA_substr($sql, $count2 + 1, 1)))) { |
|
|
382 |
$count2 ++; |
|
|
383 |
|
|
|
384 |
//TODO: a @ can also be present in expressions like |
|
|
385 |
// FROM 'user'@'%' |
|
|
386 |
// or TO 'user'@'%' |
|
|
387 |
// in this case, the @ is wrongly marked as alpha_variable |
|
|
388 |
|
|
|
389 |
$is_sql_variable = ($c == '@'); |
|
|
390 |
$is_digit = (!$is_sql_variable) && PMA_STR_isDigit($c); |
|
|
391 |
$is_hex_digit = ($is_digit) && ($c == '.') && ($c == '0') && ($count2 < $len) && (PMA_substr($sql, $count2, 1) == 'x'); |
|
|
392 |
$is_float_digit = $c == '.'; |
|
|
393 |
$is_float_digit_exponent = FALSE; |
|
|
394 |
|
|
|
395 |
// Nijel: Fast skip is especially needed for huge BLOB data, requires PHP at least 4.3.0: |
|
|
396 |
if (PMA_PHP_INT_VERSION >= 40300) { |
|
|
397 |
if ($is_hex_digit) { |
|
|
398 |
$count2++; |
|
|
399 |
$pos = strspn($sql, '0123456789abcdefABCDEF', $count2); |
|
|
400 |
if ($pos > $count2) { |
|
|
401 |
$count2 = $pos; |
|
|
402 |
} |
|
|
403 |
unset($pos); |
|
|
404 |
} elseif ($is_digit) { |
|
|
405 |
$pos = strspn($sql, '0123456789', $count2); |
|
|
406 |
if ($pos > $count2) { |
|
|
407 |
$count2 = $pos; |
|
|
408 |
} |
|
|
409 |
unset($pos); |
|
|
410 |
} |
|
|
411 |
} |
|
|
412 |
|
|
|
413 |
while (($count2 < $len) && PMA_STR_isSqlIdentifier(PMA_substr($sql, $count2, 1), ($is_sql_variable || $is_digit))) { |
|
|
414 |
$c2 = PMA_substr($sql, $count2, 1); |
|
|
415 |
if ($is_sql_variable && ($c2 == '.')) { |
|
|
416 |
$count2++; |
|
|
417 |
continue; |
|
|
418 |
} |
|
|
419 |
if ($is_digit && (!$is_hex_digit) && ($c2 == '.')) { |
|
|
420 |
$count2++; |
|
|
421 |
if (!$is_float_digit) { |
|
|
422 |
$is_float_digit = TRUE; |
|
|
423 |
continue; |
|
|
424 |
} else { |
|
|
425 |
$debugstr = $GLOBALS['strSQPBugInvalidIdentifer'] . ' @ ' . ($count1+1) . "\n" |
|
|
426 |
. 'STR: ' . htmlspecialchars(PMA_substr($sql, $count1, $count2 - $count1)); |
|
|
427 |
PMA_SQP_throwError($debugstr, $sql); |
|
|
428 |
return $sql; |
|
|
429 |
} |
|
|
430 |
} |
|
|
431 |
if ($is_digit && (!$is_hex_digit) && (($c2 == 'e') || ($c2 == 'E'))) { |
|
|
432 |
if (!$is_float_digit_exponent) { |
|
|
433 |
$is_float_digit_exponent = TRUE; |
|
|
434 |
$is_float_digit = TRUE; |
|
|
435 |
$count2++; |
|
|
436 |
continue; |
|
|
437 |
} else { |
|
|
438 |
$is_digit = FALSE; |
|
|
439 |
$is_float_digit = FALSE; |
|
|
440 |
} |
|
|
441 |
} |
|
|
442 |
if (($is_hex_digit && PMA_STR_isHexDigit($c2)) || ($is_digit && PMA_STR_isDigit($c2))) { |
|
|
443 |
$count2++; |
|
|
444 |
continue; |
|
|
445 |
} else { |
|
|
446 |
$is_digit = FALSE; |
|
|
447 |
$is_hex_digit = FALSE; |
|
|
448 |
} |
|
|
449 |
|
|
|
450 |
$count2++; |
|
|
451 |
} // end while |
|
|
452 |
|
|
|
453 |
$l = $count2 - $count1; |
|
|
454 |
$str = PMA_substr($sql, $count1, $l); |
|
|
455 |
|
|
|
456 |
$type = ''; |
|
|
457 |
if ($is_digit) { |
|
|
458 |
$type = 'digit'; |
|
|
459 |
if ($is_float_digit) { |
|
|
460 |
$type .= '_float'; |
|
|
461 |
} elseif ($is_hex_digit) { |
|
|
462 |
$type .= '_hex'; |
|
|
463 |
} else { |
|
|
464 |
$type .= '_integer'; |
|
|
465 |
} |
|
|
466 |
} else { |
|
|
467 |
if ($is_sql_variable != FALSE) { |
|
|
468 |
$type = 'alpha_variable'; |
|
|
469 |
} else { |
|
|
470 |
$type = 'alpha'; |
|
|
471 |
} |
|
|
472 |
} // end if... else.... |
|
|
473 |
PMA_SQP_arrayAdd($sql_array, $type, $str, $arraysize); |
|
|
474 |
|
|
|
475 |
continue; |
|
|
476 |
} |
|
|
477 |
|
|
|
478 |
// Checks for punct |
|
|
479 |
if (PMA_STR_strInStr($c, $allpunct_list)) { |
|
|
480 |
while (($count2 < $len) && PMA_STR_strInStr(PMA_substr($sql, $count2, 1), $allpunct_list)) { |
|
|
481 |
$count2++; |
|
|
482 |
} |
|
|
483 |
$l = $count2 - $count1; |
|
|
484 |
if ($l == 1) { |
|
|
485 |
$punct_data = $c; |
|
|
486 |
} else { |
|
|
487 |
$punct_data = PMA_substr($sql, $count1, $l); |
|
|
488 |
} |
|
|
489 |
|
|
|
490 |
// Special case, sometimes, althought two characters are |
|
|
491 |
// adjectent directly, they ACTUALLY need to be seperate |
|
|
492 |
if ($l == 1) { |
|
|
493 |
$t_suffix = ''; |
|
|
494 |
switch ($punct_data) { |
|
|
495 |
case $punct_queryend: |
|
|
496 |
$t_suffix = '_queryend'; |
|
|
497 |
break; |
|
|
498 |
case $punct_qualifier: |
|
|
499 |
$t_suffix = '_qualifier'; |
|
|
500 |
break; |
|
|
501 |
case $punct_listsep: |
|
|
502 |
$t_suffix = '_listsep'; |
|
|
503 |
break; |
|
|
504 |
default: |
|
|
505 |
break; |
|
|
506 |
} |
|
|
507 |
PMA_SQP_arrayAdd($sql_array, 'punct' . $t_suffix, $punct_data, $arraysize); |
|
|
508 |
} elseif (PMA_STR_binarySearchInArr($punct_data, $allpunct_list_pair, $allpunct_list_pair_size)) { |
|
|
509 |
// Ok, we have one of the valid combined punct expressions |
|
|
510 |
PMA_SQP_arrayAdd($sql_array, 'punct', $punct_data, $arraysize); |
|
|
511 |
} else { |
|
|
512 |
// Bad luck, lets split it up more |
|
|
513 |
$first = $punct_data[0]; |
|
|
514 |
$first2 = $punct_data[0] . $punct_data[1]; |
|
|
515 |
$last2 = $punct_data[$l - 2] . $punct_data[$l - 1]; |
|
|
516 |
$last = $punct_data[$l - 1]; |
|
|
517 |
if (($first == ',') || ($first == ';') || ($first == '.') || ($first == '*')) { |
|
|
518 |
$count2 = $count1 + 1; |
|
|
519 |
$punct_data = $first; |
|
|
520 |
} elseif (($last2 == '/*') || (($last2 == '--') && ($count2 == $len || PMA_substr($sql, $count2, 1) <= ' ') )) { |
|
|
521 |
$count2 -= 2; |
|
|
522 |
$punct_data = PMA_substr($sql, $count1, $count2 - $count1); |
|
|
523 |
} elseif (($last == '-') || ($last == '+') || ($last == '!')) { |
|
|
524 |
$count2--; |
|
|
525 |
$punct_data = PMA_substr($sql, $count1, $count2 - $count1); |
|
|
526 |
// TODO: for negation operator, split in 2 tokens ? |
|
|
527 |
// "select x&~1 from t" |
|
|
528 |
// becomes "select x & ~ 1 from t" ? |
|
|
529 |
|
|
|
530 |
} elseif ($last != '~') { |
|
|
531 |
$debugstr = $GLOBALS['strSQPBugUnknownPunctuation'] . ' @ ' . ($count1+1) . "\n" |
|
|
532 |
. 'STR: ' . htmlspecialchars($punct_data); |
|
|
533 |
PMA_SQP_throwError($debugstr, $sql); |
|
|
534 |
return $sql; |
|
|
535 |
} |
|
|
536 |
PMA_SQP_arrayAdd($sql_array, 'punct', $punct_data, $arraysize); |
|
|
537 |
continue; |
|
|
538 |
} // end if... elseif... else |
|
|
539 |
continue; |
|
|
540 |
} |
|
|
541 |
|
|
|
542 |
// DEBUG |
|
|
543 |
$count2++; |
|
|
544 |
|
|
|
545 |
$debugstr = 'C1 C2 LEN: ' . $count1 . ' ' . $count2 . ' ' . $len . "\n" |
|
|
546 |
. 'STR: ' . PMA_substr($sql, $count1, $count2 - $count1) . "\n"; |
|
|
547 |
PMA_SQP_bug($debugstr, $sql); |
|
|
548 |
return $sql; |
|
|
549 |
|
|
|
550 |
} // end while ($count2 < $len) |
|
|
551 |
|
|
|
552 |
|
|
|
553 |
if ($arraysize > 0) { |
|
|
554 |
$t_next = $sql_array[0]['type']; |
|
|
555 |
$t_prev = ''; |
|
|
556 |
$t_bef_prev = ''; |
|
|
557 |
$t_cur = ''; |
|
|
558 |
$d_next = $sql_array[0]['data']; |
|
|
559 |
$d_prev = ''; |
|
|
560 |
$d_bef_prev = ''; |
|
|
561 |
$d_cur = ''; |
|
|
562 |
$d_next_upper = $t_next == 'alpha' ? strtoupper($d_next) : $d_next; |
|
|
563 |
$d_prev_upper = ''; |
|
|
564 |
$d_bef_prev_upper = ''; |
|
|
565 |
$d_cur_upper = ''; |
|
|
566 |
} |
|
|
567 |
|
|
|
568 |
for ($i = 0; $i < $arraysize; $i++) { |
|
|
569 |
$t_bef_prev = $t_prev; |
|
|
570 |
$t_prev = $t_cur; |
|
|
571 |
$t_cur = $t_next; |
|
|
572 |
$d_bef_prev = $d_prev; |
|
|
573 |
$d_prev = $d_cur; |
|
|
574 |
$d_cur = $d_next; |
|
|
575 |
$d_bef_prev_upper = $d_prev_upper; |
|
|
576 |
$d_prev_upper = $d_cur_upper; |
|
|
577 |
$d_cur_upper = $d_next_upper; |
|
|
578 |
if (($i + 1) < $arraysize) { |
|
|
579 |
$t_next = $sql_array[$i + 1]['type']; |
|
|
580 |
$d_next = $sql_array[$i + 1]['data']; |
|
|
581 |
$d_next_upper = $t_next == 'alpha' ? strtoupper($d_next) : $d_next; |
|
|
582 |
} else { |
|
|
583 |
$t_next = ''; |
|
|
584 |
$d_next = ''; |
|
|
585 |
$d_next_upper = ''; |
|
|
586 |
} |
|
|
587 |
|
|
|
588 |
//DEBUG echo "[prev: <b>".$d_prev."</b> ".$t_prev."][cur: <b>".$d_cur."</b> ".$t_cur."][next: <b>".$d_next."</b> ".$t_next."]<br />"; |
|
|
589 |
|
|
|
590 |
if ($t_cur == 'alpha') { |
|
|
591 |
$t_suffix = '_identifier'; |
|
|
592 |
if (($t_next == 'punct_qualifier') || ($t_prev == 'punct_qualifier')) { |
|
|
593 |
$t_suffix = '_identifier'; |
|
|
594 |
} elseif (($t_next == 'punct_bracket_open_round') |
|
|
595 |
&& PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_function_name, $PMA_SQPdata_function_name_cnt)) { |
|
|
596 |
// FIXME-2005-10-16: in the case of a CREATE TABLE containing a TIMESTAMP, |
|
|
597 |
// since TIMESTAMP() is also a function, it's found here and |
|
|
598 |
// the token is wrongly marked as alpha_functionName. But we |
|
|
599 |
// compensate for this when analysing for timestamp_not_null |
|
|
600 |
// later in this script. |
|
|
601 |
$t_suffix = '_functionName'; |
|
|
602 |
} elseif (PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_column_type, $PMA_SQPdata_column_type_cnt)) { |
|
|
603 |
$t_suffix = '_columnType'; |
|
|
604 |
|
|
|
605 |
// Temporary fix for BUG #621357 |
|
|
606 |
//TODO FIX PROPERLY NEEDS OVERHAUL OF SQL TOKENIZER |
|
|
607 |
if ($d_cur_upper == 'SET' && $t_next != 'punct_bracket_open_round') { |
|
|
608 |
$t_suffix = '_reservedWord'; |
|
|
609 |
} |
|
|
610 |
//END OF TEMPORARY FIX |
|
|
611 |
|
|
|
612 |
// CHARACTER is a synonym for CHAR, but can also be meant as |
|
|
613 |
// CHARACTER SET. In this case, we have a reserved word. |
|
|
614 |
if ($d_cur_upper == 'CHARACTER' && $d_next_upper == 'SET') { |
|
|
615 |
$t_suffix = '_reservedWord'; |
|
|
616 |
} |
|
|
617 |
|
|
|
618 |
// experimental |
|
|
619 |
// current is a column type, so previous must not be |
|
|
620 |
// a reserved word but an identifier |
|
|
621 |
// CREATE TABLE SG_Persons (first varchar(64)) |
|
|
622 |
|
|
|
623 |
//if ($sql_array[$i-1]['type'] =='alpha_reservedWord') { |
|
|
624 |
// $sql_array[$i-1]['type'] = 'alpha_identifier'; |
|
|
625 |
//} |
|
|
626 |
|
|
|
627 |
} elseif (PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_reserved_word, $PMA_SQPdata_reserved_word_cnt)) { |
|
|
628 |
$t_suffix = '_reservedWord'; |
|
|
629 |
} elseif (PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_column_attrib, $PMA_SQPdata_column_attrib_cnt)) { |
|
|
630 |
$t_suffix = '_columnAttrib'; |
|
|
631 |
// INNODB is a MySQL table type, but in "SHOW INNODB STATUS", |
|
|
632 |
// it should be regarded as a reserved word. |
|
|
633 |
if ($d_cur_upper == 'INNODB' && $d_prev_upper == 'SHOW' && $d_next_upper == 'STATUS') { |
|
|
634 |
$t_suffix = '_reservedWord'; |
|
|
635 |
} |
|
|
636 |
|
|
|
637 |
if ($d_cur_upper == 'DEFAULT' && $d_next_upper == 'CHARACTER') { |
|
|
638 |
$t_suffix = '_reservedWord'; |
|
|
639 |
} |
|
|
640 |
// Binary as character set |
|
|
641 |
if ($d_cur_upper == 'BINARY' && ( |
|
|
642 |
($d_bef_prev_upper == 'CHARACTER' && $d_prev_upper == 'SET') |
|
|
643 |
|| ($d_bef_prev_upper == 'SET' && $d_prev_upper == '=') |
|
|
644 |
|| ($d_bef_prev_upper == 'CHARSET' && $d_prev_upper == '=') |
|
|
645 |
|| $d_prev_upper == 'CHARSET' |
|
|
646 |
) && PMA_STR_binarySearchInArr($d_cur, $mysql_charsets, count($mysql_charsets))) { |
|
|
647 |
$t_suffix = '_charset'; |
|
|
648 |
} |
|
|
649 |
} elseif (PMA_STR_binarySearchInArr($d_cur, $mysql_charsets, $mysql_charsets_count) |
|
|
650 |
|| PMA_STR_binarySearchInArr($d_cur, $mysql_collations_flat, $mysql_collations_count) |
|
|
651 |
|| ($d_cur{0} == '_' && PMA_STR_binarySearchInArr(substr($d_cur, 1), $mysql_charsets, $mysql_charsets_count))) { |
|
|
652 |
$t_suffix = '_charset'; |
|
|
653 |
} else { |
|
|
654 |
// Do nothing |
|
|
655 |
} |
|
|
656 |
// check if present in the list of forbidden words |
|
|
657 |
if ($t_suffix == '_reservedWord' && PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_forbidden_word, $PMA_SQPdata_forbidden_word_cnt)) { |
|
|
658 |
$sql_array[$i]['forbidden'] = TRUE; |
|
|
659 |
} else { |
|
|
660 |
$sql_array[$i]['forbidden'] = FALSE; |
|
|
661 |
} |
|
|
662 |
$sql_array[$i]['type'] .= $t_suffix; |
|
|
663 |
} |
|
|
664 |
} // end for |
|
|
665 |
|
|
|
666 |
// Stores the size of the array inside the array, as count() is a slow |
|
|
667 |
// operation. |
|
|
668 |
$sql_array['len'] = $arraysize; |
|
|
669 |
|
|
|
670 |
// Sends the data back |
|
|
671 |
return $sql_array; |
|
|
672 |
} // end of the "PMA_SQP_parse()" function |
|
|
673 |
|
|
|
674 |
/** |
|
|
675 |
* Checks for token types being what we want... |
|
|
676 |
* |
|
|
677 |
* @param string String of type that we have |
|
|
678 |
* @param string String of type that we want |
|
|
679 |
* |
|
|
680 |
* @return boolean result of check |
|
|
681 |
* |
|
|
682 |
* @access private |
|
|
683 |
*/ |
|
|
684 |
function PMA_SQP_typeCheck($toCheck, $whatWeWant) |
|
|
685 |
{ |
|
|
686 |
$typeSeperator = '_'; |
|
|
687 |
if (strcmp($whatWeWant, $toCheck) == 0) { |
|
|
688 |
return TRUE; |
|
|
689 |
} else { |
|
|
690 |
if (strpos($whatWeWant, $typeSeperator) === FALSE) { |
|
|
691 |
return strncmp($whatWeWant, $toCheck, strpos($toCheck, $typeSeperator)) == 0; |
|
|
692 |
} else { |
|
|
693 |
return FALSE; |
|
|
694 |
} |
|
|
695 |
} |
|
|
696 |
} |
|
|
697 |
|
|
|
698 |
|
|
|
699 |
/** |
|
|
700 |
* Analyzes SQL queries |
|
|
701 |
* |
|
|
702 |
* @param array The SQL queries |
|
|
703 |
* |
|
|
704 |
* @return array The analyzed SQL queries |
|
|
705 |
* |
|
|
706 |
* @access public |
|
|
707 |
*/ |
|
|
708 |
function PMA_SQP_analyze($arr) |
|
|
709 |
{ |
|
|
710 |
if ($arr == array()) { |
|
|
711 |
return array(); |
|
|
712 |
} |
|
|
713 |
$result = array(); |
|
|
714 |
$size = $arr['len']; |
|
|
715 |
$subresult = array( |
|
|
716 |
'querytype' => '', |
|
|
717 |
'select_expr_clause'=> '', // the whole stuff between SELECT and FROM , except DISTINCT |
|
|
718 |
'position_of_first_select' => '', // the array index |
|
|
719 |
'from_clause'=> '', |
|
|
720 |
'group_by_clause'=> '', |
|
|
721 |
'order_by_clause'=> '', |
|
|
722 |
'having_clause' => '', |
|
|
723 |
'where_clause' => '', |
|
|
724 |
'where_clause_identifiers' => array(), |
|
|
725 |
'unsorted_query' => '', |
|
|
726 |
'queryflags' => array(), |
|
|
727 |
'select_expr' => array(), |
|
|
728 |
'table_ref' => array(), |
|
|
729 |
'foreign_keys' => array(), |
|
|
730 |
'create_table_fields' => array() |
|
|
731 |
); |
|
|
732 |
$subresult_empty = $subresult; |
|
|
733 |
$seek_queryend = FALSE; |
|
|
734 |
$seen_end_of_table_ref = FALSE; |
|
|
735 |
$number_of_brackets_in_extract = 0; |
|
|
736 |
$number_of_brackets_in_group_concat = 0; |
|
|
737 |
|
|
|
738 |
// for SELECT EXTRACT(YEAR_MONTH FROM CURDATE()) |
|
|
739 |
// we must not use CURDATE as a table_ref |
|
|
740 |
// so we track wether we are in the EXTRACT() |
|
|
741 |
$in_extract = FALSE; |
|
|
742 |
|
|
|
743 |
// for GROUP_CONCAT( ... ) |
|
|
744 |
$in_group_concat = FALSE; |
|
|
745 |
|
|
|
746 |
/* Description of analyzer results by lem9 |
|
|
747 |
* |
|
|
748 |
* db, table, column, alias |
|
|
749 |
* ------------------------ |
|
|
750 |
* |
|
|
751 |
* Inside the $subresult array, we create ['select_expr'] and ['table_ref'] arrays. |
|
|
752 |
* |
|
|
753 |
* The SELECT syntax (simplified) is |
|
|
754 |
* |
|
|
755 |
* SELECT |
|
|
756 |
* select_expression,... |
|
|
757 |
* [FROM [table_references] |
|
|
758 |
* |
|
|
759 |
* |
|
|
760 |
* ['select_expr'] is filled with each expression, the key represents the |
|
|
761 |
* expression position in the list (0-based) (so we don't lose track of |
|
|
762 |
* multiple occurences of the same column). |
|
|
763 |
* |
|
|
764 |
* ['table_ref'] is filled with each table ref, same thing for the key. |
|
|
765 |
* |
|
|
766 |
* I create all sub-values empty, even if they are |
|
|
767 |
* not present (for example no select_expression alias). |
|
|
768 |
* |
|
|
769 |
* There is a debug section at the end of loop #1, if you want to |
|
|
770 |
* see the exact contents of select_expr and table_ref |
|
|
771 |
* |
|
|
772 |
* queryflags |
|
|
773 |
* ---------- |
|
|
774 |
* |
|
|
775 |
* In $subresult, array 'queryflags' is filled, according to what we |
|
|
776 |
* find in the query. |
|
|
777 |
* |
|
|
778 |
* Currently, those are generated: |
|
|
779 |
* |
|
|
780 |
* ['queryflags']['need_confirm'] = 1; if the query needs confirmation |
|
|
781 |
* ['queryflags']['select_from'] = 1; if this is a real SELECT...FROM |
|
|
782 |
* ['queryflags']['distinct'] = 1; for a DISTINCT |
|
|
783 |
* ['queryflags']['union'] = 1; for a UNION |
|
|
784 |
* ['queryflags']['join'] = 1; for a JOIN |
|
|
785 |
* ['queryflags']['offset'] = 1; for the presence of OFFSET |
|
|
786 |
* |
|
|
787 |
* query clauses |
|
|
788 |
* ------------- |
|
|
789 |
* |
|
|
790 |
* The select is splitted in those clauses: |
|
|
791 |
* ['select_expr_clause'] |
|
|
792 |
* ['from_clause'] |
|
|
793 |
* ['group_by_clause'] |
|
|
794 |
* ['order_by_clause'] |
|
|
795 |
* ['having_clause'] |
|
|
796 |
* ['where_clause'] |
|
|
797 |
* |
|
|
798 |
* The identifiers of the WHERE clause are put into the array |
|
|
799 |
* ['where_clause_identifier'] |
|
|
800 |
* |
|
|
801 |
* For a SELECT, the whole query without the ORDER BY clause is put into |
|
|
802 |
* ['unsorted_query'] |
|
|
803 |
* |
|
|
804 |
* foreign keys |
|
|
805 |
* ------------ |
|
|
806 |
* The CREATE TABLE may contain FOREIGN KEY clauses, so they get |
|
|
807 |
* analyzed and ['foreign_keys'] is an array filled with |
|
|
808 |
* the constraint name, the index list, |
|
|
809 |
* the REFERENCES table name and REFERENCES index list, |
|
|
810 |
* and ON UPDATE | ON DELETE clauses |
|
|
811 |
* |
|
|
812 |
* position_of_first_select |
|
|
813 |
* ------------------------ |
|
|
814 |
* |
|
|
815 |
* The array index of the first SELECT we find. Will be used to |
|
|
816 |
* insert a SQL_CALC_FOUND_ROWS. |
|
|
817 |
* |
|
|
818 |
* create_table_fields |
|
|
819 |
* ------------------- |
|
|
820 |
* |
|
|
821 |
* For now, mostly used to detect the DEFAULT CURRENT_TIMESTAMP and |
|
|
822 |
* ON UPDATE CURRENT_TIMESTAMP clauses of the CREATE TABLE query. |
|
|
823 |
* An array, each element is the identifier name. |
|
|
824 |
* Note that for now, the timestamp_not_null element is created |
|
|
825 |
* even for non-TIMESTAMP fields. |
|
|
826 |
* |
|
|
827 |
* Sub-elements: ['type'] which contains the column type |
|
|
828 |
* optional (currently they are never false but can be absent): |
|
|
829 |
* ['default_current_timestamp'] boolean |
|
|
830 |
* ['on_update_current_timestamp'] boolean |
|
|
831 |
* ['timestamp_not_null'] boolean |
|
|
832 |
* |
|
|
833 |
* section_before_limit, section_after_limit |
|
|
834 |
* ----------------------------------------- |
|
|
835 |
* |
|
|
836 |
* Marks the point of the query where we can insert a LIMIT clause; |
|
|
837 |
* so the section_before_limit will contain the left part before |
|
|
838 |
* a possible LIMIT clause |
|
|
839 |
* |
|
|
840 |
* |
|
|
841 |
* End of description of analyzer results |
|
|
842 |
*/ |
|
|
843 |
|
|
|
844 |
// must be sorted |
|
|
845 |
// TODO: current logic checks for only one word, so I put only the |
|
|
846 |
// first word of the reserved expressions that end a table ref; |
|
|
847 |
// maybe this is not ok (the first word might mean something else) |
|
|
848 |
// $words_ending_table_ref = array( |
|
|
849 |
// 'FOR UPDATE', |
|
|
850 |
// 'GROUP BY', |
|
|
851 |
// 'HAVING', |
|
|
852 |
// 'LIMIT', |
|
|
853 |
// 'LOCK IN SHARE MODE', |
|
|
854 |
// 'ORDER BY', |
|
|
855 |
// 'PROCEDURE', |
|
|
856 |
// 'UNION', |
|
|
857 |
// 'WHERE' |
|
|
858 |
// ); |
|
|
859 |
$words_ending_table_ref = array( |
|
|
860 |
'FOR', |
|
|
861 |
'GROUP', |
|
|
862 |
'HAVING', |
|
|
863 |
'LIMIT', |
|
|
864 |
'LOCK', |
|
|
865 |
'ORDER', |
|
|
866 |
'PROCEDURE', |
|
|
867 |
'UNION', |
|
|
868 |
'WHERE' |
|
|
869 |
); |
|
|
870 |
$words_ending_table_ref_cnt = 9; //count($words_ending_table_ref); |
|
|
871 |
|
|
|
872 |
$words_ending_clauses = array( |
|
|
873 |
'FOR', |
|
|
874 |
'LIMIT', |
|
|
875 |
'LOCK', |
|
|
876 |
'PROCEDURE', |
|
|
877 |
'UNION' |
|
|
878 |
); |
|
|
879 |
$words_ending_clauses_cnt = 5; //count($words_ending_clauses); |
|
|
880 |
|
|
|
881 |
|
|
|
882 |
|
|
|
883 |
|
|
|
884 |
// must be sorted |
|
|
885 |
$supported_query_types = array( |
|
|
886 |
'SELECT' |
|
|
887 |
/* |
|
|
888 |
// Support for these additional query types will come later on. |
|
|
889 |
'DELETE', |
|
|
890 |
'INSERT', |
|
|
891 |
'REPLACE', |
|
|
892 |
'TRUNCATE', |
|
|
893 |
'UPDATE' |
|
|
894 |
'EXPLAIN', |
|
|
895 |
'DESCRIBE', |
|
|
896 |
'SHOW', |
|
|
897 |
'CREATE', |
|
|
898 |
'SET', |
|
|
899 |
'ALTER' |
|
|
900 |
*/ |
|
|
901 |
); |
|
|
902 |
$supported_query_types_cnt = count($supported_query_types); |
|
|
903 |
|
|
|
904 |
// loop #1 for each token: select_expr, table_ref for SELECT |
|
|
905 |
|
|
|
906 |
for ($i = 0; $i < $size; $i++) { |
|
|
907 |
//DEBUG echo "trace loop1 <b>" . $arr[$i]['data'] . "</b> (" . $arr[$i]['type'] . ")<br />"; |
|
|
908 |
|
|
|
909 |
// High speed seek for locating the end of the current query |
|
|
910 |
if ($seek_queryend == TRUE) { |
|
|
911 |
if ($arr[$i]['type'] == 'punct_queryend') { |
|
|
912 |
$seek_queryend = FALSE; |
|
|
913 |
} else { |
|
|
914 |
continue; |
|
|
915 |
} // end if (type == punct_queryend) |
|
|
916 |
} // end if ($seek_queryend) |
|
|
917 |
|
|
|
918 |
// TODO: when we find a UNION, should we split |
|
|
919 |
// in another subresult? |
|
|
920 |
// Note: do not split if this is a punct_queryend for the |
|
|
921 |
// first and only query |
|
|
922 |
if ($arr[$i]['type'] == 'punct_queryend' && ($i + 1 != $size)) { |
|
|
923 |
$result[] = $subresult; |
|
|
924 |
$subresult = $subresult_empty; |
|
|
925 |
continue; |
|
|
926 |
} // end if (type == punct_queryend) |
|
|
927 |
|
|
|
928 |
// ============================================================== |
|
|
929 |
if ($arr[$i]['type'] == 'punct_bracket_open_round') { |
|
|
930 |
if ($in_extract) { |
|
|
931 |
$number_of_brackets_in_extract++; |
|
|
932 |
} |
|
|
933 |
if ($in_group_concat) { |
|
|
934 |
$number_of_brackets_in_group_concat++; |
|
|
935 |
} |
|
|
936 |
} |
|
|
937 |
// ============================================================== |
|
|
938 |
if ($arr[$i]['type'] == 'punct_bracket_close_round') { |
|
|
939 |
if ($in_extract) { |
|
|
940 |
$number_of_brackets_in_extract--; |
|
|
941 |
if ($number_of_brackets_in_extract == 0) { |
|
|
942 |
$in_extract = FALSE; |
|
|
943 |
} |
|
|
944 |
} |
|
|
945 |
if ($in_group_concat) { |
|
|
946 |
$number_of_brackets_in_group_concat--; |
|
|
947 |
if ($number_of_brackets_in_group_concat == 0) { |
|
|
948 |
$in_group_concat = FALSE; |
|
|
949 |
} |
|
|
950 |
} |
|
|
951 |
} |
|
|
952 |
// ============================================================== |
|
|
953 |
if ($arr[$i]['type'] == 'alpha_functionName') { |
|
|
954 |
$upper_data = strtoupper($arr[$i]['data']); |
|
|
955 |
if ($upper_data =='EXTRACT') { |
|
|
956 |
$in_extract = TRUE; |
|
|
957 |
$number_of_brackets_in_extract = 0; |
|
|
958 |
} |
|
|
959 |
if ($upper_data =='GROUP_CONCAT') { |
|
|
960 |
$in_group_concat = TRUE; |
|
|
961 |
$number_of_brackets_in_group_concat = 0; |
|
|
962 |
} |
|
|
963 |
} |
|
|
964 |
|
|
|
965 |
// ============================================================== |
|
|
966 |
if ($arr[$i]['type'] == 'alpha_reservedWord' |
|
|
967 |
// && $arr[$i]['forbidden'] == FALSE) { |
|
|
968 |
) { |
|
|
969 |
// We don't know what type of query yet, so run this |
|
|
970 |
if ($subresult['querytype'] == '') { |
|
|
971 |
$subresult['querytype'] = strtoupper($arr[$i]['data']); |
|
|
972 |
} // end if (querytype was empty) |
|
|
973 |
|
|
|
974 |
// Check if we support this type of query |
|
|
975 |
if (!PMA_STR_binarySearchInArr($subresult['querytype'], $supported_query_types, $supported_query_types_cnt)) { |
|
|
976 |
// Skip ahead to the next one if we don't |
|
|
977 |
$seek_queryend = TRUE; |
|
|
978 |
continue; |
|
|
979 |
} // end if (query not supported) |
|
|
980 |
|
|
|
981 |
// upper once |
|
|
982 |
$upper_data = strtoupper($arr[$i]['data']); |
|
|
983 |
//TODO: reset for each query? |
|
|
984 |
|
|
|
985 |
if ($upper_data == 'SELECT') { |
|
|
986 |
$seen_from = FALSE; |
|
|
987 |
$previous_was_identifier = FALSE; |
|
|
988 |
$current_select_expr = -1; |
|
|
989 |
$seen_end_of_table_ref = FALSE; |
|
|
990 |
} // end if ( data == SELECT) |
|
|
991 |
|
|
|
992 |
if ($upper_data =='FROM' && !$in_extract) { |
|
|
993 |
$current_table_ref = -1; |
|
|
994 |
$seen_from = TRUE; |
|
|
995 |
$previous_was_identifier = FALSE; |
|
|
996 |
$save_table_ref = TRUE; |
|
|
997 |
} // end if (data == FROM) |
|
|
998 |
|
|
|
999 |
// here, do not 'continue' the loop, as we have more work for |
|
|
1000 |
// reserved words below |
|
|
1001 |
} // end if (type == alpha_reservedWord) |
|
|
1002 |
|
|
|
1003 |
// ============================== |
|
|
1004 |
if ($arr[$i]['type'] == 'quote_backtick' |
|
|
1005 |
|| $arr[$i]['type'] == 'quote_double' |
|
|
1006 |
|| $arr[$i]['type'] == 'quote_single' |
|
|
1007 |
|| $arr[$i]['type'] == 'alpha_identifier' |
|
|
1008 |
|| ($arr[$i]['type'] == 'alpha_reservedWord' |
|
|
1009 |
&& $arr[$i]['forbidden'] == FALSE)) { |
|
|
1010 |
|
|
|
1011 |
switch ($arr[$i]['type']) { |
|
|
1012 |
case 'alpha_identifier': |
|
|
1013 |
case 'alpha_reservedWord': |
|
|
1014 |
// this is not a real reservedWord, because |
|
|
1015 |
// it's not present in the list of forbidden words, |
|
|
1016 |
// for example "storage" which can be used as |
|
|
1017 |
// an identifier |
|
|
1018 |
// |
|
|
1019 |
// TODO: avoid the pretty printing in color |
|
|
1020 |
// in this case |
|
|
1021 |
|
|
|
1022 |
$identifier = $arr[$i]['data']; |
|
|
1023 |
break; |
|
|
1024 |
|
|
|
1025 |
//TODO: check embedded double quotes or backticks? |
|
|
1026 |
// and/or remove just the first and last character? |
|
|
1027 |
case 'quote_backtick': |
|
|
1028 |
$identifier = str_replace('`', '', $arr[$i]['data']); |
|
|
1029 |
break; |
|
|
1030 |
case 'quote_double': |
|
|
1031 |
$identifier = str_replace('"', '', $arr[$i]['data']); |
|
|
1032 |
break; |
|
|
1033 |
case 'quote_single': |
|
|
1034 |
$identifier = str_replace("'", "", $arr[$i]['data']); |
|
|
1035 |
break; |
|
|
1036 |
} // end switch |
|
|
1037 |
|
|
|
1038 |
if ($subresult['querytype'] == 'SELECT' && !$in_group_concat) { |
|
|
1039 |
if (!$seen_from) { |
|
|
1040 |
if ($previous_was_identifier && isset($chain)) { |
|
|
1041 |
// found alias for this select_expr, save it |
|
|
1042 |
// but only if we got something in $chain |
|
|
1043 |
// (for example, SELECT COUNT(*) AS cnt |
|
|
1044 |
// puts nothing in $chain, so we avoid |
|
|
1045 |
// setting the alias) |
|
|
1046 |
$alias_for_select_expr = $identifier; |
|
|
1047 |
} else { |
|
|
1048 |
$chain[] = $identifier; |
|
|
1049 |
$previous_was_identifier = TRUE; |
|
|
1050 |
|
|
|
1051 |
} // end if !$previous_was_identifier |
|
|
1052 |
} else { |
|
|
1053 |
// ($seen_from) |
|
|
1054 |
if ($save_table_ref && !$seen_end_of_table_ref) { |
|
|
1055 |
if ($previous_was_identifier) { |
|
|
1056 |
// found alias for table ref |
|
|
1057 |
// save it for later |
|
|
1058 |
$alias_for_table_ref = $identifier; |
|
|
1059 |
} else { |
|
|
1060 |
$chain[] = $identifier; |
|
|
1061 |
$previous_was_identifier = TRUE; |
|
|
1062 |
|
|
|
1063 |
} // end if ($previous_was_identifier) |
|
|
1064 |
} // end if ($save_table_ref &&!$seen_end_of_table_ref) |
|
|
1065 |
} // end if (!$seen_from) |
|
|
1066 |
} // end if (querytype SELECT) |
|
|
1067 |
} // end if ( quote_backtick or double quote or alpha_identifier) |
|
|
1068 |
|
|
|
1069 |
// =================================== |
|
|
1070 |
if ($arr[$i]['type'] == 'punct_qualifier') { |
|
|
1071 |
// to be able to detect an identifier following another |
|
|
1072 |
$previous_was_identifier = FALSE; |
|
|
1073 |
continue; |
|
|
1074 |
} // end if (punct_qualifier) |
|
|
1075 |
|
|
|
1076 |
// TODO: check if 3 identifiers following one another -> error |
|
|
1077 |
|
|
|
1078 |
// s a v e a s e l e c t e x p r |
|
|
1079 |
// finding a list separator or FROM |
|
|
1080 |
// means that we must save the current chain of identifiers |
|
|
1081 |
// into a select expression |
|
|
1082 |
|
|
|
1083 |
// for now, we only save a select expression if it contains |
|
|
1084 |
// at least one identifier, as we are interested in checking |
|
|
1085 |
// the columns and table names, so in "select * from persons", |
|
|
1086 |
// the "*" is not saved |
|
|
1087 |
|
|
|
1088 |
if (isset($chain) && !$seen_end_of_table_ref |
|
|
1089 |
&& ( (!$seen_from |
|
|
1090 |
&& $arr[$i]['type'] == 'punct_listsep') |
|
|
1091 |
|| ($arr[$i]['type'] == 'alpha_reservedWord' && $upper_data == 'FROM')) ) { |
|
|
1092 |
$size_chain = count($chain); |
|
|
1093 |
$current_select_expr++; |
|
|
1094 |
$subresult['select_expr'][$current_select_expr] = array( |
|
|
1095 |
'expr' => '', |
|
|
1096 |
'alias' => '', |
|
|
1097 |
'db' => '', |
|
|
1098 |
'table_name' => '', |
|
|
1099 |
'table_true_name' => '', |
|
|
1100 |
'column' => '' |
|
|
1101 |
); |
|
|
1102 |
|
|
|
1103 |
if (isset($alias_for_select_expr) && strlen($alias_for_select_expr)) { |
|
|
1104 |
// we had found an alias for this select expression |
|
|
1105 |
$subresult['select_expr'][$current_select_expr]['alias'] = $alias_for_select_expr; |
|
|
1106 |
unset($alias_for_select_expr); |
|
|
1107 |
} |
|
|
1108 |
// there is at least a column |
|
|
1109 |
$subresult['select_expr'][$current_select_expr]['column'] = $chain[$size_chain - 1]; |
|
|
1110 |
$subresult['select_expr'][$current_select_expr]['expr'] = $chain[$size_chain - 1]; |
|
|
1111 |
|
|
|
1112 |
// maybe a table |
|
|
1113 |
if ($size_chain > 1) { |
|
|
1114 |
$subresult['select_expr'][$current_select_expr]['table_name'] = $chain[$size_chain - 2]; |
|
|
1115 |
// we assume for now that this is also the true name |
|
|
1116 |
$subresult['select_expr'][$current_select_expr]['table_true_name'] = $chain[$size_chain - 2]; |
|
|
1117 |
$subresult['select_expr'][$current_select_expr]['expr'] |
|
|
1118 |
= $subresult['select_expr'][$current_select_expr]['table_name'] |
|
|
1119 |
. '.' . $subresult['select_expr'][$current_select_expr]['expr']; |
|
|
1120 |
} // end if ($size_chain > 1) |
|
|
1121 |
|
|
|
1122 |
// maybe a db |
|
|
1123 |
if ($size_chain > 2) { |
|
|
1124 |
$subresult['select_expr'][$current_select_expr]['db'] = $chain[$size_chain - 3]; |
|
|
1125 |
$subresult['select_expr'][$current_select_expr]['expr'] |
|
|
1126 |
= $subresult['select_expr'][$current_select_expr]['db'] |
|
|
1127 |
. '.' . $subresult['select_expr'][$current_select_expr]['expr']; |
|
|
1128 |
} // end if ($size_chain > 2) |
|
|
1129 |
unset($chain); |
|
|
1130 |
|
|
|
1131 |
// TODO: explain this: |
|
|
1132 |
if (($arr[$i]['type'] == 'alpha_reservedWord') |
|
|
1133 |
&& ($upper_data != 'FROM')) { |
|
|
1134 |
$previous_was_identifier = TRUE; |
|
|
1135 |
} |
|
|
1136 |
|
|
|
1137 |
} // end if (save a select expr) |
|
|
1138 |
|
|
|
1139 |
|
|
|
1140 |
//====================================== |
|
|
1141 |
// s a v e a t a b l e r e f |
|
|
1142 |
//====================================== |
|
|
1143 |
|
|
|
1144 |
// maybe we just saw the end of table refs |
|
|
1145 |
// but the last table ref has to be saved |
|
|
1146 |
// or we are at the last token (TODO: there could be another |
|
|
1147 |
// query after this one) |
|
|
1148 |
// or we just got a reserved word |
|
|
1149 |
|
|
|
1150 |
if (isset($chain) && $seen_from && $save_table_ref |
|
|
1151 |
&& ($arr[$i]['type'] == 'punct_listsep' |
|
|
1152 |
|| ($arr[$i]['type'] == 'alpha_reservedWord' && $upper_data!="AS") |
|
|
1153 |
|| $seen_end_of_table_ref |
|
|
1154 |
|| $i==$size-1 )) { |
|
|
1155 |
|
|
|
1156 |
$size_chain = count($chain); |
|
|
1157 |
$current_table_ref++; |
|
|
1158 |
$subresult['table_ref'][$current_table_ref] = array( |
|
|
1159 |
'expr' => '', |
|
|
1160 |
'db' => '', |
|
|
1161 |
'table_name' => '', |
|
|
1162 |
'table_alias' => '', |
|
|
1163 |
'table_true_name' => '' |
|
|
1164 |
); |
|
|
1165 |
if (isset($alias_for_table_ref) && strlen($alias_for_table_ref)) { |
|
|
1166 |
$subresult['table_ref'][$current_table_ref]['table_alias'] = $alias_for_table_ref; |
|
|
1167 |
unset($alias_for_table_ref); |
|
|
1168 |
} |
|
|
1169 |
$subresult['table_ref'][$current_table_ref]['table_name'] = $chain[$size_chain - 1]; |
|
|
1170 |
// we assume for now that this is also the true name |
|
|
1171 |
$subresult['table_ref'][$current_table_ref]['table_true_name'] = $chain[$size_chain - 1]; |
|
|
1172 |
$subresult['table_ref'][$current_table_ref]['expr'] |
|
|
1173 |
= $subresult['table_ref'][$current_table_ref]['table_name']; |
|
|
1174 |
// maybe a db |
|
|
1175 |
if ($size_chain > 1) { |
|
|
1176 |
$subresult['table_ref'][$current_table_ref]['db'] = $chain[$size_chain - 2]; |
|
|
1177 |
$subresult['table_ref'][$current_table_ref]['expr'] |
|
|
1178 |
= $subresult['table_ref'][$current_table_ref]['db'] |
|
|
1179 |
. '.' . $subresult['table_ref'][$current_table_ref]['expr']; |
|
|
1180 |
} // end if ($size_chain > 1) |
|
|
1181 |
|
|
|
1182 |
// add the table alias into the whole expression |
|
|
1183 |
$subresult['table_ref'][$current_table_ref]['expr'] |
|
|
1184 |
.= ' ' . $subresult['table_ref'][$current_table_ref]['table_alias']; |
|
|
1185 |
|
|
|
1186 |
unset($chain); |
|
|
1187 |
$previous_was_identifier = TRUE; |
|
|
1188 |
//continue; |
|
|
1189 |
|
|
|
1190 |
} // end if (save a table ref) |
|
|
1191 |
|
|
|
1192 |
|
|
|
1193 |
// when we have found all table refs, |
|
|
1194 |
// for each table_ref alias, put the true name of the table |
|
|
1195 |
// in the corresponding select expressions |
|
|
1196 |
|
|
|
1197 |
if (isset($current_table_ref) && ($seen_end_of_table_ref || $i == $size-1) && $subresult != $subresult_empty) { |
|
|
1198 |
for ($tr=0; $tr <= $current_table_ref; $tr++) { |
|
|
1199 |
$alias = $subresult['table_ref'][$tr]['table_alias']; |
|
|
1200 |
$truename = $subresult['table_ref'][$tr]['table_true_name']; |
|
|
1201 |
for ($se=0; $se <= $current_select_expr; $se++) { |
|
|
1202 |
if (isset($alias) && strlen($alias) && $subresult['select_expr'][$se]['table_true_name'] |
|
|
1203 |
== $alias) { |
|
|
1204 |
$subresult['select_expr'][$se]['table_true_name'] |
|
|
1205 |
= $truename; |
|
|
1206 |
} // end if (found the alias) |
|
|
1207 |
} // end for (select expressions) |
|
|
1208 |
|
|
|
1209 |
} // end for (table refs) |
|
|
1210 |
} // end if (set the true names) |
|
|
1211 |
|
|
|
1212 |
|
|
|
1213 |
// e n d i n g l o o p #1 |
|
|
1214 |
// set the $previous_was_identifier to FALSE if the current |
|
|
1215 |
// token is not an identifier |
|
|
1216 |
if (($arr[$i]['type'] != 'alpha_identifier') |
|
|
1217 |
&& ($arr[$i]['type'] != 'quote_double') |
|
|
1218 |
&& ($arr[$i]['type'] != 'quote_single') |
|
|
1219 |
&& ($arr[$i]['type'] != 'quote_backtick')) { |
|
|
1220 |
$previous_was_identifier = FALSE; |
|
|
1221 |
} // end if |
|
|
1222 |
|
|
|
1223 |
// however, if we are on AS, we must keep the $previous_was_identifier |
|
|
1224 |
if (($arr[$i]['type'] == 'alpha_reservedWord') |
|
|
1225 |
&& ($upper_data == 'AS')) { |
|
|
1226 |
$previous_was_identifier = TRUE; |
|
|
1227 |
} |
|
|
1228 |
|
|
|
1229 |
if (($arr[$i]['type'] == 'alpha_reservedWord') |
|
|
1230 |
&& ($upper_data =='ON' || $upper_data =='USING')) { |
|
|
1231 |
$save_table_ref = FALSE; |
|
|
1232 |
} // end if (data == ON) |
|
|
1233 |
|
|
|
1234 |
if (($arr[$i]['type'] == 'alpha_reservedWord') |
|
|
1235 |
&& ($upper_data =='JOIN' || $upper_data =='FROM')) { |
|
|
1236 |
$save_table_ref = TRUE; |
|
|
1237 |
} // end if (data == JOIN) |
|
|
1238 |
|
|
|
1239 |
// no need to check the end of table ref if we already did |
|
|
1240 |
// TODO: maybe add "&& $seen_from" |
|
|
1241 |
if (!$seen_end_of_table_ref) { |
|
|
1242 |
// if this is the last token, it implies that we have |
|
|
1243 |
// seen the end of table references |
|
|
1244 |
// Check for the end of table references |
|
|
1245 |
// |
|
|
1246 |
// Note: if we are analyzing a GROUP_CONCAT clause, |
|
|
1247 |
// we might find a word that seems to indicate that |
|
|
1248 |
// we have found the end of table refs (like ORDER) |
|
|
1249 |
// but it's a modifier of the GROUP_CONCAT so |
|
|
1250 |
// it's not the real end of table refs |
|
|
1251 |
if (($i == $size-1) |
|
|
1252 |
|| ($arr[$i]['type'] == 'alpha_reservedWord' |
|
|
1253 |
&& !$in_group_concat |
|
|
1254 |
&& PMA_STR_binarySearchInArr($upper_data, $words_ending_table_ref, $words_ending_table_ref_cnt))) { |
|
|
1255 |
$seen_end_of_table_ref = TRUE; |
|
|
1256 |
// to be able to save the last table ref, but do not |
|
|
1257 |
// set it true if we found a word like "ON" that has |
|
|
1258 |
// already set it to false |
|
|
1259 |
if (isset($save_table_ref) && $save_table_ref != FALSE) { |
|
|
1260 |
$save_table_ref = TRUE; |
|
|
1261 |
} //end if |
|
|
1262 |
|
|
|
1263 |
} // end if (check for end of table ref) |
|
|
1264 |
} //end if (!$seen_end_of_table_ref) |
|
|
1265 |
|
|
|
1266 |
if ($seen_end_of_table_ref) { |
|
|
1267 |
$save_table_ref = FALSE; |
|
|
1268 |
} // end if |
|
|
1269 |
|
|
|
1270 |
} // end for $i (loop #1) |
|
|
1271 |
|
|
|
1272 |
// ------------------------------------------------------- |
|
|
1273 |
// This is a big hunk of debugging code by Marc for this. |
|
|
1274 |
// ------------------------------------------------------- |
|
|
1275 |
/* |
|
|
1276 |
if (isset($current_select_expr)) { |
|
|
1277 |
for ($trace=0; $trace<=$current_select_expr; $trace++) { |
|
|
1278 |
echo "<br />"; |
|
|
1279 |
reset ($subresult['select_expr'][$trace]); |
|
|
1280 |
while (list ($key, $val) = each ($subresult['select_expr'][$trace])) |
|
|
1281 |
echo "sel expr $trace $key => $val<br />\n"; |
|
|
1282 |
} |
|
|
1283 |
} |
|
|
1284 |
|
|
|
1285 |
if (isset($current_table_ref)) { |
|
|
1286 |
echo "current_table_ref = " . $current_table_ref . "<br>"; |
|
|
1287 |
for ($trace=0; $trace<=$current_table_ref; $trace++) { |
|
|
1288 |
|
|
|
1289 |
echo "<br />"; |
|
|
1290 |
reset ($subresult['table_ref'][$trace]); |
|
|
1291 |
while (list ($key, $val) = each ($subresult['table_ref'][$trace])) |
|
|
1292 |
echo "table ref $trace $key => $val<br />\n"; |
|
|
1293 |
} |
|
|
1294 |
} |
|
|
1295 |
*/ |
|
|
1296 |
// ------------------------------------------------------- |
|
|
1297 |
|
|
|
1298 |
|
|
|
1299 |
// loop #2: - queryflags |
|
|
1300 |
// - querytype (for queries != 'SELECT') |
|
|
1301 |
// - section_before_limit, section_after_limit |
|
|
1302 |
// |
|
|
1303 |
// we will also need this queryflag in loop 2 |
|
|
1304 |
// so set it here |
|
|
1305 |
if (isset($current_table_ref) && $current_table_ref > -1) { |
|
|
1306 |
$subresult['queryflags']['select_from'] = 1; |
|
|
1307 |
} |
|
|
1308 |
|
|
|
1309 |
$collect_section_before_limit = TRUE; |
|
|
1310 |
$section_before_limit = ''; |
|
|
1311 |
$section_after_limit = ''; |
|
|
1312 |
$seen_reserved_word = FALSE; |
|
|
1313 |
$seen_group = FALSE; |
|
|
1314 |
$seen_order = FALSE; |
|
|
1315 |
$in_group_by = FALSE; // true when we are inside the GROUP BY clause |
|
|
1316 |
$in_order_by = FALSE; // true when we are inside the ORDER BY clause |
|
|
1317 |
$in_having = FALSE; // true when we are inside the HAVING clause |
|
|
1318 |
$in_select_expr = FALSE; // true when we are inside the select expr clause |
|
|
1319 |
$in_where = FALSE; // true when we are inside the WHERE clause |
|
|
1320 |
$in_from = FALSE; |
|
|
1321 |
$in_group_concat = FALSE; |
|
|
1322 |
$unsorted_query = ''; |
|
|
1323 |
$first_reserved_word = ''; |
|
|
1324 |
$current_identifier = ''; |
|
|
1325 |
|
|
|
1326 |
for ($i = 0; $i < $size; $i++) { |
|
|
1327 |
//DEBUG echo "trace loop2 <b>" . $arr[$i]['data'] . "</b> (" . $arr[$i]['type'] . ")<br />"; |
|
|
1328 |
|
|
|
1329 |
// need_confirm |
|
|
1330 |
// |
|
|
1331 |
// check for reserved words that will have to generate |
|
|
1332 |
// a confirmation request later in sql.php |
|
|
1333 |
// the cases are: |
|
|
1334 |
// DROP TABLE |
|
|
1335 |
// DROP DATABASE |
|
|
1336 |
// ALTER TABLE... DROP |
|
|
1337 |
// DELETE FROM... |
|
|
1338 |
// |
|
|
1339 |
// this code is not used for confirmations coming from functions.js |
|
|
1340 |
|
|
|
1341 |
// TODO: check for punct_queryend |
|
|
1342 |
|
|
|
1343 |
|
|
|
1344 |
// TODO: verify C-style comments? |
|
|
1345 |
if ($arr[$i]['type'] == 'comment_ansi') { |
|
|
1346 |
$collect_section_before_limit = FALSE; |
|
|
1347 |
} |
|
|
1348 |
|
|
|
1349 |
if ($arr[$i]['type'] == 'alpha_reservedWord') { |
|
|
1350 |
$upper_data = strtoupper($arr[$i]['data']); |
|
|
1351 |
if (!$seen_reserved_word) { |
|
|
1352 |
$first_reserved_word = $upper_data; |
|
|
1353 |
$subresult['querytype'] = $upper_data; |
|
|
1354 |
$seen_reserved_word = TRUE; |
|
|
1355 |
|
|
|
1356 |
// if the first reserved word is DROP or DELETE, |
|
|
1357 |
// we know this is a query that needs to be confirmed |
|
|
1358 |
if ($first_reserved_word=='DROP' |
|
|
1359 |
|| $first_reserved_word == 'DELETE' |
|
|
1360 |
|| $first_reserved_word == 'TRUNCATE') { |
|
|
1361 |
$subresult['queryflags']['need_confirm'] = 1; |
|
|
1362 |
} |
|
|
1363 |
|
|
|
1364 |
if ($first_reserved_word=='SELECT'){ |
|
|
1365 |
$position_of_first_select = $i; |
|
|
1366 |
} |
|
|
1367 |
|
|
|
1368 |
} else { |
|
|
1369 |
if ($upper_data=='DROP' && $first_reserved_word=='ALTER') { |
|
|
1370 |
$subresult['queryflags']['need_confirm'] = 1; |
|
|
1371 |
} |
|
|
1372 |
} |
|
|
1373 |
|
|
|
1374 |
if ($upper_data == 'PROCEDURE') { |
|
|
1375 |
$collect_section_before_limit = FALSE; |
|
|
1376 |
} |
|
|
1377 |
// TODO: set also to FALSE if we find |
|
|
1378 |
// FOR UPDATE |
|
|
1379 |
// LOCK IN SHARE MODE |
|
|
1380 |
|
|
|
1381 |
if ($upper_data == 'SELECT') { |
|
|
1382 |
$in_select_expr = TRUE; |
|
|
1383 |
$select_expr_clause = ''; |
|
|
1384 |
} |
|
|
1385 |
if ($upper_data == 'DISTINCT' && !$in_group_concat) { |
|
|
1386 |
$subresult['queryflags']['distinct'] = 1; |
|
|
1387 |
} |
|
|
1388 |
|
|
|
1389 |
if ($upper_data == 'UNION') { |
|
|
1390 |
$subresult['queryflags']['union'] = 1; |
|
|
1391 |
} |
|
|
1392 |
|
|
|
1393 |
if ($upper_data == 'JOIN') { |
|
|
1394 |
$subresult['queryflags']['join'] = 1; |
|
|
1395 |
} |
|
|
1396 |
|
|
|
1397 |
if ($upper_data == 'OFFSET') { |
|
|
1398 |
$subresult['queryflags']['offset'] = 1; |
|
|
1399 |
} |
|
|
1400 |
|
|
|
1401 |
// if this is a real SELECT...FROM |
|
|
1402 |
if ($upper_data == 'FROM' && isset($subresult['queryflags']['select_from']) && $subresult['queryflags']['select_from'] == 1) { |
|
|
1403 |
$in_from = TRUE; |
|
|
1404 |
$from_clause = ''; |
|
|
1405 |
$in_select_expr = FALSE; |
|
|
1406 |
} |
|
|
1407 |
|
|
|
1408 |
|
|
|
1409 |
// (we could have less resetting of variables to FALSE |
|
|
1410 |
// if we trust that the query respects the standard |
|
|
1411 |
// MySQL order for clauses) |
|
|
1412 |
|
|
|
1413 |
// we use $seen_group and $seen_order because we are looking |
|
|
1414 |
// for the BY |
|
|
1415 |
if ($upper_data == 'GROUP') { |
|
|
1416 |
$seen_group = TRUE; |
|
|
1417 |
$seen_order = FALSE; |
|
|
1418 |
$in_having = FALSE; |
|
|
1419 |
$in_order_by = FALSE; |
|
|
1420 |
$in_where = FALSE; |
|
|
1421 |
$in_select_expr = FALSE; |
|
|
1422 |
$in_from = FALSE; |
|
|
1423 |
} |
|
|
1424 |
if ($upper_data == 'ORDER' && !$in_group_concat) { |
|
|
1425 |
$seen_order = TRUE; |
|
|
1426 |
$seen_group = FALSE; |
|
|
1427 |
$in_having = FALSE; |
|
|
1428 |
$in_group_by = FALSE; |
|
|
1429 |
$in_where = FALSE; |
|
|
1430 |
$in_select_expr = FALSE; |
|
|
1431 |
$in_from = FALSE; |
|
|
1432 |
} |
|
|
1433 |
if ($upper_data == 'HAVING') { |
|
|
1434 |
$in_having = TRUE; |
|
|
1435 |
$having_clause = ''; |
|
|
1436 |
$seen_group = FALSE; |
|
|
1437 |
$seen_order = FALSE; |
|
|
1438 |
$in_group_by = FALSE; |
|
|
1439 |
$in_order_by = FALSE; |
|
|
1440 |
$in_where = FALSE; |
|
|
1441 |
$in_select_expr = FALSE; |
|
|
1442 |
$in_from = FALSE; |
|
|
1443 |
} |
|
|
1444 |
|
|
|
1445 |
if ($upper_data == 'WHERE') { |
|
|
1446 |
$in_where = TRUE; |
|
|
1447 |
$where_clause = ''; |
|
|
1448 |
$where_clause_identifiers = array(); |
|
|
1449 |
$seen_group = FALSE; |
|
|
1450 |
$seen_order = FALSE; |
|
|
1451 |
$in_group_by = FALSE; |
|
|
1452 |
$in_order_by = FALSE; |
|
|
1453 |
$in_having = FALSE; |
|
|
1454 |
$in_select_expr = FALSE; |
|
|
1455 |
$in_from = FALSE; |
|
|
1456 |
} |
|
|
1457 |
|
|
|
1458 |
if ($upper_data == 'BY') { |
|
|
1459 |
if ($seen_group) { |
|
|
1460 |
$in_group_by = TRUE; |
|
|
1461 |
$group_by_clause = ''; |
|
|
1462 |
} |
|
|
1463 |
if ($seen_order) { |
|
|
1464 |
$in_order_by = TRUE; |
|
|
1465 |
$order_by_clause = ''; |
|
|
1466 |
} |
|
|
1467 |
} |
|
|
1468 |
|
|
|
1469 |
// if we find one of the words that could end the clause |
|
|
1470 |
if (PMA_STR_binarySearchInArr($upper_data, $words_ending_clauses, $words_ending_clauses_cnt)) { |
|
|
1471 |
|
|
|
1472 |
$in_group_by = FALSE; |
|
|
1473 |
$in_order_by = FALSE; |
|
|
1474 |
$in_having = FALSE; |
|
|
1475 |
$in_where = FALSE; |
|
|
1476 |
$in_select_expr = FALSE; |
|
|
1477 |
$in_from = FALSE; |
|
|
1478 |
} |
|
|
1479 |
|
|
|
1480 |
} // endif (reservedWord) |
|
|
1481 |
|
|
|
1482 |
|
|
|
1483 |
// do not add a blank after a function name |
|
|
1484 |
// TODO: can we combine loop 2 and loop 1? |
|
|
1485 |
// some code is repeated here... |
|
|
1486 |
|
|
|
1487 |
$sep=' '; |
|
|
1488 |
if ($arr[$i]['type'] == 'alpha_functionName') { |
|
|
1489 |
$sep=''; |
|
|
1490 |
$upper_data = strtoupper($arr[$i]['data']); |
|
|
1491 |
if ($upper_data =='GROUP_CONCAT') { |
|
|
1492 |
$in_group_concat = TRUE; |
|
|
1493 |
$number_of_brackets_in_group_concat = 0; |
|
|
1494 |
} |
|
|
1495 |
} |
|
|
1496 |
|
|
|
1497 |
if ($arr[$i]['type'] == 'punct_bracket_open_round') { |
|
|
1498 |
if ($in_group_concat) { |
|
|
1499 |
$number_of_brackets_in_group_concat++; |
|
|
1500 |
} |
|
|
1501 |
} |
|
|
1502 |
if ($arr[$i]['type'] == 'punct_bracket_close_round') { |
|
|
1503 |
if ($in_group_concat) { |
|
|
1504 |
$number_of_brackets_in_group_concat--; |
|
|
1505 |
if ($number_of_brackets_in_group_concat == 0) { |
|
|
1506 |
$in_group_concat = FALSE; |
|
|
1507 |
} |
|
|
1508 |
} |
|
|
1509 |
} |
|
|
1510 |
|
|
|
1511 |
if ($in_select_expr && $upper_data != 'SELECT' && $upper_data != 'DISTINCT') { |
|
|
1512 |
$select_expr_clause .= $arr[$i]['data'] . $sep; |
|
|
1513 |
} |
|
|
1514 |
if ($in_from && $upper_data != 'FROM') { |
|
|
1515 |
$from_clause .= $arr[$i]['data'] . $sep; |
|
|
1516 |
} |
|
|
1517 |
if ($in_group_by && $upper_data != 'GROUP' && $upper_data != 'BY') { |
|
|
1518 |
$group_by_clause .= $arr[$i]['data'] . $sep; |
|
|
1519 |
} |
|
|
1520 |
if ($in_order_by && $upper_data != 'ORDER' && $upper_data != 'BY') { |
|
|
1521 |
$order_by_clause .= $arr[$i]['data'] . $sep; |
|
|
1522 |
} |
|
|
1523 |
if ($in_having && $upper_data != 'HAVING') { |
|
|
1524 |
$having_clause .= $arr[$i]['data'] . $sep; |
|
|
1525 |
} |
|
|
1526 |
if ($in_where && $upper_data != 'WHERE') { |
|
|
1527 |
$where_clause .= $arr[$i]['data'] . $sep; |
|
|
1528 |
|
|
|
1529 |
if (($arr[$i]['type'] == 'quote_backtick') |
|
|
1530 |
|| ($arr[$i]['type'] == 'alpha_identifier')) { |
|
|
1531 |
$where_clause_identifiers[] = $arr[$i]['data']; |
|
|
1532 |
} |
|
|
1533 |
} |
|
|
1534 |
|
|
|
1535 |
if (isset($subresult['queryflags']['select_from']) |
|
|
1536 |
&& $subresult['queryflags']['select_from'] == 1 |
|
|
1537 |
&& !$seen_order) { |
|
|
1538 |
$unsorted_query .= $arr[$i]['data']; |
|
|
1539 |
|
|
|
1540 |
if ($arr[$i]['type'] != 'punct_bracket_open_round' |
|
|
1541 |
&& $arr[$i]['type'] != 'punct_bracket_close_round' |
|
|
1542 |
&& $arr[$i]['type'] != 'punct') { |
|
|
1543 |
$unsorted_query .= $sep; |
|
|
1544 |
} |
|
|
1545 |
} |
|
|
1546 |
|
|
|
1547 |
// clear $upper_data for next iteration |
|
|
1548 |
$upper_data=''; |
|
|
1549 |
|
|
|
1550 |
if ($collect_section_before_limit && $arr[$i]['type'] != 'punct_queryend') { |
|
|
1551 |
$section_before_limit .= $arr[$i]['data'] . $sep; |
|
|
1552 |
} else { |
|
|
1553 |
$section_after_limit .= $arr[$i]['data'] . $sep; |
|
|
1554 |
} |
|
|
1555 |
|
|
|
1556 |
|
|
|
1557 |
} // end for $i (loop #2) |
|
|
1558 |
|
|
|
1559 |
|
|
|
1560 |
// ----------------------------------------------------- |
|
|
1561 |
// loop #3: foreign keys and MySQL 4.1.2+ TIMESTAMP options |
|
|
1562 |
// (for now, check only the first query) |
|
|
1563 |
// (for now, identifiers are assumed to be backquoted) |
|
|
1564 |
|
|
|
1565 |
// If we find that we are dealing with a CREATE TABLE query, |
|
|
1566 |
// we look for the next punct_bracket_open_round, which |
|
|
1567 |
// introduces the fields list. Then, when we find a |
|
|
1568 |
// quote_backtick, it must be a field, so we put it into |
|
|
1569 |
// the create_table_fields array. Even if this field is |
|
|
1570 |
// not a timestamp, it will be useful when logic has been |
|
|
1571 |
// added for complete field attributes analysis. |
|
|
1572 |
|
|
|
1573 |
$seen_foreign = FALSE; |
|
|
1574 |
$seen_references = FALSE; |
|
|
1575 |
$seen_constraint = FALSE; |
|
|
1576 |
$foreign_key_number = -1; |
|
|
1577 |
$seen_create_table = FALSE; |
|
|
1578 |
$seen_create = FALSE; |
|
|
1579 |
$in_create_table_fields = FALSE; |
|
|
1580 |
$brackets_level = 0; |
|
|
1581 |
$in_timestamp_options = FALSE; |
|
|
1582 |
$seen_default = FALSE; |
|
|
1583 |
|
|
|
1584 |
for ($i = 0; $i < $size; $i++) { |
|
|
1585 |
// DEBUG echo "<b>" . $arr[$i]['data'] . "</b> " . $arr[$i]['type'] . "<br />"; |
|
|
1586 |
|
|
|
1587 |
if ($arr[$i]['type'] == 'alpha_reservedWord') { |
|
|
1588 |
$upper_data = strtoupper($arr[$i]['data']); |
|
|
1589 |
|
|
|
1590 |
if ($upper_data == 'NOT' && $in_timestamp_options) { |
|
|
1591 |
$create_table_fields[$current_identifier]['timestamp_not_null'] = TRUE; |
|
|
1592 |
|
|
|
1593 |
} |
|
|
1594 |
|
|
|
1595 |
if ($upper_data == 'CREATE') { |
|
|
1596 |
$seen_create = TRUE; |
|
|
1597 |
} |
|
|
1598 |
|
|
|
1599 |
if ($upper_data == 'TABLE' && $seen_create) { |
|
|
1600 |
$seen_create_table = TRUE; |
|
|
1601 |
$create_table_fields = array(); |
|
|
1602 |
} |
|
|
1603 |
|
|
|
1604 |
if ($upper_data == 'CURRENT_TIMESTAMP') { |
|
|
1605 |
if ($in_timestamp_options) { |
|
|
1606 |
if ($seen_default) { |
|
|
1607 |
$create_table_fields[$current_identifier]['default_current_timestamp'] = TRUE; |
|
|
1608 |
} |
|
|
1609 |
} |
|
|
1610 |
} |
|
|
1611 |
|
|
|
1612 |
if ($upper_data == 'CONSTRAINT') { |
|
|
1613 |
$foreign_key_number++; |
|
|
1614 |
$seen_foreign = FALSE; |
|
|
1615 |
$seen_references = FALSE; |
|
|
1616 |
$seen_constraint = TRUE; |
|
|
1617 |
} |
|
|
1618 |
if ($upper_data == 'FOREIGN') { |
|
|
1619 |
$seen_foreign = TRUE; |
|
|
1620 |
$seen_references = FALSE; |
|
|
1621 |
$seen_constraint = FALSE; |
|
|
1622 |
} |
|
|
1623 |
if ($upper_data == 'REFERENCES') { |
|
|
1624 |
$seen_foreign = FALSE; |
|
|
1625 |
$seen_references = TRUE; |
|
|
1626 |
$seen_constraint = FALSE; |
|
|
1627 |
} |
|
|
1628 |
|
|
|
1629 |
|
|
|
1630 |
// Cases covered: |
|
|
1631 |
|
|
|
1632 |
// [ON DELETE {CASCADE | SET NULL | NO ACTION | RESTRICT}] |
|
|
1633 |
// [ON UPDATE {CASCADE | SET NULL | NO ACTION | RESTRICT}] |
|
|
1634 |
|
|
|
1635 |
// but we set ['on_delete'] or ['on_cascade'] to |
|
|
1636 |
// CASCADE | SET_NULL | NO_ACTION | RESTRICT |
|
|
1637 |
|
|
|
1638 |
// ON UPDATE CURRENT_TIMESTAMP |
|
|
1639 |
|
|
|
1640 |
if ($upper_data == 'ON') { |
|
|
1641 |
if ($arr[$i+1]['type'] == 'alpha_reservedWord') { |
|
|
1642 |
$second_upper_data = strtoupper($arr[$i+1]['data']); |
|
|
1643 |
if ($second_upper_data == 'DELETE') { |
|
|
1644 |
$clause = 'on_delete'; |
|
|
1645 |
} |
|
|
1646 |
if ($second_upper_data == 'UPDATE') { |
|
|
1647 |
$clause = 'on_update'; |
|
|
1648 |
} |
|
|
1649 |
if (isset($clause) |
|
|
1650 |
&& ($arr[$i+2]['type'] == 'alpha_reservedWord' |
|
|
1651 |
|
|
|
1652 |
// ugly workaround because currently, NO is not |
|
|
1653 |
// in the list of reserved words in sqlparser.data |
|
|
1654 |
// (we got a bug report about not being able to use |
|
|
1655 |
// 'no' as an identifier) |
|
|
1656 |
|| ($arr[$i+2]['type'] == 'alpha_identifier' |
|
|
1657 |
&& strtoupper($arr[$i+2]['data'])=='NO') ) |
|
|
1658 |
) { |
|
|
1659 |
$third_upper_data = strtoupper($arr[$i+2]['data']); |
|
|
1660 |
if ($third_upper_data == 'CASCADE' |
|
|
1661 |
|| $third_upper_data == 'RESTRICT') { |
|
|
1662 |
$value = $third_upper_data; |
|
|
1663 |
} elseif ($third_upper_data == 'SET' |
|
|
1664 |
|| $third_upper_data == 'NO') { |
|
|
1665 |
if ($arr[$i+3]['type'] == 'alpha_reservedWord') { |
|
|
1666 |
$value = $third_upper_data . '_' . strtoupper($arr[$i+3]['data']); |
|
|
1667 |
} |
|
|
1668 |
} elseif ($third_upper_data == 'CURRENT_TIMESTAMP') { |
|
|
1669 |
if ($clause == 'on_update' |
|
|
1670 |
&& $in_timestamp_options) { |
|
|
1671 |
$create_table_fields[$current_identifier]['on_update_current_timestamp'] = TRUE; |
|
|
1672 |
$seen_default = FALSE; |
|
|
1673 |
} |
|
|
1674 |
|
|
|
1675 |
} else { |
|
|
1676 |
$value = ''; |
|
|
1677 |
} |
|
|
1678 |
if (!empty($value)) { |
|
|
1679 |
$foreign[$foreign_key_number][$clause] = $value; |
|
|
1680 |
} |
|
|
1681 |
unset($clause); |
|
|
1682 |
} // endif (isset($clause)) |
|
|
1683 |
} |
|
|
1684 |
} |
|
|
1685 |
|
|
|
1686 |
} // end of reserved words analysis |
|
|
1687 |
|
|
|
1688 |
|
|
|
1689 |
if ($arr[$i]['type'] == 'punct_bracket_open_round') { |
|
|
1690 |
$brackets_level++; |
|
|
1691 |
if ($seen_create_table && $brackets_level == 1) { |
|
|
1692 |
$in_create_table_fields = TRUE; |
|
|
1693 |
} |
|
|
1694 |
} |
|
|
1695 |
|
|
|
1696 |
|
|
|
1697 |
if ($arr[$i]['type'] == 'punct_bracket_close_round') { |
|
|
1698 |
$brackets_level--; |
|
|
1699 |
if ($seen_references) { |
|
|
1700 |
$seen_references = FALSE; |
|
|
1701 |
} |
|
|
1702 |
if ($seen_create_table && $brackets_level == 0) { |
|
|
1703 |
$in_create_table_fields = FALSE; |
|
|
1704 |
} |
|
|
1705 |
} |
|
|
1706 |
|
|
|
1707 |
if (($arr[$i]['type'] == 'alpha_columnAttrib')) { |
|
|
1708 |
$upper_data = strtoupper($arr[$i]['data']); |
|
|
1709 |
if ($seen_create_table && $in_create_table_fields) { |
|
|
1710 |
if ($upper_data == 'DEFAULT') { |
|
|
1711 |
$seen_default = TRUE; |
|
|
1712 |
} |
|
|
1713 |
} |
|
|
1714 |
} |
|
|
1715 |
|
|
|
1716 |
// note: the "or" part here is a workaround for a bug |
|
|
1717 |
// (see FIXME-2005-10-16) |
|
|
1718 |
if (($arr[$i]['type'] == 'alpha_columnType') || ($arr[$i]['type'] == 'alpha_functionName' && $seen_create_table)) { |
|
|
1719 |
$upper_data = strtoupper($arr[$i]['data']); |
|
|
1720 |
if ($seen_create_table && $in_create_table_fields && isset($current_identifier)) { |
|
|
1721 |
$create_table_fields[$current_identifier]['type'] = $upper_data; |
|
|
1722 |
if ($upper_data == 'TIMESTAMP') { |
|
|
1723 |
$in_timestamp_options = TRUE; |
|
|
1724 |
} else { |
|
|
1725 |
$in_timestamp_options = FALSE; |
|
|
1726 |
} |
|
|
1727 |
} |
|
|
1728 |
} |
|
|
1729 |
|
|
|
1730 |
|
|
|
1731 |
if ($arr[$i]['type'] == 'quote_backtick' || $arr[$i]['type'] == 'alpha_identifier') { |
|
|
1732 |
|
|
|
1733 |
if ($arr[$i]['type'] == 'quote_backtick') { |
|
|
1734 |
// remove backquotes |
|
|
1735 |
$identifier = str_replace('`', '', $arr[$i]['data']); |
|
|
1736 |
} else { |
|
|
1737 |
$identifier = $arr[$i]['data']; |
|
|
1738 |
} |
|
|
1739 |
|
|
|
1740 |
if ($seen_create_table && $in_create_table_fields) { |
|
|
1741 |
$current_identifier = $identifier; |
|
|
1742 |
// warning: we set this one even for non TIMESTAMP type |
|
|
1743 |
$create_table_fields[$current_identifier]['timestamp_not_null'] = FALSE; |
|
|
1744 |
} |
|
|
1745 |
|
|
|
1746 |
if ($seen_constraint) { |
|
|
1747 |
$foreign[$foreign_key_number]['constraint'] = $identifier; |
|
|
1748 |
} |
|
|
1749 |
|
|
|
1750 |
if ($seen_foreign && $brackets_level > 0) { |
|
|
1751 |
$foreign[$foreign_key_number]['index_list'][] = $identifier; |
|
|
1752 |
} |
|
|
1753 |
|
|
|
1754 |
if ($seen_references) { |
|
|
1755 |
// here, the first bracket level corresponds to the |
|
|
1756 |
// bracket of CREATE TABLE |
|
|
1757 |
// so if we are on level 2, it must be the index list |
|
|
1758 |
// of the foreign key REFERENCES |
|
|
1759 |
if ($brackets_level > 1) { |
|
|
1760 |
$foreign[$foreign_key_number]['ref_index_list'][] = $identifier; |
|
|
1761 |
} else { |
|
|
1762 |
// for MySQL 4.0.18, identifier is |
|
|
1763 |
// `table` or `db`.`table` |
|
|
1764 |
// the first pass will pick the db name |
|
|
1765 |
// the next pass will execute the else and pick the |
|
|
1766 |
// db name in $db_table[0] |
|
|
1767 |
if ($arr[$i+1]['type'] == 'punct_qualifier') { |
|
|
1768 |
$foreign[$foreign_key_number]['ref_db_name'] = $identifier; |
|
|
1769 |
} else { |
|
|
1770 |
// for MySQL 4.0.16, identifier is |
|
|
1771 |
// `table` or `db.table` |
|
|
1772 |
$db_table = explode('.', $identifier); |
|
|
1773 |
if (isset($db_table[1])) { |
|
|
1774 |
$foreign[$foreign_key_number]['ref_db_name'] = $db_table[0]; |
|
|
1775 |
$foreign[$foreign_key_number]['ref_table_name'] = $db_table[1]; |
|
|
1776 |
} else { |
|
|
1777 |
$foreign[$foreign_key_number]['ref_table_name'] = $db_table[0]; |
|
|
1778 |
} |
|
|
1779 |
} |
|
|
1780 |
} |
|
|
1781 |
} |
|
|
1782 |
} |
|
|
1783 |
} // end for $i (loop #3) |
|
|
1784 |
|
|
|
1785 |
|
|
|
1786 |
// Fill the $subresult array |
|
|
1787 |
|
|
|
1788 |
if (isset($create_table_fields)) { |
|
|
1789 |
$subresult['create_table_fields'] = $create_table_fields; |
|
|
1790 |
} |
|
|
1791 |
|
|
|
1792 |
if (isset($foreign)) { |
|
|
1793 |
$subresult['foreign_keys'] = $foreign; |
|
|
1794 |
} |
|
|
1795 |
|
|
|
1796 |
if (isset($select_expr_clause)) { |
|
|
1797 |
$subresult['select_expr_clause'] = $select_expr_clause; |
|
|
1798 |
} |
|
|
1799 |
if (isset($from_clause)) { |
|
|
1800 |
$subresult['from_clause'] = $from_clause; |
|
|
1801 |
} |
|
|
1802 |
if (isset($group_by_clause)) { |
|
|
1803 |
$subresult['group_by_clause'] = $group_by_clause; |
|
|
1804 |
} |
|
|
1805 |
if (isset($order_by_clause)) { |
|
|
1806 |
$subresult['order_by_clause'] = $order_by_clause; |
|
|
1807 |
} |
|
|
1808 |
if (isset($having_clause)) { |
|
|
1809 |
$subresult['having_clause'] = $having_clause; |
|
|
1810 |
} |
|
|
1811 |
if (isset($where_clause)) { |
|
|
1812 |
$subresult['where_clause'] = $where_clause; |
|
|
1813 |
} |
|
|
1814 |
if (isset($unsorted_query) && !empty($unsorted_query)) { |
|
|
1815 |
$subresult['unsorted_query'] = $unsorted_query; |
|
|
1816 |
} |
|
|
1817 |
if (isset($where_clause_identifiers)) { |
|
|
1818 |
$subresult['where_clause_identifiers'] = $where_clause_identifiers; |
|
|
1819 |
} |
|
|
1820 |
|
|
|
1821 |
if (isset($position_of_first_select)) { |
|
|
1822 |
$subresult['position_of_first_select'] = $position_of_first_select; |
|
|
1823 |
$subresult['section_before_limit'] = $section_before_limit; |
|
|
1824 |
$subresult['section_after_limit'] = $section_after_limit; |
|
|
1825 |
} |
|
|
1826 |
|
|
|
1827 |
// They are naughty and didn't have a trailing semi-colon, |
|
|
1828 |
// then still handle it properly |
|
|
1829 |
if ($subresult['querytype'] != '') { |
|
|
1830 |
$result[] = $subresult; |
|
|
1831 |
} |
|
|
1832 |
return $result; |
|
|
1833 |
} // end of the "PMA_SQP_analyze()" function |
|
|
1834 |
|
|
|
1835 |
|
|
|
1836 |
/** |
|
|
1837 |
* Colorizes SQL queries html formatted |
|
|
1838 |
* |
|
|
1839 |
* @param array The SQL queries html formatted |
|
|
1840 |
* |
|
|
1841 |
* @return array The colorized SQL queries |
|
|
1842 |
* |
|
|
1843 |
* @access public |
|
|
1844 |
*/ |
|
|
1845 |
function PMA_SQP_formatHtml_colorize($arr) |
|
|
1846 |
{ |
|
|
1847 |
$i = $GLOBALS['PMA_strpos']($arr['type'], '_'); |
|
|
1848 |
$class = ''; |
|
|
1849 |
if ($i > 0) { |
|
|
1850 |
$class = 'syntax_' . PMA_substr($arr['type'], 0, $i) . ' '; |
|
|
1851 |
} |
|
|
1852 |
|
|
|
1853 |
$class .= 'syntax_' . $arr['type']; |
|
|
1854 |
|
|
|
1855 |
//TODO: check why adding a "\n" after the </span> would cause extra |
|
|
1856 |
// blanks to be displayed: |
|
|
1857 |
// SELECT p . person_name |
|
|
1858 |
|
|
|
1859 |
return '<span class="' . $class . '">' . htmlspecialchars($arr['data']) . '</span>'; |
|
|
1860 |
} // end of the "PMA_SQP_formatHtml_colorize()" function |
|
|
1861 |
|
|
|
1862 |
|
|
|
1863 |
/** |
|
|
1864 |
* Formats SQL queries to html |
|
|
1865 |
* |
|
|
1866 |
* @param array The SQL queries |
|
|
1867 |
* @param string mode |
|
|
1868 |
* @param integer starting token |
|
|
1869 |
* @param integer number of tokens to format, -1 = all |
|
|
1870 |
* |
|
|
1871 |
* @return string The formatted SQL queries |
|
|
1872 |
* |
|
|
1873 |
* @access public |
|
|
1874 |
*/ |
|
|
1875 |
function PMA_SQP_formatHtml($arr, $mode='color', $start_token=0, |
|
|
1876 |
$number_of_tokens=-1) |
|
|
1877 |
{ |
|
|
1878 |
// then check for an array |
|
|
1879 |
if (!is_array($arr)) { |
|
|
1880 |
return htmlspecialchars($arr); |
|
|
1881 |
} |
|
|
1882 |
// first check for the SQL parser having hit an error |
|
|
1883 |
if (PMA_SQP_isError()) { |
|
|
1884 |
return htmlspecialchars($arr['raw']); |
|
|
1885 |
} |
|
|
1886 |
// else do it properly |
|
|
1887 |
switch ($mode) { |
|
|
1888 |
case 'color': |
|
|
1889 |
$str = '<span class="syntax">'; |
|
|
1890 |
$html_line_break = '<br />'; |
|
|
1891 |
break; |
|
|
1892 |
case 'query_only': |
|
|
1893 |
$str = ''; |
|
|
1894 |
$html_line_break = "\n"; |
|
|
1895 |
break; |
|
|
1896 |
case 'text': |
|
|
1897 |
$str = ''; |
|
|
1898 |
$html_line_break = '<br />'; |
|
|
1899 |
break; |
|
|
1900 |
} // end switch |
|
|
1901 |
$indent = 0; |
|
|
1902 |
$bracketlevel = 0; |
|
|
1903 |
$functionlevel = 0; |
|
|
1904 |
$infunction = FALSE; |
|
|
1905 |
$space_punct_listsep = ' '; |
|
|
1906 |
$space_punct_listsep_function_name = ' '; |
|
|
1907 |
// $space_alpha_reserved_word = '<br />'."\n"; |
|
|
1908 |
$space_alpha_reserved_word = ' '; |
|
|
1909 |
|
|
|
1910 |
$keywords_with_brackets_1before = array( |
|
|
1911 |
'INDEX', |
|
|
1912 |
'KEY', |
|
|
1913 |
'ON', |
|
|
1914 |
'USING' |
|
|
1915 |
); |
|
|
1916 |
$keywords_with_brackets_1before_cnt = 4; |
|
|
1917 |
|
|
|
1918 |
$keywords_with_brackets_2before = array( |
|
|
1919 |
'IGNORE', |
|
|
1920 |
'INDEX', |
|
|
1921 |
'INTO', |
|
|
1922 |
'KEY', |
|
|
1923 |
'PRIMARY', |
|
|
1924 |
'PROCEDURE', |
|
|
1925 |
'REFERENCES', |
|
|
1926 |
'UNIQUE', |
|
|
1927 |
'USE' |
|
|
1928 |
); |
|
|
1929 |
// $keywords_with_brackets_2before_cnt = count($keywords_with_brackets_2before); |
|
|
1930 |
$keywords_with_brackets_2before_cnt = 9; |
|
|
1931 |
|
|
|
1932 |
// These reserved words do NOT get a newline placed near them. |
|
|
1933 |
$keywords_no_newline = array( |
|
|
1934 |
'AS', |
|
|
1935 |
'ASC', |
|
|
1936 |
'DESC', |
|
|
1937 |
'DISTINCT', |
|
|
1938 |
'HOUR', |
|
|
1939 |
'INTERVAL', |
|
|
1940 |
'IS', |
|
|
1941 |
'LIKE', |
|
|
1942 |
'NOT', |
|
|
1943 |
'NULL', |
|
|
1944 |
'ON', |
|
|
1945 |
'REGEXP' |
|
|
1946 |
); |
|
|
1947 |
$keywords_no_newline_cnt = 12; |
|
|
1948 |
|
|
|
1949 |
// These reserved words introduce a privilege list |
|
|
1950 |
$keywords_priv_list = array( |
|
|
1951 |
'GRANT', |
|
|
1952 |
'REVOKE' |
|
|
1953 |
); |
|
|
1954 |
$keywords_priv_list_cnt = 2; |
|
|
1955 |
|
|
|
1956 |
if ($number_of_tokens == -1) { |
|
|
1957 |
$arraysize = $arr['len']; |
|
|
1958 |
} else { |
|
|
1959 |
$arraysize = $number_of_tokens; |
|
|
1960 |
} |
|
|
1961 |
$typearr = array(); |
|
|
1962 |
if ($arraysize >= 0) { |
|
|
1963 |
$typearr[0] = ''; |
|
|
1964 |
$typearr[1] = ''; |
|
|
1965 |
$typearr[2] = ''; |
|
|
1966 |
//$typearr[3] = $arr[0]['type']; |
|
|
1967 |
$typearr[3] = $arr[$start_token]['type']; |
|
|
1968 |
} |
|
|
1969 |
|
|
|
1970 |
$in_priv_list = FALSE; |
|
|
1971 |
for ($i = $start_token; $i < $arraysize; $i++) { |
|
|
1972 |
// DEBUG echo "<b>" . $arr[$i]['data'] . "</b> " . $arr[$i]['type'] . "<br />"; |
|
|
1973 |
$before = ''; |
|
|
1974 |
$after = ''; |
|
|
1975 |
$indent = 0; |
|
|
1976 |
// array_shift($typearr); |
|
|
1977 |
/* |
|
|
1978 |
|
|
|
1979 |
1 prev |
|
|
1980 |
2 current |
|
|
1981 |
3 next |
|
|
1982 |
*/ |
|
|
1983 |
if (($i + 1) < $arraysize) { |
|
|
1984 |
// array_push($typearr, $arr[$i + 1]['type']); |
|
|
1985 |
$typearr[4] = $arr[$i + 1]['type']; |
|
|
1986 |
} else { |
|
|
1987 |
//array_push($typearr, null); |
|
|
1988 |
$typearr[4] = ''; |
|
|
1989 |
} |
|
|
1990 |
|
|
|
1991 |
for ($j=0; $j<4; $j++) { |
|
|
1992 |
$typearr[$j] = $typearr[$j + 1]; |
|
|
1993 |
} |
|
|
1994 |
|
|
|
1995 |
switch ($typearr[2]) { |
|
|
1996 |
case 'white_newline': |
|
|
1997 |
$before = ''; |
|
|
1998 |
break; |
|
|
1999 |
case 'punct_bracket_open_round': |
|
|
2000 |
$bracketlevel++; |
|
|
2001 |
$infunction = FALSE; |
|
|
2002 |
// Make sure this array is sorted! |
|
|
2003 |
if (($typearr[1] == 'alpha_functionName') || ($typearr[1] == 'alpha_columnType') || ($typearr[1] == 'punct') |
|
|
2004 |
|| ($typearr[3] == 'digit_integer') || ($typearr[3] == 'digit_hex') || ($typearr[3] == 'digit_float') |
|
|
2005 |
|| (($typearr[0] == 'alpha_reservedWord') |
|
|
2006 |
&& PMA_STR_binarySearchInArr(strtoupper($arr[$i - 2]['data']), $keywords_with_brackets_2before, $keywords_with_brackets_2before_cnt)) |
|
|
2007 |
|| (($typearr[1] == 'alpha_reservedWord') |
|
|
2008 |
&& PMA_STR_binarySearchInArr(strtoupper($arr[$i - 1]['data']), $keywords_with_brackets_1before, $keywords_with_brackets_1before_cnt)) |
|
|
2009 |
) { |
|
|
2010 |
$functionlevel++; |
|
|
2011 |
$infunction = TRUE; |
|
|
2012 |
$after .= ' '; |
|
|
2013 |
} else { |
|
|
2014 |
$indent++; |
|
|
2015 |
$after .= ($mode != 'query_only' ? '<div class="syntax_indent' . $indent . '">' : ' '); |
|
|
2016 |
} |
|
|
2017 |
break; |
|
|
2018 |
case 'alpha_identifier': |
|
|
2019 |
if (($typearr[1] == 'punct_qualifier') || ($typearr[3] == 'punct_qualifier')) { |
|
|
2020 |
$after = ''; |
|
|
2021 |
$before = ''; |
|
|
2022 |
} |
|
|
2023 |
if (($typearr[3] == 'alpha_columnType') || ($typearr[3] == 'alpha_identifier')) { |
|
|
2024 |
$after .= ' '; |
|
|
2025 |
} |
|
|
2026 |
break; |
|
|
2027 |
case 'punct_qualifier': |
|
|
2028 |
$before = ''; |
|
|
2029 |
$after = ''; |
|
|
2030 |
break; |
|
|
2031 |
case 'punct_listsep': |
|
|
2032 |
if ($infunction == TRUE) { |
|
|
2033 |
$after .= $space_punct_listsep_function_name; |
|
|
2034 |
} else { |
|
|
2035 |
$after .= $space_punct_listsep; |
|
|
2036 |
} |
|
|
2037 |
break; |
|
|
2038 |
case 'punct_queryend': |
|
|
2039 |
if (($typearr[3] != 'comment_mysql') && ($typearr[3] != 'comment_ansi') && $typearr[3] != 'comment_c') { |
|
|
2040 |
$after .= $html_line_break; |
|
|
2041 |
$after .= $html_line_break; |
|
|
2042 |
} |
|
|
2043 |
$space_punct_listsep = ' '; |
|
|
2044 |
$space_punct_listsep_function_name = ' '; |
|
|
2045 |
$space_alpha_reserved_word = ' '; |
|
|
2046 |
$in_priv_list = FALSE; |
|
|
2047 |
break; |
|
|
2048 |
case 'comment_mysql': |
|
|
2049 |
case 'comment_ansi': |
|
|
2050 |
$after .= $html_line_break; |
|
|
2051 |
break; |
|
|
2052 |
case 'punct': |
|
|
2053 |
$before .= ' '; |
|
|
2054 |
// workaround for |
|
|
2055 |
// select * from mytable limit 0,-1 |
|
|
2056 |
// (a side effect of this workaround is that |
|
|
2057 |
// select 20 - 9 |
|
|
2058 |
// becomes |
|
|
2059 |
// select 20 -9 |
|
|
2060 |
// ) |
|
|
2061 |
if ($typearr[3] != 'digit_integer') { |
|
|
2062 |
$after .= ' '; |
|
|
2063 |
} |
|
|
2064 |
break; |
|
|
2065 |
case 'punct_bracket_close_round': |
|
|
2066 |
$bracketlevel--; |
|
|
2067 |
if ($infunction == TRUE) { |
|
|
2068 |
$functionlevel--; |
|
|
2069 |
$after .= ' '; |
|
|
2070 |
$before .= ' '; |
|
|
2071 |
} else { |
|
|
2072 |
$indent--; |
|
|
2073 |
$before .= ($mode != 'query_only' ? '</div>' : ' '); |
|
|
2074 |
} |
|
|
2075 |
$infunction = ($functionlevel > 0) ? TRUE : FALSE; |
|
|
2076 |
break; |
|
|
2077 |
case 'alpha_columnType': |
|
|
2078 |
if ($typearr[3] == 'alpha_columnAttrib') { |
|
|
2079 |
$after .= ' '; |
|
|
2080 |
} |
|
|
2081 |
if ($typearr[1] == 'alpha_columnType') { |
|
|
2082 |
$before .= ' '; |
|
|
2083 |
} |
|
|
2084 |
break; |
|
|
2085 |
case 'alpha_columnAttrib': |
|
|
2086 |
|
|
|
2087 |
// ALTER TABLE tbl_name AUTO_INCREMENT = 1 |
|
|
2088 |
// COLLATE LATIN1_GENERAL_CI DEFAULT |
|
|
2089 |
if ($typearr[1] == 'alpha_identifier' || $typearr[1] == 'alpha_charset') { |
|
|
2090 |
$before .= ' '; |
|
|
2091 |
} |
|
|
2092 |
if (($typearr[3] == 'alpha_columnAttrib') || ($typearr[3] == 'quote_single') || ($typearr[3] == 'digit_integer')) { |
|
|
2093 |
$after .= ' '; |
|
|
2094 |
} |
|
|
2095 |
// workaround for |
|
|
2096 |
// select * from mysql.user where binary user="root" |
|
|
2097 |
// binary is marked as alpha_columnAttrib |
|
|
2098 |
// but should be marked as a reserved word |
|
|
2099 |
if (strtoupper($arr[$i]['data']) == 'BINARY' |
|
|
2100 |
&& $typearr[3] == 'alpha_identifier') { |
|
|
2101 |
$after .= ' '; |
|
|
2102 |
} |
|
|
2103 |
break; |
|
|
2104 |
case 'alpha_reservedWord': |
|
|
2105 |
// do not uppercase the reserved word if we are calling |
|
|
2106 |
// this function in query_only mode, because we need |
|
|
2107 |
// the original query (otherwise we get problems with |
|
|
2108 |
// semi-reserved words like "storage" which is legal |
|
|
2109 |
// as an identifier name) |
|
|
2110 |
|
|
|
2111 |
if ($mode != 'query_only') { |
|
|
2112 |
$arr[$i]['data'] = strtoupper($arr[$i]['data']); |
|
|
2113 |
} |
|
|
2114 |
|
|
|
2115 |
if ((($typearr[1] != 'alpha_reservedWord') |
|
|
2116 |
|| (($typearr[1] == 'alpha_reservedWord') |
|
|
2117 |
&& PMA_STR_binarySearchInArr(strtoupper($arr[$i - 1]['data']), $keywords_no_newline, $keywords_no_newline_cnt))) |
|
|
2118 |
&& ($typearr[1] != 'punct_level_plus') |
|
|
2119 |
&& (!PMA_STR_binarySearchInArr($arr[$i]['data'], $keywords_no_newline, $keywords_no_newline_cnt))) { |
|
|
2120 |
// do not put a space before the first token, because |
|
|
2121 |
// we use a lot of eregi() checking for the first |
|
|
2122 |
// reserved word at beginning of query |
|
|
2123 |
// so do not put a newline before |
|
|
2124 |
// |
|
|
2125 |
// also we must not be inside a privilege list |
|
|
2126 |
if ($i > 0) { |
|
|
2127 |
// the alpha_identifier exception is there to |
|
|
2128 |
// catch cases like |
|
|
2129 |
// GRANT SELECT ON mydb.mytable TO myuser@localhost |
|
|
2130 |
// (else, we get mydb.mytableTO ) |
|
|
2131 |
// |
|
|
2132 |
// the quote_single exception is there to |
|
|
2133 |
// catch cases like |
|
|
2134 |
// GRANT ... TO 'marc'@'domain.com' IDENTIFIED... |
|
|
2135 |
// |
|
|
2136 |
// TODO: fix all cases and find why this happens |
|
|
2137 |
|
|
|
2138 |
if (!$in_priv_list || $typearr[1] == 'alpha_identifier' || $typearr[1] == 'quote_single' || $typearr[1] == 'white_newline') { |
|
|
2139 |
$before .= $space_alpha_reserved_word; |
|
|
2140 |
} |
|
|
2141 |
} else { |
|
|
2142 |
// on first keyword, check if it introduces a |
|
|
2143 |
// privilege list |
|
|
2144 |
if (PMA_STR_binarySearchInArr($arr[$i]['data'], $keywords_priv_list, $keywords_priv_list_cnt)) { |
|
|
2145 |
$in_priv_list = TRUE; |
|
|
2146 |
} |
|
|
2147 |
} |
|
|
2148 |
} else { |
|
|
2149 |
$before .= ' '; |
|
|
2150 |
} |
|
|
2151 |
|
|
|
2152 |
switch ($arr[$i]['data']) { |
|
|
2153 |
case 'CREATE': |
|
|
2154 |
if (!$in_priv_list) { |
|
|
2155 |
$space_punct_listsep = $html_line_break; |
|
|
2156 |
$space_alpha_reserved_word = ' '; |
|
|
2157 |
} |
|
|
2158 |
break; |
|
|
2159 |
case 'EXPLAIN': |
|
|
2160 |
case 'DESCRIBE': |
|
|
2161 |
case 'SET': |
|
|
2162 |
case 'ALTER': |
|
|
2163 |
case 'DELETE': |
|
|
2164 |
case 'SHOW': |
|
|
2165 |
case 'DROP': |
|
|
2166 |
case 'UPDATE': |
|
|
2167 |
case 'TRUNCATE': |
|
|
2168 |
case 'ANALYZE': |
|
|
2169 |
case 'ANALYSE': |
|
|
2170 |
if (!$in_priv_list) { |
|
|
2171 |
$space_punct_listsep = $html_line_break; |
|
|
2172 |
$space_alpha_reserved_word = ' '; |
|
|
2173 |
} |
|
|
2174 |
break; |
|
|
2175 |
case 'INSERT': |
|
|
2176 |
case 'REPLACE': |
|
|
2177 |
if (!$in_priv_list) { |
|
|
2178 |
$space_punct_listsep = $html_line_break; |
|
|
2179 |
$space_alpha_reserved_word = $html_line_break; |
|
|
2180 |
} |
|
|
2181 |
break; |
|
|
2182 |
case 'VALUES': |
|
|
2183 |
$space_punct_listsep = ' '; |
|
|
2184 |
$space_alpha_reserved_word = $html_line_break; |
|
|
2185 |
break; |
|
|
2186 |
case 'SELECT': |
|
|
2187 |
$space_punct_listsep = ' '; |
|
|
2188 |
$space_alpha_reserved_word = $html_line_break; |
|
|
2189 |
break; |
|
|
2190 |
default: |
|
|
2191 |
break; |
|
|
2192 |
} // end switch ($arr[$i]['data']) |
|
|
2193 |
|
|
|
2194 |
$after .= ' '; |
|
|
2195 |
break; |
|
|
2196 |
case 'digit_integer': |
|
|
2197 |
case 'digit_float': |
|
|
2198 |
case 'digit_hex': |
|
|
2199 |
//TODO: could there be other types preceding a digit? |
|
|
2200 |
if ($typearr[1] == 'alpha_reservedWord') { |
|
|
2201 |
$after .= ' '; |
|
|
2202 |
} |
|
|
2203 |
if ($infunction && $typearr[3] == 'punct_bracket_close_round') { |
|
|
2204 |
$after .= ' '; |
|
|
2205 |
} |
|
|
2206 |
if ($typearr[1] == 'alpha_columnAttrib') { |
|
|
2207 |
$before .= ' '; |
|
|
2208 |
} |
|
|
2209 |
break; |
|
|
2210 |
case 'alpha_variable': |
|
|
2211 |
// other workaround for a problem similar to the one |
|
|
2212 |
// explained below for quote_single |
|
|
2213 |
if (!$in_priv_list) { |
|
|
2214 |
$after = ' '; |
|
|
2215 |
} |
|
|
2216 |
break; |
|
|
2217 |
case 'quote_double': |
|
|
2218 |
case 'quote_single': |
|
|
2219 |
// workaround: for the query |
|
|
2220 |
// REVOKE SELECT ON `base2\_db`.* FROM 'user'@'%' |
|
|
2221 |
// the @ is incorrectly marked as alpha_variable |
|
|
2222 |
// in the parser, and here, the '%' gets a blank before, |
|
|
2223 |
// which is a syntax error |
|
|
2224 |
if ($typearr[1] !='alpha_variable') { |
|
|
2225 |
$before .= ' '; |
|
|
2226 |
} |
|
|
2227 |
if ($infunction && $typearr[3] == 'punct_bracket_close_round') { |
|
|
2228 |
$after .= ' '; |
|
|
2229 |
} |
|
|
2230 |
break; |
|
|
2231 |
case 'quote_backtick': |
|
|
2232 |
if ($typearr[3] != 'punct_qualifier') { |
|
|
2233 |
$after .= ' '; |
|
|
2234 |
} |
|
|
2235 |
if ($typearr[1] != 'punct_qualifier') { |
|
|
2236 |
$before .= ' '; |
|
|
2237 |
} |
|
|
2238 |
break; |
|
|
2239 |
default: |
|
|
2240 |
break; |
|
|
2241 |
} // end switch ($typearr[2]) |
|
|
2242 |
|
|
|
2243 |
/* |
|
|
2244 |
if ($typearr[3] != 'punct_qualifier') { |
|
|
2245 |
$after .= ' '; |
|
|
2246 |
} |
|
|
2247 |
$after .= "\n"; |
|
|
2248 |
*/ |
|
|
2249 |
$str .= $before . ($mode=='color' ? PMA_SQP_formatHTML_colorize($arr[$i]) : $arr[$i]['data']). $after; |
|
|
2250 |
} // end for |
|
|
2251 |
if ($mode=='color') { |
|
|
2252 |
$str .= '</span>'; |
|
|
2253 |
} |
|
|
2254 |
|
|
|
2255 |
return $str; |
|
|
2256 |
} // end of the "PMA_SQP_formatHtml()" function |
|
|
2257 |
} |
|
|
2258 |
|
|
|
2259 |
/** |
|
|
2260 |
* Builds a CSS rule used for html formatted SQL queries |
|
|
2261 |
* |
|
|
2262 |
* @param string The class name |
|
|
2263 |
* @param string The property name |
|
|
2264 |
* @param string The property value |
|
|
2265 |
* |
|
|
2266 |
* @return string The CSS rule |
|
|
2267 |
* |
|
|
2268 |
* @access public |
|
|
2269 |
* |
|
|
2270 |
* @see PMA_SQP_buildCssData() |
|
|
2271 |
*/ |
|
|
2272 |
function PMA_SQP_buildCssRule($classname, $property, $value) |
|
|
2273 |
{ |
|
|
2274 |
$str = '.' . $classname . ' {'; |
|
|
2275 |
if ($value != '') { |
|
|
2276 |
$str .= $property . ': ' . $value . ';'; |
|
|
2277 |
} |
|
|
2278 |
$str .= '}' . "\n"; |
|
|
2279 |
|
|
|
2280 |
return $str; |
|
|
2281 |
} // end of the "PMA_SQP_buildCssRule()" function |
|
|
2282 |
|
|
|
2283 |
|
|
|
2284 |
/** |
|
|
2285 |
* Builds CSS rules used for html formatted SQL queries |
|
|
2286 |
* |
|
|
2287 |
* @return string The CSS rules set |
|
|
2288 |
* |
|
|
2289 |
* @access public |
|
|
2290 |
* |
|
|
2291 |
* @global array The current PMA configuration |
|
|
2292 |
* |
|
|
2293 |
* @see PMA_SQP_buildCssRule() |
|
|
2294 |
*/ |
|
|
2295 |
function PMA_SQP_buildCssData() |
|
|
2296 |
{ |
|
|
2297 |
global $cfg; |
|
|
2298 |
|
|
|
2299 |
$css_string = ''; |
|
|
2300 |
foreach ($cfg['SQP']['fmtColor'] AS $key => $col) { |
|
|
2301 |
$css_string .= PMA_SQP_buildCssRule('syntax_' . $key, 'color', $col); |
|
|
2302 |
} |
|
|
2303 |
|
|
|
2304 |
for ($i = 0; $i < 8; $i++) { |
|
|
2305 |
$css_string .= PMA_SQP_buildCssRule('syntax_indent' . $i, 'margin-left', ($i * $cfg['SQP']['fmtInd']) . $cfg['SQP']['fmtIndUnit']); |
|
|
2306 |
} |
|
|
2307 |
|
|
|
2308 |
return $css_string; |
|
|
2309 |
} // end of the "PMA_SQP_buildCssData()" function |
|
|
2310 |
|
|
|
2311 |
if ( ! defined( 'PMA_MINIMUM_COMMON' ) ) { |
|
|
2312 |
/** |
|
|
2313 |
* Gets SQL queries with no format |
|
|
2314 |
* |
|
|
2315 |
* @param array The SQL queries list |
|
|
2316 |
* |
|
|
2317 |
* @return string The SQL queries with no format |
|
|
2318 |
* |
|
|
2319 |
* @access public |
|
|
2320 |
*/ |
|
|
2321 |
function PMA_SQP_formatNone($arr) |
|
|
2322 |
{ |
|
|
2323 |
$formatted_sql = htmlspecialchars($arr['raw']); |
|
|
2324 |
$formatted_sql = preg_replace("@((\015\012)|(\015)|(\012)){3,}@", "\n\n", $formatted_sql); |
|
|
2325 |
|
|
|
2326 |
return $formatted_sql; |
|
|
2327 |
} // end of the "PMA_SQP_formatNone()" function |
|
|
2328 |
|
|
|
2329 |
|
|
|
2330 |
/** |
|
|
2331 |
* Gets SQL queries in text format |
|
|
2332 |
* |
|
|
2333 |
* @param array The SQL queries list |
|
|
2334 |
* |
|
|
2335 |
* @return string The SQL queries in text format |
|
|
2336 |
* |
|
|
2337 |
* @access public |
|
|
2338 |
*/ |
|
|
2339 |
function PMA_SQP_formatText($arr) |
|
|
2340 |
{ |
|
|
2341 |
/** |
|
|
2342 |
* TODO WRITE THIS! |
|
|
2343 |
*/ |
|
|
2344 |
return PMA_SQP_formatNone($arr); |
|
|
2345 |
} // end of the "PMA_SQP_formatText()" function |
|
|
2346 |
} // end if: minimal common.lib needed? |
|
|
2347 |
|
|
|
2348 |
?> |