From 7e4309b02a7da99cbba5979078f2179b7fe8e740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 29 May 2012 13:57:57 +0200 Subject: [PATCH 01/11] Various coding style improvements --- libraries/insert_edit.lib.php | 356 +++++++++++++++++----------------- 1 file changed, 178 insertions(+), 178 deletions(-) diff --git a/libraries/insert_edit.lib.php b/libraries/insert_edit.lib.php index 10d2e60e87..52faf44324 100644 --- a/libraries/insert_edit.lib.php +++ b/libraries/insert_edit.lib.php @@ -2,7 +2,7 @@ /* vim: set expandtab sw=4 ts=4 sts=4: */ /** * set of functions with the insert/edit features in pma - * + * * @package PhpMyAdmin */ @@ -12,23 +12,23 @@ if (! defined('PHPMYADMIN')) { /** * Retrieve form parameters for insert/edit form - * - * @param string $db name of the database - * @param string $table name of the table - * @param array $where_clauses where clauses - * @param array $where_clause_array array of where clauses - * @param string $err_url error url - * - * @return array $_form_params array of insert/edit form parameters + * + * @param string $db name of the database + * @param string $table name of the table + * @param array $where_clauses where clauses + * @param array $where_clause_array array of where clauses + * @param string $err_url error url + * + * @return array $_form_params array of insert/edit form parameters */ function PMA_getFormParametersForInsertForm($db, $table, $where_clauses, $where_clause_array, $err_url) { $_form_params = array( - 'db' => $db, - 'table' => $table, - 'goto' => $GLOBALS['goto'], - 'err_url' => $err_url, - 'sql_query' => $_REQUEST['sql_query'], + 'db' => $db, + 'table' => $table, + 'goto' => $GLOBALS['goto'], + 'err_url' => $err_url, + 'sql_query' => $_REQUEST['sql_query'], ); if (isset($where_clauses)) { foreach ($where_clause_array as $key_id => $where_clause) { @@ -43,13 +43,13 @@ function PMA_getFormParametersForInsertForm($db, $table, $where_clauses, $where_ /** * Retrieve the values for pma edit mode - * - * @param type $where_clause where clauses - * @param type $table name of the table - * @param type $db name of the database - * + * + * @param type $where_clause where clauses + * @param type $table name of the table + * @param type $db name of the database + * * @return type containing insert_mode,whereClauses, result array - * where_clauses_array and found_unique_key boolean value + * where_clauses_array and found_unique_key boolean value */ function PMA_getValuesForEditMode($where_clause, $table, $db) { @@ -67,11 +67,11 @@ function PMA_getValuesForEditMode($where_clause, $table, $db) /** * - * @return whereClauseArray array of where clauses + * @return whereClauseArray array of where clauses */ function PMA_getWhereClauseArray($where_clause) { - if(isset ($where_clause)) { + if (isset ($where_clause)) { if (is_array($where_clause)) { return $where_clause; } else { @@ -82,12 +82,12 @@ function PMA_getWhereClauseArray($where_clause) /** * Analysing where cluases array - * + * * @param array $where_clause_array array of where clauses * @param string $table name of the table * @param string $db name of the database * @param boolean $found_unique_key boolean variable for unique key - * + * * @return array $where_clauses, $result, $rows */ function PMA_analyzeWhereClauses($where_clause_array, $table, $db, $found_unique_key) @@ -108,15 +108,15 @@ function PMA_analyzeWhereClauses($where_clause_array, $table, $db, $found_unique } /** - * Show message for empty reult or set the unique_condition - * + * Show message for empty reult or set the unique_condition + * * @param array $rows * @param string $key_id * @param array $where_clause_array * @param string $local_query * @param array $result * @param boolean $found_unique_key - * + * * @return boolean $found_unique_key */ function PMA_showEmptyResultMessageOrSetUniqueCondition($rows, $key_id, @@ -128,7 +128,7 @@ function PMA_showEmptyResultMessageOrSetUniqueCondition($rows, $key_id, PMA_showMessage(__('MySQL returned an empty result set (i.e. zero rows).'), $local_query); echo "\n"; include 'libraries/footer.inc.php'; - } else {// end if (no row returned) + } else {// end if (no row returned) $meta = PMA_DBI_get_fields_meta($result[$key_id]); list($unique_condition, $tmp_clause_is_unique) = PMA_getUniqueCondition($result[$key_id], count($meta), $meta, $rows[$key_id], true); @@ -142,10 +142,10 @@ function PMA_showEmptyResultMessageOrSetUniqueCondition($rows, $key_id, /** * No primary key given, just load first row - * + * * @param string $table name of the table * @param string $db name of the database - * + * * @return array containing $result and $rows arrays */ function PMA_loadFirstRowInEditMode($table, $db) @@ -161,13 +161,13 @@ function PMA_loadFirstRowInEditMode($table, $db) /** * Add some url parameters - * + * * @param array $url_params containing $db and $table as url parameters - * + * * @return array Add some url parameters to $url_params array * and return it */ -function PMA_urlParamsInEditMode($url_params) +function PMA_urlParamsInEditMode($url_params) { if (isset($_REQUEST['where_clause'])) { $url_params['where_clause'] = trim($_REQUEST['where_clause']); @@ -180,15 +180,15 @@ function PMA_urlParamsInEditMode($url_params) /** * Show function fields in data edit view in pma - * + * * @param array $url_params containing url parameters - * + * * @return string an html snippet */ function PMA_showFunctionFieldsInEditMode($url_params, $showFuncFields) { $params = array(); - if(! $showFuncFields) { + if (! $showFuncFields) { $params['ShowFunctionFields'] = 1; } else { $params['ShowFunctionFields'] = 0; @@ -196,7 +196,7 @@ function PMA_showFunctionFieldsInEditMode($url_params, $showFuncFields) $params['ShowFieldTypesInDataEditView'] = $GLOBALS['cfg']['ShowFieldTypesInDataEditView']; $params['goto'] = 'sql.php'; $this_url_params = array_merge($url_params, $params); - if(! $showFuncFields) { + if (! $showFuncFields) { return ' : ' . __('Function') . '' . "\n"; } return ' ' . __('Function') . '' . "\n"; @@ -204,15 +204,15 @@ function PMA_showFunctionFieldsInEditMode($url_params, $showFuncFields) /** * Show field types in data edit view in pma - * + * * @param array $url_params containing url parameters - * + * * @return stirng an html snippet */ function PMA_showColumnTypesInDataEditView($url_params, $showColumnType ) { $params = array(); - if(! $showColumnType) { + if (! $showColumnType) { $params['ShowFieldTypesInDataEditView'] = 1; } else { $params['ShowFieldTypesInDataEditView'] = 0; @@ -220,17 +220,17 @@ function PMA_showColumnTypesInDataEditView($url_params, $showColumnType ) $params['ShowFunctionFields'] = $GLOBALS['cfg']['ShowFunctionFields']; $params['goto'] = 'sql.php'; $this_other_url_params = array_merge($url_params, $params); - if(! $showColumnType) { + if (! $showColumnType) { return ' : ' . __('Type') . '' . "\n"; } return ' ' . __('Type') . '' . "\n"; - + } /** * Retrieve the default for datetime data type - * + * * @param array $column containing column type, Default and null */ function PMA_getDefaultForDatetime($column) @@ -258,14 +258,14 @@ function PMA_getDefaultForDatetime($column) $column['Default'] = null; } } - + /** * Analyze the table column array - * + * * @param array $column description of column in given table * @param array $comments_map comments for every column that has a comment - * @param integer $timestamp_seen 0 interger - * + * @param integer $timestamp_seen 0 interger + * * @return array description of column in given table */ function PMA_analyzeTableColumnsArray($column, $comments_map, $timestamp_seen) @@ -280,18 +280,18 @@ function PMA_analyzeTableColumnsArray($column, $comments_map, $timestamp_seen) $column['is_binary'] = PMA_isColumnBinary($column); $column['is_blob'] = PMA_isColumnBlob($column); $column['is_char'] = PMA_isColumnChar($column); - list($column['pma_type'], $column['wrap'], $column['first_timestamp']) = + list($column['pma_type'], $column['wrap'], $column['first_timestamp']) = PMA_getEnumSetAndTimestampColumns($column, $timestamp_seen); - + return $column; } - + /** * Retrieve the column title - * + * * @param array $column description of column in given table * @param array $comments_map comments for every column that has a comment - * + * * @return string column title */ function PMA_getColumnTitle($column, $comments_map) @@ -304,12 +304,12 @@ function PMA_getColumnTitle($column, $comments_map) return $column['Field_html']; } } - + /** * check whether the column is a bainary - * + * * @param array $column description of column in given table - * + * * @return boolean If check to ensure types such as "enum('one','two','binary',..)" or * "enum('one','two','varbinary',..)" are not categorized as binary. */ @@ -324,14 +324,14 @@ function PMA_isColumnBinary($column) } else { return false; } - + } - + /** * check whether the column is a blob - * + * * @param array $column description of column in given table - * + * * @return boolean If check to ensure types such as "enum('one','two','blob',..)" or * "enum('one','two','tinyblob',..)" etc. are not categorized as blob. */ @@ -350,9 +350,9 @@ function PMA_isColumnBlob($column) /** * check is table column char - * + * * @param array $column description of column in given table - * + * * @return boolean If check to ensure types such as "enum('one','two','char',..)" or * "enum('one','two','varchar',..)" are not categorized as char. */ @@ -368,10 +368,10 @@ function PMA_isColumnChar($column) } /** * Retieve set, enum, timestamp table columns - * + * * @param array $column description of column in given table * @param int $timestamp_seen 0 interger - * + * * return array $column['pma_type'], $column['wrap'], $column['first_timestamp'] */ function PMA_getEnumSetAndTimestampColumns($column, $timestamp_seen) @@ -408,7 +408,7 @@ function PMA_getEnumSetAndTimestampColumns($column, $timestamp_seen) * We don't want binary data to be destroyed * Note: from the MySQL manual: "BINARY doesn't affect how the column is * stored or retrieved" so it does not mean that the contents is binary - * + * * @param array $column description of column in given table * @param boolean $is_upload upload or no * @param string $column_name_appendix the name atttibute @@ -418,13 +418,13 @@ function PMA_getEnumSetAndTimestampColumns($column, $timestamp_seen) * @param integer $tabindex tab index * @param integer $idindex id index * @param boolean $insert_mode insert mode or edit mode - * + * * @return string an html sippet */ function PMA_getFunctionColumn($column, $is_upload, $column_name_appendix, $unnullify_trigger, $no_support_types, $tabindex_for_function, $tabindex, $idindex, $insert_mode -) { +) { $html_output = ''; if (($GLOBALS['cfg']['ProtectBinary'] && $column['is_blob'] && !$is_upload) || ($GLOBALS['cfg']['ProtectBinary'] == 'all' && $column['is_binary']) @@ -438,7 +438,7 @@ function PMA_getFunctionColumn($column, $is_upload, $column_name_appendix, $html_output .= ' --' . "\n"; } else { $html_output .= '' . "\n"; - $html_output .= '' . "\n"; @@ -449,7 +449,7 @@ function PMA_getFunctionColumn($column, $is_upload, $column_name_appendix, /** * The null column - * + * * @param array $column description of column in given table * @param string $column_name_appendix the name atttibute * @param array $real_null_value is column value null or not null @@ -457,9 +457,9 @@ function PMA_getFunctionColumn($column, $is_upload, $column_name_appendix, * @param integer $tabindex_for_null +6000 * @param integer $idindex id index * @param array $vkey [multi_edit]['row_id'] - * @param array $foreigners keys into foreign fields - * @param array $foreignData data about the foreign keys - * + * @param array $foreigners keys into foreign fields + * @param array $foreignData data about the foreign keys + * * @return string an html snippet */ function PMA_getNullColumn($column, $column_name_appendix, $real_null_value, @@ -498,11 +498,11 @@ function PMA_getNullColumn($column, $column_name_appendix, $real_null_value, /** * Retrieve the nullify code for the null column - * + * * @param array $column description of column in given table - * @param array $foreigners keys into foreign fields + * @param array $foreigners keys into foreign fields * @param array $foreignData data about the foreign keys - * + * * @return integer $nullify_code */ function PMA_getNullifyCodeForNullColumn($column, $foreigners, $foreignData) @@ -529,7 +529,7 @@ function PMA_getNullifyCodeForNullColumn($column, $foreigners, $foreignData) /** * Get the HTML elements for value column in inert form - * + * * @param array $column description of column in given table * @param string $backup_field hidden input field * @param string $column_name_appendix the name atttibute @@ -544,16 +544,16 @@ function PMA_getNullifyCodeForNullColumn($column, $foreigners, $foreignData) * @param array $rownumber_param &rownumber=row_id * @param array $titles An HTML IMG tag for a particular icon from a theme, * which may be an actual file or an icon from a sprite - * @param array $text_dir + * @param array $text_dir * @param string $special_chars_encoded replaced char if the string starts - * with a \r\n pair (0x0d0a) add an extra \n + * with a \r\n pair (0x0d0a) add an extra \n * @param integer $biggest_max_file_size 0 intger * @param string $default_char_editing default char editing mode which is stroe * in the config.inc.php script * @param array $no_support_types list of datatypes that are not (yet) handled by PMA * @param array $gis_data_types list of GIS data types - * - * @return string an html snippet + * + * @return string an html snippet */ function PMA_getValueColumn($column, $backup_field, $column_name_appendix, $unnullify_trigger,$tabindex, $tabindex_for_value, $idindex, $data, @@ -562,18 +562,18 @@ function PMA_getValueColumn($column, $backup_field, $column_name_appendix, $default_char_editing, $no_support_types, $gis_data_types, $extracted_columnspec ) { $html_output = ''; - + if ($foreignData['foreign_link'] == true) { $html_output .= PMA_getForeignLink($column, $backup_field, $column_name_appendix, $unnullify_trigger, $tabindex, $tabindex_for_value, $idindex, $data, $paramTableDbArray, $rownumber_param, $titles ); - + } elseif (is_array($foreignData['disp_row'])) { $html_output .= PMA_dispRowForeignData($backup_field, $column_name_appendix, $unnullify_trigger, $tabindex, $tabindex_for_value, $idindex, $data, $foreignData ); - + } elseif ($GLOBALS['cfg']['LongtextDoubleTextarea'] && strstr($column['pma_type'], 'longtext')) { $html_output = ' '; $html_output .= ''; @@ -582,7 +582,7 @@ function PMA_getValueColumn($column, $backup_field, $column_name_appendix, $html_output .= PMA_getTextarea($column,$backup_field, $column_name_appendix, $unnullify_trigger, $tabindex, $tabindex_for_value, $idindex, $text_dir, $special_chars_encoded ); - + } elseif (strstr($column['pma_type'], 'text')) { $html_output .= PMA_getTextarea($column,$backup_field, $column_name_appendix, $unnullify_trigger, $tabindex, $tabindex_for_value, $idindex, $text_dir, $special_chars_encoded @@ -592,35 +592,35 @@ function PMA_getValueColumn($column, $backup_field, $column_name_appendix, $html_output .= " \n"; $html_output .= ' ' . __('Because of its length,
this column might not be editable'); } - + } elseif ($column['pma_type'] == 'enum') { $html_output .= PMA_getPmaTypeEnum($paramsArrayForColumns, $column,$extracted_columnspec); - + } elseif ($column['pma_type'] == 'set') { $html_output .= PMA_getPmaTypeSet($column,$extracted_columnspec, $backup_field, $column_name_appendix, $unnullify_trigger, $tabindex, $tabindex_for_value, $idindex); - + } elseif ($column['is_binary'] || $column['is_blob']) { $html_output .= PMA_getBinaryAndBlobColumn($column, $data, $special_chars,$biggest_max_file_size, $backup_field,$column_name_appendix, $unnullify_trigger, $tabindex, $tabindex_for_value, $idindex, $text_dir, $special_chars_encoded, $vkey, $is_upload); - + } elseif (! in_array($column['pma_type'], $no_support_types)) { $html_output .= PMA_getNoSupportTypes($column, $default_char_editing,$backup_field, $column_name_appendix, $unnullify_trigger,$tabindex,$special_chars, - $tabindex_for_value, $idindex, $text_dir, $special_chars_encoded, $data, $extracted_columnspec); + $tabindex_for_value, $idindex, $text_dir, $special_chars_encoded, $data, $extracted_columnspec); } - + if (in_array($column['pma_type'], $gis_data_types)) { $html_output .= PMA_getHTMLforGisDataTypes($current_row, $column); } - + return $html_output; } /** * Get HTML for foreign link in insert form - * + * * @param array $column description of column in given table * @param string $backup_field hidden input field * @param string $column_name_appendix the name atttibute @@ -633,7 +633,7 @@ function PMA_getValueColumn($column, $backup_field, $column_name_appendix, * @param array $rownumber_param &rownumber=row_id * @param array $titles An HTML IMG tag for a particular icon from a theme, * which may be an actual file or an icon from a sprite - * + * * @return string an html snippet */ function PMA_getForeignLink($column, $backup_field, $column_name_appendix, @@ -659,7 +659,7 @@ function PMA_getForeignLink($column, $backup_field, $column_name_appendix, /** * Get HTML to display foreign data - * + * * @param string $backup_field hidden input field * @param string $column_name_appendix the name atttibute * @param string $unnullify_trigger validation string @@ -668,7 +668,7 @@ function PMA_getForeignLink($column, $backup_field, $column_name_appendix, * @param integer $idindex id index * @param array $data * @param array $foreignData data about the foreign keys - * + * * @return string an html snippet */ function PMA_dispRowForeignData($backup_field, $column_name_appendix, @@ -684,13 +684,13 @@ function PMA_dispRowForeignData($backup_field, $column_name_appendix, . PMA_foreignDropdown($foreignData['disp_row'], $foreignData['foreign_field'], $foreignData['foreign_display'], $data, $GLOBALS['cfg']['ForeignKeyMaxLimit']) . ''; - + return $html_output; } /** * Get HTML textarea for insert form - * + * * @param string $backup_field hidden input field * @param string $column_name_appendix the name atttibute * @param string $unnullify_trigger validation string @@ -700,7 +700,7 @@ function PMA_dispRowForeignData($backup_field, $column_name_appendix, * @param array $text_dir * @param array $special_chars_encoded replaced char if the string starts * with a \r\n pair (0x0d0a) add an extra \n - * + * * @return string an html snippet */ function PMA_getTextarea($column, $backup_field, $column_name_appendix, $unnullify_trigger, @@ -709,12 +709,12 @@ function PMA_getTextarea($column, $backup_field, $column_name_appendix, $unnulli $the_class = ''; $textAreaRows = $GLOBALS['cfg']['TextareaRows']; $textareaCols = $GLOBALS['cfg']['TextareaCols']; - - if($column['is_char']) { + + if ($column['is_char']) { $the_class = 'char'; $textAreaRows = $GLOBALS['cfg']['CharTextareaRows']; $textareaCols = $GLOBALS['cfg']['CharTextareaCols']; - } elseif(($GLOBALS['cfg']['LongtextDoubleTextarea'] && strstr($column['pma_type'], 'longtext'))) { + } elseif (($GLOBALS['cfg']['LongtextDoubleTextarea'] && strstr($column['pma_type'], 'longtext'))) { $textAreaRows = $GLOBALS['cfg']['TextareaRows']*2; $textareaCols = $GLOBALS['cfg']['TextareaCols']*2; } @@ -729,26 +729,26 @@ function PMA_getTextarea($column, $backup_field, $column_name_appendix, $unnulli . 'tabindex="' . ($tabindex + $tabindex_for_value) . '">' . $special_chars_encoded . ''; - + return $html_output; } /** * Get HTML for enum type - * + * * @param array $column description of column in given table * @param string $backup_field hidden input field * @param string $column_name_appendix the name atttibute * @param array $extracted_columnspec associative array containing type, spec_in_brackets * and possibly enum_set_values (another array) - * + * * @return string an html snippet */ function PMA_getPmaTypeEnum($column, $backup_field, $column_name_appendix, $extracted_columnspec) { - $html_output = ''; + $html_output = ''; if (! isset($column['values'])) { - $column['values'] = PMA_getColumnEnumValues($column, $extracted_columnspec); + $column['values'] = PMA_getColumnEnumValues($column, $extracted_columnspec); } $column_enum_values = $column['values']; $html_output .= ''; @@ -768,11 +768,11 @@ function PMA_getPmaTypeEnum($column, $backup_field, $column_name_appendix, $extr /** * Get column values - * + * * @param array $column description of column in given table * @param array $extracted_columnspec associative array containing type, spec_in_brackets * and possibly enum_set_values (another array) - * + * * @return array column values as an associative array */ function PMA_getColumnEnumValues($column, $extracted_columnspec) @@ -791,7 +791,7 @@ function PMA_getColumnEnumValues($column, $extracted_columnspec) /** * Get HTML drop down for more than 20 string length - * + * * @param array $column description of column in given table * @param string $column_name_appendix the name atttibute * @param string $unnullify_trigger validation string @@ -800,7 +800,7 @@ function PMA_getColumnEnumValues($column, $extracted_columnspec) * @param integer $idindex id index * @param array $data * @param array $column_enum_values $column['values'] - * + * * @return string an html snippet */ function PMA_getDropDownDependingOnLength($column, $column_name_appendix, $unnullify_trigger, @@ -812,7 +812,7 @@ function PMA_getDropDownDependingOnLength($column, $column_name_appendix, $unnul . 'tabindex="' . ($tabindex + $tabindex_for_value) . '"' . 'id="field_' . ($idindex) . '_3">' . '' . "\n"; - + foreach ($column_enum_values as $enum_value) { $html_output .= ' '; $html_output .= '' . ''; - + if (isset($where_clause)) { $html_output .= ''; - + // If we have just numeric primary key, we can also edit next // in 2.8.2, we were looking for `field_name` = numeric_value //if (preg_match('@^[\s]*`[^`]*` = [0-9]+@', $where_clause)) { // in 2.9.0, we are looking for `table_name`.`field_name` = numeric_value $is_numeric = false; - for($i = 0; $i < count($where_clause); $i++) { + for ($i = 0; $i < count($where_clause); $i++) { $is_numeric = preg_match('@^[\s]*`[^`]*`[\.]`[^`]*` = [0-9]+@', $where_clause[$i]); if ($is_numeric == true) { break; @@ -1346,20 +1346,20 @@ function PMA_getAfterInsertDropDown($where_clause, $after_insert, $found_unique_ if ($found_unique_key && $is_numeric) { $html_output .= ''; - + } } $html_output .= ''; return $html_output; - + } /** * get Submit button and Reset button for action panel - * + * * @param integer $tabindex tab index * @param integer $tabindex_for_value offset for the values tabindex - * + * * @return string an html snippet */ function PMA_getSumbitAndResetButtonForActionsPanel($tabindex, $tabindex_for_value) @@ -1377,9 +1377,9 @@ function PMA_getSumbitAndResetButtonForActionsPanel($tabindex, $tabindex_for_val /** * Get table head and table foot for insert row table - * + * * @param array $url_params url parameters - * + * * @return string an html snippet */ function PMA_getHeadAndFootOfInsertRowTable($url_params) @@ -1388,14 +1388,14 @@ function PMA_getHeadAndFootOfInsertRowTable($url_params) . '' . '' . '' . __('Column') . ''; - + if ($GLOBALS['cfg']['ShowFieldTypesInDataEditView']) { $html_output .= PMA_showColumnTypesInDataEditView($url_params, true); } if ($GLOBALS['cfg']['ShowFunctionFields']) { $html_output .= PMA_showFunctionFieldsInEditMode($url_params, true); } - + $html_output .= ''. __('Null') . '' . '' . __('Value') . '' . '' @@ -1412,14 +1412,14 @@ function PMA_getHeadAndFootOfInsertRowTable($url_params) /** * Prepares the field value and retrieve special chars, backup field and data array - * + * * @param array $current_row a row of the table * @param array $column description of column in given table * @param array $extracted_columnspec associative array containing type, spec_in_brackets * and possibly enum_set_values (another array) * @param boolean $real_null_value whether column value null or not null - * - * @return array $real_null_value, $data, $special_chars, $backup_field, $special_chars_encoded + * + * @return array $real_null_value, $data, $special_chars, $backup_field, $special_chars_encoded */ function PMA_getSpecialCharsAndBackupFieldForExistingRow($current_row, $column, $extracted_columnspec, $real_null_value, $gis_data_types, $column_name_appendix) @@ -1471,16 +1471,16 @@ function PMA_getSpecialCharsAndBackupFieldForExistingRow($current_row, $column, $backup_field = ''; - + return array($real_null_value, $special_chars_encoded, $special_chars, $data, $backup_field); } /** * display default values - * + * * @param type $column description of column in given table * @param boolean $real_null_value whether column value null or not null - * + * * @return array $real_null_value, $data, $special_chars, $backup_field, $special_chars_encoded */ function PMA_getSpecialCharsAndBackupFieldForInsertingMode($column, $real_null_value) @@ -1513,7 +1513,7 @@ function PMA_getSpecialCharsAndBackupFieldForInsertingMode($column, $real_null_v /** * Prepares the update/insert of a row - * + * * @return array $loop_array, $using_key, $is_insert, $is_insertignore */ function PMA_getParamsForUpdateOrInsert() @@ -1541,7 +1541,7 @@ function PMA_getParamsForUpdateOrInsert() /** * check wether insert row mode and if so include tbl_changen script and set global variables. - * + * * @return void */ function PMA_isInsertRow() @@ -1560,9 +1560,9 @@ function PMA_isInsertRow() /** * set $_SESSION for edit_next - * + * * @param string $one_where_clause one where clause from where clauses array - * + * * @return void */ function PMA_setSessionForEditNext($one_where_clause) @@ -1587,7 +1587,7 @@ function PMA_setSessionForEditNext($one_where_clause) * set $goto_include varible for different cases and retrieve like, * if $GLOBALS['goto'] empty, if $goto_include previously not defined * and new_insert, same_insert, same_insert - * + * * @param string $goto_include store some script for include, otherwise it is boolean false * @return string $goto_include */ @@ -1621,7 +1621,7 @@ function PMA_getGotoInclude($goto_include) /** * Defines the url to return in case of failure of the query - * + * * @param array $url_params url parameters * @return string error url for query failure */ @@ -1636,9 +1636,9 @@ function PMA_getErrorUrl($url_params) /** * Builds the sql query - * + * * @param boolean $is_insertignore $_REQUEST['submit_type'] == 'insertignore' - * @param array $query_fields column names array + * @param array $query_fields column names array * @param array $value_sets array of query values * @return string a query */ @@ -1657,7 +1657,7 @@ function PMA_buildSqlQuery($is_insertignore, $query_fields, $value_sets) /** * Executes the sql query and get the result, then move back to the calling page - * + * * @param array $url_params url paramters array * @param string $query built query from PMA_buildSqlQuery() * @return array $url_params, $total_affected_rows, $last_messages @@ -1673,12 +1673,12 @@ function PMA_executeSqlQuery($url_params, $query) // to ensure that the query is displayed in case of // "insert as new row" and then "insert another new row" $GLOBALS['display_query'] = $GLOBALS['sql_query']; - + $total_affected_rows = 0; $last_messages = array(); $warning_messages = array(); $error_messages = array(); - + foreach ($query as $single_query) { if ($_REQUEST['submit_type'] == 'showinsert') { $last_messages[] = PMA_Message::notice(__('Showing SQL query')); @@ -1720,7 +1720,7 @@ function PMA_executeSqlQuery($url_params, $query) /** * get the warning messages array - * + * * @return array $warning_essages */ function PMA_getWarningMessages() From 962c523a155cfd4385ae228cb724f2d0ed6ff40e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 29 May 2012 14:02:40 +0200 Subject: [PATCH 02/11] Fix phpdoc formatting --- libraries/sqlparser.lib.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/sqlparser.lib.php b/libraries/sqlparser.lib.php index 790911c080..09caf7ecc4 100644 --- a/libraries/sqlparser.lib.php +++ b/libraries/sqlparser.lib.php @@ -2705,9 +2705,9 @@ if (! defined('PMA_MINIMUM_COMMON')) { /** * Builds a CSS rule used for html formatted SQL queries * - * @param string The class name - * @param string The property name - * @param string The property value + * @param string $classname The class name + * @param string $property The property name + * @param string $value The property value * * @return string The CSS rule * @@ -2761,7 +2761,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { /** * Gets SQL queries with no format * - * @param array The SQL queries list + * @param array $arr The SQL queries list * * @return string The SQL queries with no format * From e316c37598ad42e40c8115d8f43c79b90f752a04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 29 May 2012 14:06:10 +0200 Subject: [PATCH 03/11] Move query parser CSS generating to theme --- libraries/Theme.class.php | 57 ++++++++++++++++++++++++++++++++++++- libraries/sqlparser.lib.php | 55 ----------------------------------- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/libraries/Theme.class.php b/libraries/Theme.class.php index 0783712e23..ef54a2f142 100644 --- a/libraries/Theme.class.php +++ b/libraries/Theme.class.php @@ -310,6 +310,61 @@ class PMA_Theme return $this->img_path; } + /** + * Builds a CSS rule used for html formatted SQL queries + * + * @param string $classname The class name + * @param string $property The property name + * @param string $value The property value + * + * @return string The CSS rule + * + * @access public + * + * @see PMA_SQP_buildCssData() + */ + public function SQP_buildCssRule($classname, $property, $value) + { + $str = '.' . $classname . ' {'; + if ($value != '') { + $str .= $property . ': ' . $value . ';'; + } + $str .= '}' . "\n"; + + return $str; + } // end of the "PMA_SQP_buildCssRule()" function + + + /** + * Builds CSS rules used for html formatted SQL queries + * + * @return string The CSS rules set + * + * @access public + * + * @global array The current PMA configuration + * + * @see PMA_SQP_buildCssRule() + */ + public function SQP_buildCssData() + { + global $cfg; + + $css_string = ''; + foreach ($cfg['SQP']['fmtColor'] AS $key => $col) { + $css_string .= $this->SQP_buildCssRule('syntax_' . $key, 'color', $col); + } + + for ($i = 0; $i < 8; $i++) { + $css_string .= $this->SQP_buildCssRule( + 'syntax_indent' . $i, 'margin-left', + ($i * $cfg['SQP']['fmtInd']) . $cfg['SQP']['fmtIndUnit'] + ); + } + + return $css_string; + } // end of the "PMA_SQP_buildCssData()" function + /** * load css (send to stdout, normally the browser) * @@ -320,7 +375,7 @@ class PMA_Theme { $success = true; - echo PMA_SQP_buildCssData(); + echo $this->SQP_buildCssData(); if ($GLOBALS['text_dir'] === 'ltr') { $right = 'right'; diff --git a/libraries/sqlparser.lib.php b/libraries/sqlparser.lib.php index 09caf7ecc4..d1c4c9137d 100644 --- a/libraries/sqlparser.lib.php +++ b/libraries/sqlparser.lib.php @@ -2702,61 +2702,6 @@ if (! defined('PMA_MINIMUM_COMMON')) { } // end of the "PMA_SQP_formatHtml()" function } -/** - * Builds a CSS rule used for html formatted SQL queries - * - * @param string $classname The class name - * @param string $property The property name - * @param string $value The property value - * - * @return string The CSS rule - * - * @access public - * - * @see PMA_SQP_buildCssData() - */ -function PMA_SQP_buildCssRule($classname, $property, $value) -{ - $str = '.' . $classname . ' {'; - if ($value != '') { - $str .= $property . ': ' . $value . ';'; - } - $str .= '}' . "\n"; - - return $str; -} // end of the "PMA_SQP_buildCssRule()" function - - -/** - * Builds CSS rules used for html formatted SQL queries - * - * @return string The CSS rules set - * - * @access public - * - * @global array The current PMA configuration - * - * @see PMA_SQP_buildCssRule() - */ -function PMA_SQP_buildCssData() -{ - global $cfg; - - $css_string = ''; - foreach ($cfg['SQP']['fmtColor'] AS $key => $col) { - $css_string .= PMA_SQP_buildCssRule('syntax_' . $key, 'color', $col); - } - - for ($i = 0; $i < 8; $i++) { - $css_string .= PMA_SQP_buildCssRule( - 'syntax_indent' . $i, 'margin-left', - ($i * $cfg['SQP']['fmtInd']) . $cfg['SQP']['fmtIndUnit'] - ); - } - - return $css_string; -} // end of the "PMA_SQP_buildCssData()" function - if (! defined('PMA_MINIMUM_COMMON')) { /** * Gets SQL queries with no format From d248c5ed1c22d374a7a028255217ef367d88d240 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 29 May 2012 14:06:49 +0200 Subject: [PATCH 04/11] SQL parser no longer needs to be included for generating CSS --- phpmyadmin.css.php | 1 - 1 file changed, 1 deletion(-) diff --git a/phpmyadmin.css.php b/phpmyadmin.css.php index 8158ec184e..bfe4d47e03 100644 --- a/phpmyadmin.css.php +++ b/phpmyadmin.css.php @@ -11,7 +11,6 @@ define('PMA_MINIMUM_COMMON', true); require_once 'libraries/common.inc.php'; -require_once 'libraries/sqlparser.lib.php'; // MSIE 6 (at least some unpatched versions) has problems loading CSS // when zlib_compression is on From c315d3351335c02bda79d51b6c317084d969a75c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 29 May 2012 14:07:49 +0200 Subject: [PATCH 05/11] SQL parser is now loaded only without PMA_MINIMUM_COMMON defined --- libraries/sqlparser.lib.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/libraries/sqlparser.lib.php b/libraries/sqlparser.lib.php index d1c4c9137d..92809dc4fc 100644 --- a/libraries/sqlparser.lib.php +++ b/libraries/sqlparser.lib.php @@ -30,10 +30,6 @@ if (! defined('PHPMYADMIN')) { exit; } -/** - * Minimum inclusion? (i.e. for the stylesheet builder) - */ -if (! defined('PMA_MINIMUM_COMMON')) { /** * Include the string library as we use it heavily */ @@ -2700,9 +2696,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { return $str; } // end of the "PMA_SQP_formatHtml()" function -} -if (! defined('PMA_MINIMUM_COMMON')) { /** * Gets SQL queries with no format * @@ -2724,6 +2718,4 @@ if (! defined('PMA_MINIMUM_COMMON')) { return $formatted_sql; } // end of the "PMA_SQP_formatNone()" function -} // end if: minimal common.lib needed? - ?> From ec541309eb118b84848992abb39f2562c0e846db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 29 May 2012 14:08:07 +0200 Subject: [PATCH 06/11] Fix indentation after if() removal --- libraries/sqlparser.lib.php | 5130 +++++++++++++++++------------------ 1 file changed, 2565 insertions(+), 2565 deletions(-) diff --git a/libraries/sqlparser.lib.php b/libraries/sqlparser.lib.php index 92809dc4fc..d7eaef12b2 100644 --- a/libraries/sqlparser.lib.php +++ b/libraries/sqlparser.lib.php @@ -30,2692 +30,2692 @@ if (! defined('PHPMYADMIN')) { exit; } - /** - * Include the string library as we use it heavily - */ - include_once './libraries/string.lib.php'; +/** + * Include the string library as we use it heavily + */ +include_once './libraries/string.lib.php'; +/** + * Include data for the SQL Parser + */ +include_once './libraries/sqlparser.data.php'; +if (!defined('TESTSUITE')) { + include_once './libraries/mysql_charsets.lib.php'; +} +if (! isset($mysql_charsets)) { + $mysql_charsets = array(); + $mysql_collations_flat = array(); +} + +if (!defined('DEBUG_TIMING')) { /** - * Include data for the SQL Parser + * currently we don't need the $pos (token position in query) + * for other purposes than LIMIT clause verification, + * so many calls to this function do not include the 4th parameter */ - include_once './libraries/sqlparser.data.php'; - if (!defined('TESTSUITE')) { - include_once './libraries/mysql_charsets.lib.php'; + function PMA_SQP_arrayAdd(&$arr, $type, $data, &$arrsize, $pos = 0) + { + $arr[] = array('type' => $type, 'data' => $data, 'pos' => $pos); + $arrsize++; + } // end of the "PMA_SQP_arrayAdd()" function +} else { + /** + * This is debug variant of above. + * @ignore + */ + function PMA_SQP_arrayAdd(&$arr, $type, $data, &$arrsize, $pos = 0) + { + global $timer; + + $t = $timer; + $arr[] = array( + 'type' => $type, + 'data' => $data, + 'pos' => $pos, + 'time' => $t); + $timer = microtime(); + $arrsize++; + } // end of the "PMA_SQP_arrayAdd()" function +} // end if... else... + + +/** + * Reset the error variable for the SQL parser + * + * @access public + */ +function PMA_SQP_resetError() +{ + global $SQP_errorString; + $SQP_errorString = ''; + unset($SQP_errorString); +} + +/** + * Get the contents of the error variable for the SQL parser + * + * @return string Error string from SQL parser + * + * @access public + */ +function PMA_SQP_getErrorString() +{ + global $SQP_errorString; + return isset($SQP_errorString) ? $SQP_errorString : ''; +} + +/** + * Check if the SQL parser hit an error + * + * @return boolean error state + * + * @access public + */ +function PMA_SQP_isError() +{ + global $SQP_errorString; + return isset($SQP_errorString) && !empty($SQP_errorString); +} + +/** + * Set an error message for the system + * + * @param string The error message + * @param string The failing SQL query + * + * @access private + * @scope SQL Parser internal + */ +function PMA_SQP_throwError($message, $sql) +{ + global $SQP_errorString; + $SQP_errorString = '

'.__('There seems to be an error in your SQL query. The MySQL server error output below, if there is any, may also help you in diagnosing the problem') . '

' . "\n" + . '
' . "\n"
+        . 'ERROR: ' . $message . "\n"
+        . 'SQL: ' . htmlspecialchars($sql) .  "\n"
+        . '
' . "\n"; + +} // end of the "PMA_SQP_throwError()" function + + +/** + * Do display the bug report + * + * @param string The error message + * @param string The failing SQL query + * + * @access public + */ +function PMA_SQP_bug($message, $sql) +{ + global $SQP_errorString; + $debugstr = 'ERROR: ' . $message . "\n"; + $debugstr .= 'MySQL: '.PMA_MYSQL_STR_VERSION . "\n"; + $debugstr .= 'USR OS, AGENT, VER: ' . PMA_USR_OS . ' '; + $debugstr .= PMA_USR_BROWSER_AGENT . ' ' . PMA_USR_BROWSER_VER . "\n"; + $debugstr .= 'PMA: ' . PMA_VERSION . "\n"; + $debugstr .= 'PHP VER,OS: ' . PMA_PHP_STR_VERSION . ' ' . PHP_OS . "\n"; + $debugstr .= 'LANG: ' . $GLOBALS['lang'] . "\n"; + $debugstr .= 'SQL: ' . htmlspecialchars($sql); + + $encodedstr = $debugstr; + if (@function_exists('gzcompress')) { + $encodedstr = gzcompress($debugstr, 9); } - if (! isset($mysql_charsets)) { - $mysql_charsets = array(); - $mysql_collations_flat = array(); + $encodedstr = preg_replace( + "/(\015\012)|(\015)|(\012)/", + '
' . "\n", + chunk_split(base64_encode($encodedstr)) + ); + + + $SQP_errorString .= __('There is a chance that you may have found a bug in the SQL parser. Please examine your query closely, and check that the quotes are correct and not mis-matched. Other possible failure causes may be that you are uploading a file with binary outside of a quoted text area. You can also try your query on the MySQL command line interface. The MySQL server error output below, if there is any, may also help you in diagnosing the problem. If you still have problems or if the parser fails where the command line interface succeeds, please reduce your SQL query input to the single query that causes problems, and submit a bug report with the data chunk in the CUT section below:') + . '
' . "\n" + . '----' . __('BEGIN CUT') . '----' . '
' . "\n" + . $encodedstr . "\n" + . '----' . __('END CUT') . '----' . '
' . "\n"; + + $SQP_errorString .= '----' . __('BEGIN RAW') . '----
' . "\n" + . '
' . "\n"
+         . $debugstr
+         . '
' . "\n" + . '----' . __('END RAW') . '----
' . "\n"; + +} // end of the "PMA_SQP_bug()" function + + +/** + * Parses the SQL queries + * + * @param string The SQL query list + * + * @return mixed Most of times, nothing... + * + * @global array The current PMA configuration + * @global array MySQL column attributes + * @global array MySQL reserved words + * @global array MySQL column types + * @global array MySQL function names + * @global array List of available character sets + * @global array List of available collations + * + * @access public + */ +function PMA_SQP_parse($sql) +{ + static $PMA_SQPdata_column_attrib, $PMA_SQPdata_reserved_word; + static $PMA_SQPdata_column_type; + static $PMA_SQPdata_function_name, $PMA_SQPdata_forbidden_word; + global $mysql_charsets, $mysql_collations_flat; + + // Convert all line feeds to Unix style + $sql = str_replace("\r\n", "\n", $sql); + $sql = str_replace("\r", "\n", $sql); + + $len = PMA_strlen($sql); + if ($len == 0) { + return array(); } - if (!defined('DEBUG_TIMING')) { - /** - * currently we don't need the $pos (token position in query) - * for other purposes than LIMIT clause verification, - * so many calls to this function do not include the 4th parameter - */ - function PMA_SQP_arrayAdd(&$arr, $type, $data, &$arrsize, $pos = 0) - { - $arr[] = array('type' => $type, 'data' => $data, 'pos' => $pos); - $arrsize++; - } // end of the "PMA_SQP_arrayAdd()" function - } else { - /** - * This is debug variant of above. - * @ignore - */ - function PMA_SQP_arrayAdd(&$arr, $type, $data, &$arrsize, $pos = 0) - { - global $timer; - - $t = $timer; - $arr[] = array( - 'type' => $type, - 'data' => $data, - 'pos' => $pos, - 'time' => $t); - $timer = microtime(); - $arrsize++; - } // end of the "PMA_SQP_arrayAdd()" function - } // end if... else... - - - /** - * Reset the error variable for the SQL parser - * - * @access public - */ - function PMA_SQP_resetError() - { - global $SQP_errorString; - $SQP_errorString = ''; - unset($SQP_errorString); - } - - /** - * Get the contents of the error variable for the SQL parser - * - * @return string Error string from SQL parser - * - * @access public - */ - function PMA_SQP_getErrorString() - { - global $SQP_errorString; - return isset($SQP_errorString) ? $SQP_errorString : ''; - } - - /** - * Check if the SQL parser hit an error - * - * @return boolean error state - * - * @access public - */ - function PMA_SQP_isError() - { - global $SQP_errorString; - return isset($SQP_errorString) && !empty($SQP_errorString); - } - - /** - * Set an error message for the system - * - * @param string The error message - * @param string The failing SQL query - * - * @access private - * @scope SQL Parser internal - */ - function PMA_SQP_throwError($message, $sql) - { - global $SQP_errorString; - $SQP_errorString = '

'.__('There seems to be an error in your SQL query. The MySQL server error output below, if there is any, may also help you in diagnosing the problem') . '

' . "\n" - . '
' . "\n"
-            . 'ERROR: ' . $message . "\n"
-            . 'SQL: ' . htmlspecialchars($sql) .  "\n"
-            . '
' . "\n"; - - } // end of the "PMA_SQP_throwError()" function - - - /** - * Do display the bug report - * - * @param string The error message - * @param string The failing SQL query - * - * @access public - */ - function PMA_SQP_bug($message, $sql) - { - global $SQP_errorString; - $debugstr = 'ERROR: ' . $message . "\n"; - $debugstr .= 'MySQL: '.PMA_MYSQL_STR_VERSION . "\n"; - $debugstr .= 'USR OS, AGENT, VER: ' . PMA_USR_OS . ' '; - $debugstr .= PMA_USR_BROWSER_AGENT . ' ' . PMA_USR_BROWSER_VER . "\n"; - $debugstr .= 'PMA: ' . PMA_VERSION . "\n"; - $debugstr .= 'PHP VER,OS: ' . PMA_PHP_STR_VERSION . ' ' . PHP_OS . "\n"; - $debugstr .= 'LANG: ' . $GLOBALS['lang'] . "\n"; - $debugstr .= 'SQL: ' . htmlspecialchars($sql); - - $encodedstr = $debugstr; - if (@function_exists('gzcompress')) { - $encodedstr = gzcompress($debugstr, 9); - } - $encodedstr = preg_replace( - "/(\015\012)|(\015)|(\012)/", - '
' . "\n", - chunk_split(base64_encode($encodedstr)) + // Create local hashtables + if (!isset($PMA_SQPdata_column_attrib)) { + $PMA_SQPdata_column_attrib = array_flip( + $GLOBALS['PMA_SQPdata_column_attrib'] ); - - - $SQP_errorString .= __('There is a chance that you may have found a bug in the SQL parser. Please examine your query closely, and check that the quotes are correct and not mis-matched. Other possible failure causes may be that you are uploading a file with binary outside of a quoted text area. You can also try your query on the MySQL command line interface. The MySQL server error output below, if there is any, may also help you in diagnosing the problem. If you still have problems or if the parser fails where the command line interface succeeds, please reduce your SQL query input to the single query that causes problems, and submit a bug report with the data chunk in the CUT section below:') - . '
' . "\n" - . '----' . __('BEGIN CUT') . '----' . '
' . "\n" - . $encodedstr . "\n" - . '----' . __('END CUT') . '----' . '
' . "\n"; - - $SQP_errorString .= '----' . __('BEGIN RAW') . '----
' . "\n" - . '
' . "\n"
-             . $debugstr
-             . '
' . "\n" - . '----' . __('END RAW') . '----
' . "\n"; - - } // end of the "PMA_SQP_bug()" function - - - /** - * Parses the SQL queries - * - * @param string The SQL query list - * - * @return mixed Most of times, nothing... - * - * @global array The current PMA configuration - * @global array MySQL column attributes - * @global array MySQL reserved words - * @global array MySQL column types - * @global array MySQL function names - * @global array List of available character sets - * @global array List of available collations - * - * @access public - */ - function PMA_SQP_parse($sql) - { - static $PMA_SQPdata_column_attrib, $PMA_SQPdata_reserved_word; - static $PMA_SQPdata_column_type; - static $PMA_SQPdata_function_name, $PMA_SQPdata_forbidden_word; - global $mysql_charsets, $mysql_collations_flat; - - // Convert all line feeds to Unix style - $sql = str_replace("\r\n", "\n", $sql); - $sql = str_replace("\r", "\n", $sql); - - $len = PMA_strlen($sql); - if ($len == 0) { - return array(); - } - - // Create local hashtables - if (!isset($PMA_SQPdata_column_attrib)) { - $PMA_SQPdata_column_attrib = array_flip( - $GLOBALS['PMA_SQPdata_column_attrib'] - ); - $PMA_SQPdata_function_name = array_flip( - $GLOBALS['PMA_SQPdata_function_name'] - ); - $PMA_SQPdata_reserved_word = array_flip( - $GLOBALS['PMA_SQPdata_reserved_word'] - ); - $PMA_SQPdata_forbidden_word = array_flip( - $GLOBALS['PMA_SQPdata_forbidden_word'] - ); - $PMA_SQPdata_column_type = array_flip( - $GLOBALS['PMA_SQPdata_column_type'] - ); - } - - $sql_array = array(); - $sql_array['raw'] = $sql; - $count1 = 0; - $count2 = 0; - $punct_queryend = ';'; - $punct_qualifier = '.'; - $punct_listsep = ','; - $punct_level_plus = '('; - $punct_level_minus = ')'; - $punct_user = '@'; - $digit_floatdecimal = '.'; - $digit_hexset = 'x'; - $bracket_list = '()[]{}'; - $allpunct_list = '-,;:!?/.^~\*&%+<=>|'; - $allpunct_list_pair = array( - '!=' => 1, - '&&' => 1, - ':=' => 1, - '<<' => 1, - '<=' => 1, - '<=>' => 1, - '<>' => 1, - '>=' => 1, - '>>' => 1, - '||' => 1, - '==' => 1 + $PMA_SQPdata_function_name = array_flip( + $GLOBALS['PMA_SQPdata_function_name'] ); - $quote_list = '\'"`'; - $arraysize = 0; + $PMA_SQPdata_reserved_word = array_flip( + $GLOBALS['PMA_SQPdata_reserved_word'] + ); + $PMA_SQPdata_forbidden_word = array_flip( + $GLOBALS['PMA_SQPdata_forbidden_word'] + ); + $PMA_SQPdata_column_type = array_flip( + $GLOBALS['PMA_SQPdata_column_type'] + ); + } - $previous_was_space = false; - $this_was_space = false; - $previous_was_bracket = false; - $this_was_bracket = false; - $previous_was_punct = false; - $this_was_punct = false; - $previous_was_listsep = false; - $this_was_listsep = false; - $previous_was_quote = false; - $this_was_quote = false; + $sql_array = array(); + $sql_array['raw'] = $sql; + $count1 = 0; + $count2 = 0; + $punct_queryend = ';'; + $punct_qualifier = '.'; + $punct_listsep = ','; + $punct_level_plus = '('; + $punct_level_minus = ')'; + $punct_user = '@'; + $digit_floatdecimal = '.'; + $digit_hexset = 'x'; + $bracket_list = '()[]{}'; + $allpunct_list = '-,;:!?/.^~\*&%+<=>|'; + $allpunct_list_pair = array( + '!=' => 1, + '&&' => 1, + ':=' => 1, + '<<' => 1, + '<=' => 1, + '<=>' => 1, + '<>' => 1, + '>=' => 1, + '>>' => 1, + '||' => 1, + '==' => 1 + ); + $quote_list = '\'"`'; + $arraysize = 0; - while ($count2 < $len) { - $c = PMA_substr($sql, $count2, 1); - $count1 = $count2; + $previous_was_space = false; + $this_was_space = false; + $previous_was_bracket = false; + $this_was_bracket = false; + $previous_was_punct = false; + $this_was_punct = false; + $previous_was_listsep = false; + $this_was_listsep = false; + $previous_was_quote = false; + $this_was_quote = false; - $previous_was_space = $this_was_space; - $this_was_space = false; - $previous_was_bracket = $this_was_bracket; - $this_was_bracket = false; - $previous_was_punct = $this_was_punct; - $this_was_punct = false; - $previous_was_listsep = $this_was_listsep; - $this_was_listsep = false; - $previous_was_quote = $this_was_quote; - $this_was_quote = false; + while ($count2 < $len) { + $c = PMA_substr($sql, $count2, 1); + $count1 = $count2; - if (($c == "\n")) { - $this_was_space = true; - $count2++; - PMA_SQP_arrayAdd($sql_array, 'white_newline', '', $arraysize); - continue; - } + $previous_was_space = $this_was_space; + $this_was_space = false; + $previous_was_bracket = $this_was_bracket; + $this_was_bracket = false; + $previous_was_punct = $this_was_punct; + $this_was_punct = false; + $previous_was_listsep = $this_was_listsep; + $this_was_listsep = false; + $previous_was_quote = $this_was_quote; + $this_was_quote = false; - // Checks for white space - if (PMA_STR_isSpace($c)) { - $this_was_space = true; - $count2++; - continue; - } + if (($c == "\n")) { + $this_was_space = true; + $count2++; + PMA_SQP_arrayAdd($sql_array, 'white_newline', '', $arraysize); + continue; + } - // Checks for comment lines. - // MySQL style # - // C style /* */ - // ANSI style -- - $next_c = PMA_substr($sql, $count2 + 1, 1); - if (($c == '#') - || (($count2 + 1 < $len) && ($c == '/') && ($next_c == '*')) - || (($count2 + 2 == $len) && ($c == '-') && ($next_c == '-')) - || (($count2 + 2 < $len) && ($c == '-') && ($next_c == '-') && ((PMA_substr($sql, $count2 + 2, 1) <= ' '))) - ) { - $count2++; - $pos = 0; - $type = 'bad'; - switch ($c) { - case '#': - $type = 'mysql'; - case '-': - $type = 'ansi'; - $pos = PMA_strpos($sql, "\n", $count2); - break; - case '/': - $type = 'c'; - $pos = PMA_strpos($sql, '*/', $count2); - $pos += 2; - break; - default: - break; - } // end switch - $count2 = ($pos < $count2) ? $len : $pos; - $str = PMA_substr($sql, $count1, $count2 - $count1); - PMA_SQP_arrayAdd($sql_array, 'comment_' . $type, $str, $arraysize); - continue; - } // end if + // Checks for white space + if (PMA_STR_isSpace($c)) { + $this_was_space = true; + $count2++; + continue; + } - // Checks for something inside quotation marks - if (PMA_strpos($quote_list, $c) !== false) { - $startquotepos = $count2; - $quotetype = $c; - $count2++; - $escaped = false; - $pos = $count2; - $oldpos = 0; - do { - $oldpos = $pos; - $pos = PMA_strpos(' ' . $sql, $quotetype, $oldpos + 1) - 1; - // ($pos === false) - if ($pos < 0) { - if ($c == '`') { - /* - * Behave same as MySQL and accept end of query as end of backtick. - * I know this is sick, but MySQL behaves like this: - * - * SELECT * FROM `table - * - * is treated like - * - * SELECT * FROM `table` - */ - $pos_quote_separator = PMA_strpos(' ' . $sql, $GLOBALS['sql_delimiter'], $oldpos + 1) - 1; - if ($pos_quote_separator < 0) { - $len += 1; - $sql .= '`'; - $sql_array['raw'] .= '`'; - $pos = $len; - } else { - $len += 1; - $sql = PMA_substr($sql, 0, $pos_quote_separator) . '`' . PMA_substr($sql, $pos_quote_separator); - $sql_array['raw'] = $sql; - $pos = $pos_quote_separator; - } - if (class_exists('PMA_Message') && $GLOBALS['is_ajax_request'] != true) { - PMA_Message::notice(__('Automatically appended backtick to the end of query!'))->display(); - } - } else { - $debugstr = __('Unclosed quote') . ' @ ' . $startquotepos. "\n" - . 'STR: ' . htmlspecialchars($quotetype); - PMA_SQP_throwError($debugstr, $sql); - return $sql_array; - } - } + // Checks for comment lines. + // MySQL style # + // C style /* */ + // ANSI style -- + $next_c = PMA_substr($sql, $count2 + 1, 1); + if (($c == '#') + || (($count2 + 1 < $len) && ($c == '/') && ($next_c == '*')) + || (($count2 + 2 == $len) && ($c == '-') && ($next_c == '-')) + || (($count2 + 2 < $len) && ($c == '-') && ($next_c == '-') && ((PMA_substr($sql, $count2 + 2, 1) <= ' '))) + ) { + $count2++; + $pos = 0; + $type = 'bad'; + switch ($c) { + case '#': + $type = 'mysql'; + case '-': + $type = 'ansi'; + $pos = PMA_strpos($sql, "\n", $count2); + break; + case '/': + $type = 'c'; + $pos = PMA_strpos($sql, '*/', $count2); + $pos += 2; + break; + default: + break; + } // end switch + $count2 = ($pos < $count2) ? $len : $pos; + $str = PMA_substr($sql, $count1, $count2 - $count1); + PMA_SQP_arrayAdd($sql_array, 'comment_' . $type, $str, $arraysize); + continue; + } // end if - // If the quote is the first character, it can't be - // escaped, so don't do the rest of the code - if ($pos == 0) { - break; - } - - // Checks for MySQL escaping using a \ - // And checks for ANSI escaping using the $quotetype character - if (($pos < $len) && PMA_STR_charIsEscaped($sql, $pos) && $c != '`') { - $pos ++; - continue; - } elseif (($pos + 1 < $len) && (PMA_substr($sql, $pos, 1) == $quotetype) && (PMA_substr($sql, $pos + 1, 1) == $quotetype)) { - $pos = $pos + 2; - continue; - } else { - break; - } - } while ($len > $pos); // end do - - $count2 = $pos; - $count2++; - $type = 'quote_'; - switch ($quotetype) { - case '\'': - $type .= 'single'; - $this_was_quote = true; - break; - case '"': - $type .= 'double'; - $this_was_quote = true; - break; - case '`': - $type .= 'backtick'; - $this_was_quote = true; - break; - default: - break; - } // end switch - $data = PMA_substr($sql, $count1, $count2 - $count1); - PMA_SQP_arrayAdd($sql_array, $type, $data, $arraysize); - continue; - } - - // Checks for brackets - if (PMA_strpos($bracket_list, $c) !== false) { - // All bracket tokens are only one item long - $this_was_bracket = true; - $count2++; - $type_type = ''; - if (PMA_strpos('([{', $c) !== false) { - $type_type = 'open'; - } else { - $type_type = 'close'; - } - - $type_style = ''; - if (PMA_strpos('()', $c) !== false) { - $type_style = 'round'; - } elseif (PMA_strpos('[]', $c) !== false) { - $type_style = 'square'; - } else { - $type_style = 'curly'; - } - - $type = 'punct_bracket_' . $type_type . '_' . $type_style; - PMA_SQP_arrayAdd($sql_array, $type, $c, $arraysize); - continue; - } - - /* DEBUG - echo '
1';
-            var_dump(PMA_STR_isSqlIdentifier($c, false));
-            var_dump($c == '@');
-            var_dump($c == '.');
-            var_dump(PMA_STR_isDigit(PMA_substr($sql, $count2 + 1, 1)));
-            var_dump($previous_was_space);
-            var_dump($previous_was_bracket);
-            var_dump($previous_was_listsep);
-            echo '
'; - */ - - // Checks for identifier (alpha or numeric) - if (PMA_STR_isSqlIdentifier($c, false) - || $c == '@' - || ($c == '.' - && PMA_STR_isDigit(PMA_substr($sql, $count2 + 1, 1)) - && ($previous_was_space || $previous_was_bracket || $previous_was_listsep)) - ) { - /* DEBUG - echo PMA_substr($sql, $count2); - echo '
'; - */ - - $count2++; - - /** - * @todo a @ can also be present in expressions like - * FROM 'user'@'%' or TO 'user'@'%' - * in this case, the @ is wrongly marked as alpha_variable - */ - $is_identifier = $previous_was_punct; - $is_sql_variable = $c == '@' && ! $previous_was_quote; - $is_user = $c == '@' && $previous_was_quote; - $is_digit = !$is_identifier && !$is_sql_variable && PMA_STR_isDigit($c); - $is_hex_digit = $is_digit && $c == '0' && $count2 < $len && PMA_substr($sql, $count2, 1) == 'x'; - $is_float_digit = $c == '.'; - $is_float_digit_exponent = false; - - /* DEBUG - echo '
2';
-                var_dump($is_identifier);
-                var_dump($is_sql_variable);
-                var_dump($is_digit);
-                var_dump($is_float_digit);
-                echo '
'; - */ - - // Fast skip is especially needed for huge BLOB data - if ($is_hex_digit) { - $count2++; - $pos = strspn($sql, '0123456789abcdefABCDEF', $count2); - if ($pos > $count2) { - $count2 = $pos; - } - unset($pos); - } elseif ($is_digit) { - $pos = strspn($sql, '0123456789', $count2); - if ($pos > $count2) { - $count2 = $pos; - } - unset($pos); - } - - while (($count2 < $len) && PMA_STR_isSqlIdentifier(PMA_substr($sql, $count2, 1), ($is_sql_variable || $is_digit))) { - $c2 = PMA_substr($sql, $count2, 1); - if ($is_sql_variable && ($c2 == '.')) { - $count2++; - continue; - } - if ($is_digit && (!$is_hex_digit) && ($c2 == '.')) { - $count2++; - if (!$is_float_digit) { - $is_float_digit = true; - continue; - } else { - $debugstr = __('Invalid Identifer') . ' @ ' . ($count1+1) . "\n" - . 'STR: ' . htmlspecialchars(PMA_substr($sql, $count1, $count2 - $count1)); - PMA_SQP_throwError($debugstr, $sql); - return $sql_array; - } - } - if ($is_digit && (!$is_hex_digit) && (($c2 == 'e') || ($c2 == 'E'))) { - if (!$is_float_digit_exponent) { - $is_float_digit_exponent = true; - $is_float_digit = true; - $count2++; - continue; - } else { - $is_digit = false; - $is_float_digit = false; - } - } - if (($is_hex_digit && PMA_STR_isHexDigit($c2)) || ($is_digit && PMA_STR_isDigit($c2))) { - $count2++; - continue; - } else { - $is_digit = false; - $is_hex_digit = false; - } - - $count2++; - } // end while - - $l = $count2 - $count1; - $str = PMA_substr($sql, $count1, $l); - - $type = ''; - if ($is_digit || $is_float_digit || $is_hex_digit) { - $type = 'digit'; - if ($is_float_digit) { - $type .= '_float'; - } elseif ($is_hex_digit) { - $type .= '_hex'; - } else { - $type .= '_integer'; - } - } elseif ($is_user) { - $type = 'punct_user'; - } elseif ($is_sql_variable != false) { - $type = 'alpha_variable'; - } else { - $type = 'alpha'; - } // end if... else.... - PMA_SQP_arrayAdd($sql_array, $type, $str, $arraysize, $count2); - - continue; - } - - // Checks for punct - if (PMA_strpos($allpunct_list, $c) !== false) { - while (($count2 < $len) && PMA_strpos($allpunct_list, PMA_substr($sql, $count2, 1)) !== false) { - $count2++; - } - $l = $count2 - $count1; - if ($l == 1) { - $punct_data = $c; - } else { - $punct_data = PMA_substr($sql, $count1, $l); - } - - // Special case, sometimes, althought two characters are - // adjectent directly, they ACTUALLY need to be seperate - /* DEBUG - echo '
';
-                var_dump($l);
-                var_dump($punct_data);
-                echo '
'; - */ - - if ($l == 1) { - $t_suffix = ''; - switch ($punct_data) { - case $punct_queryend: - $t_suffix = '_queryend'; - break; - case $punct_qualifier: - $t_suffix = '_qualifier'; - $this_was_punct = true; - break; - case $punct_listsep: - $this_was_listsep = true; - $t_suffix = '_listsep'; - break; - default: - break; - } - PMA_SQP_arrayAdd($sql_array, 'punct' . $t_suffix, $punct_data, $arraysize); - } elseif ($punct_data == $GLOBALS['sql_delimiter'] || isset($allpunct_list_pair[$punct_data])) { - // Ok, we have one of the valid combined punct expressions - PMA_SQP_arrayAdd($sql_array, 'punct', $punct_data, $arraysize); - } else { - // Bad luck, lets split it up more - $first = $punct_data[0]; - $first2 = $punct_data[0] . $punct_data[1]; - $last2 = $punct_data[$l - 2] . $punct_data[$l - 1]; - $last = $punct_data[$l - 1]; - if (($first == ',') || ($first == ';') || ($first == '.') || ($first == '*')) { - $count2 = $count1 + 1; - $punct_data = $first; - } elseif (($last2 == '/*') || (($last2 == '--') && ($count2 == $len || PMA_substr($sql, $count2, 1) <= ' '))) { - $count2 -= 2; - $punct_data = PMA_substr($sql, $count1, $count2 - $count1); - } elseif (($last == '-') || ($last == '+') || ($last == '!')) { - $count2--; - $punct_data = PMA_substr($sql, $count1, $count2 - $count1); - } elseif ($last != '~') { - /** - * @todo for negation operator, split in 2 tokens ? - * "select x&~1 from t" - * becomes "select x & ~ 1 from t" ? + // Checks for something inside quotation marks + if (PMA_strpos($quote_list, $c) !== false) { + $startquotepos = $count2; + $quotetype = $c; + $count2++; + $escaped = false; + $pos = $count2; + $oldpos = 0; + do { + $oldpos = $pos; + $pos = PMA_strpos(' ' . $sql, $quotetype, $oldpos + 1) - 1; + // ($pos === false) + if ($pos < 0) { + if ($c == '`') { + /* + * Behave same as MySQL and accept end of query as end of backtick. + * I know this is sick, but MySQL behaves like this: + * + * SELECT * FROM `table + * + * is treated like + * + * SELECT * FROM `table` */ - $debugstr = __('Unknown Punctuation String') . ' @ ' . ($count1+1) . "\n" - . 'STR: ' . htmlspecialchars($punct_data); + $pos_quote_separator = PMA_strpos(' ' . $sql, $GLOBALS['sql_delimiter'], $oldpos + 1) - 1; + if ($pos_quote_separator < 0) { + $len += 1; + $sql .= '`'; + $sql_array['raw'] .= '`'; + $pos = $len; + } else { + $len += 1; + $sql = PMA_substr($sql, 0, $pos_quote_separator) . '`' . PMA_substr($sql, $pos_quote_separator); + $sql_array['raw'] = $sql; + $pos = $pos_quote_separator; + } + if (class_exists('PMA_Message') && $GLOBALS['is_ajax_request'] != true) { + PMA_Message::notice(__('Automatically appended backtick to the end of query!'))->display(); + } + } else { + $debugstr = __('Unclosed quote') . ' @ ' . $startquotepos. "\n" + . 'STR: ' . htmlspecialchars($quotetype); PMA_SQP_throwError($debugstr, $sql); return $sql_array; } - PMA_SQP_arrayAdd($sql_array, 'punct', $punct_data, $arraysize); + } + + // If the quote is the first character, it can't be + // escaped, so don't do the rest of the code + if ($pos == 0) { + break; + } + + // Checks for MySQL escaping using a \ + // And checks for ANSI escaping using the $quotetype character + if (($pos < $len) && PMA_STR_charIsEscaped($sql, $pos) && $c != '`') { + $pos ++; continue; - } // end if... elseif... else - continue; + } elseif (($pos + 1 < $len) && (PMA_substr($sql, $pos, 1) == $quotetype) && (PMA_substr($sql, $pos + 1, 1) == $quotetype)) { + $pos = $pos + 2; + continue; + } else { + break; + } + } while ($len > $pos); // end do + + $count2 = $pos; + $count2++; + $type = 'quote_'; + switch ($quotetype) { + case '\'': + $type .= 'single'; + $this_was_quote = true; + break; + case '"': + $type .= 'double'; + $this_was_quote = true; + break; + case '`': + $type .= 'backtick'; + $this_was_quote = true; + break; + default: + break; + } // end switch + $data = PMA_substr($sql, $count1, $count2 - $count1); + PMA_SQP_arrayAdd($sql_array, $type, $data, $arraysize); + continue; + } + + // Checks for brackets + if (PMA_strpos($bracket_list, $c) !== false) { + // All bracket tokens are only one item long + $this_was_bracket = true; + $count2++; + $type_type = ''; + if (PMA_strpos('([{', $c) !== false) { + $type_type = 'open'; + } else { + $type_type = 'close'; } - // DEBUG - $count2++; + $type_style = ''; + if (PMA_strpos('()', $c) !== false) { + $type_style = 'round'; + } elseif (PMA_strpos('[]', $c) !== false) { + $type_style = 'square'; + } else { + $type_style = 'curly'; + } - $debugstr = 'C1 C2 LEN: ' . $count1 . ' ' . $count2 . ' ' . $len . "\n" - . 'STR: ' . PMA_substr($sql, $count1, $count2 - $count1) . "\n"; - PMA_SQP_bug($debugstr, $sql); - return $sql_array; + $type = 'punct_bracket_' . $type_type . '_' . $type_style; + PMA_SQP_arrayAdd($sql_array, $type, $c, $arraysize); + continue; + } - } // end while ($count2 < $len) - - /* - echo '
';
-        print_r($sql_array);
+        /* DEBUG
+        echo '
1';
+        var_dump(PMA_STR_isSqlIdentifier($c, false));
+        var_dump($c == '@');
+        var_dump($c == '.');
+        var_dump(PMA_STR_isDigit(PMA_substr($sql, $count2 + 1, 1)));
+        var_dump($previous_was_space);
+        var_dump($previous_was_bracket);
+        var_dump($previous_was_listsep);
         echo '
'; */ - if ($arraysize > 0) { - $t_next = $sql_array[0]['type']; - $t_prev = ''; - $t_bef_prev = ''; - $t_cur = ''; - $d_next = $sql_array[0]['data']; - $d_prev = ''; - $d_bef_prev = ''; - $d_cur = ''; - $d_next_upper = $t_next == 'alpha' ? strtoupper($d_next) : $d_next; - $d_prev_upper = ''; - $d_bef_prev_upper = ''; - $d_cur_upper = ''; - } - - for ($i = 0; $i < $arraysize; $i++) { - $t_bef_prev = $t_prev; - $t_prev = $t_cur; - $t_cur = $t_next; - $d_bef_prev = $d_prev; - $d_prev = $d_cur; - $d_cur = $d_next; - $d_bef_prev_upper = $d_prev_upper; - $d_prev_upper = $d_cur_upper; - $d_cur_upper = $d_next_upper; - if (($i + 1) < $arraysize) { - $t_next = $sql_array[$i + 1]['type']; - $d_next = $sql_array[$i + 1]['data']; - $d_next_upper = $t_next == 'alpha' ? strtoupper($d_next) : $d_next; - } else { - $t_next = ''; - $d_next = ''; - $d_next_upper = ''; - } - - //DEBUG echo "[prev: ".$d_prev." ".$t_prev."][cur: ".$d_cur." ".$t_cur."][next: ".$d_next." ".$t_next."]
"; - - if ($t_cur == 'alpha') { - $t_suffix = '_identifier'; - // for example: `thebit` bit(8) NOT NULL DEFAULT b'0' - if ($t_prev == 'alpha' && $d_prev == 'DEFAULT' && $d_cur == 'b' && $t_next == 'quote_single') { - $t_suffix = '_bitfield_constant_introducer'; - } elseif (($t_next == 'punct_qualifier') || ($t_prev == 'punct_qualifier')) { - $t_suffix = '_identifier'; - } elseif (($t_next == 'punct_bracket_open_round') - && isset($PMA_SQPdata_function_name[$d_cur_upper])) { - /** - * @todo 2005-10-16: in the case of a CREATE TABLE containing - * a TIMESTAMP, since TIMESTAMP() is also a function, it's - * found here and the token is wrongly marked as alpha_functionName. - * But we compensate for this when analysing for timestamp_not_null - * later in this script. - * - * Same applies to CHAR vs. CHAR() function. - */ - $t_suffix = '_functionName'; - /* There are functions which might be as well column types */ - } elseif (isset($PMA_SQPdata_column_type[$d_cur_upper])) { - $t_suffix = '_columnType'; - - /** - * Temporary fix for bugs #621357 and #2027720 - * - * @todo FIX PROPERLY NEEDS OVERHAUL OF SQL TOKENIZER - */ - if (($d_cur_upper == 'SET' || $d_cur_upper == 'BINARY') && $t_next != 'punct_bracket_open_round') { - $t_suffix = '_reservedWord'; - } - //END OF TEMPORARY FIX - - // CHARACTER is a synonym for CHAR, but can also be meant as - // CHARACTER SET. In this case, we have a reserved word. - if ($d_cur_upper == 'CHARACTER' && $d_next_upper == 'SET') { - $t_suffix = '_reservedWord'; - } - - // experimental - // current is a column type, so previous must not be - // a reserved word but an identifier - // CREATE TABLE SG_Persons (first varchar(64)) - - //if ($sql_array[$i-1]['type'] =='alpha_reservedWord') { - // $sql_array[$i-1]['type'] = 'alpha_identifier'; - //} - - } elseif (isset($PMA_SQPdata_reserved_word[$d_cur_upper])) { - $t_suffix = '_reservedWord'; - } elseif (isset($PMA_SQPdata_column_attrib[$d_cur_upper])) { - $t_suffix = '_columnAttrib'; - // INNODB is a MySQL table type, but in "SHOW INNODB STATUS", - // it should be regarded as a reserved word. - if ($d_cur_upper == 'INNODB' && $d_prev_upper == 'SHOW' && $d_next_upper == 'STATUS') { - $t_suffix = '_reservedWord'; - } - - if ($d_cur_upper == 'DEFAULT' && $d_next_upper == 'CHARACTER') { - $t_suffix = '_reservedWord'; - } - // Binary as character set - if ($d_cur_upper == 'BINARY' && ( - ($d_bef_prev_upper == 'CHARACTER' && $d_prev_upper == 'SET') - || ($d_bef_prev_upper == 'SET' && $d_prev_upper == '=') - || ($d_bef_prev_upper == 'CHARSET' && $d_prev_upper == '=') - || $d_prev_upper == 'CHARSET' - ) && in_array($d_cur, $mysql_charsets) - ) { - $t_suffix = '_charset'; - } - } elseif (in_array($d_cur, $mysql_charsets) - || in_array($d_cur, $mysql_collations_flat) - || ($d_cur{0} == '_' && in_array(substr($d_cur, 1), $mysql_charsets))) { - $t_suffix = '_charset'; - } else { - // Do nothing - } - // check if present in the list of forbidden words - if ($t_suffix == '_reservedWord' && isset($PMA_SQPdata_forbidden_word[$d_cur_upper])) { - $sql_array[$i]['forbidden'] = true; - } else { - $sql_array[$i]['forbidden'] = false; - } - $sql_array[$i]['type'] .= $t_suffix; - } - } // end for - - // Stores the size of the array inside the array, as count() is a slow - // operation. - $sql_array['len'] = $arraysize; - - // DEBUG echo 'After parsing
'; print_r($sql_array); echo '
'; - // Sends the data back - return $sql_array; - } // end of the "PMA_SQP_parse()" function - - /** - * Checks for token types being what we want... - * - * @param string String of type that we have - * @param string String of type that we want - * - * @return boolean result of check - * - * @access private - */ - function PMA_SQP_typeCheck($toCheck, $whatWeWant) - { - $typeSeparator = '_'; - if (strcmp($whatWeWant, $toCheck) == 0) { - return true; - } else { - if (strpos($whatWeWant, $typeSeparator) === false) { - return strncmp($whatWeWant, $toCheck, strpos($toCheck, $typeSeparator)) == 0; - } else { - return false; - } - } - } - - - /** - * Analyzes SQL queries - * - * @param array The SQL queries - * - * @return array The analyzed SQL queries - * - * @access public - */ - function PMA_SQP_analyze($arr) - { - if ($arr == array() || ! isset($arr['len'])) { - return array(); - } - $result = array(); - $size = $arr['len']; - $subresult = array( - 'querytype' => '', - 'select_expr_clause'=> '', // the whole stuff between SELECT and FROM , except DISTINCT - 'position_of_first_select' => '', // the array index - 'from_clause'=> '', - 'group_by_clause'=> '', - 'order_by_clause'=> '', - 'having_clause' => '', - 'limit_clause' => '', - 'where_clause' => '', - 'where_clause_identifiers' => array(), - 'unsorted_query' => '', - 'queryflags' => array(), - 'select_expr' => array(), - 'table_ref' => array(), - 'foreign_keys' => array(), - 'create_table_fields' => array() - ); - $subresult_empty = $subresult; - $seek_queryend = false; - $seen_end_of_table_ref = false; - $number_of_brackets_in_extract = 0; - $number_of_brackets_in_group_concat = 0; - - $number_of_brackets = 0; - $in_subquery = false; - $seen_subquery = false; - $seen_from = false; - - // for SELECT EXTRACT(YEAR_MONTH FROM CURDATE()) - // we must not use CURDATE as a table_ref - // so we track whether we are in the EXTRACT() - $in_extract = false; - - // for GROUP_CONCAT(...) - $in_group_concat = false; - - /* Description of analyzer results - * - * db, table, column, alias - * ------------------------ - * - * Inside the $subresult array, we create ['select_expr'] and ['table_ref'] arrays. - * - * The SELECT syntax (simplified) is - * - * SELECT - * select_expression,... - * [FROM [table_references] - * - * - * ['select_expr'] is filled with each expression, the key represents the - * expression position in the list (0-based) (so we don't lose track of - * multiple occurences of the same column). - * - * ['table_ref'] is filled with each table ref, same thing for the key. - * - * I create all sub-values empty, even if they are - * not present (for example no select_expression alias). - * - * There is a debug section at the end of loop #1, if you want to - * see the exact contents of select_expr and table_ref - * - * queryflags - * ---------- - * - * In $subresult, array 'queryflags' is filled, according to what we - * find in the query. - * - * Currently, those are generated: - * - * ['queryflags']['need_confirm'] = 1; if the query needs confirmation - * ['queryflags']['select_from'] = 1; if this is a real SELECT...FROM - * ['queryflags']['distinct'] = 1; for a DISTINCT - * ['queryflags']['union'] = 1; for a UNION - * ['queryflags']['join'] = 1; for a JOIN - * ['queryflags']['offset'] = 1; for the presence of OFFSET - * ['queryflags']['procedure'] = 1; for the presence of PROCEDURE - * - * query clauses - * ------------- - * - * The select is splitted in those clauses: - * ['select_expr_clause'] - * ['from_clause'] - * ['group_by_clause'] - * ['order_by_clause'] - * ['having_clause'] - * ['limit_clause'] - * ['where_clause'] - * - * The identifiers of the WHERE clause are put into the array - * ['where_clause_identifier'] - * - * For a SELECT, the whole query without the ORDER BY clause is put into - * ['unsorted_query'] - * - * foreign keys - * ------------ - * The CREATE TABLE may contain FOREIGN KEY clauses, so they get - * analyzed and ['foreign_keys'] is an array filled with - * the constraint name, the index list, - * the REFERENCES table name and REFERENCES index list, - * and ON UPDATE | ON DELETE clauses - * - * position_of_first_select - * ------------------------ - * - * The array index of the first SELECT we find. Will be used to - * insert a SQL_CALC_FOUND_ROWS. - * - * create_table_fields - * ------------------- - * - * Used to detect the DEFAULT CURRENT_TIMESTAMP and - * ON UPDATE CURRENT_TIMESTAMP clauses of the CREATE TABLE query. - * Also used to store the default value of the field. - * An array, each element is the identifier name. - * Note that for now, the timestamp_not_null element is created - * even for non-TIMESTAMP fields. - * - * Sub-elements: ['type'] which contains the column type - * optional (currently they are never false but can be absent): - * ['default_current_timestamp'] boolean - * ['on_update_current_timestamp'] boolean - * ['timestamp_not_null'] boolean - * - * section_before_limit, section_after_limit - * ----------------------------------------- - * - * Marks the point of the query where we can insert a LIMIT clause; - * so the section_before_limit will contain the left part before - * a possible LIMIT clause - * - * - * End of description of analyzer results - */ - - // must be sorted - // TODO: current logic checks for only one word, so I put only the - // first word of the reserved expressions that end a table ref; - // maybe this is not ok (the first word might mean something else) - // $words_ending_table_ref = array( - // 'FOR UPDATE', - // 'GROUP BY', - // 'HAVING', - // 'LIMIT', - // 'LOCK IN SHARE MODE', - // 'ORDER BY', - // 'PROCEDURE', - // 'UNION', - // 'WHERE' - // ); - $words_ending_table_ref = array( - 'FOR' => 1, - 'GROUP' => 1, - 'HAVING' => 1, - 'LIMIT' => 1, - 'LOCK' => 1, - 'ORDER' => 1, - 'PROCEDURE' => 1, - 'UNION' => 1, - 'WHERE' => 1 - ); - - $words_ending_clauses = array( - 'FOR' => 1, - 'LIMIT' => 1, - 'LOCK' => 1, - 'PROCEDURE' => 1, - 'UNION' => 1 - ); - - $supported_query_types = array( - 'SELECT' => 1, - /* - // Support for these additional query types will come later on. - 'DELETE' => 1, - 'INSERT' => 1, - 'REPLACE' => 1, - 'TRUNCATE' => 1, - 'UPDATE' => 1, - 'EXPLAIN' => 1, - 'DESCRIBE' => 1, - 'SHOW' => 1, - 'CREATE' => 1, - 'SET' => 1, - 'ALTER' => 1 + // Checks for identifier (alpha or numeric) + if (PMA_STR_isSqlIdentifier($c, false) + || $c == '@' + || ($c == '.' + && PMA_STR_isDigit(PMA_substr($sql, $count2 + 1, 1)) + && ($previous_was_space || $previous_was_bracket || $previous_was_listsep)) + ) { + /* DEBUG + echo PMA_substr($sql, $count2); + echo '
'; */ - ); - // loop #1 for each token: select_expr, table_ref for SELECT - - for ($i = 0; $i < $size; $i++) { - //DEBUG echo "Loop1 " . $arr[$i]['data'] . " (" . $arr[$i]['type'] . ")
"; - - // High speed seek for locating the end of the current query - if ($seek_queryend == true) { - if ($arr[$i]['type'] == 'punct_queryend') { - $seek_queryend = false; - } else { - continue; - } // end if (type == punct_queryend) - } // end if ($seek_queryend) + $count2++; /** - * Note: do not split if this is a punct_queryend for the first and only query - * @todo when we find a UNION, should we split in another subresult? + * @todo a @ can also be present in expressions like + * FROM 'user'@'%' or TO 'user'@'%' + * in this case, the @ is wrongly marked as alpha_variable */ - if ($arr[$i]['type'] == 'punct_queryend' && ($i + 1 != $size)) { - $result[] = $subresult; - $subresult = $subresult_empty; + $is_identifier = $previous_was_punct; + $is_sql_variable = $c == '@' && ! $previous_was_quote; + $is_user = $c == '@' && $previous_was_quote; + $is_digit = !$is_identifier && !$is_sql_variable && PMA_STR_isDigit($c); + $is_hex_digit = $is_digit && $c == '0' && $count2 < $len && PMA_substr($sql, $count2, 1) == 'x'; + $is_float_digit = $c == '.'; + $is_float_digit_exponent = false; + + /* DEBUG + echo '
2';
+            var_dump($is_identifier);
+            var_dump($is_sql_variable);
+            var_dump($is_digit);
+            var_dump($is_float_digit);
+            echo '
'; + */ + + // Fast skip is especially needed for huge BLOB data + if ($is_hex_digit) { + $count2++; + $pos = strspn($sql, '0123456789abcdefABCDEF', $count2); + if ($pos > $count2) { + $count2 = $pos; + } + unset($pos); + } elseif ($is_digit) { + $pos = strspn($sql, '0123456789', $count2); + if ($pos > $count2) { + $count2 = $pos; + } + unset($pos); + } + + while (($count2 < $len) && PMA_STR_isSqlIdentifier(PMA_substr($sql, $count2, 1), ($is_sql_variable || $is_digit))) { + $c2 = PMA_substr($sql, $count2, 1); + if ($is_sql_variable && ($c2 == '.')) { + $count2++; + continue; + } + if ($is_digit && (!$is_hex_digit) && ($c2 == '.')) { + $count2++; + if (!$is_float_digit) { + $is_float_digit = true; + continue; + } else { + $debugstr = __('Invalid Identifer') . ' @ ' . ($count1+1) . "\n" + . 'STR: ' . htmlspecialchars(PMA_substr($sql, $count1, $count2 - $count1)); + PMA_SQP_throwError($debugstr, $sql); + return $sql_array; + } + } + if ($is_digit && (!$is_hex_digit) && (($c2 == 'e') || ($c2 == 'E'))) { + if (!$is_float_digit_exponent) { + $is_float_digit_exponent = true; + $is_float_digit = true; + $count2++; + continue; + } else { + $is_digit = false; + $is_float_digit = false; + } + } + if (($is_hex_digit && PMA_STR_isHexDigit($c2)) || ($is_digit && PMA_STR_isDigit($c2))) { + $count2++; + continue; + } else { + $is_digit = false; + $is_hex_digit = false; + } + + $count2++; + } // end while + + $l = $count2 - $count1; + $str = PMA_substr($sql, $count1, $l); + + $type = ''; + if ($is_digit || $is_float_digit || $is_hex_digit) { + $type = 'digit'; + if ($is_float_digit) { + $type .= '_float'; + } elseif ($is_hex_digit) { + $type .= '_hex'; + } else { + $type .= '_integer'; + } + } elseif ($is_user) { + $type = 'punct_user'; + } elseif ($is_sql_variable != false) { + $type = 'alpha_variable'; + } else { + $type = 'alpha'; + } // end if... else.... + PMA_SQP_arrayAdd($sql_array, $type, $str, $arraysize, $count2); + + continue; + } + + // Checks for punct + if (PMA_strpos($allpunct_list, $c) !== false) { + while (($count2 < $len) && PMA_strpos($allpunct_list, PMA_substr($sql, $count2, 1)) !== false) { + $count2++; + } + $l = $count2 - $count1; + if ($l == 1) { + $punct_data = $c; + } else { + $punct_data = PMA_substr($sql, $count1, $l); + } + + // Special case, sometimes, althought two characters are + // adjectent directly, they ACTUALLY need to be seperate + /* DEBUG + echo '
';
+            var_dump($l);
+            var_dump($punct_data);
+            echo '
'; + */ + + if ($l == 1) { + $t_suffix = ''; + switch ($punct_data) { + case $punct_queryend: + $t_suffix = '_queryend'; + break; + case $punct_qualifier: + $t_suffix = '_qualifier'; + $this_was_punct = true; + break; + case $punct_listsep: + $this_was_listsep = true; + $t_suffix = '_listsep'; + break; + default: + break; + } + PMA_SQP_arrayAdd($sql_array, 'punct' . $t_suffix, $punct_data, $arraysize); + } elseif ($punct_data == $GLOBALS['sql_delimiter'] || isset($allpunct_list_pair[$punct_data])) { + // Ok, we have one of the valid combined punct expressions + PMA_SQP_arrayAdd($sql_array, 'punct', $punct_data, $arraysize); + } else { + // Bad luck, lets split it up more + $first = $punct_data[0]; + $first2 = $punct_data[0] . $punct_data[1]; + $last2 = $punct_data[$l - 2] . $punct_data[$l - 1]; + $last = $punct_data[$l - 1]; + if (($first == ',') || ($first == ';') || ($first == '.') || ($first == '*')) { + $count2 = $count1 + 1; + $punct_data = $first; + } elseif (($last2 == '/*') || (($last2 == '--') && ($count2 == $len || PMA_substr($sql, $count2, 1) <= ' '))) { + $count2 -= 2; + $punct_data = PMA_substr($sql, $count1, $count2 - $count1); + } elseif (($last == '-') || ($last == '+') || ($last == '!')) { + $count2--; + $punct_data = PMA_substr($sql, $count1, $count2 - $count1); + } elseif ($last != '~') { + /** + * @todo for negation operator, split in 2 tokens ? + * "select x&~1 from t" + * becomes "select x & ~ 1 from t" ? + */ + $debugstr = __('Unknown Punctuation String') . ' @ ' . ($count1+1) . "\n" + . 'STR: ' . htmlspecialchars($punct_data); + PMA_SQP_throwError($debugstr, $sql); + return $sql_array; + } + PMA_SQP_arrayAdd($sql_array, 'punct', $punct_data, $arraysize); + continue; + } // end if... elseif... else + continue; + } + + // DEBUG + $count2++; + + $debugstr = 'C1 C2 LEN: ' . $count1 . ' ' . $count2 . ' ' . $len . "\n" + . 'STR: ' . PMA_substr($sql, $count1, $count2 - $count1) . "\n"; + PMA_SQP_bug($debugstr, $sql); + return $sql_array; + + } // end while ($count2 < $len) + + /* + echo '
';
+    print_r($sql_array);
+    echo '
'; + */ + + if ($arraysize > 0) { + $t_next = $sql_array[0]['type']; + $t_prev = ''; + $t_bef_prev = ''; + $t_cur = ''; + $d_next = $sql_array[0]['data']; + $d_prev = ''; + $d_bef_prev = ''; + $d_cur = ''; + $d_next_upper = $t_next == 'alpha' ? strtoupper($d_next) : $d_next; + $d_prev_upper = ''; + $d_bef_prev_upper = ''; + $d_cur_upper = ''; + } + + for ($i = 0; $i < $arraysize; $i++) { + $t_bef_prev = $t_prev; + $t_prev = $t_cur; + $t_cur = $t_next; + $d_bef_prev = $d_prev; + $d_prev = $d_cur; + $d_cur = $d_next; + $d_bef_prev_upper = $d_prev_upper; + $d_prev_upper = $d_cur_upper; + $d_cur_upper = $d_next_upper; + if (($i + 1) < $arraysize) { + $t_next = $sql_array[$i + 1]['type']; + $d_next = $sql_array[$i + 1]['data']; + $d_next_upper = $t_next == 'alpha' ? strtoupper($d_next) : $d_next; + } else { + $t_next = ''; + $d_next = ''; + $d_next_upper = ''; + } + + //DEBUG echo "[prev: ".$d_prev." ".$t_prev."][cur: ".$d_cur." ".$t_cur."][next: ".$d_next." ".$t_next."]
"; + + if ($t_cur == 'alpha') { + $t_suffix = '_identifier'; + // for example: `thebit` bit(8) NOT NULL DEFAULT b'0' + if ($t_prev == 'alpha' && $d_prev == 'DEFAULT' && $d_cur == 'b' && $t_next == 'quote_single') { + $t_suffix = '_bitfield_constant_introducer'; + } elseif (($t_next == 'punct_qualifier') || ($t_prev == 'punct_qualifier')) { + $t_suffix = '_identifier'; + } elseif (($t_next == 'punct_bracket_open_round') + && isset($PMA_SQPdata_function_name[$d_cur_upper])) { + /** + * @todo 2005-10-16: in the case of a CREATE TABLE containing + * a TIMESTAMP, since TIMESTAMP() is also a function, it's + * found here and the token is wrongly marked as alpha_functionName. + * But we compensate for this when analysing for timestamp_not_null + * later in this script. + * + * Same applies to CHAR vs. CHAR() function. + */ + $t_suffix = '_functionName'; + /* There are functions which might be as well column types */ + } elseif (isset($PMA_SQPdata_column_type[$d_cur_upper])) { + $t_suffix = '_columnType'; + + /** + * Temporary fix for bugs #621357 and #2027720 + * + * @todo FIX PROPERLY NEEDS OVERHAUL OF SQL TOKENIZER + */ + if (($d_cur_upper == 'SET' || $d_cur_upper == 'BINARY') && $t_next != 'punct_bracket_open_round') { + $t_suffix = '_reservedWord'; + } + //END OF TEMPORARY FIX + + // CHARACTER is a synonym for CHAR, but can also be meant as + // CHARACTER SET. In this case, we have a reserved word. + if ($d_cur_upper == 'CHARACTER' && $d_next_upper == 'SET') { + $t_suffix = '_reservedWord'; + } + + // experimental + // current is a column type, so previous must not be + // a reserved word but an identifier + // CREATE TABLE SG_Persons (first varchar(64)) + + //if ($sql_array[$i-1]['type'] =='alpha_reservedWord') { + // $sql_array[$i-1]['type'] = 'alpha_identifier'; + //} + + } elseif (isset($PMA_SQPdata_reserved_word[$d_cur_upper])) { + $t_suffix = '_reservedWord'; + } elseif (isset($PMA_SQPdata_column_attrib[$d_cur_upper])) { + $t_suffix = '_columnAttrib'; + // INNODB is a MySQL table type, but in "SHOW INNODB STATUS", + // it should be regarded as a reserved word. + if ($d_cur_upper == 'INNODB' && $d_prev_upper == 'SHOW' && $d_next_upper == 'STATUS') { + $t_suffix = '_reservedWord'; + } + + if ($d_cur_upper == 'DEFAULT' && $d_next_upper == 'CHARACTER') { + $t_suffix = '_reservedWord'; + } + // Binary as character set + if ($d_cur_upper == 'BINARY' && ( + ($d_bef_prev_upper == 'CHARACTER' && $d_prev_upper == 'SET') + || ($d_bef_prev_upper == 'SET' && $d_prev_upper == '=') + || ($d_bef_prev_upper == 'CHARSET' && $d_prev_upper == '=') + || $d_prev_upper == 'CHARSET' + ) && in_array($d_cur, $mysql_charsets) + ) { + $t_suffix = '_charset'; + } + } elseif (in_array($d_cur, $mysql_charsets) + || in_array($d_cur, $mysql_collations_flat) + || ($d_cur{0} == '_' && in_array(substr($d_cur, 1), $mysql_charsets))) { + $t_suffix = '_charset'; + } else { + // Do nothing + } + // check if present in the list of forbidden words + if ($t_suffix == '_reservedWord' && isset($PMA_SQPdata_forbidden_word[$d_cur_upper])) { + $sql_array[$i]['forbidden'] = true; + } else { + $sql_array[$i]['forbidden'] = false; + } + $sql_array[$i]['type'] .= $t_suffix; + } + } // end for + + // Stores the size of the array inside the array, as count() is a slow + // operation. + $sql_array['len'] = $arraysize; + + // DEBUG echo 'After parsing
'; print_r($sql_array); echo '
'; + // Sends the data back + return $sql_array; +} // end of the "PMA_SQP_parse()" function + +/** + * Checks for token types being what we want... + * + * @param string String of type that we have + * @param string String of type that we want + * + * @return boolean result of check + * + * @access private + */ +function PMA_SQP_typeCheck($toCheck, $whatWeWant) +{ + $typeSeparator = '_'; + if (strcmp($whatWeWant, $toCheck) == 0) { + return true; + } else { + if (strpos($whatWeWant, $typeSeparator) === false) { + return strncmp($whatWeWant, $toCheck, strpos($toCheck, $typeSeparator)) == 0; + } else { + return false; + } + } +} + + +/** + * Analyzes SQL queries + * + * @param array The SQL queries + * + * @return array The analyzed SQL queries + * + * @access public + */ +function PMA_SQP_analyze($arr) +{ + if ($arr == array() || ! isset($arr['len'])) { + return array(); + } + $result = array(); + $size = $arr['len']; + $subresult = array( + 'querytype' => '', + 'select_expr_clause'=> '', // the whole stuff between SELECT and FROM , except DISTINCT + 'position_of_first_select' => '', // the array index + 'from_clause'=> '', + 'group_by_clause'=> '', + 'order_by_clause'=> '', + 'having_clause' => '', + 'limit_clause' => '', + 'where_clause' => '', + 'where_clause_identifiers' => array(), + 'unsorted_query' => '', + 'queryflags' => array(), + 'select_expr' => array(), + 'table_ref' => array(), + 'foreign_keys' => array(), + 'create_table_fields' => array() + ); + $subresult_empty = $subresult; + $seek_queryend = false; + $seen_end_of_table_ref = false; + $number_of_brackets_in_extract = 0; + $number_of_brackets_in_group_concat = 0; + + $number_of_brackets = 0; + $in_subquery = false; + $seen_subquery = false; + $seen_from = false; + + // for SELECT EXTRACT(YEAR_MONTH FROM CURDATE()) + // we must not use CURDATE as a table_ref + // so we track whether we are in the EXTRACT() + $in_extract = false; + + // for GROUP_CONCAT(...) + $in_group_concat = false; + + /* Description of analyzer results + * + * db, table, column, alias + * ------------------------ + * + * Inside the $subresult array, we create ['select_expr'] and ['table_ref'] arrays. + * + * The SELECT syntax (simplified) is + * + * SELECT + * select_expression,... + * [FROM [table_references] + * + * + * ['select_expr'] is filled with each expression, the key represents the + * expression position in the list (0-based) (so we don't lose track of + * multiple occurences of the same column). + * + * ['table_ref'] is filled with each table ref, same thing for the key. + * + * I create all sub-values empty, even if they are + * not present (for example no select_expression alias). + * + * There is a debug section at the end of loop #1, if you want to + * see the exact contents of select_expr and table_ref + * + * queryflags + * ---------- + * + * In $subresult, array 'queryflags' is filled, according to what we + * find in the query. + * + * Currently, those are generated: + * + * ['queryflags']['need_confirm'] = 1; if the query needs confirmation + * ['queryflags']['select_from'] = 1; if this is a real SELECT...FROM + * ['queryflags']['distinct'] = 1; for a DISTINCT + * ['queryflags']['union'] = 1; for a UNION + * ['queryflags']['join'] = 1; for a JOIN + * ['queryflags']['offset'] = 1; for the presence of OFFSET + * ['queryflags']['procedure'] = 1; for the presence of PROCEDURE + * + * query clauses + * ------------- + * + * The select is splitted in those clauses: + * ['select_expr_clause'] + * ['from_clause'] + * ['group_by_clause'] + * ['order_by_clause'] + * ['having_clause'] + * ['limit_clause'] + * ['where_clause'] + * + * The identifiers of the WHERE clause are put into the array + * ['where_clause_identifier'] + * + * For a SELECT, the whole query without the ORDER BY clause is put into + * ['unsorted_query'] + * + * foreign keys + * ------------ + * The CREATE TABLE may contain FOREIGN KEY clauses, so they get + * analyzed and ['foreign_keys'] is an array filled with + * the constraint name, the index list, + * the REFERENCES table name and REFERENCES index list, + * and ON UPDATE | ON DELETE clauses + * + * position_of_first_select + * ------------------------ + * + * The array index of the first SELECT we find. Will be used to + * insert a SQL_CALC_FOUND_ROWS. + * + * create_table_fields + * ------------------- + * + * Used to detect the DEFAULT CURRENT_TIMESTAMP and + * ON UPDATE CURRENT_TIMESTAMP clauses of the CREATE TABLE query. + * Also used to store the default value of the field. + * An array, each element is the identifier name. + * Note that for now, the timestamp_not_null element is created + * even for non-TIMESTAMP fields. + * + * Sub-elements: ['type'] which contains the column type + * optional (currently they are never false but can be absent): + * ['default_current_timestamp'] boolean + * ['on_update_current_timestamp'] boolean + * ['timestamp_not_null'] boolean + * + * section_before_limit, section_after_limit + * ----------------------------------------- + * + * Marks the point of the query where we can insert a LIMIT clause; + * so the section_before_limit will contain the left part before + * a possible LIMIT clause + * + * + * End of description of analyzer results + */ + + // must be sorted + // TODO: current logic checks for only one word, so I put only the + // first word of the reserved expressions that end a table ref; + // maybe this is not ok (the first word might mean something else) + // $words_ending_table_ref = array( + // 'FOR UPDATE', + // 'GROUP BY', + // 'HAVING', + // 'LIMIT', + // 'LOCK IN SHARE MODE', + // 'ORDER BY', + // 'PROCEDURE', + // 'UNION', + // 'WHERE' + // ); + $words_ending_table_ref = array( + 'FOR' => 1, + 'GROUP' => 1, + 'HAVING' => 1, + 'LIMIT' => 1, + 'LOCK' => 1, + 'ORDER' => 1, + 'PROCEDURE' => 1, + 'UNION' => 1, + 'WHERE' => 1 + ); + + $words_ending_clauses = array( + 'FOR' => 1, + 'LIMIT' => 1, + 'LOCK' => 1, + 'PROCEDURE' => 1, + 'UNION' => 1 + ); + + $supported_query_types = array( + 'SELECT' => 1, + /* + // Support for these additional query types will come later on. + 'DELETE' => 1, + 'INSERT' => 1, + 'REPLACE' => 1, + 'TRUNCATE' => 1, + 'UPDATE' => 1, + 'EXPLAIN' => 1, + 'DESCRIBE' => 1, + 'SHOW' => 1, + 'CREATE' => 1, + 'SET' => 1, + 'ALTER' => 1 + */ + ); + + // loop #1 for each token: select_expr, table_ref for SELECT + + for ($i = 0; $i < $size; $i++) { + //DEBUG echo "Loop1 " . $arr[$i]['data'] . " (" . $arr[$i]['type'] . ")
"; + + // High speed seek for locating the end of the current query + if ($seek_queryend == true) { + if ($arr[$i]['type'] == 'punct_queryend') { + $seek_queryend = false; + } else { continue; } // end if (type == punct_queryend) + } // end if ($seek_queryend) - // ============================================================== - if ($arr[$i]['type'] == 'punct_bracket_open_round') { - $number_of_brackets++; - if ($in_extract) { - $number_of_brackets_in_extract++; - } - if ($in_group_concat) { - $number_of_brackets_in_group_concat++; + /** + * Note: do not split if this is a punct_queryend for the first and only query + * @todo when we find a UNION, should we split in another subresult? + */ + if ($arr[$i]['type'] == 'punct_queryend' && ($i + 1 != $size)) { + $result[] = $subresult; + $subresult = $subresult_empty; + continue; + } // end if (type == punct_queryend) + + // ============================================================== + if ($arr[$i]['type'] == 'punct_bracket_open_round') { + $number_of_brackets++; + if ($in_extract) { + $number_of_brackets_in_extract++; + } + if ($in_group_concat) { + $number_of_brackets_in_group_concat++; + } + } + // ============================================================== + if ($arr[$i]['type'] == 'punct_bracket_close_round') { + $number_of_brackets--; + if ($number_of_brackets == 0) { + $in_subquery = false; + } + if ($in_extract) { + $number_of_brackets_in_extract--; + if ($number_of_brackets_in_extract == 0) { + $in_extract = false; } } - // ============================================================== - if ($arr[$i]['type'] == 'punct_bracket_close_round') { - $number_of_brackets--; - if ($number_of_brackets == 0) { - $in_subquery = false; - } - if ($in_extract) { - $number_of_brackets_in_extract--; - if ($number_of_brackets_in_extract == 0) { - $in_extract = false; - } - } - if ($in_group_concat) { - $number_of_brackets_in_group_concat--; - if ($number_of_brackets_in_group_concat == 0) { - $in_group_concat = false; - } + if ($in_group_concat) { + $number_of_brackets_in_group_concat--; + if ($number_of_brackets_in_group_concat == 0) { + $in_group_concat = false; } } + } - if ($in_subquery) { - /** - * skip the subquery to avoid setting - * select_expr or table_ref with the contents - * of this subquery; this is to avoid a bug when - * trying to edit the results of - * select * from child where not exists (select id from - * parent where child.parent_id = parent.id); - */ - continue; + if ($in_subquery) { + /** + * skip the subquery to avoid setting + * select_expr or table_ref with the contents + * of this subquery; this is to avoid a bug when + * trying to edit the results of + * select * from child where not exists (select id from + * parent where child.parent_id = parent.id); + */ + continue; + } + // ============================================================== + if ($arr[$i]['type'] == 'alpha_functionName') { + $upper_data = strtoupper($arr[$i]['data']); + if ($upper_data =='EXTRACT') { + $in_extract = true; + $number_of_brackets_in_extract = 0; } - // ============================================================== - if ($arr[$i]['type'] == 'alpha_functionName') { - $upper_data = strtoupper($arr[$i]['data']); - if ($upper_data =='EXTRACT') { - $in_extract = true; - $number_of_brackets_in_extract = 0; - } - if ($upper_data =='GROUP_CONCAT') { - $in_group_concat = true; - $number_of_brackets_in_group_concat = 0; - } + if ($upper_data =='GROUP_CONCAT') { + $in_group_concat = true; + $number_of_brackets_in_group_concat = 0; } + } - // ============================================================== - if ($arr[$i]['type'] == 'alpha_reservedWord' - //&& $arr[$i]['forbidden'] == false) { - ) { - // We don't know what type of query yet, so run this - if ($subresult['querytype'] == '') { - $subresult['querytype'] = strtoupper($arr[$i]['data']); - } // end if (querytype was empty) - - // Check if we support this type of query - if (!isset($supported_query_types[$subresult['querytype']])) { - // Skip ahead to the next one if we don't - $seek_queryend = true; - continue; - } // end if (query not supported) - - // upper once - $upper_data = strtoupper($arr[$i]['data']); - /** - * @todo reset for each query? - */ - - if ($upper_data == 'SELECT') { - if ($number_of_brackets > 0) { - $in_subquery = true; - $seen_subquery = true; - // this is a subquery so do not analyze inside it - continue; - } - $seen_from = false; - $previous_was_identifier = false; - $current_select_expr = -1; - $seen_end_of_table_ref = false; - } // end if (data == SELECT) - - if ($upper_data =='FROM' && !$in_extract) { - $current_table_ref = -1; - $seen_from = true; - $previous_was_identifier = false; - $save_table_ref = true; - } // end if (data == FROM) - - // here, do not 'continue' the loop, as we have more work for - // reserved words below - } // end if (type == alpha_reservedWord) - - // ============================== - if ($arr[$i]['type'] == 'quote_backtick' - || $arr[$i]['type'] == 'quote_double' - || $arr[$i]['type'] == 'quote_single' - || $arr[$i]['type'] == 'alpha_identifier' - || ($arr[$i]['type'] == 'alpha_reservedWord' - && $arr[$i]['forbidden'] == false) + // ============================================================== + if ($arr[$i]['type'] == 'alpha_reservedWord' + //&& $arr[$i]['forbidden'] == false) { ) { - switch ($arr[$i]['type']) { - case 'alpha_identifier': - case 'alpha_reservedWord': - /** - * this is not a real reservedWord, because it's not - * present in the list of forbidden words, for example - * "storage" which can be used as an identifier - * - * @todo avoid the pretty printing in color in this case - */ - $identifier = $arr[$i]['data']; - break; + // We don't know what type of query yet, so run this + if ($subresult['querytype'] == '') { + $subresult['querytype'] = strtoupper($arr[$i]['data']); + } // end if (querytype was empty) - case 'quote_backtick': - case 'quote_double': - case 'quote_single': - $identifier = PMA_unQuote($arr[$i]['data']); - break; - } // end switch + // Check if we support this type of query + if (!isset($supported_query_types[$subresult['querytype']])) { + // Skip ahead to the next one if we don't + $seek_queryend = true; + continue; + } // end if (query not supported) - if ($subresult['querytype'] == 'SELECT' - && ! $in_group_concat - && ! ($seen_subquery && $arr[$i - 1]['type'] == 'punct_bracket_close_round') - ) { - if (!$seen_from) { - if ($previous_was_identifier && isset($chain)) { - // found alias for this select_expr, save it - // but only if we got something in $chain - // (for example, SELECT COUNT(*) AS cnt - // puts nothing in $chain, so we avoid - // setting the alias) - $alias_for_select_expr = $identifier; + // upper once + $upper_data = strtoupper($arr[$i]['data']); + /** + * @todo reset for each query? + */ + + if ($upper_data == 'SELECT') { + if ($number_of_brackets > 0) { + $in_subquery = true; + $seen_subquery = true; + // this is a subquery so do not analyze inside it + continue; + } + $seen_from = false; + $previous_was_identifier = false; + $current_select_expr = -1; + $seen_end_of_table_ref = false; + } // end if (data == SELECT) + + if ($upper_data =='FROM' && !$in_extract) { + $current_table_ref = -1; + $seen_from = true; + $previous_was_identifier = false; + $save_table_ref = true; + } // end if (data == FROM) + + // here, do not 'continue' the loop, as we have more work for + // reserved words below + } // end if (type == alpha_reservedWord) + + // ============================== + if ($arr[$i]['type'] == 'quote_backtick' + || $arr[$i]['type'] == 'quote_double' + || $arr[$i]['type'] == 'quote_single' + || $arr[$i]['type'] == 'alpha_identifier' + || ($arr[$i]['type'] == 'alpha_reservedWord' + && $arr[$i]['forbidden'] == false) + ) { + switch ($arr[$i]['type']) { + case 'alpha_identifier': + case 'alpha_reservedWord': + /** + * this is not a real reservedWord, because it's not + * present in the list of forbidden words, for example + * "storage" which can be used as an identifier + * + * @todo avoid the pretty printing in color in this case + */ + $identifier = $arr[$i]['data']; + break; + + case 'quote_backtick': + case 'quote_double': + case 'quote_single': + $identifier = PMA_unQuote($arr[$i]['data']); + break; + } // end switch + + if ($subresult['querytype'] == 'SELECT' + && ! $in_group_concat + && ! ($seen_subquery && $arr[$i - 1]['type'] == 'punct_bracket_close_round') + ) { + if (!$seen_from) { + if ($previous_was_identifier && isset($chain)) { + // found alias for this select_expr, save it + // but only if we got something in $chain + // (for example, SELECT COUNT(*) AS cnt + // puts nothing in $chain, so we avoid + // setting the alias) + $alias_for_select_expr = $identifier; + } else { + $chain[] = $identifier; + $previous_was_identifier = true; + + } // end if !$previous_was_identifier + } else { + // ($seen_from) + if ($save_table_ref && !$seen_end_of_table_ref) { + if ($previous_was_identifier) { + // found alias for table ref + // save it for later + $alias_for_table_ref = $identifier; } else { $chain[] = $identifier; $previous_was_identifier = true; - } // end if !$previous_was_identifier - } else { - // ($seen_from) - if ($save_table_ref && !$seen_end_of_table_ref) { - if ($previous_was_identifier) { - // found alias for table ref - // save it for later - $alias_for_table_ref = $identifier; - } else { - $chain[] = $identifier; - $previous_was_identifier = true; + } // end if ($previous_was_identifier) + } // end if ($save_table_ref &&!$seen_end_of_table_ref) + } // end if (!$seen_from) + } // end if (querytype SELECT) + } // end if (quote_backtick or double quote or alpha_identifier) - } // end if ($previous_was_identifier) - } // end if ($save_table_ref &&!$seen_end_of_table_ref) - } // end if (!$seen_from) - } // end if (querytype SELECT) - } // end if (quote_backtick or double quote or alpha_identifier) + // =================================== + if ($arr[$i]['type'] == 'punct_qualifier') { + // to be able to detect an identifier following another + $previous_was_identifier = false; + continue; + } // end if (punct_qualifier) - // =================================== - if ($arr[$i]['type'] == 'punct_qualifier') { - // to be able to detect an identifier following another - $previous_was_identifier = false; - continue; - } // end if (punct_qualifier) + /** + * @todo check if 3 identifiers following one another -> error + */ - /** - * @todo check if 3 identifiers following one another -> error - */ + // s a v e a s e l e c t e x p r + // finding a list separator or FROM + // means that we must save the current chain of identifiers + // into a select expression - // s a v e a s e l e c t e x p r - // finding a list separator or FROM - // means that we must save the current chain of identifiers - // into a select expression + // for now, we only save a select expression if it contains + // at least one identifier, as we are interested in checking + // the columns and table names, so in "select * from persons", + // the "*" is not saved - // for now, we only save a select expression if it contains - // at least one identifier, as we are interested in checking - // the columns and table names, so in "select * from persons", - // the "*" is not saved + if (isset($chain) && !$seen_end_of_table_ref + && ((!$seen_from && $arr[$i]['type'] == 'punct_listsep') + || ($arr[$i]['type'] == 'alpha_reservedWord' && $upper_data == 'FROM')) + ) { + $size_chain = count($chain); + $current_select_expr++; + $subresult['select_expr'][$current_select_expr] = array( + 'expr' => '', + 'alias' => '', + 'db' => '', + 'table_name' => '', + 'table_true_name' => '', + 'column' => '' + ); - if (isset($chain) && !$seen_end_of_table_ref - && ((!$seen_from && $arr[$i]['type'] == 'punct_listsep') - || ($arr[$i]['type'] == 'alpha_reservedWord' && $upper_data == 'FROM')) - ) { - $size_chain = count($chain); - $current_select_expr++; - $subresult['select_expr'][$current_select_expr] = array( - 'expr' => '', - 'alias' => '', - 'db' => '', - 'table_name' => '', - 'table_true_name' => '', - 'column' => '' - ); + if (isset($alias_for_select_expr) && strlen($alias_for_select_expr)) { + // we had found an alias for this select expression + $subresult['select_expr'][$current_select_expr]['alias'] = $alias_for_select_expr; + unset($alias_for_select_expr); + } + // there is at least a column + $subresult['select_expr'][$current_select_expr]['column'] = $chain[$size_chain - 1]; + $subresult['select_expr'][$current_select_expr]['expr'] = $chain[$size_chain - 1]; - if (isset($alias_for_select_expr) && strlen($alias_for_select_expr)) { - // we had found an alias for this select expression - $subresult['select_expr'][$current_select_expr]['alias'] = $alias_for_select_expr; - unset($alias_for_select_expr); - } - // there is at least a column - $subresult['select_expr'][$current_select_expr]['column'] = $chain[$size_chain - 1]; - $subresult['select_expr'][$current_select_expr]['expr'] = $chain[$size_chain - 1]; - - // maybe a table - if ($size_chain > 1) { - $subresult['select_expr'][$current_select_expr]['table_name'] = $chain[$size_chain - 2]; - // we assume for now that this is also the true name - $subresult['select_expr'][$current_select_expr]['table_true_name'] = $chain[$size_chain - 2]; - $subresult['select_expr'][$current_select_expr]['expr'] - = $subresult['select_expr'][$current_select_expr]['table_name'] - . '.' . $subresult['select_expr'][$current_select_expr]['expr']; - } // end if ($size_chain > 1) - - // maybe a db - if ($size_chain > 2) { - $subresult['select_expr'][$current_select_expr]['db'] = $chain[$size_chain - 3]; - $subresult['select_expr'][$current_select_expr]['expr'] - = $subresult['select_expr'][$current_select_expr]['db'] - . '.' . $subresult['select_expr'][$current_select_expr]['expr']; - } // end if ($size_chain > 2) - unset($chain); - - /** - * @todo explain this: - */ - if (($arr[$i]['type'] == 'alpha_reservedWord') - && ($upper_data != 'FROM') - ) { - $previous_was_identifier = true; - } - - } // end if (save a select expr) - - - //====================================== - // s a v e a t a b l e r e f - //====================================== - - // maybe we just saw the end of table refs - // but the last table ref has to be saved - // or we are at the last token - // or we just got a reserved word - /** - * @todo there could be another query after this one - */ - - if (isset($chain) && $seen_from && $save_table_ref - && ($arr[$i]['type'] == 'punct_listsep' - || ($arr[$i]['type'] == 'alpha_reservedWord' && $upper_data!="AS") - || $seen_end_of_table_ref - || $i==$size-1) - ) { - - $size_chain = count($chain); - $current_table_ref++; - $subresult['table_ref'][$current_table_ref] = array( - 'expr' => '', - 'db' => '', - 'table_name' => '', - 'table_alias' => '', - 'table_true_name' => '' - ); - if (isset($alias_for_table_ref) && strlen($alias_for_table_ref)) { - $subresult['table_ref'][$current_table_ref]['table_alias'] = $alias_for_table_ref; - unset($alias_for_table_ref); - } - $subresult['table_ref'][$current_table_ref]['table_name'] = $chain[$size_chain - 1]; + // maybe a table + if ($size_chain > 1) { + $subresult['select_expr'][$current_select_expr]['table_name'] = $chain[$size_chain - 2]; // we assume for now that this is also the true name - $subresult['table_ref'][$current_table_ref]['table_true_name'] = $chain[$size_chain - 1]; - $subresult['table_ref'][$current_table_ref]['expr'] - = $subresult['table_ref'][$current_table_ref]['table_name']; - // maybe a db - if ($size_chain > 1) { - $subresult['table_ref'][$current_table_ref]['db'] = $chain[$size_chain - 2]; - $subresult['table_ref'][$current_table_ref]['expr'] - = $subresult['table_ref'][$current_table_ref]['db'] - . '.' . $subresult['table_ref'][$current_table_ref]['expr']; - } // end if ($size_chain > 1) + $subresult['select_expr'][$current_select_expr]['table_true_name'] = $chain[$size_chain - 2]; + $subresult['select_expr'][$current_select_expr]['expr'] + = $subresult['select_expr'][$current_select_expr]['table_name'] + . '.' . $subresult['select_expr'][$current_select_expr]['expr']; + } // end if ($size_chain > 1) - // add the table alias into the whole expression - $subresult['table_ref'][$current_table_ref]['expr'] - .= ' ' . $subresult['table_ref'][$current_table_ref]['table_alias']; + // maybe a db + if ($size_chain > 2) { + $subresult['select_expr'][$current_select_expr]['db'] = $chain[$size_chain - 3]; + $subresult['select_expr'][$current_select_expr]['expr'] + = $subresult['select_expr'][$current_select_expr]['db'] + . '.' . $subresult['select_expr'][$current_select_expr]['expr']; + } // end if ($size_chain > 2) + unset($chain); - unset($chain); - $previous_was_identifier = true; - //continue; - - } // end if (save a table ref) - - - // when we have found all table refs, - // for each table_ref alias, put the true name of the table - // in the corresponding select expressions - - if (isset($current_table_ref) && ($seen_end_of_table_ref || $i == $size-1) && $subresult != $subresult_empty) { - for ($tr=0; $tr <= $current_table_ref; $tr++) { - $alias = $subresult['table_ref'][$tr]['table_alias']; - $truename = $subresult['table_ref'][$tr]['table_true_name']; - for ($se=0; $se <= $current_select_expr; $se++) { - if (isset($alias) - && strlen($alias) - && $subresult['select_expr'][$se]['table_true_name'] == $alias - ) { - $subresult['select_expr'][$se]['table_true_name'] = $truename; - } // end if (found the alias) - } // end for (select expressions) - - } // end for (table refs) - } // end if (set the true names) - - - // e n d i n g l o o p #1 - // set the $previous_was_identifier to false if the current - // token is not an identifier - if (($arr[$i]['type'] != 'alpha_identifier') - && ($arr[$i]['type'] != 'quote_double') - && ($arr[$i]['type'] != 'quote_single') - && ($arr[$i]['type'] != 'quote_backtick') - ) { - $previous_was_identifier = false; - } // end if - - // however, if we are on AS, we must keep the $previous_was_identifier + /** + * @todo explain this: + */ if (($arr[$i]['type'] == 'alpha_reservedWord') - && ($upper_data == 'AS') + && ($upper_data != 'FROM') ) { $previous_was_identifier = true; } - if (($arr[$i]['type'] == 'alpha_reservedWord') - && ($upper_data =='ON' || $upper_data =='USING') + } // end if (save a select expr) + + + //====================================== + // s a v e a t a b l e r e f + //====================================== + + // maybe we just saw the end of table refs + // but the last table ref has to be saved + // or we are at the last token + // or we just got a reserved word + /** + * @todo there could be another query after this one + */ + + if (isset($chain) && $seen_from && $save_table_ref + && ($arr[$i]['type'] == 'punct_listsep' + || ($arr[$i]['type'] == 'alpha_reservedWord' && $upper_data!="AS") + || $seen_end_of_table_ref + || $i==$size-1) + ) { + + $size_chain = count($chain); + $current_table_ref++; + $subresult['table_ref'][$current_table_ref] = array( + 'expr' => '', + 'db' => '', + 'table_name' => '', + 'table_alias' => '', + 'table_true_name' => '' + ); + if (isset($alias_for_table_ref) && strlen($alias_for_table_ref)) { + $subresult['table_ref'][$current_table_ref]['table_alias'] = $alias_for_table_ref; + unset($alias_for_table_ref); + } + $subresult['table_ref'][$current_table_ref]['table_name'] = $chain[$size_chain - 1]; + // we assume for now that this is also the true name + $subresult['table_ref'][$current_table_ref]['table_true_name'] = $chain[$size_chain - 1]; + $subresult['table_ref'][$current_table_ref]['expr'] + = $subresult['table_ref'][$current_table_ref]['table_name']; + // maybe a db + if ($size_chain > 1) { + $subresult['table_ref'][$current_table_ref]['db'] = $chain[$size_chain - 2]; + $subresult['table_ref'][$current_table_ref]['expr'] + = $subresult['table_ref'][$current_table_ref]['db'] + . '.' . $subresult['table_ref'][$current_table_ref]['expr']; + } // end if ($size_chain > 1) + + // add the table alias into the whole expression + $subresult['table_ref'][$current_table_ref]['expr'] + .= ' ' . $subresult['table_ref'][$current_table_ref]['table_alias']; + + unset($chain); + $previous_was_identifier = true; + //continue; + + } // end if (save a table ref) + + + // when we have found all table refs, + // for each table_ref alias, put the true name of the table + // in the corresponding select expressions + + if (isset($current_table_ref) && ($seen_end_of_table_ref || $i == $size-1) && $subresult != $subresult_empty) { + for ($tr=0; $tr <= $current_table_ref; $tr++) { + $alias = $subresult['table_ref'][$tr]['table_alias']; + $truename = $subresult['table_ref'][$tr]['table_true_name']; + for ($se=0; $se <= $current_select_expr; $se++) { + if (isset($alias) + && strlen($alias) + && $subresult['select_expr'][$se]['table_true_name'] == $alias + ) { + $subresult['select_expr'][$se]['table_true_name'] = $truename; + } // end if (found the alias) + } // end for (select expressions) + + } // end for (table refs) + } // end if (set the true names) + + + // e n d i n g l o o p #1 + // set the $previous_was_identifier to false if the current + // token is not an identifier + if (($arr[$i]['type'] != 'alpha_identifier') + && ($arr[$i]['type'] != 'quote_double') + && ($arr[$i]['type'] != 'quote_single') + && ($arr[$i]['type'] != 'quote_backtick') + ) { + $previous_was_identifier = false; + } // end if + + // however, if we are on AS, we must keep the $previous_was_identifier + if (($arr[$i]['type'] == 'alpha_reservedWord') + && ($upper_data == 'AS') + ) { + $previous_was_identifier = true; + } + + if (($arr[$i]['type'] == 'alpha_reservedWord') + && ($upper_data =='ON' || $upper_data =='USING') + ) { + $save_table_ref = false; + } // end if (data == ON) + + if (($arr[$i]['type'] == 'alpha_reservedWord') + && ($upper_data =='JOIN' || $upper_data =='FROM') + ) { + $save_table_ref = true; + } // end if (data == JOIN) + + /** + * no need to check the end of table ref if we already did + * + * @todo maybe add "&& $seen_from" + */ + if (!$seen_end_of_table_ref) { + // if this is the last token, it implies that we have + // seen the end of table references + // Check for the end of table references + // + // Note: if we are analyzing a GROUP_CONCAT clause, + // we might find a word that seems to indicate that + // we have found the end of table refs (like ORDER) + // but it's a modifier of the GROUP_CONCAT so + // it's not the real end of table refs + if (($i == $size-1) + || ($arr[$i]['type'] == 'alpha_reservedWord' + && !$in_group_concat + && isset($words_ending_table_ref[$upper_data])) ) { - $save_table_ref = false; - } // end if (data == ON) + $seen_end_of_table_ref = true; + // to be able to save the last table ref, but do not + // set it true if we found a word like "ON" that has + // already set it to false + if (isset($save_table_ref) && $save_table_ref != false) { + $save_table_ref = true; + } //end if - if (($arr[$i]['type'] == 'alpha_reservedWord') - && ($upper_data =='JOIN' || $upper_data =='FROM') - ) { - $save_table_ref = true; - } // end if (data == JOIN) + } // end if (check for end of table ref) + } //end if (!$seen_end_of_table_ref) - /** - * no need to check the end of table ref if we already did - * - * @todo maybe add "&& $seen_from" - */ - if (!$seen_end_of_table_ref) { - // if this is the last token, it implies that we have - // seen the end of table references - // Check for the end of table references - // - // Note: if we are analyzing a GROUP_CONCAT clause, - // we might find a word that seems to indicate that - // we have found the end of table refs (like ORDER) - // but it's a modifier of the GROUP_CONCAT so - // it's not the real end of table refs - if (($i == $size-1) - || ($arr[$i]['type'] == 'alpha_reservedWord' - && !$in_group_concat - && isset($words_ending_table_ref[$upper_data])) - ) { - $seen_end_of_table_ref = true; - // to be able to save the last table ref, but do not - // set it true if we found a word like "ON" that has - // already set it to false - if (isset($save_table_ref) && $save_table_ref != false) { - $save_table_ref = true; - } //end if + if ($seen_end_of_table_ref) { + $save_table_ref = false; + } // end if - } // end if (check for end of table ref) - } //end if (!$seen_end_of_table_ref) + } // end for $i (loop #1) - if ($seen_end_of_table_ref) { - $save_table_ref = false; - } // end if + //DEBUG + /* + if (isset($current_select_expr)) { + for ($trace=0; $trace<=$current_select_expr; $trace++) { + echo "
"; + reset ($subresult['select_expr'][$trace]); + while (list ($key, $val) = each ($subresult['select_expr'][$trace])) + echo "sel expr $trace $key => $val
\n"; + } + } - } // end for $i (loop #1) + if (isset($current_table_ref)) { + echo "current_table_ref = " . $current_table_ref . "
"; + for ($trace=0; $trace<=$current_table_ref; $trace++) { - //DEBUG - /* - if (isset($current_select_expr)) { - for ($trace=0; $trace<=$current_select_expr; $trace++) { - echo "
"; - reset ($subresult['select_expr'][$trace]); - while (list ($key, $val) = each ($subresult['select_expr'][$trace])) - echo "sel expr $trace $key => $val
\n"; - } - } - - if (isset($current_table_ref)) { - echo "current_table_ref = " . $current_table_ref . "
"; - for ($trace=0; $trace<=$current_table_ref; $trace++) { - - echo "
"; - reset ($subresult['table_ref'][$trace]); - while (list ($key, $val) = each ($subresult['table_ref'][$trace])) - echo "table ref $trace $key => $val
\n"; - } - } - */ - // ------------------------------------------------------- + echo "
"; + reset ($subresult['table_ref'][$trace]); + while (list ($key, $val) = each ($subresult['table_ref'][$trace])) + echo "table ref $trace $key => $val
\n"; + } + } + */ + // ------------------------------------------------------- - // loop #2: - queryflags - // - querytype (for queries != 'SELECT') - // - section_before_limit, section_after_limit + // loop #2: - queryflags + // - querytype (for queries != 'SELECT') + // - section_before_limit, section_after_limit + // + // we will also need this queryflag in loop 2 + // so set it here + if (isset($current_table_ref) && $current_table_ref > -1) { + $subresult['queryflags']['select_from'] = 1; + } + + $section_before_limit = ''; + $section_after_limit = ''; // truly the section after the limit clause + $seen_reserved_word = false; + $seen_group = false; + $seen_order = false; + $seen_order_by = false; + $in_group_by = false; // true when we are inside the GROUP BY clause + $in_order_by = false; // true when we are inside the ORDER BY clause + $in_having = false; // true when we are inside the HAVING clause + $in_select_expr = false; // true when we are inside the select expr clause + $in_where = false; // true when we are inside the WHERE clause + $seen_limit = false; // true if we have seen a LIMIT clause + $in_limit = false; // true when we are inside the LIMIT clause + $after_limit = false; // true when we are after the LIMIT clause + $in_from = false; // true when we are in the FROM clause + $in_group_concat = false; + $first_reserved_word = ''; + $current_identifier = ''; + $unsorted_query = $arr['raw']; // in case there is no ORDER BY + $number_of_brackets = 0; + $in_subquery = false; + + for ($i = 0; $i < $size; $i++) { + //DEBUG echo "Loop2 " . $arr[$i]['data'] . " (" . $arr[$i]['type'] . ")
"; + + // need_confirm // - // we will also need this queryflag in loop 2 - // so set it here - if (isset($current_table_ref) && $current_table_ref > -1) { - $subresult['queryflags']['select_from'] = 1; + // check for reserved words that will have to generate + // a confirmation request later in sql.php + // the cases are: + // DROP TABLE + // DROP DATABASE + // ALTER TABLE... DROP + // DELETE FROM... + // + // this code is not used for confirmations coming from functions.js + + if ($arr[$i]['type'] == 'punct_bracket_open_round') { + $number_of_brackets++; } - $section_before_limit = ''; - $section_after_limit = ''; // truly the section after the limit clause - $seen_reserved_word = false; - $seen_group = false; - $seen_order = false; - $seen_order_by = false; - $in_group_by = false; // true when we are inside the GROUP BY clause - $in_order_by = false; // true when we are inside the ORDER BY clause - $in_having = false; // true when we are inside the HAVING clause - $in_select_expr = false; // true when we are inside the select expr clause - $in_where = false; // true when we are inside the WHERE clause - $seen_limit = false; // true if we have seen a LIMIT clause - $in_limit = false; // true when we are inside the LIMIT clause - $after_limit = false; // true when we are after the LIMIT clause - $in_from = false; // true when we are in the FROM clause - $in_group_concat = false; - $first_reserved_word = ''; - $current_identifier = ''; - $unsorted_query = $arr['raw']; // in case there is no ORDER BY - $number_of_brackets = 0; - $in_subquery = false; + if ($arr[$i]['type'] == 'punct_bracket_close_round') { + $number_of_brackets--; + if ($number_of_brackets == 0) { + $in_subquery = false; + } + } - for ($i = 0; $i < $size; $i++) { - //DEBUG echo "Loop2 " . $arr[$i]['data'] . " (" . $arr[$i]['type'] . ")
"; + if ($arr[$i]['type'] == 'alpha_reservedWord') { + $upper_data = strtoupper($arr[$i]['data']); - // need_confirm - // - // check for reserved words that will have to generate - // a confirmation request later in sql.php - // the cases are: - // DROP TABLE - // DROP DATABASE - // ALTER TABLE... DROP - // DELETE FROM... - // - // this code is not used for confirmations coming from functions.js - - if ($arr[$i]['type'] == 'punct_bracket_open_round') { - $number_of_brackets++; + if ($upper_data == 'SELECT' && $number_of_brackets > 0) { + $in_subquery = true; } - if ($arr[$i]['type'] == 'punct_bracket_close_round') { - $number_of_brackets--; - if ($number_of_brackets == 0) { - $in_subquery = false; - } - } + if (!$seen_reserved_word) { + $first_reserved_word = $upper_data; + $subresult['querytype'] = $upper_data; + $seen_reserved_word = true; - if ($arr[$i]['type'] == 'alpha_reservedWord') { - $upper_data = strtoupper($arr[$i]['data']); - - if ($upper_data == 'SELECT' && $number_of_brackets > 0) { - $in_subquery = true; - } - - if (!$seen_reserved_word) { - $first_reserved_word = $upper_data; - $subresult['querytype'] = $upper_data; - $seen_reserved_word = true; - - // if the first reserved word is DROP or DELETE, - // we know this is a query that needs to be confirmed - if ($first_reserved_word=='DROP' - || $first_reserved_word == 'DELETE' - || $first_reserved_word == 'TRUNCATE' - ) { - $subresult['queryflags']['need_confirm'] = 1; - } - - if ($first_reserved_word=='SELECT') { - $position_of_first_select = $i; - } - - } else { - if ($upper_data == 'DROP' && $first_reserved_word == 'ALTER') { - $subresult['queryflags']['need_confirm'] = 1; - } - } - - if ($upper_data == 'LIMIT' && ! $in_subquery) { - $section_before_limit = substr($arr['raw'], 0, $arr[$i]['pos'] - 5); - $in_limit = true; - $seen_limit = true; - $limit_clause = ''; - $in_order_by = false; // @todo maybe others to set false - } - - if ($upper_data == 'PROCEDURE') { - $subresult['queryflags']['procedure'] = 1; - $in_limit = false; - $after_limit = true; - } - /** - * @todo set also to false if we find FOR UPDATE or LOCK IN SHARE MODE - */ - if ($upper_data == 'SELECT') { - $in_select_expr = true; - $select_expr_clause = ''; - } - if ($upper_data == 'DISTINCT' && !$in_group_concat) { - $subresult['queryflags']['distinct'] = 1; - } - - if ($upper_data == 'UNION') { - $subresult['queryflags']['union'] = 1; - } - - if ($upper_data == 'JOIN') { - $subresult['queryflags']['join'] = 1; - } - - if ($upper_data == 'OFFSET') { - $subresult['queryflags']['offset'] = 1; - } - - // if this is a real SELECT...FROM - if ($upper_data == 'FROM' && isset($subresult['queryflags']['select_from']) && $subresult['queryflags']['select_from'] == 1) { - $in_from = true; - $from_clause = ''; - $in_select_expr = false; - } - - - // (we could have less resetting of variables to false - // if we trust that the query respects the standard - // MySQL order for clauses) - - // we use $seen_group and $seen_order because we are looking - // for the BY - if ($upper_data == 'GROUP') { - $seen_group = true; - $seen_order = false; - $in_having = false; - $in_order_by = false; - $in_where = false; - $in_select_expr = false; - $in_from = false; - } - if ($upper_data == 'ORDER' && !$in_group_concat) { - $seen_order = true; - $seen_group = false; - $in_having = false; - $in_group_by = false; - $in_where = false; - $in_select_expr = false; - $in_from = false; - } - if ($upper_data == 'HAVING') { - $in_having = true; - $having_clause = ''; - $seen_group = false; - $seen_order = false; - $in_group_by = false; - $in_order_by = false; - $in_where = false; - $in_select_expr = false; - $in_from = false; - } - - if ($upper_data == 'WHERE') { - $in_where = true; - $where_clause = ''; - $where_clause_identifiers = array(); - $seen_group = false; - $seen_order = false; - $in_group_by = false; - $in_order_by = false; - $in_having = false; - $in_select_expr = false; - $in_from = false; - } - - if ($upper_data == 'BY') { - if ($seen_group) { - $in_group_by = true; - $group_by_clause = ''; - } - if ($seen_order) { - $seen_order_by = true; - // Here we assume that the ORDER BY keywords took - // exactly 8 characters. - // We use PMA_substr() to be charset-safe; otherwise - // if the table name contains accents, the unsorted - // query would be missing some characters. - $unsorted_query = PMA_substr($arr['raw'], 0, $arr[$i]['pos'] - 8); - $in_order_by = true; - $order_by_clause = ''; - } - } - - // if we find one of the words that could end the clause - if (isset($words_ending_clauses[$upper_data])) { - - $in_group_by = false; - $in_order_by = false; - $in_having = false; - $in_where = false; - $in_select_expr = false; - $in_from = false; - } - - } // endif (reservedWord) - - - // do not add a space after a function name - /** - * @todo can we combine loop 2 and loop 1? some code is repeated here... - */ - - $sep = ' '; - if ($arr[$i]['type'] == 'alpha_functionName') { - $sep=''; - $upper_data = strtoupper($arr[$i]['data']); - if ($upper_data =='GROUP_CONCAT') { - $in_group_concat = true; - $number_of_brackets_in_group_concat = 0; - } - } - - if ($arr[$i]['type'] == 'punct_bracket_open_round') { - if ($in_group_concat) { - $number_of_brackets_in_group_concat++; - } - } - if ($arr[$i]['type'] == 'punct_bracket_close_round') { - if ($in_group_concat) { - $number_of_brackets_in_group_concat--; - if ($number_of_brackets_in_group_concat == 0) { - $in_group_concat = false; - } - } - } - - // do not add a space after an identifier if followed by a dot - if ($arr[$i]['type'] == 'alpha_identifier' && $i < $size - 1 && $arr[$i + 1]['data'] == '.') { - $sep = ''; - } - - // do not add a space after a dot if followed by an identifier - if ($arr[$i]['data'] == '.' && $i < $size - 1 && $arr[$i + 1]['type'] == 'alpha_identifier') { - $sep = ''; - } - - if ($in_select_expr && $upper_data != 'SELECT' && $upper_data != 'DISTINCT') { - $select_expr_clause .= $arr[$i]['data'] . $sep; - } - if ($in_from && $upper_data != 'FROM') { - $from_clause .= $arr[$i]['data'] . $sep; - } - if ($in_group_by && $upper_data != 'GROUP' && $upper_data != 'BY') { - $group_by_clause .= $arr[$i]['data'] . $sep; - } - if ($in_order_by && $upper_data != 'ORDER' && $upper_data != 'BY') { - // add a space only before ASC or DESC - // not around the dot between dbname and tablename - if ($arr[$i]['type'] == 'alpha_reservedWord') { - $order_by_clause .= $sep; - } - $order_by_clause .= $arr[$i]['data']; - } - if ($in_having && $upper_data != 'HAVING') { - $having_clause .= $arr[$i]['data'] . $sep; - } - if ($in_where && $upper_data != 'WHERE') { - $where_clause .= $arr[$i]['data'] . $sep; - - if (($arr[$i]['type'] == 'quote_backtick') - || ($arr[$i]['type'] == 'alpha_identifier') + // if the first reserved word is DROP or DELETE, + // we know this is a query that needs to be confirmed + if ($first_reserved_word=='DROP' + || $first_reserved_word == 'DELETE' + || $first_reserved_word == 'TRUNCATE' ) { - $where_clause_identifiers[] = $arr[$i]['data']; - } - } - - // to grab the rest of the query after the ORDER BY clause - if (isset($subresult['queryflags']['select_from']) - && $subresult['queryflags']['select_from'] == 1 - && ! $in_order_by - && $seen_order_by - && $upper_data != 'BY' - ) { - $unsorted_query .= $arr[$i]['data']; - if ($arr[$i]['type'] != 'punct_bracket_open_round' - && $arr[$i]['type'] != 'punct_bracket_close_round' - && $arr[$i]['type'] != 'punct' - ) { - $unsorted_query .= $sep; - } - } - - if ($in_limit) { - if ($upper_data == 'OFFSET') { - $limit_clause .= $sep; - } - $limit_clause .= $arr[$i]['data']; - if ($upper_data == 'LIMIT' || $upper_data == 'OFFSET') { - $limit_clause .= $sep; - } - } - if ($after_limit && $seen_limit) { - $section_after_limit .= $arr[$i]['data'] . $sep; - } - - // clear $upper_data for next iteration - $upper_data=''; - } // end for $i (loop #2) - if (empty($section_before_limit)) { - $section_before_limit = $arr['raw']; - } - - // ----------------------------------------------------- - // loop #3: foreign keys and MySQL 4.1.2+ TIMESTAMP options - // (for now, check only the first query) - // (for now, identifiers are assumed to be backquoted) - - // If we find that we are dealing with a CREATE TABLE query, - // we look for the next punct_bracket_open_round, which - // introduces the fields list. Then, when we find a - // quote_backtick, it must be a field, so we put it into - // the create_table_fields array. Even if this field is - // not a timestamp, it will be useful when logic has been - // added for complete field attributes analysis. - - $seen_foreign = false; - $seen_references = false; - $seen_constraint = false; - $foreign_key_number = -1; - $seen_create_table = false; - $seen_create = false; - $seen_alter = false; - $in_create_table_fields = false; - $brackets_level = 0; - $in_timestamp_options = false; - $seen_default = false; - - for ($i = 0; $i < $size; $i++) { - if ($arr[$i]['type'] == 'alpha_reservedWord') { - $upper_data = strtoupper($arr[$i]['data']); - - if ($upper_data == 'NOT' && $in_timestamp_options) { - $create_table_fields[$current_identifier]['timestamp_not_null'] = true; - + $subresult['queryflags']['need_confirm'] = 1; } - if ($upper_data == 'CREATE') { - $seen_create = true; + if ($first_reserved_word=='SELECT') { + $position_of_first_select = $i; } - if ($upper_data == 'ALTER') { - $seen_alter = true; - } - - if ($upper_data == 'TABLE' && $seen_create) { - $seen_create_table = true; - $create_table_fields = array(); - } - - if ($upper_data == 'CURRENT_TIMESTAMP') { - if ($in_timestamp_options) { - if ($seen_default) { - $create_table_fields[$current_identifier]['default_current_timestamp'] = true; - } - } - } - - if ($upper_data == 'CONSTRAINT') { - $foreign_key_number++; - $seen_foreign = false; - $seen_references = false; - $seen_constraint = true; - } - if ($upper_data == 'FOREIGN') { - $seen_foreign = true; - $seen_references = false; - $seen_constraint = false; - } - if ($upper_data == 'REFERENCES') { - $seen_foreign = false; - $seen_references = true; - $seen_constraint = false; - } - - - // Cases covered: - - // [ON DELETE {CASCADE | SET NULL | NO ACTION | RESTRICT}] - // [ON UPDATE {CASCADE | SET NULL | NO ACTION | RESTRICT}] - - // but we set ['on_delete'] or ['on_cascade'] to - // CASCADE | SET_NULL | NO_ACTION | RESTRICT - - // ON UPDATE CURRENT_TIMESTAMP - - if ($upper_data == 'ON') { - if (isset($arr[$i+1]) && $arr[$i+1]['type'] == 'alpha_reservedWord') { - $second_upper_data = strtoupper($arr[$i+1]['data']); - if ($second_upper_data == 'DELETE') { - $clause = 'on_delete'; - } - if ($second_upper_data == 'UPDATE') { - $clause = 'on_update'; - } - if (isset($clause) - && ($arr[$i+2]['type'] == 'alpha_reservedWord' - - // ugly workaround because currently, NO is not - // in the list of reserved words in sqlparser.data - // (we got a bug report about not being able to use - // 'no' as an identifier) - || ($arr[$i+2]['type'] == 'alpha_identifier' - && strtoupper($arr[$i+2]['data'])=='NO')) - ) { - $third_upper_data = strtoupper($arr[$i+2]['data']); - if ($third_upper_data == 'CASCADE' - || $third_upper_data == 'RESTRICT' - ) { - $value = $third_upper_data; - } elseif ($third_upper_data == 'SET' - || $third_upper_data == 'NO' - ) { - if ($arr[$i+3]['type'] == 'alpha_reservedWord') { - $value = $third_upper_data . '_' . strtoupper($arr[$i+3]['data']); - } - } elseif ($third_upper_data == 'CURRENT_TIMESTAMP') { - if ($clause == 'on_update' - && $in_timestamp_options - ) { - $create_table_fields[$current_identifier]['on_update_current_timestamp'] = true; - $seen_default = false; - } - - } else { - $value = ''; - } - if (!empty($value)) { - $foreign[$foreign_key_number][$clause] = $value; - } - unset($clause); - } // endif (isset($clause)) - } - } - - } // end of reserved words analysis - - - if ($arr[$i]['type'] == 'punct_bracket_open_round') { - $brackets_level++; - if ($seen_create_table && $brackets_level == 1) { - $in_create_table_fields = true; - } - } - - - if ($arr[$i]['type'] == 'punct_bracket_close_round') { - $brackets_level--; - if ($seen_references) { - $seen_references = false; - } - if ($seen_create_table && $brackets_level == 0) { - $in_create_table_fields = false; - } - } - - if (($arr[$i]['type'] == 'alpha_columnAttrib')) { - $upper_data = strtoupper($arr[$i]['data']); - if ($seen_create_table && $in_create_table_fields) { - if ($upper_data == 'DEFAULT') { - $seen_default = true; - $create_table_fields[$current_identifier]['default_value'] = $arr[$i + 1]['data']; - } - } - } - - /** - * @see @todo 2005-10-16 note: the "or" part here is a workaround for a bug - */ - if (($arr[$i]['type'] == 'alpha_columnType') || ($arr[$i]['type'] == 'alpha_functionName' && $seen_create_table)) { - $upper_data = strtoupper($arr[$i]['data']); - if ($seen_create_table && $in_create_table_fields && isset($current_identifier)) { - $create_table_fields[$current_identifier]['type'] = $upper_data; - if ($upper_data == 'TIMESTAMP') { - $arr[$i]['type'] = 'alpha_columnType'; - $in_timestamp_options = true; - } else { - $in_timestamp_options = false; - if ($upper_data == 'CHAR') { - $arr[$i]['type'] = 'alpha_columnType'; - } - } - } - } - - - if ($arr[$i]['type'] == 'quote_backtick' || $arr[$i]['type'] == 'alpha_identifier') { - - if ($arr[$i]['type'] == 'quote_backtick') { - // remove backquotes - $identifier = PMA_unQuote($arr[$i]['data']); - } else { - $identifier = $arr[$i]['data']; - } - - if ($seen_create_table && $in_create_table_fields) { - $current_identifier = $identifier; - // we set this one even for non TIMESTAMP type - $create_table_fields[$current_identifier]['timestamp_not_null'] = false; - } - - if ($seen_constraint) { - $foreign[$foreign_key_number]['constraint'] = $identifier; - } - - if ($seen_foreign && $brackets_level > 0) { - $foreign[$foreign_key_number]['index_list'][] = $identifier; - } - - if ($seen_references) { - if ($seen_alter && $brackets_level > 0) { - $foreign[$foreign_key_number]['ref_index_list'][] = $identifier; - // here, the first bracket level corresponds to the - // bracket of CREATE TABLE - // so if we are on level 2, it must be the index list - // of the foreign key REFERENCES - } elseif ($brackets_level > 1) { - $foreign[$foreign_key_number]['ref_index_list'][] = $identifier; - } elseif ($arr[$i+1]['type'] == 'punct_qualifier') { - // identifier is `db`.`table` - // the first pass will pick the db name - // the next pass will pick the table name - $foreign[$foreign_key_number]['ref_db_name'] = $identifier; - } else { - // identifier is `table` - $foreign[$foreign_key_number]['ref_table_name'] = $identifier; - } - } - } - } // end for $i (loop #3) - - - // Fill the $subresult array - - if (isset($create_table_fields)) { - $subresult['create_table_fields'] = $create_table_fields; - } - - if (isset($foreign)) { - $subresult['foreign_keys'] = $foreign; - } - - if (isset($select_expr_clause)) { - $subresult['select_expr_clause'] = $select_expr_clause; - } - if (isset($from_clause)) { - $subresult['from_clause'] = $from_clause; - } - if (isset($group_by_clause)) { - $subresult['group_by_clause'] = $group_by_clause; - } - if (isset($order_by_clause)) { - $subresult['order_by_clause'] = $order_by_clause; - } - if (isset($having_clause)) { - $subresult['having_clause'] = $having_clause; - } - if (isset($limit_clause)) { - $subresult['limit_clause'] = $limit_clause; - } - if (isset($where_clause)) { - $subresult['where_clause'] = $where_clause; - } - if (isset($unsorted_query) && !empty($unsorted_query)) { - $subresult['unsorted_query'] = $unsorted_query; - } - if (isset($where_clause_identifiers)) { - $subresult['where_clause_identifiers'] = $where_clause_identifiers; - } - - if (isset($position_of_first_select)) { - $subresult['position_of_first_select'] = $position_of_first_select; - $subresult['section_before_limit'] = $section_before_limit; - $subresult['section_after_limit'] = $section_after_limit; - } - - // They are naughty and didn't have a trailing semi-colon, - // then still handle it properly - if ($subresult['querytype'] != '') { - $result[] = $subresult; - } - return $result; - } // end of the "PMA_SQP_analyze()" function - - - /** - * Colorizes SQL queries html formatted - * - * @todo check why adding a "\n" after the would cause extra blanks - * to be displayed: SELECT p . person_name - * @param array The SQL queries html formatted - * - * @return array The colorized SQL queries - * - * @access public - */ - function PMA_SQP_formatHtml_colorize($arr) - { - $i = PMA_strpos($arr['type'], '_'); - $class = ''; - if ($i > 0) { - $class = 'syntax_' . PMA_substr($arr['type'], 0, $i) . ' '; - } - - $class .= 'syntax_' . $arr['type']; - - return '' . htmlspecialchars($arr['data']) . ''; - } // end of the "PMA_SQP_formatHtml_colorize()" function - - - /** - * Formats SQL queries to html - * - * @param array The SQL queries - * @param string mode - * @param integer starting token - * @param integer number of tokens to format, -1 = all - * - * @return string The formatted SQL queries - * - * @access public - */ - function PMA_SQP_formatHtml( - $arr, $mode='color', $start_token=0, - $number_of_tokens=-1 - ) { - global $PMA_SQPdata_operators_docs, $PMA_SQPdata_functions_docs; - //DEBUG echo 'in Format
'; print_r($arr); echo '
'; - // then check for an array - if (! is_array($arr)) { - return htmlspecialchars($arr); - } - // first check for the SQL parser having hit an error - if (PMA_SQP_isError()) { - return htmlspecialchars($arr['raw']); - } - // else do it properly - switch ($mode) { - case 'color': - $str = ''; - $html_line_break = '
'; - $docu = true; - break; - case 'query_only': - $str = ''; - $html_line_break = "\n"; - $docu = false; - break; - case 'text': - $str = ''; - $html_line_break = '
'; - $docu = true; - break; - } // end switch - // inner_sql is a span that exists for all cases, except query_only - // of $cfg['SQP']['fmtType'] to make possible a replacement - // for inline editing - if ($mode!='query_only') { - $str .= ''; - } - $close_docu_link = false; - $indent = 0; - $bracketlevel = 0; - $functionlevel = 0; - $infunction = false; - $space_punct_listsep = ' '; - $space_punct_listsep_function_name = ' '; - // $space_alpha_reserved_word = '
'."\n"; - $space_alpha_reserved_word = ' '; - - $keywords_with_brackets_1before = array( - 'INDEX' => 1, - 'KEY' => 1, - 'ON' => 1, - 'USING' => 1 - ); - - $keywords_with_brackets_2before = array( - 'IGNORE' => 1, - 'INDEX' => 1, - 'INTO' => 1, - 'KEY' => 1, - 'PRIMARY' => 1, - 'PROCEDURE' => 1, - 'REFERENCES' => 1, - 'UNIQUE' => 1, - 'USE' => 1 - ); - - // These reserved words do NOT get a newline placed near them. - $keywords_no_newline = array( - 'AS' => 1, - 'ASC' => 1, - 'DESC' => 1, - 'DISTINCT' => 1, - 'DUPLICATE' => 1, - 'HOUR' => 1, - 'INTERVAL' => 1, - 'IS' => 1, - 'LIKE' => 1, - 'NOT' => 1, - 'NULL' => 1, - 'ON' => 1, - 'REGEXP' => 1 - ); - - // These reserved words introduce a privilege list - $keywords_priv_list = array( - 'GRANT' => 1, - 'REVOKE' => 1 - ); - - if ($number_of_tokens == -1) { - $number_of_tokens = $arr['len']; - } - $typearr = array(); - if ($number_of_tokens >= 0) { - $typearr[0] = ''; - $typearr[1] = ''; - $typearr[2] = ''; - $typearr[3] = $arr[$start_token]['type']; - } - - $in_priv_list = false; - for ($i = $start_token; $i < $number_of_tokens; $i++) { - // DEBUG echo "Loop format " . $arr[$i]['data'] . " " . $arr[$i]['type'] . "
"; - $before = ''; - $after = ''; - // array_shift($typearr); - /* - 0 prev2 - 1 prev - 2 current - 3 next - */ - if (($i + 1) < $number_of_tokens) { - $typearr[4] = $arr[$i + 1]['type']; } else { - $typearr[4] = ''; + if ($upper_data == 'DROP' && $first_reserved_word == 'ALTER') { + $subresult['queryflags']['need_confirm'] = 1; + } } - for ($j=0; $j<4; $j++) { - $typearr[$j] = $typearr[$j + 1]; + if ($upper_data == 'LIMIT' && ! $in_subquery) { + $section_before_limit = substr($arr['raw'], 0, $arr[$i]['pos'] - 5); + $in_limit = true; + $seen_limit = true; + $limit_clause = ''; + $in_order_by = false; // @todo maybe others to set false } - switch ($typearr[2]) { - case 'alpha_bitfield_constant_introducer': - $before = ' '; - $after = ''; - break; - case 'white_newline': - $before = ''; - break; - case 'punct_bracket_open_round': - $bracketlevel++; - $infunction = false; - // Make sure this array is sorted! - if (($typearr[1] == 'alpha_functionName') || ($typearr[1] == 'alpha_columnType') || ($typearr[1] == 'punct') - || ($typearr[3] == 'digit_integer') || ($typearr[3] == 'digit_hex') || ($typearr[3] == 'digit_float') - || (($typearr[0] == 'alpha_reservedWord') - && isset($keywords_with_brackets_2before[strtoupper($arr[$i - 2]['data'])])) - || (($typearr[1] == 'alpha_reservedWord') - && isset($keywords_with_brackets_1before[strtoupper($arr[$i - 1]['data'])])) - ) { - $functionlevel++; - $infunction = true; - $after .= ' '; - } else { - $indent++; - $after .= ($mode != 'query_only' ? '
' : ' '); - } - break; - case 'alpha_identifier': - if (($typearr[1] == 'punct_qualifier') || ($typearr[3] == 'punct_qualifier')) { - $after = ''; - $before = ''; - } - // for example SELECT 1 somealias - if ($typearr[1] == 'digit_integer') { - $before = ' '; - } - if (($typearr[3] == 'alpha_columnType') || ($typearr[3] == 'alpha_identifier')) { - $after .= ' '; - } - break; - case 'punct_user': - case 'punct_qualifier': - $before = ''; - $after = ''; - break; - case 'punct_listsep': - if ($infunction == true) { - $after .= $space_punct_listsep_function_name; - } else { - $after .= $space_punct_listsep; - } - break; - case 'punct_queryend': - if (($typearr[3] != 'comment_mysql') && ($typearr[3] != 'comment_ansi') && $typearr[3] != 'comment_c') { - $after .= $html_line_break; - $after .= $html_line_break; - } - $space_punct_listsep = ' '; - $space_punct_listsep_function_name = ' '; - $space_alpha_reserved_word = ' '; - $in_priv_list = false; - break; - case 'comment_mysql': - case 'comment_ansi': - $after .= $html_line_break; - break; - case 'punct': - $before .= ' '; - if ($docu && isset($PMA_SQPdata_operators_docs[$arr[$i]['data']]) - && ($arr[$i]['data'] != '*' || in_array($arr[$i]['type'], array('digit_integer','digit_float','digit_hex'))) - ) { - $before .= PMA_showMySQLDocu( - 'functions', - $PMA_SQPdata_operators_docs[$arr[$i]['data']]['link'], - false, - $PMA_SQPdata_operators_docs[$arr[$i]['data']]['anchor'], - true - ); - $after .= ''; - } + if ($upper_data == 'PROCEDURE') { + $subresult['queryflags']['procedure'] = 1; + $in_limit = false; + $after_limit = true; + } + /** + * @todo set also to false if we find FOR UPDATE or LOCK IN SHARE MODE + */ + if ($upper_data == 'SELECT') { + $in_select_expr = true; + $select_expr_clause = ''; + } + if ($upper_data == 'DISTINCT' && !$in_group_concat) { + $subresult['queryflags']['distinct'] = 1; + } - // workaround for - // select * from mytable limit 0,-1 - // (a side effect of this workaround is that - // select 20 - 9 - // becomes - // select 20 -9 - // ) - if ($typearr[3] != 'digit_integer') { - $after .= ' '; - } - break; - case 'punct_bracket_close_round': - // only close bracket level when it was opened before - if ($bracketlevel > 0) { - $bracketlevel--; - if ($infunction == true) { - $functionlevel--; - $after .= ' '; - $before .= ' '; - } else { - $indent--; - $before .= ($mode != 'query_only' ? '
' : ' '); - } - $infunction = ($functionlevel > 0) ? true : false; - } - break; - case 'alpha_columnType': - if ($docu) { - switch ($arr[$i]['data']) { - case 'tinyint': - case 'smallint': - case 'mediumint': - case 'int': - case 'bigint': - case 'decimal': - case 'float': - case 'double': - case 'real': - case 'bit': - case 'boolean': - case 'serial': - $before .= PMA_showMySQLDocu('data-types', 'numeric-types', false, '', true); - $after = '' . $after; - break; - case 'date': - case 'datetime': - case 'timestamp': - case 'time': - case 'year': - $before .= PMA_showMySQLDocu('data-types', 'date-and-time-types', false, '', true); - $after = '' . $after; - break; - case 'char': - case 'varchar': - case 'tinytext': - case 'text': - case 'mediumtext': - case 'longtext': - case 'binary': - case 'varbinary': - case 'tinyblob': - case 'mediumblob': - case 'blob': - case 'longblob': - case 'enum': - case 'set': - $before .= PMA_showMySQLDocu('data-types', 'string-types', false, '', true); - $after = '' . $after; - break; - } - } - if ($typearr[3] == 'alpha_columnAttrib') { - $after .= ' '; - } - if ($typearr[1] == 'alpha_columnType') { - $before .= ' '; - } - break; - case 'alpha_columnAttrib': + if ($upper_data == 'UNION') { + $subresult['queryflags']['union'] = 1; + } - // ALTER TABLE tbl_name AUTO_INCREMENT = 1 - // COLLATE LATIN1_GENERAL_CI DEFAULT - if ($typearr[1] == 'alpha_identifier' || $typearr[1] == 'alpha_charset') { - $before .= ' '; - } - if (($typearr[3] == 'alpha_columnAttrib') || ($typearr[3] == 'quote_single') || ($typearr[3] == 'digit_integer')) { - $after .= ' '; - } - // workaround for - // AUTO_INCREMENT = 31DEFAULT_CHARSET = utf-8 + if ($upper_data == 'JOIN') { + $subresult['queryflags']['join'] = 1; + } - if ($typearr[2] == 'alpha_columnAttrib' && $typearr[3] == 'alpha_reservedWord') { - $before .= ' '; - } - // workaround for - // select * from mysql.user where binary user="root" - // binary is marked as alpha_columnAttrib - // but should be marked as a reserved word - if (strtoupper($arr[$i]['data']) == 'BINARY' - && $typearr[3] == 'alpha_identifier' - ) { - $after .= ' '; - } - break; - case 'alpha_functionName': - $funcname = strtoupper($arr[$i]['data']); - if ($docu && isset($PMA_SQPdata_functions_docs[$funcname])) { - $before .= PMA_showMySQLDocu( - 'functions', - $PMA_SQPdata_functions_docs[$funcname]['link'], - false, - $PMA_SQPdata_functions_docs[$funcname]['anchor'], - true - ); - $after .= ''; - } - break; - case 'alpha_reservedWord': - // do not uppercase the reserved word if we are calling - // this function in query_only mode, because we need - // the original query (otherwise we get problems with - // semi-reserved words like "storage" which is legal - // as an identifier name) + if ($upper_data == 'OFFSET') { + $subresult['queryflags']['offset'] = 1; + } - if ($mode != 'query_only') { - $arr[$i]['data'] = strtoupper($arr[$i]['data']); + // if this is a real SELECT...FROM + if ($upper_data == 'FROM' && isset($subresult['queryflags']['select_from']) && $subresult['queryflags']['select_from'] == 1) { + $in_from = true; + $from_clause = ''; + $in_select_expr = false; + } + + + // (we could have less resetting of variables to false + // if we trust that the query respects the standard + // MySQL order for clauses) + + // we use $seen_group and $seen_order because we are looking + // for the BY + if ($upper_data == 'GROUP') { + $seen_group = true; + $seen_order = false; + $in_having = false; + $in_order_by = false; + $in_where = false; + $in_select_expr = false; + $in_from = false; + } + if ($upper_data == 'ORDER' && !$in_group_concat) { + $seen_order = true; + $seen_group = false; + $in_having = false; + $in_group_by = false; + $in_where = false; + $in_select_expr = false; + $in_from = false; + } + if ($upper_data == 'HAVING') { + $in_having = true; + $having_clause = ''; + $seen_group = false; + $seen_order = false; + $in_group_by = false; + $in_order_by = false; + $in_where = false; + $in_select_expr = false; + $in_from = false; + } + + if ($upper_data == 'WHERE') { + $in_where = true; + $where_clause = ''; + $where_clause_identifiers = array(); + $seen_group = false; + $seen_order = false; + $in_group_by = false; + $in_order_by = false; + $in_having = false; + $in_select_expr = false; + $in_from = false; + } + + if ($upper_data == 'BY') { + if ($seen_group) { + $in_group_by = true; + $group_by_clause = ''; } - - if ((($typearr[1] != 'alpha_reservedWord') - || (($typearr[1] == 'alpha_reservedWord') - && isset($keywords_no_newline[strtoupper($arr[$i - 1]['data'])]))) - && ($typearr[1] != 'punct_level_plus') - && (!isset($keywords_no_newline[$arr[$i]['data']])) - ) { - // do not put a space before the first token, because - // we use a lot of pattern matching checking for the - // first reserved word at beginning of query - // so do not put a newline before - // - // also we must not be inside a privilege list - if ($i > 0) { - // the alpha_identifier exception is there to - // catch cases like - // GRANT SELECT ON mydb.mytable TO myuser@localhost - // (else, we get mydb.mytableTO) - // - // the quote_single exception is there to - // catch cases like - // GRANT ... TO 'marc'@'domain.com' IDENTIFIED... - /** - * @todo fix all cases and find why this happens - */ - - if (!$in_priv_list || $typearr[1] == 'alpha_identifier' || $typearr[1] == 'quote_single' || $typearr[1] == 'white_newline') { - $before .= $space_alpha_reserved_word; - } - } else { - // on first keyword, check if it introduces a - // privilege list - if (isset($keywords_priv_list[$arr[$i]['data']])) { - $in_priv_list = true; - } - } - } else { - $before .= ' '; + if ($seen_order) { + $seen_order_by = true; + // Here we assume that the ORDER BY keywords took + // exactly 8 characters. + // We use PMA_substr() to be charset-safe; otherwise + // if the table name contains accents, the unsorted + // query would be missing some characters. + $unsorted_query = PMA_substr($arr['raw'], 0, $arr[$i]['pos'] - 8); + $in_order_by = true; + $order_by_clause = ''; } + } - switch ($arr[$i]['data']) { - case 'CREATE': - case 'ALTER': - case 'DROP': - case 'RENAME'; - case 'TRUNCATE': - case 'ANALYZE': - case 'ANALYSE': - case 'OPTIMIZE': - if ($docu) { - switch ($arr[$i + 1]['data']) { - case 'EVENT': - case 'TABLE': - case 'TABLESPACE': - case 'FUNCTION': - case 'INDEX': - case 'PROCEDURE': - case 'TRIGGER': - case 'SERVER': - case 'DATABASE': - case 'VIEW': - $before .= PMA_showMySQLDocu('SQL-Syntax', $arr[$i]['data'] . '_' . $arr[$i + 1]['data'], false, '', true); - $close_docu_link = true; - break; - } - if ($arr[$i + 1]['data'] == 'LOGFILE' && $arr[$i + 2]['data'] == 'GROUP') { - $before .= PMA_showMySQLDocu('SQL-Syntax', $arr[$i]['data'] . '_LOGFILE_GROUP', false, '', true); - $close_docu_link = true; - } + // if we find one of the words that could end the clause + if (isset($words_ending_clauses[$upper_data])) { + + $in_group_by = false; + $in_order_by = false; + $in_having = false; + $in_where = false; + $in_select_expr = false; + $in_from = false; + } + + } // endif (reservedWord) + + + // do not add a space after a function name + /** + * @todo can we combine loop 2 and loop 1? some code is repeated here... + */ + + $sep = ' '; + if ($arr[$i]['type'] == 'alpha_functionName') { + $sep=''; + $upper_data = strtoupper($arr[$i]['data']); + if ($upper_data =='GROUP_CONCAT') { + $in_group_concat = true; + $number_of_brackets_in_group_concat = 0; + } + } + + if ($arr[$i]['type'] == 'punct_bracket_open_round') { + if ($in_group_concat) { + $number_of_brackets_in_group_concat++; + } + } + if ($arr[$i]['type'] == 'punct_bracket_close_round') { + if ($in_group_concat) { + $number_of_brackets_in_group_concat--; + if ($number_of_brackets_in_group_concat == 0) { + $in_group_concat = false; + } + } + } + + // do not add a space after an identifier if followed by a dot + if ($arr[$i]['type'] == 'alpha_identifier' && $i < $size - 1 && $arr[$i + 1]['data'] == '.') { + $sep = ''; + } + + // do not add a space after a dot if followed by an identifier + if ($arr[$i]['data'] == '.' && $i < $size - 1 && $arr[$i + 1]['type'] == 'alpha_identifier') { + $sep = ''; + } + + if ($in_select_expr && $upper_data != 'SELECT' && $upper_data != 'DISTINCT') { + $select_expr_clause .= $arr[$i]['data'] . $sep; + } + if ($in_from && $upper_data != 'FROM') { + $from_clause .= $arr[$i]['data'] . $sep; + } + if ($in_group_by && $upper_data != 'GROUP' && $upper_data != 'BY') { + $group_by_clause .= $arr[$i]['data'] . $sep; + } + if ($in_order_by && $upper_data != 'ORDER' && $upper_data != 'BY') { + // add a space only before ASC or DESC + // not around the dot between dbname and tablename + if ($arr[$i]['type'] == 'alpha_reservedWord') { + $order_by_clause .= $sep; + } + $order_by_clause .= $arr[$i]['data']; + } + if ($in_having && $upper_data != 'HAVING') { + $having_clause .= $arr[$i]['data'] . $sep; + } + if ($in_where && $upper_data != 'WHERE') { + $where_clause .= $arr[$i]['data'] . $sep; + + if (($arr[$i]['type'] == 'quote_backtick') + || ($arr[$i]['type'] == 'alpha_identifier') + ) { + $where_clause_identifiers[] = $arr[$i]['data']; + } + } + + // to grab the rest of the query after the ORDER BY clause + if (isset($subresult['queryflags']['select_from']) + && $subresult['queryflags']['select_from'] == 1 + && ! $in_order_by + && $seen_order_by + && $upper_data != 'BY' + ) { + $unsorted_query .= $arr[$i]['data']; + if ($arr[$i]['type'] != 'punct_bracket_open_round' + && $arr[$i]['type'] != 'punct_bracket_close_round' + && $arr[$i]['type'] != 'punct' + ) { + $unsorted_query .= $sep; + } + } + + if ($in_limit) { + if ($upper_data == 'OFFSET') { + $limit_clause .= $sep; + } + $limit_clause .= $arr[$i]['data']; + if ($upper_data == 'LIMIT' || $upper_data == 'OFFSET') { + $limit_clause .= $sep; + } + } + if ($after_limit && $seen_limit) { + $section_after_limit .= $arr[$i]['data'] . $sep; + } + + // clear $upper_data for next iteration + $upper_data=''; + } // end for $i (loop #2) + if (empty($section_before_limit)) { + $section_before_limit = $arr['raw']; + } + + // ----------------------------------------------------- + // loop #3: foreign keys and MySQL 4.1.2+ TIMESTAMP options + // (for now, check only the first query) + // (for now, identifiers are assumed to be backquoted) + + // If we find that we are dealing with a CREATE TABLE query, + // we look for the next punct_bracket_open_round, which + // introduces the fields list. Then, when we find a + // quote_backtick, it must be a field, so we put it into + // the create_table_fields array. Even if this field is + // not a timestamp, it will be useful when logic has been + // added for complete field attributes analysis. + + $seen_foreign = false; + $seen_references = false; + $seen_constraint = false; + $foreign_key_number = -1; + $seen_create_table = false; + $seen_create = false; + $seen_alter = false; + $in_create_table_fields = false; + $brackets_level = 0; + $in_timestamp_options = false; + $seen_default = false; + + for ($i = 0; $i < $size; $i++) { + if ($arr[$i]['type'] == 'alpha_reservedWord') { + $upper_data = strtoupper($arr[$i]['data']); + + if ($upper_data == 'NOT' && $in_timestamp_options) { + $create_table_fields[$current_identifier]['timestamp_not_null'] = true; + + } + + if ($upper_data == 'CREATE') { + $seen_create = true; + } + + if ($upper_data == 'ALTER') { + $seen_alter = true; + } + + if ($upper_data == 'TABLE' && $seen_create) { + $seen_create_table = true; + $create_table_fields = array(); + } + + if ($upper_data == 'CURRENT_TIMESTAMP') { + if ($in_timestamp_options) { + if ($seen_default) { + $create_table_fields[$current_identifier]['default_current_timestamp'] = true; } - if (!$in_priv_list) { - $space_punct_listsep = $html_line_break; - $space_alpha_reserved_word = ' '; + } + } + + if ($upper_data == 'CONSTRAINT') { + $foreign_key_number++; + $seen_foreign = false; + $seen_references = false; + $seen_constraint = true; + } + if ($upper_data == 'FOREIGN') { + $seen_foreign = true; + $seen_references = false; + $seen_constraint = false; + } + if ($upper_data == 'REFERENCES') { + $seen_foreign = false; + $seen_references = true; + $seen_constraint = false; + } + + + // Cases covered: + + // [ON DELETE {CASCADE | SET NULL | NO ACTION | RESTRICT}] + // [ON UPDATE {CASCADE | SET NULL | NO ACTION | RESTRICT}] + + // but we set ['on_delete'] or ['on_cascade'] to + // CASCADE | SET_NULL | NO_ACTION | RESTRICT + + // ON UPDATE CURRENT_TIMESTAMP + + if ($upper_data == 'ON') { + if (isset($arr[$i+1]) && $arr[$i+1]['type'] == 'alpha_reservedWord') { + $second_upper_data = strtoupper($arr[$i+1]['data']); + if ($second_upper_data == 'DELETE') { + $clause = 'on_delete'; } - break; - case 'EVENT': - case 'TABLESPACE': - case 'TABLE': - case 'FUNCTION': - case 'INDEX': - case 'PROCEDURE': - case 'SERVER': - case 'TRIGGER': - case 'DATABASE': - case 'VIEW': - case 'GROUP': - if ($close_docu_link) { - $after = '' . $after; - $close_docu_link = false; + if ($second_upper_data == 'UPDATE') { + $clause = 'on_update'; } - break; - case 'SET': - if ($docu && ($i == 0 || $arr[$i - 1]['data'] != 'CHARACTER')) { - $before .= PMA_showMySQLDocu('SQL-Syntax', $arr[$i]['data'], false, '', true); - $after = '' . $after; - } - if (!$in_priv_list) { - $space_punct_listsep = $html_line_break; - $space_alpha_reserved_word = ' '; - } - break; - case 'EXPLAIN': - case 'DESCRIBE': - case 'DELETE': - case 'SHOW': - case 'UPDATE': - if ($docu) { - $before .= PMA_showMySQLDocu('SQL-Syntax', $arr[$i]['data'], false, '', true); - $after = '' . $after; - } - if (!$in_priv_list) { - $space_punct_listsep = $html_line_break; - $space_alpha_reserved_word = ' '; - } - break; - case 'INSERT': - case 'REPLACE': - if ($docu) { - $before .= PMA_showMySQLDocu('SQL-Syntax', $arr[$i]['data'], false, '', true); - $after = '' . $after; - } - if (!$in_priv_list) { - $space_punct_listsep = $html_line_break; - $space_alpha_reserved_word = $html_line_break; - } - break; - case 'VALUES': - $space_punct_listsep = ' '; - $space_alpha_reserved_word = $html_line_break; - break; - case 'SELECT': - if ($docu) { - $before .= PMA_showMySQLDocu('SQL-Syntax', 'SELECT', false, '', true); - $after = '' . $after; - } - $space_punct_listsep = ' '; - $space_alpha_reserved_word = $html_line_break; - break; - case 'CALL': - case 'DO': - case 'HANDLER': - if ($docu) { - $before .= PMA_showMySQLDocu('SQL-Syntax', $arr[$i]['data'], false, '', true); - $after = '' . $after; - } - break; - default: - if ($close_docu_link && in_array($arr[$i]['data'], array('LIKE', 'NOT', 'IN', 'REGEXP', 'NULL'))) { - $after .= ''; - $close_docu_link = false; - } else if ($docu && isset($PMA_SQPdata_functions_docs[$arr[$i]['data']])) { - /* Handle multi word statements first */ - if (isset($typearr[4]) && $typearr[4] == 'alpha_reservedWord' && $typearr[3] == 'alpha_reservedWord' && isset($PMA_SQPdata_functions_docs[strtoupper($arr[$i]['data'] . '_' . $arr[$i + 1]['data'] . '_' . $arr[$i + 2]['data'])])) { - $tempname = strtoupper($arr[$i]['data'] . '_' . $arr[$i + 1]['data'] . '_' . $arr[$i + 2]['data']); - $before .= PMA_showMySQLDocu('functions', $PMA_SQPdata_functions_docs[$tempname]['link'], false, $PMA_SQPdata_functions_docs[$tempname]['anchor'], true); - $close_docu_link = true; - } else if (isset($typearr[3]) && $typearr[3] == 'alpha_reservedWord' && isset($PMA_SQPdata_functions_docs[strtoupper($arr[$i]['data'] . '_' . $arr[$i + 1]['data'])])) { - $tempname = strtoupper($arr[$i]['data'] . '_' . $arr[$i + 1]['data']); - $before .= PMA_showMySQLDocu('functions', $PMA_SQPdata_functions_docs[$tempname]['link'], false, $PMA_SQPdata_functions_docs[$tempname]['anchor'], true); - $close_docu_link = true; + if (isset($clause) + && ($arr[$i+2]['type'] == 'alpha_reservedWord' + + // ugly workaround because currently, NO is not + // in the list of reserved words in sqlparser.data + // (we got a bug report about not being able to use + // 'no' as an identifier) + || ($arr[$i+2]['type'] == 'alpha_identifier' + && strtoupper($arr[$i+2]['data'])=='NO')) + ) { + $third_upper_data = strtoupper($arr[$i+2]['data']); + if ($third_upper_data == 'CASCADE' + || $third_upper_data == 'RESTRICT' + ) { + $value = $third_upper_data; + } elseif ($third_upper_data == 'SET' + || $third_upper_data == 'NO' + ) { + if ($arr[$i+3]['type'] == 'alpha_reservedWord') { + $value = $third_upper_data . '_' . strtoupper($arr[$i+3]['data']); + } + } elseif ($third_upper_data == 'CURRENT_TIMESTAMP') { + if ($clause == 'on_update' + && $in_timestamp_options + ) { + $create_table_fields[$current_identifier]['on_update_current_timestamp'] = true; + $seen_default = false; + } + } else { - $before .= PMA_showMySQLDocu('functions', $PMA_SQPdata_functions_docs[$arr[$i]['data']]['link'], false, $PMA_SQPdata_functions_docs[$arr[$i]['data']]['anchor'], true); - $after .= ''; + $value = ''; } - } - break; - } // end switch ($arr[$i]['data']) + if (!empty($value)) { + $foreign[$foreign_key_number][$clause] = $value; + } + unset($clause); + } // endif (isset($clause)) + } + } - $after .= ' '; - break; - case 'digit_integer': - case 'digit_float': - case 'digit_hex': - /** - * @todo could there be other types preceding a digit? - */ - if ($typearr[1] == 'alpha_reservedWord') { - $after .= ' '; + } // end of reserved words analysis + + + if ($arr[$i]['type'] == 'punct_bracket_open_round') { + $brackets_level++; + if ($seen_create_table && $brackets_level == 1) { + $in_create_table_fields = true; + } + } + + + if ($arr[$i]['type'] == 'punct_bracket_close_round') { + $brackets_level--; + if ($seen_references) { + $seen_references = false; + } + if ($seen_create_table && $brackets_level == 0) { + $in_create_table_fields = false; + } + } + + if (($arr[$i]['type'] == 'alpha_columnAttrib')) { + $upper_data = strtoupper($arr[$i]['data']); + if ($seen_create_table && $in_create_table_fields) { + if ($upper_data == 'DEFAULT') { + $seen_default = true; + $create_table_fields[$current_identifier]['default_value'] = $arr[$i + 1]['data']; } - if ($infunction && $typearr[3] == 'punct_bracket_close_round') { + } + } + + /** + * @see @todo 2005-10-16 note: the "or" part here is a workaround for a bug + */ + if (($arr[$i]['type'] == 'alpha_columnType') || ($arr[$i]['type'] == 'alpha_functionName' && $seen_create_table)) { + $upper_data = strtoupper($arr[$i]['data']); + if ($seen_create_table && $in_create_table_fields && isset($current_identifier)) { + $create_table_fields[$current_identifier]['type'] = $upper_data; + if ($upper_data == 'TIMESTAMP') { + $arr[$i]['type'] = 'alpha_columnType'; + $in_timestamp_options = true; + } else { + $in_timestamp_options = false; + if ($upper_data == 'CHAR') { + $arr[$i]['type'] = 'alpha_columnType'; + } + } + } + } + + + if ($arr[$i]['type'] == 'quote_backtick' || $arr[$i]['type'] == 'alpha_identifier') { + + if ($arr[$i]['type'] == 'quote_backtick') { + // remove backquotes + $identifier = PMA_unQuote($arr[$i]['data']); + } else { + $identifier = $arr[$i]['data']; + } + + if ($seen_create_table && $in_create_table_fields) { + $current_identifier = $identifier; + // we set this one even for non TIMESTAMP type + $create_table_fields[$current_identifier]['timestamp_not_null'] = false; + } + + if ($seen_constraint) { + $foreign[$foreign_key_number]['constraint'] = $identifier; + } + + if ($seen_foreign && $brackets_level > 0) { + $foreign[$foreign_key_number]['index_list'][] = $identifier; + } + + if ($seen_references) { + if ($seen_alter && $brackets_level > 0) { + $foreign[$foreign_key_number]['ref_index_list'][] = $identifier; + // here, the first bracket level corresponds to the + // bracket of CREATE TABLE + // so if we are on level 2, it must be the index list + // of the foreign key REFERENCES + } elseif ($brackets_level > 1) { + $foreign[$foreign_key_number]['ref_index_list'][] = $identifier; + } elseif ($arr[$i+1]['type'] == 'punct_qualifier') { + // identifier is `db`.`table` + // the first pass will pick the db name + // the next pass will pick the table name + $foreign[$foreign_key_number]['ref_db_name'] = $identifier; + } else { + // identifier is `table` + $foreign[$foreign_key_number]['ref_table_name'] = $identifier; + } + } + } + } // end for $i (loop #3) + + + // Fill the $subresult array + + if (isset($create_table_fields)) { + $subresult['create_table_fields'] = $create_table_fields; + } + + if (isset($foreign)) { + $subresult['foreign_keys'] = $foreign; + } + + if (isset($select_expr_clause)) { + $subresult['select_expr_clause'] = $select_expr_clause; + } + if (isset($from_clause)) { + $subresult['from_clause'] = $from_clause; + } + if (isset($group_by_clause)) { + $subresult['group_by_clause'] = $group_by_clause; + } + if (isset($order_by_clause)) { + $subresult['order_by_clause'] = $order_by_clause; + } + if (isset($having_clause)) { + $subresult['having_clause'] = $having_clause; + } + if (isset($limit_clause)) { + $subresult['limit_clause'] = $limit_clause; + } + if (isset($where_clause)) { + $subresult['where_clause'] = $where_clause; + } + if (isset($unsorted_query) && !empty($unsorted_query)) { + $subresult['unsorted_query'] = $unsorted_query; + } + if (isset($where_clause_identifiers)) { + $subresult['where_clause_identifiers'] = $where_clause_identifiers; + } + + if (isset($position_of_first_select)) { + $subresult['position_of_first_select'] = $position_of_first_select; + $subresult['section_before_limit'] = $section_before_limit; + $subresult['section_after_limit'] = $section_after_limit; + } + + // They are naughty and didn't have a trailing semi-colon, + // then still handle it properly + if ($subresult['querytype'] != '') { + $result[] = $subresult; + } + return $result; +} // end of the "PMA_SQP_analyze()" function + + +/** + * Colorizes SQL queries html formatted + * + * @todo check why adding a "\n" after the
would cause extra blanks + * to be displayed: SELECT p . person_name + * @param array The SQL queries html formatted + * + * @return array The colorized SQL queries + * + * @access public + */ +function PMA_SQP_formatHtml_colorize($arr) +{ + $i = PMA_strpos($arr['type'], '_'); + $class = ''; + if ($i > 0) { + $class = 'syntax_' . PMA_substr($arr['type'], 0, $i) . ' '; + } + + $class .= 'syntax_' . $arr['type']; + + return '' . htmlspecialchars($arr['data']) . ''; +} // end of the "PMA_SQP_formatHtml_colorize()" function + + +/** + * Formats SQL queries to html + * + * @param array The SQL queries + * @param string mode + * @param integer starting token + * @param integer number of tokens to format, -1 = all + * + * @return string The formatted SQL queries + * + * @access public + */ +function PMA_SQP_formatHtml( + $arr, $mode='color', $start_token=0, + $number_of_tokens=-1 +) { + global $PMA_SQPdata_operators_docs, $PMA_SQPdata_functions_docs; + //DEBUG echo 'in Format
'; print_r($arr); echo '
'; + // then check for an array + if (! is_array($arr)) { + return htmlspecialchars($arr); + } + // first check for the SQL parser having hit an error + if (PMA_SQP_isError()) { + return htmlspecialchars($arr['raw']); + } + // else do it properly + switch ($mode) { + case 'color': + $str = ''; + $html_line_break = '
'; + $docu = true; + break; + case 'query_only': + $str = ''; + $html_line_break = "\n"; + $docu = false; + break; + case 'text': + $str = ''; + $html_line_break = '
'; + $docu = true; + break; + } // end switch + // inner_sql is a span that exists for all cases, except query_only + // of $cfg['SQP']['fmtType'] to make possible a replacement + // for inline editing + if ($mode!='query_only') { + $str .= ''; + } + $close_docu_link = false; + $indent = 0; + $bracketlevel = 0; + $functionlevel = 0; + $infunction = false; + $space_punct_listsep = ' '; + $space_punct_listsep_function_name = ' '; + // $space_alpha_reserved_word = '
'."\n"; + $space_alpha_reserved_word = ' '; + + $keywords_with_brackets_1before = array( + 'INDEX' => 1, + 'KEY' => 1, + 'ON' => 1, + 'USING' => 1 + ); + + $keywords_with_brackets_2before = array( + 'IGNORE' => 1, + 'INDEX' => 1, + 'INTO' => 1, + 'KEY' => 1, + 'PRIMARY' => 1, + 'PROCEDURE' => 1, + 'REFERENCES' => 1, + 'UNIQUE' => 1, + 'USE' => 1 + ); + + // These reserved words do NOT get a newline placed near them. + $keywords_no_newline = array( + 'AS' => 1, + 'ASC' => 1, + 'DESC' => 1, + 'DISTINCT' => 1, + 'DUPLICATE' => 1, + 'HOUR' => 1, + 'INTERVAL' => 1, + 'IS' => 1, + 'LIKE' => 1, + 'NOT' => 1, + 'NULL' => 1, + 'ON' => 1, + 'REGEXP' => 1 + ); + + // These reserved words introduce a privilege list + $keywords_priv_list = array( + 'GRANT' => 1, + 'REVOKE' => 1 + ); + + if ($number_of_tokens == -1) { + $number_of_tokens = $arr['len']; + } + $typearr = array(); + if ($number_of_tokens >= 0) { + $typearr[0] = ''; + $typearr[1] = ''; + $typearr[2] = ''; + $typearr[3] = $arr[$start_token]['type']; + } + + $in_priv_list = false; + for ($i = $start_token; $i < $number_of_tokens; $i++) { + // DEBUG echo "Loop format " . $arr[$i]['data'] . " " . $arr[$i]['type'] . "
"; + $before = ''; + $after = ''; + // array_shift($typearr); + /* + 0 prev2 + 1 prev + 2 current + 3 next + */ + if (($i + 1) < $number_of_tokens) { + $typearr[4] = $arr[$i + 1]['type']; + } else { + $typearr[4] = ''; + } + + for ($j=0; $j<4; $j++) { + $typearr[$j] = $typearr[$j + 1]; + } + + switch ($typearr[2]) { + case 'alpha_bitfield_constant_introducer': + $before = ' '; + $after = ''; + break; + case 'white_newline': + $before = ''; + break; + case 'punct_bracket_open_round': + $bracketlevel++; + $infunction = false; + // Make sure this array is sorted! + if (($typearr[1] == 'alpha_functionName') || ($typearr[1] == 'alpha_columnType') || ($typearr[1] == 'punct') + || ($typearr[3] == 'digit_integer') || ($typearr[3] == 'digit_hex') || ($typearr[3] == 'digit_float') + || (($typearr[0] == 'alpha_reservedWord') + && isset($keywords_with_brackets_2before[strtoupper($arr[$i - 2]['data'])])) + || (($typearr[1] == 'alpha_reservedWord') + && isset($keywords_with_brackets_1before[strtoupper($arr[$i - 1]['data'])])) + ) { + $functionlevel++; + $infunction = true; + $after .= ' '; + } else { + $indent++; + $after .= ($mode != 'query_only' ? '
' : ' '); + } + break; + case 'alpha_identifier': + if (($typearr[1] == 'punct_qualifier') || ($typearr[3] == 'punct_qualifier')) { + $after = ''; + $before = ''; + } + // for example SELECT 1 somealias + if ($typearr[1] == 'digit_integer') { + $before = ' '; + } + if (($typearr[3] == 'alpha_columnType') || ($typearr[3] == 'alpha_identifier')) { + $after .= ' '; + } + break; + case 'punct_user': + case 'punct_qualifier': + $before = ''; + $after = ''; + break; + case 'punct_listsep': + if ($infunction == true) { + $after .= $space_punct_listsep_function_name; + } else { + $after .= $space_punct_listsep; + } + break; + case 'punct_queryend': + if (($typearr[3] != 'comment_mysql') && ($typearr[3] != 'comment_ansi') && $typearr[3] != 'comment_c') { + $after .= $html_line_break; + $after .= $html_line_break; + } + $space_punct_listsep = ' '; + $space_punct_listsep_function_name = ' '; + $space_alpha_reserved_word = ' '; + $in_priv_list = false; + break; + case 'comment_mysql': + case 'comment_ansi': + $after .= $html_line_break; + break; + case 'punct': + $before .= ' '; + if ($docu && isset($PMA_SQPdata_operators_docs[$arr[$i]['data']]) + && ($arr[$i]['data'] != '*' || in_array($arr[$i]['type'], array('digit_integer','digit_float','digit_hex'))) + ) { + $before .= PMA_showMySQLDocu( + 'functions', + $PMA_SQPdata_operators_docs[$arr[$i]['data']]['link'], + false, + $PMA_SQPdata_operators_docs[$arr[$i]['data']]['anchor'], + true + ); + $after .= ''; + } + + // workaround for + // select * from mytable limit 0,-1 + // (a side effect of this workaround is that + // select 20 - 9 + // becomes + // select 20 -9 + // ) + if ($typearr[3] != 'digit_integer') { + $after .= ' '; + } + break; + case 'punct_bracket_close_round': + // only close bracket level when it was opened before + if ($bracketlevel > 0) { + $bracketlevel--; + if ($infunction == true) { + $functionlevel--; $after .= ' '; - } - if ($typearr[1] == 'alpha_columnAttrib') { - $before .= ' '; - } - break; - case 'alpha_variable': - $after = ' '; - break; - case 'quote_double': - case 'quote_single': - // workaround: for the query - // REVOKE SELECT ON `base2\_db`.* FROM 'user'@'%' - // the @ is incorrectly marked as alpha_variable - // in the parser, and here, the '%' gets a blank before, - // which is a syntax error - if ($typearr[1] != 'punct_user' && $typearr[1] != 'alpha_bitfield_constant_introducer') { - $before .= ' '; - } - if ($infunction && $typearr[3] == 'punct_bracket_close_round') { - $after .= ' '; - } - break; - case 'quote_backtick': - // here we check for punct_user to handle correctly - // DEFINER = `username`@`%` - // where @ is the punct_user and `%` is the quote_backtick - if ($typearr[3] != 'punct_qualifier' && $typearr[3] != 'alpha_variable' && $typearr[3] != 'punct_user') { - $after .= ' '; - } - if ($typearr[1] != 'punct_qualifier' && $typearr[1] != 'alpha_variable' && $typearr[1] != 'punct_user') { $before .= ' '; + } else { + $indent--; + $before .= ($mode != 'query_only' ? '
' : ' '); + } + $infunction = ($functionlevel > 0) ? true : false; + } + break; + case 'alpha_columnType': + if ($docu) { + switch ($arr[$i]['data']) { + case 'tinyint': + case 'smallint': + case 'mediumint': + case 'int': + case 'bigint': + case 'decimal': + case 'float': + case 'double': + case 'real': + case 'bit': + case 'boolean': + case 'serial': + $before .= PMA_showMySQLDocu('data-types', 'numeric-types', false, '', true); + $after = '' . $after; + break; + case 'date': + case 'datetime': + case 'timestamp': + case 'time': + case 'year': + $before .= PMA_showMySQLDocu('data-types', 'date-and-time-types', false, '', true); + $after = '' . $after; + break; + case 'char': + case 'varchar': + case 'tinytext': + case 'text': + case 'mediumtext': + case 'longtext': + case 'binary': + case 'varbinary': + case 'tinyblob': + case 'mediumblob': + case 'blob': + case 'longblob': + case 'enum': + case 'set': + $before .= PMA_showMySQLDocu('data-types', 'string-types', false, '', true); + $after = '' . $after; + break; + } + } + if ($typearr[3] == 'alpha_columnAttrib') { + $after .= ' '; + } + if ($typearr[1] == 'alpha_columnType') { + $before .= ' '; + } + break; + case 'alpha_columnAttrib': + + // ALTER TABLE tbl_name AUTO_INCREMENT = 1 + // COLLATE LATIN1_GENERAL_CI DEFAULT + if ($typearr[1] == 'alpha_identifier' || $typearr[1] == 'alpha_charset') { + $before .= ' '; + } + if (($typearr[3] == 'alpha_columnAttrib') || ($typearr[3] == 'quote_single') || ($typearr[3] == 'digit_integer')) { + $after .= ' '; + } + // workaround for + // AUTO_INCREMENT = 31DEFAULT_CHARSET = utf-8 + + if ($typearr[2] == 'alpha_columnAttrib' && $typearr[3] == 'alpha_reservedWord') { + $before .= ' '; + } + // workaround for + // select * from mysql.user where binary user="root" + // binary is marked as alpha_columnAttrib + // but should be marked as a reserved word + if (strtoupper($arr[$i]['data']) == 'BINARY' + && $typearr[3] == 'alpha_identifier' + ) { + $after .= ' '; + } + break; + case 'alpha_functionName': + $funcname = strtoupper($arr[$i]['data']); + if ($docu && isset($PMA_SQPdata_functions_docs[$funcname])) { + $before .= PMA_showMySQLDocu( + 'functions', + $PMA_SQPdata_functions_docs[$funcname]['link'], + false, + $PMA_SQPdata_functions_docs[$funcname]['anchor'], + true + ); + $after .= ''; + } + break; + case 'alpha_reservedWord': + // do not uppercase the reserved word if we are calling + // this function in query_only mode, because we need + // the original query (otherwise we get problems with + // semi-reserved words like "storage" which is legal + // as an identifier name) + + if ($mode != 'query_only') { + $arr[$i]['data'] = strtoupper($arr[$i]['data']); + } + + if ((($typearr[1] != 'alpha_reservedWord') + || (($typearr[1] == 'alpha_reservedWord') + && isset($keywords_no_newline[strtoupper($arr[$i - 1]['data'])]))) + && ($typearr[1] != 'punct_level_plus') + && (!isset($keywords_no_newline[$arr[$i]['data']])) + ) { + // do not put a space before the first token, because + // we use a lot of pattern matching checking for the + // first reserved word at beginning of query + // so do not put a newline before + // + // also we must not be inside a privilege list + if ($i > 0) { + // the alpha_identifier exception is there to + // catch cases like + // GRANT SELECT ON mydb.mytable TO myuser@localhost + // (else, we get mydb.mytableTO) + // + // the quote_single exception is there to + // catch cases like + // GRANT ... TO 'marc'@'domain.com' IDENTIFIED... + /** + * @todo fix all cases and find why this happens + */ + + if (!$in_priv_list || $typearr[1] == 'alpha_identifier' || $typearr[1] == 'quote_single' || $typearr[1] == 'white_newline') { + $before .= $space_alpha_reserved_word; + } + } else { + // on first keyword, check if it introduces a + // privilege list + if (isset($keywords_priv_list[$arr[$i]['data']])) { + $in_priv_list = true; + } + } + } else { + $before .= ' '; + } + + switch ($arr[$i]['data']) { + case 'CREATE': + case 'ALTER': + case 'DROP': + case 'RENAME'; + case 'TRUNCATE': + case 'ANALYZE': + case 'ANALYSE': + case 'OPTIMIZE': + if ($docu) { + switch ($arr[$i + 1]['data']) { + case 'EVENT': + case 'TABLE': + case 'TABLESPACE': + case 'FUNCTION': + case 'INDEX': + case 'PROCEDURE': + case 'TRIGGER': + case 'SERVER': + case 'DATABASE': + case 'VIEW': + $before .= PMA_showMySQLDocu('SQL-Syntax', $arr[$i]['data'] . '_' . $arr[$i + 1]['data'], false, '', true); + $close_docu_link = true; + break; + } + if ($arr[$i + 1]['data'] == 'LOGFILE' && $arr[$i + 2]['data'] == 'GROUP') { + $before .= PMA_showMySQLDocu('SQL-Syntax', $arr[$i]['data'] . '_LOGFILE_GROUP', false, '', true); + $close_docu_link = true; + } + } + if (!$in_priv_list) { + $space_punct_listsep = $html_line_break; + $space_alpha_reserved_word = ' '; + } + break; + case 'EVENT': + case 'TABLESPACE': + case 'TABLE': + case 'FUNCTION': + case 'INDEX': + case 'PROCEDURE': + case 'SERVER': + case 'TRIGGER': + case 'DATABASE': + case 'VIEW': + case 'GROUP': + if ($close_docu_link) { + $after = '' . $after; + $close_docu_link = false; + } + break; + case 'SET': + if ($docu && ($i == 0 || $arr[$i - 1]['data'] != 'CHARACTER')) { + $before .= PMA_showMySQLDocu('SQL-Syntax', $arr[$i]['data'], false, '', true); + $after = '' . $after; + } + if (!$in_priv_list) { + $space_punct_listsep = $html_line_break; + $space_alpha_reserved_word = ' '; + } + break; + case 'EXPLAIN': + case 'DESCRIBE': + case 'DELETE': + case 'SHOW': + case 'UPDATE': + if ($docu) { + $before .= PMA_showMySQLDocu('SQL-Syntax', $arr[$i]['data'], false, '', true); + $after = '' . $after; + } + if (!$in_priv_list) { + $space_punct_listsep = $html_line_break; + $space_alpha_reserved_word = ' '; + } + break; + case 'INSERT': + case 'REPLACE': + if ($docu) { + $before .= PMA_showMySQLDocu('SQL-Syntax', $arr[$i]['data'], false, '', true); + $after = '' . $after; + } + if (!$in_priv_list) { + $space_punct_listsep = $html_line_break; + $space_alpha_reserved_word = $html_line_break; + } + break; + case 'VALUES': + $space_punct_listsep = ' '; + $space_alpha_reserved_word = $html_line_break; + break; + case 'SELECT': + if ($docu) { + $before .= PMA_showMySQLDocu('SQL-Syntax', 'SELECT', false, '', true); + $after = '' . $after; + } + $space_punct_listsep = ' '; + $space_alpha_reserved_word = $html_line_break; + break; + case 'CALL': + case 'DO': + case 'HANDLER': + if ($docu) { + $before .= PMA_showMySQLDocu('SQL-Syntax', $arr[$i]['data'], false, '', true); + $after = '' . $after; } break; default: + if ($close_docu_link && in_array($arr[$i]['data'], array('LIKE', 'NOT', 'IN', 'REGEXP', 'NULL'))) { + $after .= ''; + $close_docu_link = false; + } else if ($docu && isset($PMA_SQPdata_functions_docs[$arr[$i]['data']])) { + /* Handle multi word statements first */ + if (isset($typearr[4]) && $typearr[4] == 'alpha_reservedWord' && $typearr[3] == 'alpha_reservedWord' && isset($PMA_SQPdata_functions_docs[strtoupper($arr[$i]['data'] . '_' . $arr[$i + 1]['data'] . '_' . $arr[$i + 2]['data'])])) { + $tempname = strtoupper($arr[$i]['data'] . '_' . $arr[$i + 1]['data'] . '_' . $arr[$i + 2]['data']); + $before .= PMA_showMySQLDocu('functions', $PMA_SQPdata_functions_docs[$tempname]['link'], false, $PMA_SQPdata_functions_docs[$tempname]['anchor'], true); + $close_docu_link = true; + } else if (isset($typearr[3]) && $typearr[3] == 'alpha_reservedWord' && isset($PMA_SQPdata_functions_docs[strtoupper($arr[$i]['data'] . '_' . $arr[$i + 1]['data'])])) { + $tempname = strtoupper($arr[$i]['data'] . '_' . $arr[$i + 1]['data']); + $before .= PMA_showMySQLDocu('functions', $PMA_SQPdata_functions_docs[$tempname]['link'], false, $PMA_SQPdata_functions_docs[$tempname]['anchor'], true); + $close_docu_link = true; + } else { + $before .= PMA_showMySQLDocu('functions', $PMA_SQPdata_functions_docs[$arr[$i]['data']]['link'], false, $PMA_SQPdata_functions_docs[$arr[$i]['data']]['anchor'], true); + $after .= ''; + } + } break; - } // end switch ($typearr[2]) + } // end switch ($arr[$i]['data']) - /* - if ($typearr[3] != 'punct_qualifier') { - $after .= ' '; + $after .= ' '; + break; + case 'digit_integer': + case 'digit_float': + case 'digit_hex': + /** + * @todo could there be other types preceding a digit? + */ + if ($typearr[1] == 'alpha_reservedWord') { + $after .= ' '; } - $after .= "\n"; - */ - $str .= $before; - if ($mode=='color') { - $str .= PMA_SQP_formatHTML_colorize($arr[$i]); - } elseif ($mode == 'text') { - $str .= htmlspecialchars($arr[$i]['data']); - } else { - $str .= $arr[$i]['data']; + if ($infunction && $typearr[3] == 'punct_bracket_close_round') { + $after .= ' '; } - $str .= $after; - } // end for - // close unclosed indent levels - while ($indent > 0) { - $indent--; - $str .= ($mode != 'query_only' ? '' : ' '); - } - /* End possibly unclosed documentation link */ - if ($close_docu_link) { - $str .= ''; - $close_docu_link = false; - } - if ($mode!='query_only') { - // close inner_sql span - $str .= '
'; + if ($typearr[1] == 'alpha_columnAttrib') { + $before .= ' '; + } + break; + case 'alpha_variable': + $after = ' '; + break; + case 'quote_double': + case 'quote_single': + // workaround: for the query + // REVOKE SELECT ON `base2\_db`.* FROM 'user'@'%' + // the @ is incorrectly marked as alpha_variable + // in the parser, and here, the '%' gets a blank before, + // which is a syntax error + if ($typearr[1] != 'punct_user' && $typearr[1] != 'alpha_bitfield_constant_introducer') { + $before .= ' '; + } + if ($infunction && $typearr[3] == 'punct_bracket_close_round') { + $after .= ' '; + } + break; + case 'quote_backtick': + // here we check for punct_user to handle correctly + // DEFINER = `username`@`%` + // where @ is the punct_user and `%` is the quote_backtick + if ($typearr[3] != 'punct_qualifier' && $typearr[3] != 'alpha_variable' && $typearr[3] != 'punct_user') { + $after .= ' '; + } + if ($typearr[1] != 'punct_qualifier' && $typearr[1] != 'alpha_variable' && $typearr[1] != 'punct_user') { + $before .= ' '; + } + break; + default: + break; + } // end switch ($typearr[2]) + + /* + if ($typearr[3] != 'punct_qualifier') { + $after .= ' '; } + $after .= "\n"; + */ + $str .= $before; if ($mode=='color') { - // close syntax span - $str .= '
'; + $str .= PMA_SQP_formatHTML_colorize($arr[$i]); + } elseif ($mode == 'text') { + $str .= htmlspecialchars($arr[$i]['data']); + } else { + $str .= $arr[$i]['data']; } + $str .= $after; + } // end for + // close unclosed indent levels + while ($indent > 0) { + $indent--; + $str .= ($mode != 'query_only' ? '' : ' '); + } + /* End possibly unclosed documentation link */ + if ($close_docu_link) { + $str .= ''; + $close_docu_link = false; + } + if ($mode!='query_only') { + // close inner_sql span + $str .= '
'; + } + if ($mode=='color') { + // close syntax span + $str .= ''; + } - return $str; - } // end of the "PMA_SQP_formatHtml()" function + return $str; +} // end of the "PMA_SQP_formatHtml()" function - /** - * Gets SQL queries with no format - * - * @param array $arr The SQL queries list - * - * @return string The SQL queries with no format - * - * @access public - */ - function PMA_SQP_formatNone($arr) - { - $formatted_sql = htmlspecialchars($arr['raw']); - $formatted_sql = preg_replace( - "@((\015\012)|(\015)|(\012)){3,}@", - "\n\n", - $formatted_sql - ); +/** + * Gets SQL queries with no format + * + * @param array $arr The SQL queries list + * + * @return string The SQL queries with no format + * + * @access public + */ +function PMA_SQP_formatNone($arr) +{ + $formatted_sql = htmlspecialchars($arr['raw']); + $formatted_sql = preg_replace( + "@((\015\012)|(\015)|(\012)){3,}@", + "\n\n", + $formatted_sql + ); - return $formatted_sql; - } // end of the "PMA_SQP_formatNone()" function + return $formatted_sql; +} // end of the "PMA_SQP_formatNone()" function ?> From d3640d0e39dc5b6bd691d2a17cb6c626a7c5f425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 29 May 2012 14:10:28 +0200 Subject: [PATCH 07/11] Use require for unconditional inclusion --- libraries/sqlparser.lib.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libraries/sqlparser.lib.php b/libraries/sqlparser.lib.php index d7eaef12b2..89789cb68c 100644 --- a/libraries/sqlparser.lib.php +++ b/libraries/sqlparser.lib.php @@ -33,12 +33,16 @@ if (! defined('PHPMYADMIN')) { /** * Include the string library as we use it heavily */ -include_once './libraries/string.lib.php'; +require_once './libraries/string.lib.php'; /** * Include data for the SQL Parser */ -include_once './libraries/sqlparser.data.php'; +require_once './libraries/sqlparser.data.php'; + +/** + * Charset information + */ if (!defined('TESTSUITE')) { include_once './libraries/mysql_charsets.lib.php'; } From bcab4bfe256c532505598e04fa0cfdff8ef02f01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 29 May 2012 14:10:52 +0200 Subject: [PATCH 08/11] Fix indentation --- libraries/sqlparser.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/sqlparser.lib.php b/libraries/sqlparser.lib.php index 89789cb68c..82e0928382 100644 --- a/libraries/sqlparser.lib.php +++ b/libraries/sqlparser.lib.php @@ -2448,7 +2448,7 @@ function PMA_SQP_formatHtml( if ((($typearr[1] != 'alpha_reservedWord') || (($typearr[1] == 'alpha_reservedWord') - && isset($keywords_no_newline[strtoupper($arr[$i - 1]['data'])]))) + && isset($keywords_no_newline[strtoupper($arr[$i - 1]['data'])]))) && ($typearr[1] != 'punct_level_plus') && (!isset($keywords_no_newline[$arr[$i]['data']])) ) { From da452baa11c2a1db7a048b90fa4ecb3ecb8ad37b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 29 May 2012 14:12:25 +0200 Subject: [PATCH 09/11] Debug variant is not used and not documented how to use that --- libraries/sqlparser.lib.php | 41 +++++++++---------------------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/libraries/sqlparser.lib.php b/libraries/sqlparser.lib.php index 82e0928382..eea18baf9b 100644 --- a/libraries/sqlparser.lib.php +++ b/libraries/sqlparser.lib.php @@ -51,37 +51,16 @@ if (! isset($mysql_charsets)) { $mysql_collations_flat = array(); } -if (!defined('DEBUG_TIMING')) { - /** - * currently we don't need the $pos (token position in query) - * for other purposes than LIMIT clause verification, - * so many calls to this function do not include the 4th parameter - */ - function PMA_SQP_arrayAdd(&$arr, $type, $data, &$arrsize, $pos = 0) - { - $arr[] = array('type' => $type, 'data' => $data, 'pos' => $pos); - $arrsize++; - } // end of the "PMA_SQP_arrayAdd()" function -} else { - /** - * This is debug variant of above. - * @ignore - */ - function PMA_SQP_arrayAdd(&$arr, $type, $data, &$arrsize, $pos = 0) - { - global $timer; - - $t = $timer; - $arr[] = array( - 'type' => $type, - 'data' => $data, - 'pos' => $pos, - 'time' => $t); - $timer = microtime(); - $arrsize++; - } // end of the "PMA_SQP_arrayAdd()" function -} // end if... else... - +/** + * currently we don't need the $pos (token position in query) + * for other purposes than LIMIT clause verification, + * so many calls to this function do not include the 4th parameter + */ +function PMA_SQP_arrayAdd(&$arr, $type, $data, &$arrsize, $pos = 0) +{ + $arr[] = array('type' => $type, 'data' => $data, 'pos' => $pos); + $arrsize++; +} // end of the "PMA_SQP_arrayAdd()" function /** * Reset the error variable for the SQL parser From c0ff61f8da8a3e374d91564b9b85cb79c8373a8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 29 May 2012 14:15:21 +0200 Subject: [PATCH 10/11] Document PMA_SQP_arrayAdd --- libraries/sqlparser.lib.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/libraries/sqlparser.lib.php b/libraries/sqlparser.lib.php index eea18baf9b..0bc92c6a01 100644 --- a/libraries/sqlparser.lib.php +++ b/libraries/sqlparser.lib.php @@ -52,9 +52,19 @@ if (! isset($mysql_charsets)) { } /** - * currently we don't need the $pos (token position in query) + * Stores parsed elemented of query to array. + * + * Currently we don't need the $pos (token position in query) * for other purposes than LIMIT clause verification, * so many calls to this function do not include the 4th parameter + * + * @param array &$arr Array to store element + * @param string $type Type of element + * @param string $data Data (text) of element + * @param int &$arrsize Size of array + * @param int $pos Position of an element + * + * @return nothing */ function PMA_SQP_arrayAdd(&$arr, $type, $data, &$arrsize, $pos = 0) { From 600979f4464e78168246d05d4f273f208e25390c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 29 May 2012 14:20:11 +0200 Subject: [PATCH 11/11] Fix docs --- libraries/sqlparser.lib.php | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/libraries/sqlparser.lib.php b/libraries/sqlparser.lib.php index 0bc92c6a01..8ddb58e987 100644 --- a/libraries/sqlparser.lib.php +++ b/libraries/sqlparser.lib.php @@ -76,6 +76,8 @@ function PMA_SQP_arrayAdd(&$arr, $type, $data, &$arrsize, $pos = 0) * Reset the error variable for the SQL parser * * @access public + * + * @return nothing */ function PMA_SQP_resetError() { @@ -113,8 +115,8 @@ function PMA_SQP_isError() /** * Set an error message for the system * - * @param string The error message - * @param string The failing SQL query + * @param string $message The error message + * @param string $sql The failing SQL query * * @access private * @scope SQL Parser internal @@ -134,8 +136,10 @@ function PMA_SQP_throwError($message, $sql) /** * Do display the bug report * - * @param string The error message - * @param string The failing SQL query + * @param string $message The error message + * @param string $sql The failing SQL query + * + * @return nothing * * @access public */ @@ -180,9 +184,9 @@ function PMA_SQP_bug($message, $sql) /** * Parses the SQL queries * - * @param string The SQL query list + * @param string $sql The SQL query list * - * @return mixed Most of times, nothing... + * @return mixed Most of times, nothing... * * @global array The current PMA configuration * @global array MySQL column attributes @@ -805,8 +809,8 @@ function PMA_SQP_parse($sql) /** * Checks for token types being what we want... * - * @param string String of type that we have - * @param string String of type that we want + * @param string $toCheck String of type that we have + * @param string $whatWeWant String of type that we want * * @return boolean result of check * @@ -830,7 +834,7 @@ function PMA_SQP_typeCheck($toCheck, $whatWeWant) /** * Analyzes SQL queries * - * @param array The SQL queries + * @param array $arr The SQL queries * * @return array The analyzed SQL queries * @@ -2071,7 +2075,8 @@ function PMA_SQP_analyze($arr) * * @todo check why adding a "\n" after the would cause extra blanks * to be displayed: SELECT p . person_name - * @param array The SQL queries html formatted + * + * @param array $arr The SQL queries html formatted * * @return array The colorized SQL queries * @@ -2094,10 +2099,10 @@ function PMA_SQP_formatHtml_colorize($arr) /** * Formats SQL queries to html * - * @param array The SQL queries - * @param string mode - * @param integer starting token - * @param integer number of tokens to format, -1 = all + * @param array $arr The SQL queries + * @param string $mode mode of printing + * @param integer $start_token starting token + * @param integer $numbr_of_tokens number of tokens to format, -1 = all * * @return string The formatted SQL queries *