home *** CD-ROM | disk | FTP | other *** search
/ Chip 2006 July / CHIP 2006-07.2.iso / program / web_gelistirme / easyphp1-7_setup.exe / {app} / phpmyadmin / libraries / sqlparser.lib.php < prev    next >
Encoding:
PHP Script  |  2003-09-07  |  79.5 KB  |  1,942 lines

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