Documentation TYPO3 par Ameos

sqlparser.lib.php

00001 <?php
00002 /* $Id: sqlparser.lib.php,v 2.36 2005/08/08 20:22:11 lem9 Exp $ */
00003 // vim: expandtab sw=4 ts=4 sts=4:
00004 
00038 if (!isset($is_minimum_common)) {
00039     $is_minimum_common = FALSE;
00040 }
00041 
00042 if ($is_minimum_common == FALSE) {
00046     require_once('./libraries/string.lib.php');
00047 
00051     require_once('./libraries/sqlparser.data.php');
00052     require_once('./libraries/mysql_charsets.lib.php');
00053     if (!isset($mysql_charsets)) {
00054         $mysql_charsets = array();
00055         $mysql_charsets_count = 0;
00056         $mysql_collations_flat = array();
00057         $mysql_collations_count = 0;
00058     }
00059 
00060     if (!defined('DEBUG_TIMING')) {
00061         function PMA_SQP_arrayAdd(&$arr, $type, $data, &$arrsize)
00062         {
00063             $arr[] = array('type' => $type, 'data' => $data);
00064             $arrsize++;
00065         } // end of the "PMA_SQP_arrayAdd()" function
00066     } else {
00067         function PMA_SQP_arrayAdd(&$arr, $type, $data, &$arrsize)
00068         {
00069             global $timer;
00070 
00071             $t     = $timer;
00072             $arr[] = array('type' => $type, 'data' => $data , 'time' => $t);
00073             $timer = microtime();
00074             $arrsize++;
00075         } // end of the "PMA_SQP_arrayAdd()" function
00076     } // end if... else...
00077 
00078 
00084     // Added, Robbat2 - 13 Janurary 2003, 2:59PM
00085     function PMA_SQP_resetError() {
00086         global $SQP_errorString;
00087         $SQP_errorString = '';
00088         unset($SQP_errorString);
00089     }
00090 
00098     // Added, Robbat2 - 13 Janurary 2003, 2:59PM
00099     function PMA_SQP_getErrorString() {
00100         global $SQP_errorString;
00101         return isset($SQP_errorString) ? $SQP_errorString : '';
00102     }
00103 
00111     // Added, Robbat2 - 13 Janurary 2003, 2:59PM
00112     function PMA_SQP_isError() {
00113         global $SQP_errorString;
00114         return isset($SQP_errorString) && !empty($SQP_errorString);
00115     }
00116 
00126     // Revised, Robbat2 - 13 Janurary 2003, 2:59PM
00127     function PMA_SQP_throwError($message, $sql)
00128     {
00129 
00130         global $SQP_errorString;
00131         $SQP_errorString = '<p>'.$GLOBALS['strSQLParserUserError'] . '</p>' . "\n"
00132             . '<pre>' . "\n"
00133             . 'ERROR: ' . $message . "\n"
00134             . 'SQL: ' . htmlspecialchars($sql) .  "\n"
00135             . '</pre>' . "\n";
00136 
00137     } // end of the "PMA_SQP_throwError()" function
00138 
00139 
00148     function PMA_SQP_bug($message, $sql)
00149     {
00150         global $SQP_errorString;
00151         $debugstr = 'ERROR: ' . $message . "\n";
00152         $debugstr .= 'CVS: $Id: sqlparser.lib.php,v 2.36 2005/08/08 20:22:11 lem9 Exp $' . "\n";
00153         $debugstr .= 'MySQL: '.PMA_MYSQL_STR_VERSION . "\n";
00154         $debugstr .= 'USR OS, AGENT, VER: ' . PMA_USR_OS . ' ' . PMA_USR_BROWSER_AGENT . ' ' . PMA_USR_BROWSER_VER . "\n";
00155         $debugstr .= 'PMA: ' . PMA_VERSION . "\n";
00156         $debugstr .= 'PHP VER,OS: ' . PMA_PHP_STR_VERSION . ' ' . PHP_OS . "\n";
00157         $debugstr .= 'LANG: ' . $GLOBALS['lang'] . "\n";
00158         $debugstr .= 'SQL: ' . htmlspecialchars($sql);
00159 
00160         $encodedstr     = $debugstr;
00161         if (@function_exists('gzcompress')) {
00162             $encodedstr = gzcompress($debugstr, 9);
00163         }
00164         $encodedstr     = preg_replace("/(\015\012)|(\015)|(\012)/", '<br />' . "\n", chunk_split(base64_encode($encodedstr)));
00165 
00166         $SQP_errorString .= $GLOBALS['strSQLParserBugMessage'] . '<br />' . "\n"
00167              . '----' . $GLOBALS['strBeginCut'] . '----' . '<br />' . "\n"
00168              . $encodedstr . "\n"
00169              . '----' . $GLOBALS['strEndCut'] . '----' . '<br />' . "\n";
00170 
00171         $SQP_errorString .= '----' . $GLOBALS['strBeginRaw'] . '----<br />' . "\n"
00172              . '<pre>' . "\n"
00173              . $debugstr
00174              . '</pre>' . "\n"
00175              . '----' . $GLOBALS['strEndRaw'] . '----<br />' . "\n";
00176 
00177     } // end of the "PMA_SQP_bug()" function
00178 
00179 
00203     function PMA_SQP_parse($sql)
00204     {
00205         global $cfg;
00206         global $PMA_SQPdata_column_attrib, $PMA_SQPdata_reserved_word, $PMA_SQPdata_column_type, $PMA_SQPdata_function_name,
00207                $PMA_SQPdata_column_attrib_cnt, $PMA_SQPdata_reserved_word_cnt, $PMA_SQPdata_column_type_cnt, $PMA_SQPdata_function_name_cnt;
00208         global $mysql_charsets, $mysql_collations_flat, $mysql_charsets_count, $mysql_collations_count;
00209         global $PMA_SQPdata_forbidden_word, $PMA_SQPdata_forbidden_word_cnt; 
00210 
00211         // rabus: Convert all line feeds to Unix style
00212         $sql = str_replace("\r\n", "\n", $sql);
00213         $sql = str_replace("\r", "\n", $sql);
00214 
00215         $len = PMA_strlen($sql);
00216         if ($len == 0) {
00217             return array();
00218         }
00219 
00220         $sql_array               = array();
00221         $sql_array['raw']        = $sql;
00222         $count1                  = 0;
00223         $count2                  = 0;
00224         $punct_queryend          = ';';
00225         $punct_qualifier         = '.';
00226         $punct_listsep           = ',';
00227         $punct_level_plus        = '(';
00228         $punct_level_minus       = ')';
00229         $digit_floatdecimal      = '.';
00230         $digit_hexset            = 'x';
00231         $bracket_list            = '()[]{}';
00232         $allpunct_list           =  '-,;:!?/.^~\*&%+<=>|';
00233         $allpunct_list_pair      = array (
00234             0 => '!=',
00235             1 => '&&',
00236             2 => ':=',
00237             3 => '<<',
00238             4 => '<=',
00239             5 => '<=>',
00240             6 => '<>',
00241             7 => '>=',
00242             8 => '>>',
00243             9 => '||'
00244         );
00245         $allpunct_list_pair_size = 10; //count($allpunct_list_pair);
00246         $quote_list              = '\'"`';
00247         $arraysize               = 0;
00248 
00249         while ($count2 < $len) {
00250             $c      = PMA_substr($sql, $count2, 1);
00251             $count1 = $count2;
00252 
00253             if (($c == "\n")) {
00254                 $count2++;
00255                 PMA_SQP_arrayAdd($sql_array, 'white_newline', '', $arraysize);
00256                 continue;
00257             }
00258 
00259             // Checks for white space
00260             if (PMA_STR_isSpace($c)) {
00261                 $count2++;
00262                 continue;
00263             }
00264 
00265             // Checks for comment lines.
00266             // MySQL style #
00267             // C style /* */
00268             // ANSI style --
00269             if (($c == '#')
00270                 || (($count2 + 1 < $len) && ($c == '/') && (PMA_substr($sql, $count2 + 1, 1) == '*'))
00271                 || (($count2 + 2 == $len) && ($c == '-') && (PMA_substr($sql, $count2 + 1, 1) == '-'))
00272                 || (($count2 + 2 < $len) && ($c == '-') && (PMA_substr($sql, $count2 + 1, 1) == '-') && ((PMA_substr($sql, $count2 + 2, 1) <= ' ')))) {
00273                 $count2++;
00274                 $pos  = 0;
00275                 $type = 'bad';
00276                 switch ($c) {
00277                     case '#':
00278                         $type = 'mysql';
00279                     case '-':
00280                         $type = 'ansi';
00281                         $pos  = $GLOBALS['PMA_strpos']($sql, "\n", $count2);
00282                         break;
00283                     case '/':
00284                         $type = 'c';
00285                         $pos  = $GLOBALS['PMA_strpos']($sql, '*/', $count2);
00286                         $pos  += 2;
00287                         break;
00288                     default:
00289                         break;
00290                 } // end switch
00291                 $count2 = ($pos < $count2) ? $len : $pos;
00292                 $str    = PMA_substr($sql, $count1, $count2 - $count1);
00293                 PMA_SQP_arrayAdd($sql_array, 'comment_' . $type, $str, $arraysize);
00294                 continue;
00295             } // end if
00296 
00297             // Checks for something inside quotation marks
00298             if (PMA_STR_strInStr($c, $quote_list)) {
00299                 $startquotepos   = $count2;
00300                 $quotetype       = $c;
00301                 $count2++;
00302                 $escaped         = FALSE;
00303                 $escaped_escaped = FALSE;
00304                 $pos             = $count2;
00305                 $oldpos          = 0;
00306                 do {
00307                     $oldpos = $pos;
00308                     $pos    = $GLOBALS['PMA_strpos'](' ' . $sql, $quotetype, $oldpos + 1) - 1;
00309                     // ($pos === FALSE)
00310                     if ($pos < 0) {
00311                         $debugstr = $GLOBALS['strSQPBugUnclosedQuote'] . ' @ ' . $startquotepos. "\n"
00312                                   . 'STR: ' . htmlspecialchars($quotetype);
00313                         PMA_SQP_throwError($debugstr, $sql);
00314                         return $sql;
00315                     }
00316 
00317                     // If the quote is the first character, it can't be
00318                     // escaped, so don't do the rest of the code
00319                     if ($pos == 0) {
00320                         break;
00321                     }
00322 
00323                     // Checks for MySQL escaping using a \
00324                     // And checks for ANSI escaping using the $quotetype character
00325                     if (($pos < $len) && PMA_STR_charIsEscaped($sql, $pos)) {
00326                         $pos ++;
00327                         continue;
00328                     } else if (($pos + 1 < $len) && (PMA_substr($sql, $pos, 1) == $quotetype) && (PMA_substr($sql, $pos + 1, 1) == $quotetype)) {
00329                         $pos = $pos + 2;
00330                         continue;
00331                     } else {
00332                         break;
00333                     }
00334                 } while ($len > $pos); // end do
00335 
00336                 $count2       = $pos;
00337                 $count2++;
00338                 $type         = 'quote_';
00339                 switch ($quotetype) {
00340                     case '\'':
00341                         $type .= 'single';
00342                         break;
00343                     case '"':
00344                         $type .= 'double';
00345                         break;
00346                     case '`':
00347                         $type .= 'backtick';
00348                         break;
00349                     default:
00350                         break;
00351                 } // end switch
00352                 $data = PMA_substr($sql, $count1, $count2 - $count1);
00353                 PMA_SQP_arrayAdd($sql_array, $type, $data, $arraysize);
00354                 continue;
00355             }
00356 
00357             // Checks for brackets
00358             if (PMA_STR_strInStr($c, $bracket_list)) {
00359                 // All bracket tokens are only one item long
00360                 $count2++;
00361                 $type_type     = '';
00362                 if (PMA_STR_strInStr($c, '([{')) {
00363                     $type_type = 'open';
00364                 } else {
00365                     $type_type = 'close';
00366                 }
00367 
00368                 $type_style     = '';
00369                 if (PMA_STR_strInStr($c, '()')) {
00370                     $type_style = 'round';
00371                 } elseif (PMA_STR_strInStr($c, '[]')) {
00372                     $type_style = 'square';
00373                 } else {
00374                     $type_style = 'curly';
00375                 }
00376 
00377                 $type = 'punct_bracket_' . $type_type . '_' . $type_style;
00378                 PMA_SQP_arrayAdd($sql_array, $type, $c, $arraysize);
00379                 continue;
00380             }
00381 
00382             // Checks for punct
00383             if (PMA_STR_strInStr($c, $allpunct_list)) {
00384                 while (($count2 < $len) && PMA_STR_strInStr(PMA_substr($sql, $count2, 1), $allpunct_list)) {
00385                     $count2++;
00386                 }
00387                 $l = $count2 - $count1;
00388                 if ($l == 1) {
00389                     $punct_data = $c;
00390                 } else {
00391                     $punct_data = PMA_substr($sql, $count1, $l);
00392                 }
00393 
00394                 // Special case, sometimes, althought two characters are
00395                 // adjectent directly, they ACTUALLY need to be seperate
00396                 if ($l == 1) {
00397                     $t_suffix         = '';
00398                     switch ($punct_data) {
00399                         case $punct_queryend:
00400                             $t_suffix = '_queryend';
00401                             break;
00402                         case $punct_qualifier:
00403                             $t_suffix = '_qualifier';
00404                             break;
00405                         case $punct_listsep:
00406                             $t_suffix = '_listsep';
00407                             break;
00408                         default:
00409                             break;
00410                     }
00411                     PMA_SQP_arrayAdd($sql_array, 'punct' . $t_suffix, $punct_data, $arraysize);
00412                 }
00413                 else if (PMA_STR_binarySearchInArr($punct_data, $allpunct_list_pair, $allpunct_list_pair_size)) {
00414                     // Ok, we have one of the valid combined punct expressions
00415                     PMA_SQP_arrayAdd($sql_array, 'punct', $punct_data, $arraysize);
00416                 }
00417                 else {
00418                     // Bad luck, lets split it up more
00419                     $first  = $punct_data[0];
00420                     $first2 = $punct_data[0] . $punct_data[1];
00421                     $last2  = $punct_data[$l - 2] . $punct_data[$l - 1];
00422                     $last   = $punct_data[$l - 1];
00423                     if (($first == ',') || ($first == ';') || ($first == '.') || ($first == '*')) {
00424                         $count2     = $count1 + 1;
00425                         $punct_data = $first;
00426                     } else if (($last2 == '/*') || (($last2 == '--') && ($count2 == $len || PMA_substr($sql, $count2, 1) <= ' ') )) {
00427                         $count2     -= 2;
00428                         $punct_data = PMA_substr($sql, $count1, $count2 - $count1);
00429                     } else if (($last == '-') || ($last == '+') || ($last == '!')) {
00430                         $count2--;
00431                         $punct_data = PMA_substr($sql, $count1, $count2 - $count1);
00432                     // TODO: for negation operator, split in 2 tokens ?
00433                     // "select x&~1 from t"
00434                     // becomes "select x & ~ 1 from t" ?
00435 
00436                     } else if ($last != '~') {
00437                         $debugstr =  $GLOBALS['strSQPBugUnknownPunctuation'] . ' @ ' . ($count1+1) . "\n"
00438                                   . 'STR: ' . htmlspecialchars($punct_data);
00439                         PMA_SQP_throwError($debugstr, $sql);
00440                         return $sql;
00441                     }
00442                     PMA_SQP_arrayAdd($sql_array, 'punct', $punct_data, $arraysize);
00443                     continue;
00444                 } // end if... else if... else
00445                 continue;
00446             }
00447 
00448             // Checks for alpha
00449             if (PMA_STR_isSqlIdentifier($c, FALSE) || ($c == '@')) {
00450                 $count2 ++;
00451 
00452                 //TODO: a @ can also be present in expressions like
00453                 // FROM 'user'@'%'
00454                 // or  TO 'user'@'%'
00455                 // in this case, the @ is wrongly marked as alpha_variable
00456 
00457                 $is_sql_variable         = ($c == '@');
00458                 $is_digit                = (!$is_sql_variable) && PMA_STR_isDigit($c);
00459                 $is_hex_digit            = ($is_digit) && ($c == '0') && ($count2 < $len) && (PMA_substr($sql, $count2, 1) == 'x');
00460                 $is_float_digit          = FALSE;
00461                 $is_float_digit_exponent = FALSE;
00462 
00463                 if ($is_hex_digit) {
00464                     $count2++;
00465                 }
00466 
00467                 while (($count2 < $len) && PMA_STR_isSqlIdentifier(PMA_substr($sql, $count2, 1), ($is_sql_variable || $is_digit))) {
00468                     $c2 = PMA_substr($sql, $count2, 1);
00469                     if ($is_sql_variable && ($c2 == '.')) {
00470                         $count2++;
00471                         continue;
00472                     }
00473                     if ($is_digit && (!$is_hex_digit) && ($c2 == '.')) {
00474                         $count2++;
00475                         if (!$is_float_digit) {
00476                             $is_float_digit = TRUE;
00477                             continue;
00478                         } else {
00479                             $debugstr = $GLOBALS['strSQPBugInvalidIdentifer'] . ' @ ' . ($count1+1) . "\n"
00480                                       . 'STR: ' . htmlspecialchars(PMA_substr($sql, $count1, $count2 - $count1));
00481                             PMA_SQP_throwError($debugstr, $sql);
00482                             return $sql;
00483                         }
00484                     }
00485                     if ($is_digit && (!$is_hex_digit) && (($c2 == 'e') || ($c2 == 'E'))) {
00486                         if (!$is_float_digit_exponent) {
00487                             $is_float_digit_exponent = TRUE;
00488                             $is_float_digit          = TRUE;
00489                             $count2++;
00490                             continue;
00491                         } else {
00492                             $is_digit                = FALSE;
00493                             $is_float_digit          = FALSE;
00494                         }
00495                     }
00496                     if (($is_hex_digit && PMA_STR_isHexDigit($c2)) || ($is_digit && PMA_STR_isDigit($c2))) {
00497                         $count2++;
00498                         continue;
00499                     } else {
00500                         $is_digit     = FALSE;
00501                         $is_hex_digit = FALSE;
00502                     }
00503 
00504                     $count2++;
00505                 } // end while
00506 
00507                 $l    = $count2 - $count1;
00508                 $str  = PMA_substr($sql, $count1, $l);
00509 
00510                 $type = '';
00511                 if ($is_digit) {
00512                     $type     = 'digit';
00513                     if ($is_float_digit) {
00514                         $type .= '_float';
00515                     } else if ($is_hex_digit) {
00516                         $type .= '_hex';
00517                     } else {
00518                         $type .= '_integer';
00519                     }
00520                 }
00521                 else {
00522                     if ($is_sql_variable != FALSE) {
00523                         $type = 'alpha_variable';
00524                     } else {
00525                         $type = 'alpha';
00526                     }
00527                 } // end if... else....
00528                 PMA_SQP_arrayAdd($sql_array, $type, $str, $arraysize);
00529 
00530                 continue;
00531             }
00532 
00533             // DEBUG
00534             $count2++;
00535 
00536             $debugstr = 'C1 C2 LEN: ' . $count1 . ' ' . $count2 . ' ' . $len .  "\n"
00537                       . 'STR: ' . PMA_substr($sql, $count1, $count2 - $count1) . "\n";
00538             PMA_SQP_bug($debugstr, $sql);
00539             return $sql;
00540 
00541         } // end while ($count2 < $len)
00542 
00543 
00544         if ($arraysize > 0) {
00545           $t_next           = $sql_array[0]['type'];
00546           $t_prev           = '';
00547           $t_bef_prev       = '';
00548           $t_cur            = '';
00549           $d_next           = $sql_array[0]['data'];
00550           $d_prev           = '';
00551           $d_bef_prev       = '';
00552           $d_cur            = '';
00553           $d_next_upper     = $t_next == 'alpha' ? strtoupper($d_next) : $d_next;
00554           $d_prev_upper     = '';
00555           $d_bef_prev_upper = '';
00556           $d_cur_upper      = '';
00557         }
00558 
00559         for ($i = 0; $i < $arraysize; $i++) {
00560           $t_bef_prev       = $t_prev;
00561           $t_prev           = $t_cur;
00562           $t_cur            = $t_next;
00563           $d_bef_prev       = $d_prev;
00564           $d_prev           = $d_cur;
00565           $d_cur            = $d_next;
00566           $d_bef_prev_upper = $d_prev_upper;
00567           $d_prev_upper     = $d_cur_upper;
00568           $d_cur_upper      = $d_next_upper;
00569           if (($i + 1) < $arraysize) {
00570             $t_next = $sql_array[$i + 1]['type'];
00571             $d_next = $sql_array[$i + 1]['data'];
00572             $d_next_upper = $t_next == 'alpha' ? strtoupper($d_next) : $d_next;
00573           } else {
00574             $t_next       = '';
00575             $d_next       = '';
00576             $d_next_upper = '';
00577           }
00578 
00579           //DEBUG echo "[prev: <b>".$d_prev."</b> ".$t_prev."][cur: <b>".$d_cur."</b> ".$t_cur."][next: <b>".$d_next."</b> ".$t_next."]<br />";
00580 
00581           if ($t_cur == 'alpha') {
00582             $t_suffix     = '_identifier';
00583             if (($t_next == 'punct_qualifier') || ($t_prev == 'punct_qualifier')) {
00584               $t_suffix = '_identifier';
00585             } else if (($t_next == 'punct_bracket_open_round')
00586             && PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_function_name, $PMA_SQPdata_function_name_cnt)) {
00587               $t_suffix = '_functionName';
00588             } else if (PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_column_type, $PMA_SQPdata_column_type_cnt))  {
00589               $t_suffix = '_columnType';
00590 
00591               // Temporary fix for BUG #621357
00592               //TODO FIX PROPERLY NEEDS OVERHAUL OF SQL TOKENIZER
00593               if ($d_cur_upper == 'SET' && $t_next != 'punct_bracket_open_round') {
00594                 $t_suffix = '_reservedWord';
00595               }
00596               //END OF TEMPORARY FIX
00597 
00598               // CHARACTER is a synonym for CHAR, but can also be meant as
00599               // CHARACTER SET. In this case, we have a reserved word.
00600               if ($d_cur_upper == 'CHARACTER' && $d_next_upper == 'SET') {
00601                 $t_suffix = '_reservedWord';
00602               }
00603 
00604               // experimental
00605               // current is a column type, so previous must not be
00606               // a reserved word but an identifier
00607               // CREATE TABLE SG_Persons (first varchar(64))
00608 
00609               //if ($sql_array[$i-1]['type'] =='alpha_reservedWord') {
00610               //    $sql_array[$i-1]['type'] = 'alpha_identifier';
00611               //}
00612 
00613             } else if (PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_reserved_word, $PMA_SQPdata_reserved_word_cnt)) {
00614               $t_suffix = '_reservedWord';
00615             } else if (PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_column_attrib, $PMA_SQPdata_column_attrib_cnt)) {
00616               $t_suffix = '_columnAttrib';
00617               // INNODB is a MySQL table type, but in "SHOW INNODB STATUS",
00618               // it should be regarded as a reserved word.
00619               if ($d_cur_upper == 'INNODB' && $d_prev_upper == 'SHOW' && $d_next_upper == 'STATUS') {
00620                 $t_suffix = '_reservedWord';
00621               }
00622 
00623               if ($d_cur_upper == 'DEFAULT' && $d_next_upper == 'CHARACTER') {
00624                 $t_suffix = '_reservedWord';
00625               }
00626               // Binary as character set
00627               if ($d_cur_upper == 'BINARY' && (
00628                   ($d_bef_prev_upper == 'CHARACTER' && $d_prev_upper == 'SET')
00629                   || ($d_bef_prev_upper == 'SET' && $d_prev_upper == '=')
00630                   || ($d_bef_prev_upper == 'CHARSET' && $d_prev_upper == '=')
00631                   || $d_prev_upper == 'CHARSET'
00632                   ) && PMA_STR_binarySearchInArr($d_cur, $mysql_charsets, count($mysql_charsets))) {
00633                   $t_suffix = '_charset';
00634               }
00635             } elseif (PMA_STR_binarySearchInArr($d_cur, $mysql_charsets, $mysql_charsets_count)
00636               || PMA_STR_binarySearchInArr($d_cur, $mysql_collations_flat, $mysql_collations_count)
00637               || ($d_cur{0} == '_' && PMA_STR_binarySearchInArr(substr($d_cur, 1), $mysql_charsets, $mysql_charsets_count))) {
00638               $t_suffix = '_charset';
00639             } else {
00640               // Do nothing
00641             }
00642             // check if present in the list of forbidden words
00643             if ($t_suffix == '_reservedWord' && PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_forbidden_word, $PMA_SQPdata_forbidden_word_cnt)) {
00644                 $sql_array[$i]['forbidden'] = TRUE;
00645             } else {
00646                 $sql_array[$i]['forbidden'] = FALSE;
00647             }
00648             $sql_array[$i]['type'] .= $t_suffix;
00649           }
00650         } // end for
00651 
00652         // Stores the size of the array inside the array, as count() is a slow
00653         // operation.
00654         $sql_array['len'] = $arraysize;
00655 
00656         // Sends the data back
00657         return $sql_array;
00658     } // end of the "PMA_SQP_parse()" function
00659 
00670     function PMA_SQP_typeCheck($toCheck, $whatWeWant)
00671     {
00672         $typeSeperator = '_';
00673         if (strcmp($whatWeWant, $toCheck) == 0) {
00674             return TRUE;
00675         } else {
00676             if (strpos($whatWeWant, $typeSeperator) === FALSE) {
00677                 return strncmp($whatWeWant, $toCheck , strpos($toCheck, $typeSeperator)) == 0;
00678             } else {
00679                 return FALSE;
00680             }
00681         }
00682     }
00683 
00684 
00694     function PMA_SQP_analyze($arr)
00695     {
00696         $result          = array();
00697         $size            = $arr['len'];
00698         $subresult       = array(
00699             'querytype'      => '',
00700             'select_expr_clause'=> '', // the whole stuff between SELECT and FROM , except DISTINCT
00701             'position_of_first_select' => '', // the array index
00702             'from_clause'=> '',
00703             'group_by_clause'=> '',
00704             'order_by_clause'=> '',
00705             'having_clause'  => '',
00706             'where_clause'   => '',
00707             'where_clause_identifiers'   => array(),
00708             'unsorted_query' => '',
00709             'queryflags'     => array(),
00710             'select_expr'    => array(),
00711             'table_ref'      => array(),
00712             'foreign_keys'   => array(),
00713             'create_table_fields' => array()
00714         );
00715         $subresult_empty = $subresult;
00716         $seek_queryend         = FALSE;
00717         $seen_end_of_table_ref = FALSE;
00718         $number_of_brackets_in_extract = 0;
00719         $number_of_brackets_in_group_concat = 0;
00720 
00721         // for SELECT EXTRACT(YEAR_MONTH FROM CURDATE())
00722         // we must not use CURDATE as a table_ref
00723         // so we track wether we are in the EXTRACT()
00724         $in_extract          = FALSE;
00725 
00726         // for GROUP_CONCAT( ... )
00727         $in_group_concat     = FALSE;
00728 
00729 /* Description of analyzer results by lem9
00730  *
00731  * db, table, column, alias
00732  * ------------------------
00733  *
00734  * Inside the $subresult array, we create ['select_expr'] and ['table_ref'] arrays.
00735  *
00736  * The SELECT syntax (simplified) is
00737  *
00738  * SELECT
00739  *    select_expression,...
00740  *    [FROM [table_references]
00741  *
00742  *
00743  * ['select_expr'] is filled with each expression, the key represents the
00744  * expression position in the list (0-based) (so we don't lose track of
00745  * multiple occurences of the same column).
00746  *
00747  * ['table_ref'] is filled with each table ref, same thing for the key.
00748  *
00749  * I create all sub-values empty, even if they are
00750  * not present (for example no select_expression alias).
00751  *
00752  * There is a debug section at the end of loop #1, if you want to
00753  * see the exact contents of select_expr and table_ref
00754  *
00755  * queryflags
00756  * ----------
00757  *
00758  * In $subresult, array 'queryflags' is filled, according to what we
00759  * find in the query.
00760  *
00761  * Currently, those are generated:
00762  *
00763  * ['queryflags']['need_confirm'] = 1; if the query needs confirmation
00764  * ['queryflags']['select_from'] = 1;  if this is a real SELECT...FROM
00765  * ['queryflags']['distinct'] = 1;     for a DISTINCT
00766  * ['queryflags']['union'] = 1;        for a UNION
00767  * ['queryflags']['join'] = 1;         for a JOIN
00768  * ['queryflags']['offset'] = 1;       for the presence of OFFSET 
00769  *
00770  * query clauses
00771  * -------------
00772  *
00773  * The select is splitted in those clauses:
00774  * ['select_expr_clause']
00775  * ['from_clause']
00776  * ['group_by_clause']
00777  * ['order_by_clause']
00778  * ['having_clause']
00779  * ['where_clause']
00780  *
00781  * The identifiers of the WHERE clause are put into the array
00782  * ['where_clause_identifier']
00783  *
00784  * For a SELECT, the whole query without the ORDER BY clause is put into
00785  * ['unsorted_query']
00786  *
00787  * foreign keys
00788  * ------------
00789  * The CREATE TABLE may contain FOREIGN KEY clauses, so they get
00790  * analyzed and ['foreign_keys'] is an array filled with
00791  * the constraint name, the index list,
00792  * the REFERENCES table name and REFERENCES index list,
00793  * and ON UPDATE | ON DELETE clauses
00794  *
00795  * position_of_first_select
00796  * ------------------------
00797  *
00798  * The array index of the first SELECT we find. Will be used to
00799  * insert a SQL_CALC_FOUND_ROWS.
00800  *
00801  * create_table_fields
00802  * -------------------
00803  *
00804  * For now, mostly used to detect the DEFAULT CURRENT_TIMESTAMP and
00805  * ON UPDATE CURRENT_TIMESTAMP clauses of the CREATE TABLE query.
00806  * An array, each element is the identifier name.
00807  * Note that for now, the timestamp_not_null element is created
00808  * even for non-TIMESTAMP fields.
00809  *
00810  * Sub-elements: ['type'] which contains the column type
00811  *               optional (currently they are never false but can be absent):
00812  *               ['default_current_timestamp'] boolean
00813  *               ['on_update_current_timestamp'] boolean
00814  *               ['timestamp_not_null'] boolean
00815  *
00816  * section_before_limit, section_after_limit
00817  * -----------------------------------------
00818  * 
00819  * Marks the point of the query where we can insert a LIMIT clause;
00820  * so the section_before_limit will contain the left part before
00821  * a possible LIMIT clause
00822  *
00823  *
00824  * End of description of analyzer results
00825  */
00826 
00827         // must be sorted
00828         // TODO: current logic checks for only one word, so I put only the
00829         // first word of the reserved expressions that end a table ref;
00830         // maybe this is not ok (the first word might mean something else)
00831 //        $words_ending_table_ref = array(
00832 //            'FOR UPDATE',
00833 //            'GROUP BY',
00834 //            'HAVING',
00835 //            'LIMIT',
00836 //            'LOCK IN SHARE MODE',
00837 //            'ORDER BY',
00838 //            'PROCEDURE',
00839 //            'UNION',
00840 //            'WHERE'
00841 //        );
00842         $words_ending_table_ref = array(
00843             'FOR',
00844             'GROUP',
00845             'HAVING',
00846             'LIMIT',
00847             'LOCK',
00848             'ORDER',
00849             'PROCEDURE',
00850             'UNION',
00851             'WHERE'
00852         );
00853         $words_ending_table_ref_cnt = 9; //count($words_ending_table_ref);
00854 
00855         $words_ending_clauses = array(
00856             'FOR',
00857             'LIMIT',
00858             'LOCK',
00859             'PROCEDURE',
00860             'UNION'
00861         );
00862         $words_ending_clauses_cnt = 5; //count($words_ending_clauses);
00863 
00864 
00865 
00866 
00867         // must be sorted
00868         $supported_query_types = array(
00869             'SELECT'
00870             /*
00871             // Support for these additional query types will come later on.
00872             'DELETE',
00873             'INSERT',
00874             'REPLACE',
00875             'TRUNCATE',
00876             'UPDATE'
00877             'EXPLAIN',
00878             'DESCRIBE',
00879             'SHOW',
00880             'CREATE',
00881             'SET',
00882             'ALTER'
00883             */
00884         );
00885         $supported_query_types_cnt = count($supported_query_types);
00886 
00887         // loop #1 for each token: select_expr, table_ref for SELECT
00888 
00889         for ($i = 0; $i < $size; $i++) {
00890 //DEBUG echo "trace loop1 <b>"  . $arr[$i]['data'] . "</b> (" . $arr[$i]['type'] . ")<br />";
00891 
00892             // High speed seek for locating the end of the current query
00893             if ($seek_queryend == TRUE) {
00894                 if ($arr[$i]['type'] == 'punct_queryend') {
00895                     $seek_queryend = FALSE;
00896                 } else {
00897                     continue;
00898                 } // end if (type == punct_queryend)
00899             } // end if ($seek_queryend)
00900 
00901             // TODO: when we find a UNION, should we split
00902             // in another subresult?
00903             if ($arr[$i]['type'] == 'punct_queryend') {
00904                 $result[]  = $subresult;
00905                 $subresult = $subresult_empty;
00906                 continue;
00907             } // end if (type == punct_queryend)
00908 
00909 // ==============================================================
00910             if ($arr[$i]['type'] == 'punct_bracket_open_round') {
00911                 if ($in_extract) {
00912                     $number_of_brackets_in_extract++;
00913                 }
00914                 if ($in_group_concat) {
00915                     $number_of_brackets_in_group_concat++;
00916                 }
00917             }
00918 // ==============================================================
00919             if ($arr[$i]['type'] == 'punct_bracket_close_round') {
00920                 if ($in_extract) {
00921                     $number_of_brackets_in_extract--;
00922                     if ($number_of_brackets_in_extract == 0) {
00923                        $in_extract = FALSE;
00924                     }
00925                 }
00926                 if ($in_group_concat) {
00927                     $number_of_brackets_in_group_concat--;
00928                     if ($number_of_brackets_in_group_concat == 0) {
00929                        $in_group_concat = FALSE;
00930                     }
00931                 }
00932             }
00933 // ==============================================================
00934             if ($arr[$i]['type'] == 'alpha_functionName') {
00935                 $upper_data = strtoupper($arr[$i]['data']);
00936                 if ($upper_data =='EXTRACT') {
00937                     $in_extract = TRUE;
00938                     $number_of_brackets_in_extract = 0;
00939                 }
00940                 if ($upper_data =='GROUP_CONCAT') {
00941                     $in_group_concat = TRUE;
00942                     $number_of_brackets_in_group_concat = 0;
00943                 }
00944             }
00945 
00946 // ==============================================================
00947             if ($arr[$i]['type'] == 'alpha_reservedWord'
00948 //             && $arr[$i]['forbidden'] == FALSE) {
00949   ){
00950                 // We don't know what type of query yet, so run this
00951                 if ($subresult['querytype'] == '') {
00952                     $subresult['querytype'] = strtoupper($arr[$i]['data']);
00953                 } // end if (querytype was empty)
00954 
00955                 // Check if we support this type of query
00956                 if (!PMA_STR_binarySearchInArr($subresult['querytype'], $supported_query_types, $supported_query_types_cnt)) {
00957                     // Skip ahead to the next one if we don't
00958                     $seek_queryend = TRUE;
00959                     continue;
00960                 } // end if (query not supported)
00961 
00962                 // upper once
00963                 $upper_data = strtoupper($arr[$i]['data']);
00964                 //TODO: reset for each query?
00965 
00966                 if ($upper_data == 'SELECT') {
00967                     $seen_from = FALSE;
00968                     $previous_was_identifier = FALSE;
00969                     $current_select_expr = -1;
00970                     $seen_end_of_table_ref = FALSE;
00971                 } // end if ( data == SELECT)
00972 
00973                 if ($upper_data =='FROM' && !$in_extract) {
00974                     $current_table_ref = -1;
00975                     $seen_from = TRUE;
00976                     $previous_was_identifier = FALSE;
00977                     $save_table_ref = TRUE;
00978                 } // end if (data == FROM)
00979 
00980                 // here, do not 'continue' the loop, as we have more work for
00981                 // reserved words below
00982             } // end if (type == alpha_reservedWord)
00983 
00984 // ==============================
00985             if ($arr[$i]['type'] == 'quote_backtick'
00986              || $arr[$i]['type'] == 'quote_double'
00987              || $arr[$i]['type'] == 'quote_single'
00988              || $arr[$i]['type'] == 'alpha_identifier'
00989              || ($arr[$i]['type'] == 'alpha_reservedWord'
00990                 && $arr[$i]['forbidden'] == FALSE)) {
00991 
00992                 switch ($arr[$i]['type']) {
00993                     case 'alpha_identifier':
00994                     case 'alpha_reservedWord':
00995                         // this is not a real reservedWord, because
00996                         // it's not present in the list of forbidden words,
00997                         // for example "storage" which can be used as 
00998                         // an identifier
00999                         //
01000                         // TODO: avoid the pretty printing in color
01001                         //       in this case
01002 
01003                         $identifier = $arr[$i]['data'];
01004                         break;
01005 
01006                 //TODO: check embedded double quotes or backticks?
01007                 // and/or remove just the first and last character?
01008                     case 'quote_backtick':
01009                         $identifier = str_replace('`','',$arr[$i]['data']);
01010                         break;
01011                     case 'quote_double':
01012                         $identifier = str_replace('"','',$arr[$i]['data']);
01013                         break;
01014                     case 'quote_single':
01015                         $identifier = str_replace("'","",$arr[$i]['data']);
01016                         break;
01017                 } // end switch
01018 
01019                 if ($subresult['querytype'] == 'SELECT' && !$in_group_concat) {
01020                     if (!$seen_from) {
01021                         if ($previous_was_identifier && isset($chain)) {
01022                             // found alias for this select_expr, save it
01023                             // but only if we got something in $chain
01024                             // (for example, SELECT COUNT(*) AS cnt
01025                             // puts nothing in $chain, so we avoid
01026                             // setting the alias)
01027                             $alias_for_select_expr = $identifier;
01028                         } else {
01029                             $chain[] = $identifier;
01030                             $previous_was_identifier = TRUE;
01031 
01032                         } // end if !$previous_was_identifier
01033                     } else {
01034                         // ($seen_from)
01035                         if ($save_table_ref && !$seen_end_of_table_ref) {
01036                             if ($previous_was_identifier) {
01037                                 // found alias for table ref
01038                                 // save it for later
01039                                 $alias_for_table_ref = $identifier;
01040                             } else {
01041                                 $chain[] = $identifier;
01042                                 $previous_was_identifier = TRUE;
01043 
01044                             } // end if ($previous_was_identifier)
01045                         } // end if ($save_table_ref &&!$seen_end_of_table_ref)
01046                     } // end if (!$seen_from)
01047                 } // end if (querytype SELECT)
01048             } // end if ( quote_backtick or double quote or alpha_identifier)
01049 
01050 // ===================================
01051             if ($arr[$i]['type'] == 'punct_qualifier') {
01052                 // to be able to detect an identifier following another
01053                 $previous_was_identifier = FALSE;
01054                 continue;
01055             } // end if (punct_qualifier)
01056 
01057             // TODO: check if 3 identifiers following one another -> error
01058 
01059             //    s a v e    a    s e l e c t    e x p r
01060             // finding a list separator or FROM
01061             // means that we must save the current chain of identifiers
01062             // into a select expression
01063 
01064             // for now, we only save a select expression if it contains
01065             // at least one identifier, as we are interested in checking
01066             // the columns and table names, so in "select * from persons",
01067             // the "*" is not saved
01068 
01069             if (isset($chain) && !$seen_end_of_table_ref
01070                && (   (!$seen_from
01071                    && $arr[$i]['type'] == 'punct_listsep')
01072                   || ($arr[$i]['type'] == 'alpha_reservedWord' && $upper_data == 'FROM')) ) {
01073                 $size_chain = count($chain);
01074                 $current_select_expr++;
01075                 $subresult['select_expr'][$current_select_expr] = array(
01076                   'expr' => '',
01077                   'alias' => '',
01078                   'db'   => '',
01079                   'table_name' => '',
01080                   'table_true_name' => '',
01081                   'column' => ''
01082                  );
01083 
01084                 if (!empty($alias_for_select_expr)) {
01085                     // we had found an alias for this select expression
01086                     $subresult['select_expr'][$current_select_expr]['alias'] = $alias_for_select_expr;
01087                     unset($alias_for_select_expr);
01088                 }
01089                 // there is at least a column
01090                 $subresult['select_expr'][$current_select_expr]['column'] = $chain[$size_chain - 1];
01091                 $subresult['select_expr'][$current_select_expr]['expr'] = $chain[$size_chain - 1];
01092 
01093                 // maybe a table
01094                 if ($size_chain > 1) {
01095                     $subresult['select_expr'][$current_select_expr]['table_name'] = $chain[$size_chain - 2];
01096                     // we assume for now that this is also the true name
01097                     $subresult['select_expr'][$current_select_expr]['table_true_name'] = $chain[$size_chain - 2];
01098                     $subresult['select_expr'][$current_select_expr]['expr']
01099                      = $subresult['select_expr'][$current_select_expr]['table_name']
01100                       . '.' . $subresult['select_expr'][$current_select_expr]['expr'];
01101                 } // end if ($size_chain > 1)
01102 
01103                 // maybe a db
01104                 if ($size_chain > 2) {
01105                     $subresult['select_expr'][$current_select_expr]['db'] = $chain[$size_chain - 3];
01106                     $subresult['select_expr'][$current_select_expr]['expr']
01107                      = $subresult['select_expr'][$current_select_expr]['db']
01108                       . '.' . $subresult['select_expr'][$current_select_expr]['expr'];
01109                 } // end if ($size_chain > 2)
01110                 unset($chain);
01111 
01112                 // TODO: explain this:
01113                 if (($arr[$i]['type'] == 'alpha_reservedWord')
01114                  && ($upper_data != 'FROM')) {
01115                     $previous_was_identifier = TRUE;
01116                 }
01117 
01118             } // end if (save a select expr)
01119 
01120 
01121             //======================================
01122             //    s a v e    a    t a b l e    r e f
01123             //======================================
01124 
01125             // maybe we just saw the end of table refs
01126             // but the last table ref has to be saved
01127             // or we are at the last token (TODO: there could be another
01128             // query after this one)
01129             // or we just got a reserved word
01130 
01131             if (isset($chain) && $seen_from && $save_table_ref
01132              && ($arr[$i]['type'] == 'punct_listsep'
01133                || ($arr[$i]['type'] == 'alpha_reservedWord' && $upper_data!="AS")
01134                || $seen_end_of_table_ref
01135                || $i==$size-1 )) {
01136 
01137                 $size_chain = count($chain);
01138                 $current_table_ref++;
01139                 $subresult['table_ref'][$current_table_ref] = array(
01140                   'expr'            => '',
01141                   'db'              => '',
01142                   'table_name'      => '',
01143                   'table_alias'     => '',
01144                   'table_true_name' => ''
01145                  );
01146                 if (!empty($alias_for_table_ref)) {
01147                     $subresult['table_ref'][$current_table_ref]['table_alias'] = $alias_for_table_ref;
01148                     unset($alias_for_table_ref);
01149                 }
01150                 $subresult['table_ref'][$current_table_ref]['table_name'] = $chain[$size_chain - 1];
01151                 // we assume for now that this is also the true name
01152                 $subresult['table_ref'][$current_table_ref]['table_true_name'] = $chain[$size_chain - 1];
01153                 $subresult['table_ref'][$current_table_ref]['expr']
01154                      = $subresult['table_ref'][$current_table_ref]['table_name'];
01155                 // maybe a db
01156                 if ($size_chain > 1) {
01157                     $subresult['table_ref'][$current_table_ref]['db'] = $chain[$size_chain - 2];
01158                     $subresult['table_ref'][$current_table_ref]['expr']
01159                      = $subresult['table_ref'][$current_table_ref]['db']
01160                       . '.' . $subresult['table_ref'][$current_table_ref]['expr'];
01161                 } // end if ($size_chain > 1)
01162 
01163                 // add the table alias into the whole expression
01164                 $subresult['table_ref'][$current_table_ref]['expr']
01165                  .= ' ' . $subresult['table_ref'][$current_table_ref]['table_alias'];
01166 
01167                 unset($chain);
01168                 $previous_was_identifier = TRUE;
01169                 //continue;
01170 
01171             } // end if (save a table ref)
01172 
01173 
01174             // when we have found all table refs,
01175             // for each table_ref alias, put the true name of the table
01176             // in the corresponding select expressions
01177 
01178             if (isset($current_table_ref) && ($seen_end_of_table_ref || $i == $size-1)) {
01179                 for ($tr=0; $tr <= $current_table_ref; $tr++) {
01180                     $alias = $subresult['table_ref'][$tr]['table_alias'];
01181                     $truename = $subresult['table_ref'][$tr]['table_true_name'];
01182                     for ($se=0; $se <= $current_select_expr; $se++) {
01183                         if (!empty($alias) && $subresult['select_expr'][$se]['table_true_name']
01184                            == $alias) {
01185                             $subresult['select_expr'][$se]['table_true_name']
01186                              = $truename;
01187                         } // end if (found the alias)
01188                     } // end for (select expressions)
01189 
01190                 } // end for (table refs)
01191             } // end if (set the true names)
01192 
01193 
01194            // e n d i n g    l o o p  #1
01195            // set the $previous_was_identifier to FALSE if the current
01196            // token is not an identifier
01197            if (($arr[$i]['type'] != 'alpha_identifier')
01198             && ($arr[$i]['type'] != 'quote_double')
01199             && ($arr[$i]['type'] != 'quote_single')
01200             && ($arr[$i]['type'] != 'quote_backtick')) {
01201                $previous_was_identifier = FALSE;
01202            } // end if
01203 
01204            // however, if we are on AS, we must keep the $previous_was_identifier
01205            if (($arr[$i]['type'] == 'alpha_reservedWord')
01206             && ($upper_data == 'AS'))  {
01207                $previous_was_identifier = TRUE;
01208            }
01209 
01210            if (($arr[$i]['type'] == 'alpha_reservedWord')
01211             && ($upper_data =='ON' || $upper_data =='USING')) {
01212                $save_table_ref = FALSE;
01213            } // end if (data == ON)
01214 
01215            if (($arr[$i]['type'] == 'alpha_reservedWord')
01216             && ($upper_data =='JOIN' || $upper_data =='FROM')) {
01217                $save_table_ref = TRUE;
01218            } // end if (data == JOIN)
01219 
01220            // no need to check the end of table ref if we already did
01221            // TODO: maybe add "&& $seen_from"
01222            if (!$seen_end_of_table_ref) {
01223                // if this is the last token, it implies that we have
01224                // seen the end of table references
01225                // Check for the end of table references
01226                //
01227                // Note: if we are analyzing a GROUP_CONCAT clause,
01228                // we might find a word that seems to indicate that
01229                // we have found the end of table refs (like ORDER)
01230                // but it's a modifier of the GROUP_CONCAT so
01231                // it's not the real end of table refs
01232                if (($i == $size-1)
01233                || ($arr[$i]['type'] == 'alpha_reservedWord'
01234                   && !$in_group_concat
01235                   && PMA_STR_binarySearchInArr($upper_data, $words_ending_table_ref, $words_ending_table_ref_cnt))) {
01236                    $seen_end_of_table_ref = TRUE;
01237                    // to be able to save the last table ref, but do not
01238                    // set it true if we found a word like "ON" that has
01239                    // already set it to false
01240                    if (isset($save_table_ref) && $save_table_ref != FALSE) {
01241                       $save_table_ref = TRUE;
01242                    } //end if
01243 
01244                } // end if (check for end of table ref)
01245            } //end if (!$seen_end_of_table_ref)
01246 
01247            if ($seen_end_of_table_ref) {
01248                $save_table_ref = FALSE;
01249            } // end if
01250 
01251         } // end for $i (loop #1)
01252 
01253         // -------------------------------------------------------
01254         // This is a big hunk of debugging code by Marc for this.
01255         // -------------------------------------------------------
01256         /*
01257           if (isset($current_select_expr)) {
01258            for ($trace=0; $trace<=$current_select_expr; $trace++) {
01259                echo "<br />";
01260                reset ($subresult['select_expr'][$trace]);
01261                while (list ($key, $val) = each ($subresult['select_expr'][$trace]))
01262                    echo "sel expr $trace $key => $val<br />\n";
01263                }
01264           }
01265 
01266           if (isset($current_table_ref)) {
01267            echo "current_table_ref = " . $current_table_ref . "<br>";
01268            for ($trace=0; $trace<=$current_table_ref; $trace++) {
01269 
01270                echo "<br />";
01271                reset ($subresult['table_ref'][$trace]);
01272                while (list ($key, $val) = each ($subresult['table_ref'][$trace]))
01273                echo "table ref $trace $key => $val<br />\n";
01274                }
01275           }
01276         */
01277         // -------------------------------------------------------
01278 
01279 
01280         // loop #2: - queryflags
01281         //          - querytype (for queries != 'SELECT')
01282         //          - section_before_limit, section_after_limit
01283         //
01284         // we will also need this queryflag in loop 2
01285         // so set it here
01286         if (isset($current_table_ref) && $current_table_ref > -1) {
01287             $subresult['queryflags']['select_from'] = 1;
01288         }
01289 
01290         $collect_section_before_limit = TRUE;
01291         $section_before_limit = '';
01292         $section_after_limit = '';
01293         $seen_reserved_word = FALSE;
01294         $seen_group = FALSE;
01295         $seen_order = FALSE;
01296         $in_group_by = FALSE; // true when we are inside the GROUP BY clause
01297         $in_order_by = FALSE; // true when we are inside the ORDER BY clause
01298         $in_having = FALSE; // true when we are inside the HAVING clause
01299         $in_select_expr = FALSE; // true when we are inside the select expr clause
01300         $in_where = FALSE; // true when we are inside the WHERE clause
01301         $in_from = FALSE;
01302         $in_group_concat = FALSE;
01303         $unsorted_query = '';
01304         $first_reserved_word = '';
01305         $current_identifier = ''; 
01306 
01307         for ($i = 0; $i < $size; $i++) {
01308 //DEBUG echo "trace loop2 <b>"  . $arr[$i]['data'] . "</b> (" . $arr[$i]['type'] . ")<br />";
01309 
01310            // need_confirm
01311            //
01312            // check for reserved words that will have to generate
01313            // a confirmation request later in sql.php
01314            // the cases are:
01315            //   DROP TABLE
01316            //   DROP DATABASE
01317            //   ALTER TABLE... DROP
01318            //   DELETE FROM...
01319            //
01320            // this code is not used for confirmations coming from functions.js
01321 
01322            // TODO: check for punct_queryend
01323 
01324 
01325            // TODO: verify C-style comments?
01326            if ($arr[$i]['type'] == 'comment_ansi') {
01327                $collect_section_before_limit = FALSE;
01328            }
01329 
01330            if ($arr[$i]['type'] == 'alpha_reservedWord') {
01331                $upper_data = strtoupper($arr[$i]['data']);
01332                if (!$seen_reserved_word) {
01333                    $first_reserved_word = $upper_data;
01334                    $subresult['querytype'] = $upper_data;
01335                    $seen_reserved_word = TRUE;
01336 
01337                    // if the first reserved word is DROP or DELETE,
01338                    // we know this is a query that needs to be confirmed
01339                    if ($first_reserved_word=='DROP'
01340                        || $first_reserved_word == 'DELETE'
01341                        || $first_reserved_word == 'TRUNCATE') {
01342                       $subresult['queryflags']['need_confirm'] = 1;
01343                    }
01344 
01345                    if ($first_reserved_word=='SELECT'){
01346                        $position_of_first_select = $i;
01347                    }
01348 
01349                } else {
01350                    if ($upper_data=='DROP' && $first_reserved_word=='ALTER') {
01351                       $subresult['queryflags']['need_confirm'] = 1;
01352                    }
01353                }
01354 
01355                if ($upper_data == 'PROCEDURE') {
01356                    $collect_section_before_limit = FALSE;
01357                }
01358                // TODO: set also to FALSE if we find
01359                //      FOR UPDATE
01360                //      LOCK IN SHARE MODE
01361 
01362                if ($upper_data == 'SELECT') {
01363                    $in_select_expr = TRUE;
01364                    $select_expr_clause = '';
01365                }
01366                if ($upper_data == 'DISTINCT' && !$in_group_concat) {
01367                       $subresult['queryflags']['distinct'] = 1;
01368                }
01369 
01370                if ($upper_data == 'UNION') {
01371                       $subresult['queryflags']['union'] = 1;
01372                }
01373 
01374                if ($upper_data == 'JOIN') {
01375                       $subresult['queryflags']['join'] = 1;
01376                }
01377 
01378                if ($upper_data == 'OFFSET') {
01379                       $subresult['queryflags']['offset'] = 1;
01380                }
01381 
01382                // if this is a real SELECT...FROM
01383                if ($upper_data == 'FROM' && isset($subresult['queryflags']['select_from']) && $subresult['queryflags']['select_from'] == 1) {
01384                    $in_from = TRUE;
01385                    $from_clause = '';
01386                    $in_select_expr = FALSE;
01387                }
01388 
01389 
01390                // (we could have less resetting of variables to FALSE
01391                // if we trust that the query respects the standard
01392                // MySQL order for clauses)
01393 
01394                // we use $seen_group and $seen_order because we are looking
01395                // for the BY
01396                if ($upper_data == 'GROUP') {
01397                    $seen_group = TRUE;
01398                    $seen_order = FALSE;
01399                    $in_having = FALSE;
01400                    $in_order_by = FALSE;
01401                    $in_where = FALSE;
01402                    $in_select_expr = FALSE;
01403                    $in_from = FALSE;
01404                }
01405                if ($upper_data == 'ORDER' && !$in_group_concat) {
01406                    $seen_order = TRUE;
01407                    $seen_group = FALSE;
01408                    $in_having = FALSE;
01409                    $in_group_by = FALSE;
01410                    $in_where = FALSE;
01411                    $in_select_expr = FALSE;
01412                    $in_from = FALSE;
01413                }
01414                if ($upper_data == 'HAVING') {
01415                    $in_having = TRUE;
01416                    $having_clause = '';
01417                    $seen_group = FALSE;
01418                    $seen_order = FALSE;
01419                    $in_group_by = FALSE;
01420                    $in_order_by = FALSE;
01421                    $in_where = FALSE;
01422                    $in_select_expr = FALSE;
01423                    $in_from = FALSE;
01424                }
01425 
01426                if ($upper_data == 'WHERE') {
01427                    $in_where = TRUE;
01428                    $where_clause = '';
01429                    $where_clause_identifiers = array();
01430                    $seen_group = FALSE;
01431                    $seen_order = FALSE;
01432                    $in_group_by = FALSE;
01433                    $in_order_by = FALSE;
01434                    $in_having = FALSE;
01435                    $in_select_expr = FALSE;
01436                    $in_from = FALSE;
01437                }
01438 
01439                if ($upper_data == 'BY') {
01440                    if ($seen_group) {
01441                        $in_group_by = TRUE;
01442                        $group_by_clause = '';
01443                    }
01444                    if ($seen_order) {
01445                        $in_order_by = TRUE;
01446                        $order_by_clause = '';
01447                    }
01448                }
01449 
01450                // if we find one of the words that could end the clause
01451                if (PMA_STR_binarySearchInArr($upper_data, $words_ending_clauses, $words_ending_clauses_cnt)) {
01452 
01453                    $in_group_by = FALSE;
01454                    $in_order_by = FALSE;
01455                    $in_having   = FALSE;
01456                    $in_where    = FALSE;
01457                    $in_select_expr = FALSE;
01458                    $in_from = FALSE;
01459                }
01460 
01461            } // endif (reservedWord)
01462 
01463 
01464            // do not add a blank after a function name
01465            // TODO: can we combine loop 2 and loop 1?
01466            // some code is repeated here...
01467 
01468            $sep=' ';
01469            if ($arr[$i]['type'] == 'alpha_functionName') {
01470                $sep='';
01471                $upper_data = strtoupper($arr[$i]['data']);
01472                if ($upper_data =='GROUP_CONCAT') {
01473                    $in_group_concat = TRUE;
01474                    $number_of_brackets_in_group_concat = 0;
01475                }
01476            }
01477 
01478            if ($arr[$i]['type'] == 'punct_bracket_open_round') {
01479                if ($in_group_concat) {
01480                   $number_of_brackets_in_group_concat++;
01481                }
01482            }
01483            if ($arr[$i]['type'] == 'punct_bracket_close_round') {
01484                if ($in_group_concat) {
01485                   $number_of_brackets_in_group_concat--;
01486                   if ($number_of_brackets_in_group_concat == 0) {
01487                      $in_group_concat = FALSE;
01488                   }
01489                }
01490            }
01491 
01492            if ($in_select_expr && $upper_data != 'SELECT' && $upper_data != 'DISTINCT') {
01493                $select_expr_clause .= $arr[$i]['data'] . $sep;
01494            }
01495            if ($in_from && $upper_data != 'FROM') {
01496                $from_clause .= $arr[$i]['data'] . $sep;
01497            }
01498            if ($in_group_by && $upper_data != 'GROUP' && $upper_data != 'BY') {
01499                $group_by_clause .= $arr[$i]['data'] . $sep;
01500            }
01501            if ($in_order_by && $upper_data != 'ORDER' && $upper_data != 'BY') {
01502                $order_by_clause .= $arr[$i]['data'] . $sep;
01503            }
01504            if ($in_having && $upper_data != 'HAVING') {
01505                $having_clause .= $arr[$i]['data'] . $sep;
01506            }
01507            if ($in_where && $upper_data != 'WHERE') {
01508                $where_clause .= $arr[$i]['data'] . $sep;
01509 
01510                if (($arr[$i]['type'] == 'quote_backtick')
01511                 || ($arr[$i]['type'] == 'alpha_identifier')) {
01512                    $where_clause_identifiers[] = $arr[$i]['data'];
01513                }
01514            }
01515 
01516            if (isset($subresult['queryflags']['select_from'])
01517              && $subresult['queryflags']['select_from'] == 1
01518              && !$seen_order) {
01519                $unsorted_query .= $arr[$i]['data'];
01520 
01521                if ($arr[$i]['type'] != 'punct_bracket_open_round'
01522                && $arr[$i]['type'] != 'punct_bracket_close_round'
01523                && $arr[$i]['type'] != 'punct') {
01524                    $unsorted_query .= $sep;
01525                }
01526            }
01527 
01528            // clear $upper_data for next iteration
01529            $upper_data='';
01530 
01531            if ($collect_section_before_limit) {
01532                $section_before_limit .= $arr[$i]['data'] . $sep;
01533            } else {
01534                $section_after_limit .= $arr[$i]['data'] . $sep;
01535            }
01536 
01537 
01538         } // end for $i (loop #2)
01539 
01540 
01541         // -----------------------------------------------------
01542         // loop #3: foreign keys and MySQL 4.1.2+ TIMESTAMP options
01543         // (for now, check only the first query)
01544         // (for now, identifiers are assumed to be backquoted)
01545 
01546         // If we find that we are dealing with a CREATE TABLE query,
01547         // we look for the next punct_bracket_open_round, which 
01548         // introduces the fields list. Then, when we find a
01549         // quote_backtick, it must be a field, so we put it into
01550         // the create_table_fields array. Even if this field is
01551         // not a timestamp, it will be useful when logic has been
01552         // added for complete field attributes analysis.
01553 
01554         $seen_foreign = FALSE;
01555         $seen_references = FALSE;
01556         $seen_constraint = FALSE;
01557         $foreign_key_number = -1;
01558         $seen_create_table = FALSE;
01559         $seen_create = FALSE;
01560         $in_create_table_fields = FALSE;
01561         $brackets_level = 0;
01562         $in_timestamp_options = FALSE;
01563         $seen_default = FALSE;
01564 
01565         for ($i = 0; $i < $size; $i++) {
01566         // DEBUG echo "<b>" . $arr[$i]['data'] . "</b> " . $arr[$i]['type'] . "<br />";
01567 
01568             if ($arr[$i]['type'] == 'alpha_reservedWord') {
01569                 $upper_data = strtoupper($arr[$i]['data']);
01570 
01571                 if ($upper_data == 'NOT' && $in_timestamp_options) {
01572                     $create_table_fields[$current_identifier]['timestamp_not_null'] = TRUE; 
01573 
01574                 }
01575 
01576                 if ($upper_data == 'CREATE') {
01577                     $seen_create = TRUE;
01578                 }
01579 
01580                 if ($upper_data == 'TABLE' && $seen_create) {
01581                     $seen_create_table = TRUE;
01582                     $create_table_fields = array();
01583                 }
01584 
01585                 if ($upper_data == 'CURRENT_TIMESTAMP') {
01586                     if ($in_timestamp_options) {
01587                         if ($seen_default) {
01588                             $create_table_fields[$current_identifier]['default_current_timestamp'] = TRUE;
01589                         }
01590                     }
01591                 }
01592 
01593                 if ($upper_data == 'CONSTRAINT') {
01594                     $foreign_key_number++;
01595                     $seen_foreign = FALSE;
01596                     $seen_references = FALSE;
01597                     $seen_constraint = TRUE;
01598                 }
01599                 if ($upper_data == 'FOREIGN') {
01600                     $seen_foreign = TRUE;
01601                     $seen_references = FALSE;
01602                     $seen_constraint = FALSE;
01603                 }
01604                 if ($upper_data == 'REFERENCES') {
01605                     $seen_foreign = FALSE;
01606                     $seen_references = TRUE;
01607                     $seen_constraint = FALSE;
01608                 }
01609 
01610 
01611                 // Cases covered:
01612 
01613                 // [ON DELETE {CASCADE | SET NULL | NO ACTION | RESTRICT}]
01614                 // [ON UPDATE {CASCADE | SET NULL | NO ACTION | RESTRICT}]
01615 
01616                 // but we set ['on_delete'] or ['on_cascade'] to
01617                 // CASCADE | SET_NULL | NO_ACTION | RESTRICT
01618 
01619                 // ON UPDATE CURRENT_TIMESTAMP
01620 
01621                 if ($upper_data == 'ON') {
01622                     if ($arr[$i+1]['type'] == 'alpha_reservedWord') {
01623                         $second_upper_data = strtoupper($arr[$i+1]['data']);
01624                         if ($second_upper_data == 'DELETE') {
01625                             $clause = 'on_delete';
01626                         }
01627                         if ($second_upper_data == 'UPDATE') {
01628                             $clause = 'on_update';
01629                         }
01630                         if (isset($clause)
01631                         && ($arr[$i+2]['type'] == 'alpha_reservedWord'
01632 
01633                 // ugly workaround because currently, NO is not
01634                 // in the list of reserved words in sqlparser.data
01635                 // (we got a bug report about not being able to use
01636                 // 'no' as an identifier)
01637                            || ($arr[$i+2]['type'] == 'alpha_identifier'
01638                               && strtoupper($arr[$i+2]['data'])=='NO') )
01639                           ) {
01640                             $third_upper_data = strtoupper($arr[$i+2]['data']);
01641                             if ($third_upper_data == 'CASCADE'
01642                             || $third_upper_data == 'RESTRICT') {
01643                                 $value = $third_upper_data;
01644                             } elseif ($third_upper_data == 'SET'
01645                               || $third_upper_data == 'NO') {
01646                                 if ($arr[$i+3]['type'] == 'alpha_reservedWord') {
01647                                     $value = $third_upper_data . '_' . strtoupper($arr[$i+3]['data']);
01648                                 }
01649                             } elseif ($third_upper_data == 'CURRENT_TIMESTAMP') {
01650                                 if ($clause == 'on_update' 
01651                                 && $in_timestamp_options) {
01652                                     $create_table_fields[$current_identifier]['on_update_current_timestamp'] = TRUE;
01653                                     $seen_default = FALSE;
01654                                 }
01655                               
01656                             } else {
01657                                 $value = '';
01658                             }
01659                             if (!empty($value)) {
01660                                 $foreign[$foreign_key_number][$clause] = $value;
01661                             }
01662                             unset($clause);
01663                         } // endif (isset($clause))
01664                     }
01665                 }
01666 
01667             } // end of reserved words analysis
01668             
01669 
01670             if ($arr[$i]['type'] == 'punct_bracket_open_round') {
01671                 $brackets_level++;
01672                 if ($seen_create_table && $brackets_level == 1) {
01673                     $in_create_table_fields = TRUE;
01674                 }
01675             }
01676 
01677             
01678             if ($arr[$i]['type'] == 'punct_bracket_close_round') {
01679                 $brackets_level--;
01680                 if ($seen_references) {
01681                     $seen_references = FALSE;
01682                 }
01683                 if ($seen_create_table && $brackets_level == 0) {
01684                     $in_create_table_fields = FALSE;
01685                 }
01686             }
01687 
01688             if (($arr[$i]['type'] == 'alpha_columnAttrib')) {
01689                 $upper_data = strtoupper($arr[$i]['data']);
01690                 if ($seen_create_table && $in_create_table_fields) {
01691                     if ($upper_data == 'DEFAULT') {
01692                         $seen_default = TRUE;
01693                     }
01694                 }
01695             }
01696 
01697             if (($arr[$i]['type'] == 'alpha_columnType')) {
01698                 $upper_data = strtoupper($arr[$i]['data']);
01699                 if ($seen_create_table && $in_create_table_fields && isset($current_identifier)) {
01700                     $create_table_fields[$current_identifier]['type'] = $upper_data;
01701                     if ($upper_data == 'TIMESTAMP') {
01702                         $in_timestamp_options = TRUE;
01703                     } else {
01704                         $in_timestamp_options = FALSE;
01705                     }
01706                 }
01707             }
01708 
01709             
01710             if ($arr[$i]['type'] == 'quote_backtick' || $arr[$i]['type'] == 'alpha_identifier') {
01711 
01712                 if ($arr[$i]['type'] == 'quote_backtick') {
01713                     // remove backquotes
01714                     $identifier = str_replace('`','',$arr[$i]['data']);
01715                 } else {
01716                     $identifier = $arr[$i]['data'];
01717                 }
01718 
01719                 if ($seen_create_table && $in_create_table_fields) {
01720                     $current_identifier = $identifier;
01721                     // warning: we set this one even for non TIMESTAMP type
01722                     $create_table_fields[$current_identifier]['timestamp_not_null'] = FALSE; 
01723                 }
01724 
01725                 if ($seen_constraint) {
01726                     $foreign[$foreign_key_number]['constraint'] = $identifier;
01727                 }
01728 
01729                 if ($seen_foreign && $brackets_level > 0) {
01730                     $foreign[$foreign_key_number]['index_list'][] = $identifier;
01731                 }
01732 
01733                 if ($seen_references) {
01734                     // here, the first bracket level corresponds to the
01735                     // bracket of CREATE TABLE
01736                     // so if we are on level 2, it must be the index list
01737                     // of the foreign key REFERENCES
01738                     if ($brackets_level > 1) {
01739                         $foreign[$foreign_key_number]['ref_index_list'][] = $identifier;
01740                     } else {
01741                         // for MySQL 4.0.18, identifier is
01742                         // `table` or `db`.`table`
01743                         // the first pass will pick the db name
01744                         // the next pass will execute the else and pick the
01745                         // db name in $db_table[0]
01746                         if ($arr[$i+1]['type'] == 'punct_qualifier') {
01747                                 $foreign[$foreign_key_number]['ref_db_name'] = $identifier;
01748                         } else {
01749                         // for MySQL 4.0.16, identifier is
01750                         // `table` or `db.table`
01751                             $db_table = explode('.',$identifier);
01752                             if (isset($db_table[1])) {
01753                                 $foreign[$foreign_key_number]['ref_db_name'] = $db_table[0];
01754                                 $foreign[$foreign_key_number]['ref_table_name'] = $db_table[1];
01755                             } else {
01756                                 $foreign[$foreign_key_number]['ref_table_name'] = $db_table[0];
01757                             }
01758                         }
01759                     }
01760                 }
01761             }
01762         } // end for $i (loop #3)
01763 
01764 
01765         // Fill the $subresult array
01766 
01767         if (isset($create_table_fields)) {
01768             $subresult['create_table_fields'] = $create_table_fields;
01769         }
01770 
01771         if (isset($foreign)) {
01772             $subresult['foreign_keys'] = $foreign;
01773         }
01774 
01775         if (isset($select_expr_clause)) {
01776             $subresult['select_expr_clause'] = $select_expr_clause;
01777         }
01778         if (isset($from_clause)) {
01779             $subresult['from_clause'] = $from_clause;
01780         }
01781         if (isset($group_by_clause)) {
01782             $subresult['group_by_clause'] = $group_by_clause;
01783         }
01784         if (isset($order_by_clause)) {
01785             $subresult['order_by_clause'] = $order_by_clause;
01786         }
01787         if (isset($having_clause)) {
01788             $subresult['having_clause'] = $having_clause;
01789         }
01790         if (isset($where_clause)) {
01791             $subresult['where_clause'] = $where_clause;
01792         }
01793         if (isset($unsorted_query) && !empty($unsorted_query)) {
01794             $subresult['unsorted_query'] = $unsorted_query;
01795         }
01796         if (isset($where_clause_identifiers)) {
01797             $subresult['where_clause_identifiers'] = $where_clause_identifiers;
01798         }
01799 
01800         if (isset($position_of_first_select)) {
01801             $subresult['position_of_first_select'] = $position_of_first_select;
01802             $subresult['section_before_limit'] = $section_before_limit;
01803             $subresult['section_after_limit'] = $section_after_limit;
01804         }
01805 
01806         // They are naughty and didn't have a trailing semi-colon,
01807         // then still handle it properly
01808         if ($subresult['querytype'] != '') {
01809             $result[] = $subresult;
01810         }
01811         return $result;
01812     } // end of the "PMA_SQP_analyze()" function
01813 
01814 
01824     function PMA_SQP_formatHtml_colorize($arr)
01825     {
01826         $i         = $GLOBALS['PMA_strpos']($arr['type'], '_');
01827         $class     = '';
01828         if ($i > 0) {
01829             $class = 'syntax_' . PMA_substr($arr['type'], 0, $i) . ' ';
01830         }
01831 
01832         $class     .= 'syntax_' . $arr['type'];
01833 
01834         //TODO: check why adding a "\n" after the </span> would cause extra
01835         //      blanks to be displayed:
01836         //      SELECT p . person_name
01837 
01838         return '<span class="' . $class . '">' . htmlspecialchars($arr['data']) . '</span>';
01839     } // end of the "PMA_SQP_formatHtml_colorize()" function
01840 
01841 
01854     function PMA_SQP_formatHtml($arr, $mode='color', $start_token=0,
01855         $number_of_tokens=-1)
01856     {
01857         // then check for an array
01858         if (!is_array($arr)) {
01859             return htmlspecialchars($arr);
01860         }
01861         // first check for the SQL parser having hit an error
01862         if (PMA_SQP_isError()) {
01863             return htmlspecialchars($arr['raw']);
01864         }
01865         // else do it properly
01866         switch ($mode) {
01867             case 'color':
01868                 $str                                = '<span class="syntax">';
01869                 $html_line_break                    = '<br />';
01870                 break;
01871             case 'query_only':
01872                 $str                                = '';
01873                 $html_line_break                    = "\n";
01874                 break;
01875             case 'text':
01876                 $str                                = '';
01877                 $html_line_break                    = '<br />';
01878                 break;
01879         } // end switch
01880         $indent                                     = 0;
01881         $bracketlevel                               = 0;
01882         $functionlevel                              = 0;
01883         $infunction                                 = FALSE;
01884         $space_punct_listsep                        = ' ';
01885         $space_punct_listsep_function_name          = ' ';
01886         // $space_alpha_reserved_word = '<br />'."\n";
01887         $space_alpha_reserved_word                  = ' ';
01888 
01889         $keywords_with_brackets_1before            = array(
01890             'INDEX',
01891             'KEY',
01892             'ON',
01893             'USING'
01894         );
01895         $keywords_with_brackets_1before_cnt        = 4;
01896 
01897         $keywords_with_brackets_2before            = array(
01898             'IGNORE',
01899             'INDEX',
01900             'INTO',
01901             'KEY',
01902             'PRIMARY',
01903             'PROCEDURE',
01904             'REFERENCES',
01905             'UNIQUE',
01906             'USE'
01907         );
01908         // $keywords_with_brackets_2before_cnt = count($keywords_with_brackets_2before);
01909         $keywords_with_brackets_2before_cnt        = 9;
01910 
01911         // These reserved words do NOT get a newline placed near them.
01912         $keywords_no_newline               = array(
01913             'AS',
01914             'ASC',
01915             'DESC',
01916             'DISTINCT',
01917             'HOUR',
01918             'INTERVAL',
01919             'IS',
01920             'LIKE',
01921             'NOT',
01922             'NULL',
01923             'ON',
01924             'REGEXP'
01925         );
01926         $keywords_no_newline_cnt           = 12;
01927 
01928         // These reserved words introduce a privilege list
01929         $keywords_priv_list                = array(
01930             'GRANT',
01931             'REVOKE'
01932         );
01933         $keywords_priv_list_cnt            = 2;
01934 
01935         if ($number_of_tokens == -1) {
01936             $arraysize = $arr['len'];
01937         } else {
01938             $arraysize = $number_of_tokens;
01939         }
01940         $typearr   = array();
01941         if ($arraysize >= 0) {
01942             $typearr[0] = '';
01943             $typearr[1] = '';
01944             $typearr[2] = '';
01945             //$typearr[3] = $arr[0]['type'];
01946             $typearr[3] = $arr[$start_token]['type'];
01947         }
01948 
01949         $in_priv_list = FALSE;
01950         for ($i = $start_token; $i < $arraysize; $i++) {
01951 // DEBUG echo "<b>" . $arr[$i]['data'] . "</b> " . $arr[$i]['type'] . "<br />";
01952             $before = '';
01953             $after  = '';
01954             $indent = 0;
01955             // array_shift($typearr);
01956             /*
01957             0 prev2
01958             1 prev
01959             2 current
01960             3 next
01961             */
01962             if (($i + 1) < $arraysize) {
01963                 // array_push($typearr, $arr[$i + 1]['type']);
01964                 $typearr[4] = $arr[$i + 1]['type'];
01965             } else {
01966                 //array_push($typearr, NULL);
01967                 $typearr[4] = '';
01968             }
01969 
01970             for ($j=0; $j<4; $j++) {
01971                 $typearr[$j] = $typearr[$j + 1];
01972             }
01973 
01974             switch ($typearr[2]) {
01975                 case 'white_newline':
01976                     $before     = '';
01977                     break;
01978                 case 'punct_bracket_open_round':
01979                     $bracketlevel++;
01980                     $infunction = FALSE;
01981                     // Make sure this array is sorted!
01982                     if (($typearr[1] == 'alpha_functionName') || ($typearr[1] == 'alpha_columnType') || ($typearr[1] == 'punct')
01983                         || ($typearr[3] == 'digit_integer') || ($typearr[3] == 'digit_hex') || ($typearr[3] == 'digit_float')
01984                         || (($typearr[0] == 'alpha_reservedWord')
01985                             && PMA_STR_binarySearchInArr(strtoupper($arr[$i - 2]['data']), $keywords_with_brackets_2before, $keywords_with_brackets_2before_cnt))
01986                         || (($typearr[1] == 'alpha_reservedWord')
01987                             && PMA_STR_binarySearchInArr(strtoupper($arr[$i - 1]['data']), $keywords_with_brackets_1before, $keywords_with_brackets_1before_cnt))
01988                         ) {
01989                         $functionlevel++;
01990                         $infunction = TRUE;
01991                         $after      .= ' ';
01992                     } else {
01993                         $indent++;
01994                         $after      .= ($mode != 'query_only' ? '<div class="syntax_indent' . $indent . '">' : ' ');
01995                     }
01996                     break;
01997                 case 'alpha_identifier':
01998                     if (($typearr[1] == 'punct_qualifier') || ($typearr[3] == 'punct_qualifier')) {
01999                         $after      = '';
02000                         $before     = '';
02001                     }
02002                     if (($typearr[3] == 'alpha_columnType') || ($typearr[3] == 'alpha_identifier')) {
02003                         $after      .= ' ';
02004                     }
02005                     break;
02006                 case 'punct_qualifier':
02007                     $before         = '';
02008                     $after          = '';
02009                     break;
02010                 case 'punct_listsep':
02011                     if ($infunction == TRUE) {
02012                         $after      .= $space_punct_listsep_function_name;
02013                     } else {
02014                         $after      .= $space_punct_listsep;
02015                     }
02016                     break;
02017                 case 'punct_queryend':
02018                     if (($typearr[3] != 'comment_mysql') && ($typearr[3] != 'comment_ansi') && $typearr[3] != 'comment_c') {
02019                         $after     .= $html_line_break;
02020                         $after     .= $html_line_break;
02021                     }
02022                     $space_punct_listsep               = ' ';
02023                     $space_punct_listsep_function_name = ' ';
02024                     $space_alpha_reserved_word         = ' ';
02025                     $in_priv_list                      = FALSE;
02026                     break;
02027                 case 'comment_mysql':
02028                 case 'comment_ansi':
02029                     $after         .= $html_line_break;
02030                     break;
02031                 case 'punct':
02032                     $before         .= ' ';
02033                     // workaround for
02034                     // select * from mytable limit 0,-1
02035                     // (a side effect of this workaround is that
02036                     // select 20 - 9
02037                     // becomes
02038                     // select 20 -9
02039                     // )
02040                     if ($typearr[3] != 'digit_integer') {
02041                        $after        .= ' ';
02042                     }
02043                     break;
02044                 case 'punct_bracket_close_round':
02045                     $bracketlevel--;
02046                     if ($infunction == TRUE) {
02047                         $functionlevel--;
02048                         $after     .= ' ';
02049                         $before    .= ' ';
02050                     } else {
02051                         $indent--;
02052                         $before    .= ($mode != 'query_only' ? '</div>' : ' ');
02053                     }
02054                     $infunction    = ($functionlevel > 0) ? TRUE : FALSE;
02055                     break;
02056                 case 'alpha_columnType':
02057                     if ($typearr[3] == 'alpha_columnAttrib') {
02058                         $after     .= ' ';
02059                     }
02060                     if ($typearr[1] == 'alpha_columnType') {
02061                         $before    .= ' ';
02062                     }
02063                     break;
02064                 case 'alpha_columnAttrib':
02065 
02066                     // ALTER TABLE tbl_name AUTO_INCREMENT = 1
02067                     // COLLATE LATIN1_GENERAL_CI DEFAULT
02068                     if ($typearr[1] == 'alpha_identifier' || $typearr[1] == 'alpha_charset') {
02069                         $before .= ' ';
02070                     }
02071                     if (($typearr[3] == 'alpha_columnAttrib') || ($typearr[3] == 'quote_single') || ($typearr[3] == 'digit_integer')) {
02072                         $after     .= ' ';
02073                     }
02074                     // workaround for
02075                     // select * from mysql.user where binary user="root"
02076                     // binary is marked as alpha_columnAttrib
02077                     // but should be marked as a reserved word
02078                     if (strtoupper($arr[$i]['data']) == 'BINARY'
02079                       && $typearr[3] == 'alpha_identifier') {
02080                         $after     .= ' ';
02081                     }
02082                     break;
02083                 case 'alpha_reservedWord':
02084                     // do not uppercase the reserved word if we are calling
02085                     // this function in query_only mode, because we need
02086                     // the original query (otherwise we get problems with
02087                     // semi-reserved words like "storage" which is legal
02088                     // as an identifier name)
02089 
02090                     if ($mode != 'query_only') {
02091                         $arr[$i]['data'] = strtoupper($arr[$i]['data']);
02092                     }
02093 
02094                     if ((($typearr[1] != 'alpha_reservedWord')
02095                         || (($typearr[1] == 'alpha_reservedWord')
02096                             && PMA_STR_binarySearchInArr(strtoupper($arr[$i - 1]['data']), $keywords_no_newline, $keywords_no_newline_cnt)))
02097                         && ($typearr[1] != 'punct_level_plus')
02098                         && (!PMA_STR_binarySearchInArr($arr[$i]['data'], $keywords_no_newline, $keywords_no_newline_cnt))) {
02099                         // do not put a space before the first token, because
02100                         // we use a lot of eregi() checking for the first
02101                         // reserved word at beginning of query
02102                         // so do not put a newline before
02103                         //
02104                         // also we must not be inside a privilege list
02105                         if ($i > 0) {
02106                             // the alpha_identifier exception is there to
02107                             // catch cases like
02108                             // GRANT SELECT ON mydb.mytable TO myuser@localhost
02109                             // (else, we get mydb.mytableTO )
02110                             //
02111                             // the quote_single exception is there to
02112                             // catch cases like
02113                             // GRANT ... TO 'marc'@'domain.com' IDENTIFIED...
02114                             //
02115                             // TODO: fix all cases and find why this happens
02116 
02117                             if (!$in_priv_list || $typearr[1] == 'alpha_identifier' || $typearr[1] == 'quote_single' || $typearr[1] == 'white_newline') {
02118                                 $before    .= $space_alpha_reserved_word;
02119                             }
02120                         } else {
02121                         // on first keyword, check if it introduces a
02122                         // privilege list
02123                             if (PMA_STR_binarySearchInArr($arr[$i]['data'], $keywords_priv_list, $keywords_priv_list_cnt)) {
02124                                 $in_priv_list = TRUE;
02125                             }
02126                         }
02127                     } else {
02128                         $before    .= ' ';
02129                     }
02130 
02131                     switch ($arr[$i]['data']) {
02132                         case 'CREATE':
02133                             if (!$in_priv_list) {
02134                                 $space_punct_listsep       = $html_line_break;
02135                                 $space_alpha_reserved_word = ' ';
02136                             }
02137                             break;
02138                         case 'EXPLAIN':
02139                         case 'DESCRIBE':
02140                         case 'SET':
02141                         case 'ALTER':
02142                         case 'DELETE':
02143                         case 'SHOW':
02144                         case 'DROP':
02145                         case 'UPDATE':
02146                         case 'TRUNCATE':
02147                         case 'ANALYZE':
02148                         case 'ANALYSE':
02149                             if (!$in_priv_list) {
02150                                 $space_punct_listsep       = $html_line_break;
02151                                 $space_alpha_reserved_word = ' ';
02152                             }
02153                             break;
02154                         case 'INSERT':
02155                         case 'REPLACE':
02156                             if (!$in_priv_list) {
02157                                 $space_punct_listsep       = $html_line_break;
02158                                 $space_alpha_reserved_word = $html_line_break;
02159                             }
02160                             break;
02161                         case 'VALUES':
02162                             $space_punct_listsep       = ' ';
02163                             $space_alpha_reserved_word = $html_line_break;
02164                             break;
02165                         case 'SELECT':
02166                             $space_punct_listsep       = ' ';
02167                             $space_alpha_reserved_word = $html_line_break;
02168                             break;
02169                         default:
02170                             break;
02171                     } // end switch ($arr[$i]['data'])
02172 
02173                     $after         .= ' ';
02174                     break;
02175                 case 'digit_integer':
02176                 case 'digit_float':
02177                 case 'digit_hex':
02178                     //TODO: could there be other types preceding a digit?
02179                     if ($typearr[1] == 'alpha_reservedWord') {
02180                         $after .= ' ';
02181                     }
02182                     if ($infunction && $typearr[3] == 'punct_bracket_close_round') {
02183                         $after     .= ' ';
02184                     }
02185                     if ($typearr[1] == 'alpha_columnAttrib') {
02186                         $before .= ' ';
02187                     }
02188                     break;
02189                 case 'alpha_variable':
02190                     // other workaround for a problem similar to the one
02191                     // explained below for quote_single
02192                     if (!$in_priv_list) {
02193                         $after      = ' ';
02194                     }
02195                     break;
02196                 case 'quote_double':
02197                 case 'quote_single':
02198                     // workaround: for the query
02199                     // REVOKE SELECT ON `base2\_db`.* FROM 'user'@'%'
02200                     // the @ is incorrectly marked as alpha_variable
02201                     // in the parser, and here, the '%' gets a blank before,
02202                     // which is a syntax error
02203                     if ($typearr[1] !='alpha_variable') {
02204                         $before        .= ' ';
02205                     }
02206                     if ($infunction && $typearr[3] == 'punct_bracket_close_round') {
02207                         $after     .= ' ';
02208                     }
02209                     break;
02210                 case 'quote_backtick':
02211                     if ($typearr[3] != 'punct_qualifier') {
02212                         $after     .= ' ';
02213                     }
02214                     if ($typearr[1] != 'punct_qualifier') {
02215                         $before    .= ' ';
02216                     }
02217                     break;
02218                 default:
02219                     break;
02220             } // end switch ($typearr[2])
02221 
02222 /*
02223             if ($typearr[3] != 'punct_qualifier') {
02224                 $after             .= ' ';
02225             }
02226             $after                 .= "\n";
02227 */
02228             $str .= $before . ($mode=='color' ? PMA_SQP_formatHTML_colorize($arr[$i]) : $arr[$i]['data']). $after;
02229         } // end for
02230         if ($mode=='color') {
02231             $str .= '</span>';
02232         }
02233 
02234         return $str;
02235     } // end of the "PMA_SQP_formatHtml()" function
02236 }
02237 
02251 function PMA_SQP_buildCssRule($classname, $property, $value)
02252 {
02253     $str     = '.' . $classname . ' {';
02254     if ($value != '') {
02255         $str .= $property . ': ' . $value . ';';
02256     }
02257     $str     .= '}' . "\n";
02258 
02259     return $str;
02260 } // end of the "PMA_SQP_buildCssRule()" function
02261 
02262 
02274 function PMA_SQP_buildCssData()
02275 {
02276     global $cfg;
02277 
02278     $css_string     = '';
02279     foreach ($cfg['SQP']['fmtColor'] AS $key => $col) {
02280         $css_string .= PMA_SQP_buildCssRule('syntax_' . $key, 'color', $col);
02281     }
02282 
02283     for ($i = 0; $i < 8; $i++) {
02284         $css_string .= PMA_SQP_buildCssRule('syntax_indent' . $i, 'margin-left', ($i * $cfg['SQP']['fmtInd']) . $cfg['SQP']['fmtIndUnit']);
02285     }
02286 
02287     return $css_string;
02288 } // end of the "PMA_SQP_buildCssData()" function
02289 
02290 if ($is_minimum_common == FALSE) {
02300     function PMA_SQP_formatNone($arr)
02301     {
02302         $formatted_sql = htmlspecialchars($arr['raw']);
02303         $formatted_sql = preg_replace("@((\015\012)|(\015)|(\012)){3,}@", "\n\n", $formatted_sql);
02304 
02305         return $formatted_sql;
02306     } // end of the "PMA_SQP_formatNone()" function
02307 
02308 
02318     function PMA_SQP_formatText($arr)
02319     {
02323          return PMA_SQP_formatNone($arr);
02324     } // end of the "PMA_SQP_formatText()" function
02325 } // end if: minimal common.lib needed?
02326 
02327 ?>


Généré par TYPO3 Ameos avec  doxygen 1.4.6