* http://www.orbis-terrarum.net/?l=people.robbat2 * * These functions define an SQL parser system, capable of understanding and * extracting data from a MySQL type SQL query. * * The basic procedure for using the new SQL parser: * On any page that needs to extract data from a query or to pretty-print a * query, you need code like this up at the top: * * ($sql contains the query) * $parsed_sql = PMA_SQP_parse($sql); * * If you want to extract data from it then, you just need to run * $sql_info = PMA_SQP_analyze($parsed_sql); * (returned structure of this function is being rewritten presently); * * If you want a pretty-printed version of the query, do: * $string = PMA_SQP_formatHtml($parsed_sql); * (note that that you need to have syntax.css.php3 included somehow in your * page for it to work, I recommend '' at the moment.) */ if (!defined('PMA_SQP_LIB_INCLUDED')) { define('PMA_SQP_LIB_INCLUDED', 1); /** * Include the string libarry as we use it heavily */ include('./libraries/string.lib.php3'); /** * Include data for the SQL Parser */ include('./libraries/sqlparser.data.php3'); if (!defined('DEBUG_TIMING')) { function PMA_SQP_arrayAdd(&$arr, $type, $data, &$arrsize) { $arr[] = array('type' => $type, 'data' => $data); $arrsize++; } // end of the "PMA_SQP_arrayAdd" function } else { function PMA_SQP_arrayAdd(&$arr, $type, $data, &$arrsize) { global $timer; $t = $timer; $arr[] = array('type' => $type, 'data' => $data , 'time' => $t); $timer = microtime(); $arrsize++; } // end of the "PMA_SQP_arrayAdd" function } // end if... else... function PMA_SQP_parse($sql) { global $cfg; global $PMA_SQPdata_column_attrib, $PMA_SQPdata_reserved_word, $PMA_SQPdata_column_type, $PMA_SQPdata_function_name, $PMA_SQPdata_column_attrib_cnt, $PMA_SQPdata_reserved_word_cnt, $PMA_SQPdata_column_type_cnt, $PMA_SQPdata_function_name_cnt; // if the SQL parser is disabled just return the original query string if ($cfg['SQP']['enable'] == FALSE) { // Debug : echo 'FALSE'; return $sql; } $len = strlen($sql); if ($len == 0) { return array(); } $sql_array = array(); $sql_array['raw'] = $sql; $count1 = 0; $count2 = 0; $punct_queryend = ';'; $punct_qualifier = '.'; $punct_listsep = ','; $punct_level_plus = '('; $punct_level_minus = ')'; $digit_floatdecimal = '.'; $digit_hexset = 'x'; $bracket_list = '()[]{}'; $allpunct_list = '-,;:!?/.^~\*&%+<=>|'; $allpunct_list_pair = array ( 0 => '!=', 1 => '&&', 2 => ':=', 3 => '<<', 4 => '<=', 5 => '<=>', 6 => '<>', 7 => '>=', 8 => '>>', 9 => '||' ); $allpunct_list_pair_size = 10; //count($allpunct_list_pair); $quote_list = "\'\"\`"; $arraysize = 0; while ($count2 < $len) { $c = $sql[$count2]; $count1 = $count2; if (($c == "\n")) { $count2++; PMA_SQP_arrayAdd($sql_array, 'white_newline', '', $arraysize); continue; } // Checks for white space if (PMA_STR_isSpace($c)) { $count2++; continue; } // Checks for comment lines. // MySQL style # // C style /* */ // ANSI style -- if (($c == '#') || (($count2 + 1 < $len) && ($c == '/') && ($sql[$count2 + 1] == '*')) || (($count2 + 2 < $len) && ($c == '-') && ($sql[$count2 + 1] == '-') && ($sql[$count2 + 2] == ' '))) { $count2++; $pos = 0; $type = 'bad'; switch ($c) { case '#': $type = 'mysql'; case '-': $type = 'ansi'; $pos = strpos($sql, "\n", $count2); break; case '/': $type = 'c'; $pos = strpos($sql, '*/', $count2); $pos += 2; break; default: break; } // end switch $count2 = ($pos < $count2) ? $len : $pos; $str = substr($sql, $count1, $count2 - $count1); PMA_SQP_arrayAdd($sql_array, 'comment_' . $type, $str, $arraysize); continue; } // end if // Checks for something inside quotation marks if (PMA_STR_strInStr($c, $quote_list)) { $startquotepos = $count2; $quotetype = $c; $count2++; $escaped = FALSE; $escaped_escaped = FALSE; $pos = $count2; $oldpos = 0; do { $oldpos = $pos; $pos = strpos(' ' . $sql, $quotetype, $oldpos + 1) - 1; // ($pos === FALSE) if ($pos < 0) { trigger_error('Syntax: Unclosed quote (' . $quotetype . ') at ' . $startquotepos); return; } // If the quote is the first character, it can't be // escaped, so don't do the rest of the code if ($pos == 0) { break; } if (PMA_STR_charIsEscaped($sql, $pos)) { $pos ++; continue; } else { break; } } while ($len > $pos); // end do $count2 = $pos; $count2++; $type = 'quote_'; switch ($quotetype) { case '\'': $type .= 'single'; break; case '"': $type .= 'double'; break; case '`': $type .= 'backtick'; break; default: break; } // end switch $data = substr($sql, $count1, $count2 - $count1); PMA_SQP_arrayAdd($sql_array, $type, $data, $arraysize); continue; } // Checks for brackets if (PMA_STR_strInStr($c, $bracket_list)) { // All bracket tokens are only one item long $count2++; $type_type = ''; if (PMA_STR_strInStr($c, '([{')) { $type_type = 'open'; } else { $type_type = 'close'; } $type_style = ''; if (PMA_STR_strInStr($c, '()')) { $type_style = 'round'; } elseif (PMA_STR_strInStr($c, '[]')) { $type_style = 'square'; } else { $type_style = 'curly'; } $type = 'punct_bracket_' . $type_type . '_' . $type_style; PMA_SQP_arrayAdd($sql_array, $type, $c, $arraysize); continue; } // Checks for punct if (PMA_STR_strInStr($c, $allpunct_list)) { while (($count2 < $len) && PMA_STR_strInStr($sql[$count2], $allpunct_list)) { $count2++; } $l = $count2 - $count1; if ($l == 1) { $punct_data = $c; } else { $punct_data = substr($sql, $count1, $l); } // Special case, sometimes, althought two characters are // adjectent directly, they ACTUALLY need to be seperate if ($l == 1) { $t_suffix = ''; switch ($punct_data) { case $punct_queryend: $t_suffix = '_queryend'; break; case $punct_qualifier: $t_suffix = '_qualifier'; break; case $punct_listsep: $t_suffix = '_listsep'; break; default: break; } PMA_SQP_arrayAdd($sql_array, 'punct' . $t_suffix, $punct_data, $arraysize); } else if (PMA_STR_binarySearchInArr($punct_data, $allpunct_list_pair, $allpunct_list_pair_size)) { // Ok, we have one of the valid combined punct expressions PMA_SQP_arrayAdd($sql_array, 'punct', $punct_data, $arraysize); } else { // Bad luck, lets split it up more $first = $punct_data[0]; $first2 = $punct_data[0] . $punct_data[1]; $last2 = $punct_data[$l - 2] . $punct_data[$l - 1]; $last = $punct_data[$l - 1]; if (($first == ',') || ($first == ';') || ($first == '.') || ($first = '*')) { $count2 = $count1 + 1; $punct_data = $first; } else if (($last2 == '/*') || ($last2 == '--')) { $count2 -= 2; $punct_data = substr($sql, $count1, $count2 - $count1); } else if (($last == '-') || ($last == '+') || ($last == '!')) { $count2--; $punct_data = substr($sql, $count1, $count2 - $count1); } else { trigger_error('Syntax: Unknown punctation string (' . $punct_data . ') at ' . $count1); return; } PMA_SQP_arrayAdd($sql_array, 'punct', $punct_data, $arraysize); continue; } // end if... else if... else continue; } // Checks for alpha if (PMA_STR_isSqlIdentifier($c, FALSE) || ($c == '@')) { $count2 ++; $is_sql_variable = ($c == '@'); $is_digit = (!$is_sql_variable) && PMA_STR_isDigit($c); $is_hex_digit = ($is_digit) && ($c == '0') && ($sql[$count2] == 'x'); $is_float_digit = FALSE; $is_float_digit_exponent = FALSE; if ($is_hex_digit) { $count2++; } while (($count2 < $len) && PMA_STR_isSqlIdentifier($sql[$count2], ($is_sql_variable || $is_digit))) { $c2 = $sql[$count2]; if ($is_sql_variable && ($c2 == '.')) { $count2++; continue; } if ($is_digit && (!$is_hex_digit) && ($c2 == '.')) { $count2++; if (!$is_float_digit) { $is_float_digit = TRUE; continue; } else { trigger_error('Syntax: Invalid Identifer (' . substr($sql, $count1, $count2 - $count1) . ') at ' . $count1); return; } } if ($is_digit && (!$is_hex_digit) && (($c2 == 'e') || ($c2 == 'E'))) { if (!$is_float_digit_exponent) { $is_float_digit_exponent = TRUE; $is_float_digit = TRUE; $count2++; continue; } else { $is_digit = FALSE; $is_float_digit = FALSE; } } if (($is_hex_digit && PMA_STR_isHexDigit($c2)) || ($is_digit && PMA_STR_isDigit($c2))) { $count2++; continue; } else { $is_digit = FALSE; $is_hex_digit = FALSE; } $count2++; } // end while $l = $count2 - $count1; $str = substr($sql, $count1, $l); $type = ''; if ($is_digit) { $type = 'digit'; if ($is_float_digit) { $type .= '_float'; } else if ($is_hex_digit) { $type .= '_hex'; } else { $type .= '_integer'; } } else { if ($is_sql_variable != FALSE) { $type = 'alpha_variable'; } else { $type = 'alpha'; } } // end if... else.... PMA_SQP_arrayAdd($sql_array, $type, $str, $arraysize); continue; } // DEBUG $count2++; echo "\n" . '
' . "\n";
echo 'You seem to have found a bug in the SQL parser.
Please submit a bug report with the data chunk below:
' . "\n" . '--BEGIN CUT--
' . "\n";
$debugstr = '$Id$
' . "\n";
$debugstr .= 'Why did we get here? ' . $count1 . ' ' . $count2 . ' ' . $len . '
' . "\n";
$debugstr .= 'Leftover: ' . substr($sql, $count1, $count2 - $count1) . '
' . "\n";
$debugstr .= 'A: ' . $count1 . ' ' . $count2 . '
' . "\n";
$debugstr .= 'SQL: ' . $sql;
$encodedstr = nl2br(chunk_split(base64_encode(gzcompress($debugstr, 9))));
echo $encodedstr . "\n";
echo '---END CUT---
' . "\n\n";
//$decodedstr = /*gzuncompress(*/base64_decode(str_replace('
', '', $encodedstr))/*)*/;
//echo $decodedstr . "\n";
echo '