2 /* vim: set expandtab sw=4 ts=4 sts=4: */
4 * Common Option Constants For DBI Functions
8 if (! defined('PHPMYADMIN')) {
15 // PMA_DBI_try_query()
16 define('PMA_DBI_QUERY_STORE', 1); // Force STORE_RESULT method, ignored by classic MySQL.
17 define('PMA_DBI_QUERY_UNBUFFERED', 2); // Do not read whole query
18 // PMA_DBI_get_variable()
19 define('PMA_DBI_GETVAR_SESSION', 1);
20 define('PMA_DBI_GETVAR_GLOBAL', 2);
23 * Loads the mysql extensions if it is not loaded yet
25 * @param string $extension mysql extension to load
27 function PMA_DBI_checkAndLoadMysqlExtension($extension = 'mysql') {
28 if (! function_exists($extension . '_connect')) {
30 // check whether mysql is available
31 if (! function_exists($extension . '_connect')) {
41 * check for requested extension
43 if (! PMA_DBI_checkAndLoadMysqlExtension($GLOBALS['cfg']['Server']['extension'])) {
45 // if it fails try alternative extension ...
46 // and display an error ...
49 * @todo 2.7.1: add different messages for alternativ extension
50 * and complete fail (no alternativ extension too)
52 $GLOBALS['PMA_errors'][] =
53 sprintf(PMA_sanitize($GLOBALS['strCantLoad']),
54 $GLOBALS['cfg']['Server']['extension'])
55 .' - <a href="./Documentation.html#faqmysql" target="documentation">'
56 .$GLOBALS['strDocu'] . '</a>';
58 if ($GLOBALS['cfg']['Server']['extension'] === 'mysql') {
59 $alternativ_extension = 'mysqli';
61 $alternativ_extension = 'mysql';
64 if (! PMA_DBI_checkAndLoadMysqlExtension($alternativ_extension)) {
65 // if alternativ fails too ...
67 sprintf($GLOBALS['strCantLoad'],
68 $GLOBALS['cfg']['Server']['extension'])
69 . ' - [a@./Documentation.html#faqmysql@documentation]'
70 . $GLOBALS['strDocu'] . '[/a]');
73 $GLOBALS['cfg']['Server']['extension'] = $alternativ_extension;
74 unset($alternativ_extension);
78 * Including The DBI Plugin
80 require_once './libraries/dbi/' . $GLOBALS['cfg']['Server']['extension'] . '.dbi.lib.php';
85 function PMA_DBI_query($query, $link = null, $options = 0) {
86 $res = PMA_DBI_try_query($query, $link, $options)
87 or PMA_mysqlDie(PMA_DBI_getError($link), $query);
92 * converts charset of a mysql message, usally coming from mysql_error(),
93 * into PMA charset, usally UTF-8
94 * uses language to charset mapping from mysql/share/errmsg.txt
95 * and charset names to ISO charset from information_schema.CHARACTER_SETS
97 * @uses $GLOBALS['cfg']['IconvExtraParams']
98 * @uses $GLOBALS['charset'] as target charset
99 * @uses PMA_DBI_fetch_value() to get server_language
100 * @uses preg_match() to filter server_language
102 * @uses function_exists() to check for a convert function
103 * @uses iconv() to convert message
104 * @uses libiconv() to convert message
105 * @uses recode_string() to convert message
106 * @uses mb_convert_encoding() to convert message
107 * @param string $message
108 * @return string $message
110 function PMA_DBI_convert_message($message) {
111 // latin always last!
113 'japanese' => 'EUC-JP', //'ujis',
114 'japanese-sjis' => 'Shift-JIS', //'sjis',
115 'korean' => 'EUC-KR', //'euckr',
116 'russian' => 'KOI8-R', //'koi8r',
117 'ukrainian' => 'KOI8-U', //'koi8u',
118 'greek' => 'ISO-8859-7', //'greek',
119 'serbian' => 'CP1250', //'cp1250',
120 'estonian' => 'ISO-8859-13', //'latin7',
121 'slovak' => 'ISO-8859-2', //'latin2',
122 'czech' => 'ISO-8859-2', //'latin2',
123 'hungarian' => 'ISO-8859-2', //'latin2',
124 'polish' => 'ISO-8859-2', //'latin2',
125 'romanian' => 'ISO-8859-2', //'latin2',
126 'spanish' => 'CP1252', //'latin1',
127 'swedish' => 'CP1252', //'latin1',
128 'italian' => 'CP1252', //'latin1',
129 'norwegian-ny' => 'CP1252', //'latin1',
130 'norwegian' => 'CP1252', //'latin1',
131 'portuguese' => 'CP1252', //'latin1',
132 'danish' => 'CP1252', //'latin1',
133 'dutch' => 'CP1252', //'latin1',
134 'english' => 'CP1252', //'latin1',
135 'french' => 'CP1252', //'latin1',
136 'german' => 'CP1252', //'latin1',
139 if ($server_language = PMA_DBI_fetch_value('SHOW VARIABLES LIKE \'language\';', 0, 1)) {
141 if (preg_match('&(?:\\\|\\/)([^\\\\\/]*)(?:\\\|\\/)$&i', $server_language, $found)) {
142 $server_language = $found[1];
146 if (! empty($server_language) && isset($encodings[$server_language])) {
147 if (function_exists('iconv')) {
148 if ((@stristr
(PHP_OS
, 'AIX')) && (@strcasecmp
(ICONV_IMPL
, 'unknown') == 0) && (@strcasecmp
(ICONV_VERSION
, 'unknown') == 0)) {
149 require_once './libraries/iconv_wrapper.lib.php';
150 $message = PMA_aix_iconv_wrapper($encodings[$server_language],
151 $GLOBALS['charset'] . $GLOBALS['cfg']['IconvExtraParams'], $message);
153 $message = iconv($encodings[$server_language],
154 $GLOBALS['charset'] . $GLOBALS['cfg']['IconvExtraParams'], $message);
156 } elseif (function_exists('recode_string')) {
157 $message = recode_string($encodings[$server_language] . '..' . $GLOBALS['charset'],
159 } elseif (function_exists('libiconv')) {
160 $message = libiconv($encodings[$server_language], $GLOBALS['charset'], $message);
161 } elseif (function_exists('mb_convert_encoding')) {
162 // do not try unsupported charsets
163 if (! in_array($server_language, array('ukrainian', 'greek', 'serbian'))) {
164 $message = mb_convert_encoding($message, $GLOBALS['charset'],
165 $encodings[$server_language]);
170 * @todo lang not found, try all, what TODO ?
178 * returns array with table names for given db
180 * @param string $database name of database
181 * @param mixed $link mysql link resource|object
182 * @return array tables names
184 function PMA_DBI_get_tables($database, $link = null)
186 return PMA_DBI_fetch_result('SHOW TABLES FROM ' . PMA_backquote($database) . ';',
187 null, 0, $link, PMA_DBI_QUERY_STORE
);
191 * usort comparison callback
193 * @param string $a first argument to sort
194 * @param string $b second argument to sort
196 * @return integer a value representing whether $a should be before $b in the
197 * sorted array or not
199 * @global string the column the array shall be sorted by
200 * @global string the sorting order ('ASC' or 'DESC')
204 function PMA_usort_comparison_callback($a, $b)
206 if ($GLOBALS['cfg']['NaturalOrder']) {
207 $sorter = 'strnatcasecmp';
209 $sorter = 'strcasecmp';
212 // return -1 * strnatcasecmp($a["SCHEMA_TABLES"], $b["SCHEMA_TABLES"])
213 return ($GLOBALS['callback_sort_order'] == 'ASC' ?
1 : -1) * $sorter($a[$GLOBALS['callback_sort_by']], $b[$GLOBALS['callback_sort_by']]);
214 } // end of the 'PMA_usort_comparison_callback()' function
217 * returns array of all tables in given db or dbs
218 * this function expects unquoted names:
220 * WRONG: `my_database`
221 * WRONG: my\_database
222 * if $tbl_is_group is true, $table is used as filter for table names
223 * if $tbl_is_group is 'comment, $table is used as filter for table comments
226 * PMA_DBI_get_tables_full('my_database');
227 * PMA_DBI_get_tables_full('my_database', 'my_table'));
228 * PMA_DBI_get_tables_full('my_database', 'my_tables_', true));
229 * PMA_DBI_get_tables_full('my_database', 'my_tables_', 'comment'));
232 * @uses PMA_MYSQL_INT_VERSION
233 * @uses PMA_DBI_fetch_result()
234 * @uses PMA_escape_mysql_wildcards()
235 * @uses PMA_backquote()
240 * @param string $databases database
241 * @param string $table table
242 * @param boolean|string $tbl_is_group $table is a table group
243 * @param resource $link mysql link
244 * @param integer $limit_offset zero-based offset for the count
245 * @param boolean|integer $limit_count number of tables to return
246 * @return array list of tables in given db(s)
248 function PMA_DBI_get_tables_full($database, $table = false,
249 $tbl_is_group = false, $link = null, $limit_offset = 0, $limit_count = false)
251 if (true === $limit_count) {
252 $limit_count = $GLOBALS['cfg']['MaxTableList'];
254 // prepare and check parameters
255 if (! is_array($database)) {
256 $databases = array($database);
258 $databases = $database;
263 if (PMA_MYSQL_INT_VERSION
>= 50002) {
264 // get table information from information_schema
266 if (true === $tbl_is_group) {
267 $sql_where_table = 'AND `TABLE_NAME` LIKE \''
268 . PMA_escape_mysql_wildcards(addslashes($table)) . '%\'';
269 } elseif ('comment' === $tbl_is_group) {
270 $sql_where_table = 'AND `TABLE_COMMENT` LIKE \''
271 . PMA_escape_mysql_wildcards(addslashes($table)) . '%\'';
273 $sql_where_table = 'AND `TABLE_NAME` = \'' . addslashes($table) . '\'';
276 $sql_where_table = '';
280 // `SCHEMA_FIELD_NAME` AS `SHOW_TABLE_STATUS_FIELD_NAME`
282 // on non-Windows servers,
283 // added BINARY in the WHERE clause to force a case sensitive
284 // comparison (if we are looking for the db Aa we don't want
285 // to find the db aa)
286 $this_databases = array_map('PMA_sqlAddslashes', $databases);
290 `TABLE_SCHEMA` AS `Db`,
291 `TABLE_NAME` AS `Name`,
292 `ENGINE` AS `Engine`,
294 `VERSION` AS `Version`,
295 `ROW_FORMAT` AS `Row_format`,
296 `TABLE_ROWS` AS `Rows`,
297 `AVG_ROW_LENGTH` AS `Avg_row_length`,
298 `DATA_LENGTH` AS `Data_length`,
299 `MAX_DATA_LENGTH` AS `Max_data_length`,
300 `INDEX_LENGTH` AS `Index_length`,
301 `DATA_FREE` AS `Data_free`,
302 `AUTO_INCREMENT` AS `Auto_increment`,
303 `CREATE_TIME` AS `Create_time`,
304 `UPDATE_TIME` AS `Update_time`,
305 `CHECK_TIME` AS `Check_time`,
306 `TABLE_COLLATION` AS `Collation`,
307 `CHECKSUM` AS `Checksum`,
308 `CREATE_OPTIONS` AS `Create_options`,
309 `TABLE_COMMENT` AS `Comment`
310 FROM `information_schema`.`TABLES`
311 WHERE ' . (PMA_IS_WINDOWS ?
'' : 'BINARY') . ' `TABLE_SCHEMA` IN (\'' . implode("', '", $this_databases) . '\')
312 ' . $sql_where_table;
315 $sql .= ' LIMIT ' . $limit_count . ' OFFSET ' . $limit_offset;
317 $tables = PMA_DBI_fetch_result($sql, array('TABLE_SCHEMA', 'TABLE_NAME'),
319 unset($sql_where_table, $sql);
321 // If permissions are wrong on even one database directory,
322 // information_schema does not return any table info for any database
323 // this is why we fall back to SHOW TABLE STATUS even for MySQL >= 50002
324 if (PMA_MYSQL_INT_VERSION
< 50002 ||
empty($tables)) {
325 foreach ($databases as $each_database) {
326 if (true === $tbl_is_group) {
327 $sql = 'SHOW TABLE STATUS FROM '
328 . PMA_backquote($each_database)
329 .' LIKE \'' . PMA_escape_mysql_wildcards(addslashes($table)) . '%\'';
331 $sql = 'SHOW TABLE STATUS FROM '
332 . PMA_backquote($each_database) . ';';
334 $each_tables = PMA_DBI_fetch_result($sql, 'Name', null, $link);
336 $each_tables = array_slice($each_tables, $limit_offset, $limit_count);
339 foreach ($each_tables as $table_name => $each_table) {
340 if ('comment' === $tbl_is_group
341 && 0 === strpos($each_table['Comment'], $table))
343 // remove table from list
344 unset($each_tables[$table_name]);
348 if (! isset($each_tables[$table_name]['Type'])
349 && isset($each_tables[$table_name]['Engine'])) {
350 // pma BC, same parts of PMA still uses 'Type'
351 $each_tables[$table_name]['Type']
352 =& $each_tables[$table_name]['Engine'];
353 } elseif (! isset($each_tables[$table_name]['Engine'])
354 && isset($each_tables[$table_name]['Type'])) {
355 // old MySQL reports Type, newer MySQL reports Engine
356 $each_tables[$table_name]['Engine']
357 =& $each_tables[$table_name]['Type'];
360 // MySQL forward compatibility
361 // so pma could use this array as if every server is of version >5.0
362 $each_tables[$table_name]['TABLE_SCHEMA'] = $each_database;
363 $each_tables[$table_name]['TABLE_NAME'] =& $each_tables[$table_name]['Name'];
364 $each_tables[$table_name]['ENGINE'] =& $each_tables[$table_name]['Engine'];
365 $each_tables[$table_name]['VERSION'] =& $each_tables[$table_name]['Version'];
366 $each_tables[$table_name]['ROW_FORMAT'] =& $each_tables[$table_name]['Row_format'];
367 $each_tables[$table_name]['TABLE_ROWS'] =& $each_tables[$table_name]['Rows'];
368 $each_tables[$table_name]['AVG_ROW_LENGTH'] =& $each_tables[$table_name]['Avg_row_length'];
369 $each_tables[$table_name]['DATA_LENGTH'] =& $each_tables[$table_name]['Data_length'];
370 $each_tables[$table_name]['MAX_DATA_LENGTH'] =& $each_tables[$table_name]['Max_data_length'];
371 $each_tables[$table_name]['INDEX_LENGTH'] =& $each_tables[$table_name]['Index_length'];
372 $each_tables[$table_name]['DATA_FREE'] =& $each_tables[$table_name]['Data_free'];
373 $each_tables[$table_name]['AUTO_INCREMENT'] =& $each_tables[$table_name]['Auto_increment'];
374 $each_tables[$table_name]['CREATE_TIME'] =& $each_tables[$table_name]['Create_time'];
375 $each_tables[$table_name]['UPDATE_TIME'] =& $each_tables[$table_name]['Update_time'];
376 $each_tables[$table_name]['CHECK_TIME'] =& $each_tables[$table_name]['Check_time'];
377 $each_tables[$table_name]['TABLE_COLLATION'] =& $each_tables[$table_name]['Collation'];
378 $each_tables[$table_name]['CHECKSUM'] =& $each_tables[$table_name]['Checksum'];
379 $each_tables[$table_name]['CREATE_OPTIONS'] =& $each_tables[$table_name]['Create_options'];
380 $each_tables[$table_name]['TABLE_COMMENT'] =& $each_tables[$table_name]['Comment'];
382 if (strtoupper($each_tables[$table_name]['Comment']) === 'VIEW') {
383 $each_tables[$table_name]['TABLE_TYPE'] = 'VIEW';
386 * @todo difference between 'TEMPORARY' and 'BASE TABLE' but how to detect?
388 $each_tables[$table_name]['TABLE_TYPE'] = 'BASE TABLE';
392 $tables[$each_database] = $each_tables;
396 if ($GLOBALS['cfg']['NaturalOrder']) {
397 foreach ($tables as $key => $val) {
398 uksort($tables[$key], 'strnatcasecmp');
402 if (! is_array($database)) {
403 if (isset($tables[$database])) {
404 return $tables[$database];
405 } elseif (isset($tables[strtolower($database)])) {
406 // on windows with lower_case_table_names = 1
408 // with SHOW DATABASES or information_schema.SCHEMATA: `Test`
409 // but information_schema.TABLES gives `test`
411 // http://sf.net/support/tracker.php?aid=1436171
412 return $tables[strtolower($database)];
422 * returns array with databases containing extended infos about them
424 * @todo move into PMA_List_Database?
425 * @param string $databases database
426 * @param boolean $force_stats retrieve stats also for MySQL < 5
427 * @param resource $link mysql link
428 * @param string $sort_by column to order by
429 * @param string $sort_order ASC or DESC
430 * @param integer $limit_offset starting offset for LIMIT
431 * @param bool|int $limit_count row count for LIMIT or true for $GLOBALS['cfg']['MaxDbList']
432 * @return array $databases
434 function PMA_DBI_get_databases_full($database = null, $force_stats = false,
435 $link = null, $sort_by = 'SCHEMA_NAME', $sort_order = 'ASC',
436 $limit_offset = 0, $limit_count = false)
438 $sort_order = strtoupper($sort_order);
440 if (true === $limit_count) {
441 $limit_count = $GLOBALS['cfg']['MaxDbList'];
444 // initialize to avoid errors when there are no databases
445 $databases = array();
447 $apply_limit_and_order_manual = true;
449 if (PMA_MYSQL_INT_VERSION
>= 50002) {
451 * if $GLOBALS['cfg']['NaturalOrder'] is enabled, we cannot use LIMIT
452 * cause MySQL does not support natural ordering, we have to do it afterward
454 if ($GLOBALS['cfg']['NaturalOrder']) {
458 $limit = ' LIMIT ' . $limit_count . ' OFFSET ' . $limit_offset;
461 $apply_limit_and_order_manual = false;
464 // get table information from information_schema
466 $sql_where_schema = 'WHERE `SCHEMA_NAME` LIKE \''
467 . addslashes($database) . '\'';
469 $sql_where_schema = '';
473 // `SCHEMA_FIELD_NAME` AS `SHOW_TABLE_STATUS_FIELD_NAME`
475 SELECT `information_schema`.`SCHEMATA`.*';
478 COUNT(`information_schema`.`TABLES`.`TABLE_SCHEMA`)
480 SUM(`information_schema`.`TABLES`.`TABLE_ROWS`)
481 AS `SCHEMA_TABLE_ROWS`,
482 SUM(`information_schema`.`TABLES`.`DATA_LENGTH`)
483 AS `SCHEMA_DATA_LENGTH`,
484 SUM(`information_schema`.`TABLES`.`MAX_DATA_LENGTH`)
485 AS `SCHEMA_MAX_DATA_LENGTH`,
486 SUM(`information_schema`.`TABLES`.`INDEX_LENGTH`)
487 AS `SCHEMA_INDEX_LENGTH`,
488 SUM(`information_schema`.`TABLES`.`DATA_LENGTH`
489 + `information_schema`.`TABLES`.`INDEX_LENGTH`)
491 SUM(`information_schema`.`TABLES`.`DATA_FREE`)
492 AS `SCHEMA_DATA_FREE`';
495 FROM `information_schema`.`SCHEMATA`';
498 LEFT JOIN `information_schema`.`TABLES`
499 ON BINARY `information_schema`.`TABLES`.`TABLE_SCHEMA`
500 = BINARY `information_schema`.`SCHEMATA`.`SCHEMA_NAME`';
503 ' . $sql_where_schema . '
504 GROUP BY BINARY `information_schema`.`SCHEMATA`.`SCHEMA_NAME`
505 ORDER BY BINARY ' . PMA_backquote($sort_by) . ' ' . $sort_order
507 $databases = PMA_DBI_fetch_result($sql, 'SCHEMA_NAME', null, $link);
509 $mysql_error = PMA_DBI_getError($link);
510 if (! count($databases) && $GLOBALS['errno']) {
511 PMA_mysqlDie($mysql_error, $sql);
514 // display only databases also in official database list
515 // f.e. to apply hide_db and only_db
516 $drops = array_diff(array_keys($databases), $GLOBALS['PMA_List_Database']->items
);
518 foreach ($drops as $drop) {
519 unset($databases[$drop]);
523 unset($sql_where_schema, $sql, $drops);
525 foreach ($GLOBALS['PMA_List_Database']->items
as $database_name) {
526 // MySQL forward compatibility
527 // so pma could use this array as if every server is of version >5.0
528 $databases[$database_name]['SCHEMA_NAME'] = $database_name;
531 require_once 'mysql_charsets.lib.php';
533 $databases[$database_name]['DEFAULT_COLLATION_NAME']
534 = PMA_getDbCollation($database_name);
536 // get additonal info about tables
537 $databases[$database_name]['SCHEMA_TABLES'] = 0;
538 $databases[$database_name]['SCHEMA_TABLE_ROWS'] = 0;
539 $databases[$database_name]['SCHEMA_DATA_LENGTH'] = 0;
540 $databases[$database_name]['SCHEMA_MAX_DATA_LENGTH'] = 0;
541 $databases[$database_name]['SCHEMA_INDEX_LENGTH'] = 0;
542 $databases[$database_name]['SCHEMA_LENGTH'] = 0;
543 $databases[$database_name]['SCHEMA_DATA_FREE'] = 0;
545 $res = PMA_DBI_query('SHOW TABLE STATUS FROM ' . PMA_backquote($database_name) . ';');
546 while ($row = PMA_DBI_fetch_assoc($res)) {
547 $databases[$database_name]['SCHEMA_TABLES']++
;
548 $databases[$database_name]['SCHEMA_TABLE_ROWS']
550 $databases[$database_name]['SCHEMA_DATA_LENGTH']
551 +
= $row['Data_length'];
552 $databases[$database_name]['SCHEMA_MAX_DATA_LENGTH']
553 +
= $row['Max_data_length'];
554 $databases[$database_name]['SCHEMA_INDEX_LENGTH']
555 +
= $row['Index_length'];
556 $databases[$database_name]['SCHEMA_DATA_FREE']
557 +
= $row['Data_free'];
558 $databases[$database_name]['SCHEMA_LENGTH']
559 +
= $row['Data_length'] +
$row['Index_length'];
561 PMA_DBI_free_result($res);
568 * apply limit and order manually now
569 * (caused by older MySQL < 5 or $GLOBALS['cfg']['NaturalOrder'])
571 if ($apply_limit_and_order_manual) {
572 $GLOBALS['callback_sort_order'] = $sort_order;
573 $GLOBALS['callback_sort_by'] = $sort_by;
574 usort($databases, 'PMA_usort_comparison_callback');
575 unset($GLOBALS['callback_sort_order'], $GLOBALS['callback_sort_by']);
581 $databases = array_slice($databases, $limit_offset, $limit_count);
589 * returns detailed array with all columns for given table in database,
590 * or all tables/databases
592 * @param string $database name of database
593 * @param string $table name of table to retrieve columns from
594 * @param string $column name of specific column
595 * @param mixed $link mysql link resource
597 function PMA_DBI_get_columns_full($database = null, $table = null,
598 $column = null, $link = null)
602 if (PMA_MYSQL_INT_VERSION
>= 50002) {
603 $sql_wheres = array();
604 $array_keys = array();
606 // get columns information from information_schema
607 if (null !== $database) {
608 $sql_wheres[] = '`TABLE_SCHEMA` = \'' . addslashes($database) . '\' ';
610 $array_keys[] = 'TABLE_SCHEMA';
612 if (null !== $table) {
613 $sql_wheres[] = '`TABLE_NAME` = \'' . addslashes($table) . '\' ';
615 $array_keys[] = 'TABLE_NAME';
617 if (null !== $column) {
618 $sql_wheres[] = '`COLUMN_NAME` = \'' . addslashes($column) . '\' ';
620 $array_keys[] = 'COLUMN_NAME';
624 // `[SCHEMA_FIELD_NAME]` AS `[SHOW_FULL_COLUMNS_FIELD_NAME]`
627 `COLUMN_NAME` AS `Field`,
628 `COLUMN_TYPE` AS `Type`,
629 `COLLATION_NAME` AS `Collation`,
630 `IS_NULLABLE` AS `Null`,
631 `COLUMN_KEY` AS `Key`,
632 `COLUMN_DEFAULT` AS `Default`,
634 `PRIVILEGES` AS `Privileges`,
635 `COLUMN_COMMENT` AS `Comment`
636 FROM `information_schema`.`COLUMNS`';
637 if (count($sql_wheres)) {
638 $sql .= "\n" . ' WHERE ' . implode(' AND ', $sql_wheres);
641 $columns = PMA_DBI_fetch_result($sql, $array_keys, null, $link);
642 unset($sql_wheres, $sql);
644 if (null === $database) {
645 foreach ($GLOBALS['PMA_List_Database']->items
as $database) {
646 $columns[$database] = PMA_DBI_get_columns_full($database, null,
650 } elseif (null === $table) {
651 $tables = PMA_DBI_get_tables($database);
652 foreach ($tables as $table) {
653 $columns[$table] = PMA_DBI_get_columns_full(
654 $database, $table, null, $link);
659 $sql = 'SHOW FULL COLUMNS FROM '
660 . PMA_backquote($database) . '.' . PMA_backquote($table);
661 if (null !== $column) {
662 $sql .= " LIKE '" . $column . "'";
665 $columns = PMA_DBI_fetch_result($sql, 'Field', null, $link);
667 $ordinal_position = 1;
668 foreach ($columns as $column_name => $each_column) {
670 // MySQL forward compatibility
671 // so pma could use this array as if every server is of version >5.0
672 $columns[$column_name]['COLUMN_NAME'] =& $columns[$column_name]['Field'];
673 $columns[$column_name]['COLUMN_TYPE'] =& $columns[$column_name]['Type'];
674 $columns[$column_name]['COLLATION_NAME'] =& $columns[$column_name]['Collation'];
675 $columns[$column_name]['IS_NULLABLE'] =& $columns[$column_name]['Null'];
676 $columns[$column_name]['COLUMN_KEY'] =& $columns[$column_name]['Key'];
677 $columns[$column_name]['COLUMN_DEFAULT'] =& $columns[$column_name]['Default'];
678 $columns[$column_name]['EXTRA'] =& $columns[$column_name]['Extra'];
679 $columns[$column_name]['PRIVILEGES'] =& $columns[$column_name]['Privileges'];
680 $columns[$column_name]['COLUMN_COMMENT'] =& $columns[$column_name]['Comment'];
682 $columns[$column_name]['TABLE_CATALOG'] = null;
683 $columns[$column_name]['TABLE_SCHEMA'] = $database;
684 $columns[$column_name]['TABLE_NAME'] = $table;
685 $columns[$column_name]['ORDINAL_POSITION'] = $ordinal_position;
686 $columns[$column_name]['DATA_TYPE'] =
687 substr($columns[$column_name]['COLUMN_TYPE'], 0,
688 strpos($columns[$column_name]['COLUMN_TYPE'], '('));
690 * @todo guess CHARACTER_MAXIMUM_LENGTH from COLUMN_TYPE
692 $columns[$column_name]['CHARACTER_MAXIMUM_LENGTH'] = null;
694 * @todo guess CHARACTER_OCTET_LENGTH from CHARACTER_MAXIMUM_LENGTH
696 $columns[$column_name]['CHARACTER_OCTET_LENGTH'] = null;
697 $columns[$column_name]['NUMERIC_PRECISION'] = null;
698 $columns[$column_name]['NUMERIC_SCALE'] = null;
699 $columns[$column_name]['CHARACTER_SET_NAME'] =
700 substr($columns[$column_name]['COLLATION_NAME'], 0,
701 strpos($columns[$column_name]['COLLATION_NAME'], '_'));
706 if (null !== $column) {
708 $columns = current($columns);
716 * @todo should only return columns names, for more info use PMA_DBI_get_columns_full()
718 * @deprecated by PMA_DBI_get_columns() or PMA_DBI_get_columns_full()
719 * @param string $database name of database
720 * @param string $table name of table to retrieve columns from
721 * @param mixed $link mysql link resource
722 * @return array column info
724 function PMA_DBI_get_fields($database, $table, $link = null)
726 // here we use a try_query because when coming from
727 // tbl_create + tbl_properties.inc.php, the table does not exist
728 $fields = PMA_DBI_fetch_result(
730 FROM ' . PMA_backquote($database) . '.' . PMA_backquote($table),
732 if (! is_array($fields) ||
count($fields) < 1) {
739 * array PMA_DBI_get_columns(string $database, string $table, bool $full = false, mysql db link $link = null)
741 * @param string $database name of database
742 * @param string $table name of table to retrieve columns from
743 * @param boolean $full wether to return full info or only column names
744 * @param mixed $link mysql link resource
745 * @return array column names
747 function PMA_DBI_get_columns($database, $table, $full = false, $link = null)
749 $fields = PMA_DBI_fetch_result(
750 'SHOW ' . ($full ?
'FULL' : '') . ' COLUMNS
751 FROM ' . PMA_backquote($database) . '.' . PMA_backquote($table),
752 'Field', ($full ?
null : 'Field'), $link);
753 if (! is_array($fields) ||
count($fields) < 1) {
760 * returns value of given mysql server variable
762 * @param string $var mysql server variable name
763 * @param int $type PMA_DBI_GETVAR_SESSION|PMA_DBI_GETVAR_GLOBAL
764 * @param mixed $link mysql link resource|object
765 * @return mixed value for mysql server variable
767 function PMA_DBI_get_variable($var, $type = PMA_DBI_GETVAR_SESSION
, $link = null)
769 if ($link === null) {
770 if (isset($GLOBALS['userlink'])) {
771 $link = $GLOBALS['userlink'];
776 if (PMA_MYSQL_INT_VERSION
< 40002) {
780 case PMA_DBI_GETVAR_SESSION
:
781 $modifier = ' SESSION';
783 case PMA_DBI_GETVAR_GLOBAL
:
784 $modifier = ' GLOBAL';
789 return PMA_DBI_fetch_value(
790 'SHOW' . $modifier . ' VARIABLES LIKE \'' . $var . '\';', 0, 1, $link);
794 * @uses ./libraries/charset_conversion.lib.php
795 * @uses PMA_DBI_QUERY_STORE
796 * @uses PMA_REMOVED_NON_UTF_8
797 * @uses PMA_MYSQL_INT_VERSION
798 * @uses PMA_MYSQL_STR_VERSION
799 * @uses PMA_DBI_GETVAR_SESSION
800 * @uses PMA_DBI_fetch_value()
801 * @uses PMA_DBI_query()
802 * @uses PMA_DBI_get_variable()
803 * @uses $GLOBALS['collation_connection']
804 * @uses $GLOBALS['charset_connection']
805 * @uses $GLOBALS['available_languages']
806 * @uses $GLOBALS['mysql_charset_map']
807 * @uses $GLOBALS['charset']
808 * @uses $GLOBALS['lang']
809 * @uses $GLOBALS['cfg']['Lang']
810 * @uses $GLOBALS['cfg']['ColumnTypes']
819 * @param mixed $link mysql link resource|object
820 * @param boolean $is_controluser
822 function PMA_DBI_postConnect($link, $is_controluser = false)
824 if (!defined('PMA_MYSQL_INT_VERSION')) {
825 $mysql_version = PMA_DBI_fetch_value(
826 'SELECT VERSION()', 0, 0, $link, PMA_DBI_QUERY_STORE
);
827 if ($mysql_version) {
828 $match = explode('.', $mysql_version);
829 define('PMA_MYSQL_INT_VERSION',
830 (int) sprintf('%d%02d%02d', $match[0], $match[1],
832 define('PMA_MYSQL_STR_VERSION', $mysql_version);
833 unset($mysql_version, $match);
835 define('PMA_MYSQL_INT_VERSION', 32332);
836 define('PMA_MYSQL_STR_VERSION', '3.23.32');
840 if (!defined('PMA_ENGINE_KEYWORD')) {
841 if (PMA_MYSQL_INT_VERSION
>= 40102) {
842 define('PMA_ENGINE_KEYWORD','ENGINE');
844 define('PMA_ENGINE_KEYWORD','TYPE');
848 if (PMA_MYSQL_INT_VERSION
>= 40100) {
850 // If $lang is defined and we are on MySQL >= 4.1.x,
851 // we auto-switch the lang to its UTF-8 version (if it exists and user
852 // didn't force language)
853 if (!empty($GLOBALS['lang'])
854 && (substr($GLOBALS['lang'], -5) != 'utf-8')
855 && !isset($GLOBALS['cfg']['Lang'])) {
856 $lang_utf_8_version =
857 substr($GLOBALS['lang'], 0, strpos($GLOBALS['lang'], '-'))
859 if (!empty($GLOBALS['available_languages'][$lang_utf_8_version])) {
860 $GLOBALS['lang'] = $lang_utf_8_version;
861 $GLOBALS['charset'] = 'utf-8';
862 define('PMA_LANG_RELOAD', 1);
866 // and we remove the non-UTF-8 choices to avoid confusion
867 // (unless there is a forced language)
868 if (!defined('PMA_REMOVED_NON_UTF_8') && ! isset($GLOBALS['cfg']['Lang'])) {
869 foreach ($GLOBALS['available_languages'] as $each_lang => $dummy) {
870 if (substr($each_lang, -5) != 'utf-8') {
871 unset($GLOBALS['available_languages'][$each_lang]);
874 define('PMA_REMOVED_NON_UTF_8', 1);
877 $mysql_charset = $GLOBALS['mysql_charset_map'][$GLOBALS['charset']];
879 ||
empty($GLOBALS['collation_connection'])
880 ||
(strpos($GLOBALS['collation_connection'], '_')
881 ?
substr($GLOBALS['collation_connection'], 0, strpos($GLOBALS['collation_connection'], '_'))
882 : $GLOBALS['collation_connection']) == $mysql_charset) {
884 PMA_DBI_query('SET NAMES ' . $mysql_charset . ';', $link,
885 PMA_DBI_QUERY_STORE
);
887 PMA_DBI_query('SET CHARACTER SET ' . $mysql_charset . ';', $link,
888 PMA_DBI_QUERY_STORE
);
890 if (!empty($GLOBALS['collation_connection'])) {
891 PMA_DBI_query('SET collation_connection = \'' . $GLOBALS['collation_connection'] . '\';',
892 $link, PMA_DBI_QUERY_STORE
);
894 if (!$is_controluser) {
895 $GLOBALS['collation_connection'] = PMA_DBI_get_variable('collation_connection',
896 PMA_DBI_GETVAR_SESSION
, $link);
897 $GLOBALS['charset_connection'] = PMA_DBI_get_variable('character_set_connection',
898 PMA_DBI_GETVAR_SESSION
, $link);
901 // Add some field types to the list, this needs to be done once per session!
902 if (!in_array('BINARY', $GLOBALS['cfg']['ColumnTypes'])) {
903 $GLOBALS['cfg']['ColumnTypes'][] = 'BINARY';
905 if (!in_array('VARBINARY', $GLOBALS['cfg']['ColumnTypes'])) {
906 $GLOBALS['cfg']['ColumnTypes'][] = 'VARBINARY';
909 require_once './libraries/charset_conversion.lib.php';
914 * returns a single value from the given result or query,
915 * if the query or the result has more than one row or field
916 * the first field of the first row is returned
919 * $sql = 'SELECT `name` FROM `user` WHERE `id` = 123';
920 * $user_name = PMA_DBI_fetch_value($sql);
922 * // $user_name = 'John Doe'
927 * @uses PMA_DBI_try_query()
928 * @uses PMA_DBI_num_rows()
929 * @uses PMA_DBI_fetch_row()
930 * @uses PMA_DBI_fetch_assoc()
931 * @uses PMA_DBI_free_result()
932 * @param string|mysql_result $result query or mysql result
933 * @param integer $row_number row to fetch the value from,
934 * starting at 0, with 0 beeing default
935 * @param integer|string $field field to fetch the value from,
936 * starting at 0, with 0 beeing default
937 * @param resource $link mysql link
938 * @param mixed $options
939 * @return mixed value of first field in first row from result
940 * or false if not found
942 function PMA_DBI_fetch_value($result, $row_number = 0, $field = 0, $link = null, $options = 0) {
945 if (is_string($result)) {
946 $result = PMA_DBI_try_query($result, $link, $options | PMA_DBI_QUERY_STORE
);
949 // return false if result is empty or false
950 // or requested row is larger than rows in result
951 if (PMA_DBI_num_rows($result) < ($row_number +
1)) {
955 // if $field is an integer use non associative mysql fetch function
956 if (is_int($field)) {
957 $fetch_function = 'PMA_DBI_fetch_row';
959 $fetch_function = 'PMA_DBI_fetch_assoc';
963 for ($i = 0; $i <= $row_number; $i++
) {
964 $row = $fetch_function($result);
966 PMA_DBI_free_result($result);
968 // return requested field
969 if (isset($row[$field])) {
970 $value = $row[$field];
978 * returns only the first row from the result
981 * $sql = 'SELECT * FROM `user` WHERE `id` = 123';
982 * $user = PMA_DBI_fetch_single_row($sql);
984 * // $user = array('id' => 123, 'name' => 'John Doe')
988 * @uses PMA_DBI_try_query()
989 * @uses PMA_DBI_num_rows()
990 * @uses PMA_DBI_fetch_row()
991 * @uses PMA_DBI_fetch_assoc()
992 * @uses PMA_DBI_fetch_array()
993 * @uses PMA_DBI_free_result()
994 * @param string|mysql_result $result query or mysql result
995 * @param string $type NUM|ASSOC|BOTH
996 * returned array should either numeric
997 * associativ or booth
998 * @param resource $link mysql link
999 * @param mixed $options
1000 * @return array|boolean first row from result
1001 * or false if result is empty
1003 function PMA_DBI_fetch_single_row($result, $type = 'ASSOC', $link = null, $options = 0) {
1004 if (is_string($result)) {
1005 $result = PMA_DBI_try_query($result, $link, $options | PMA_DBI_QUERY_STORE
);
1008 // return null if result is empty or false
1009 if (! PMA_DBI_num_rows($result)) {
1015 $fetch_function = 'PMA_DBI_fetch_row';
1018 $fetch_function = 'PMA_DBI_fetch_assoc';
1022 $fetch_function = 'PMA_DBI_fetch_array';
1026 $row = $fetch_function($result);
1027 PMA_DBI_free_result($result);
1032 * returns all rows in the resultset in one array
1035 * $sql = 'SELECT * FROM `user`';
1036 * $users = PMA_DBI_fetch_result($sql);
1038 * // $users[] = array('id' => 123, 'name' => 'John Doe')
1040 * $sql = 'SELECT `id`, `name` FROM `user`';
1041 * $users = PMA_DBI_fetch_result($sql, 'id');
1043 * // $users['123'] = array('id' => 123, 'name' => 'John Doe')
1045 * $sql = 'SELECT `id`, `name` FROM `user`';
1046 * $users = PMA_DBI_fetch_result($sql, 0);
1048 * // $users['123'] = array(0 => 123, 1 => 'John Doe')
1050 * $sql = 'SELECT `id`, `name` FROM `user`';
1051 * $users = PMA_DBI_fetch_result($sql, 'id', 'name');
1053 * $users = PMA_DBI_fetch_result($sql, 0, 1);
1055 * // $users['123'] = 'John Doe'
1057 * $sql = 'SELECT `name` FROM `user`';
1058 * $users = PMA_DBI_fetch_result($sql);
1060 * // $users[] = 'John Doe'
1065 * @uses PMA_DBI_try_query()
1066 * @uses PMA_DBI_num_rows()
1067 * @uses PMA_DBI_num_fields()
1068 * @uses PMA_DBI_fetch_row()
1069 * @uses PMA_DBI_fetch_assoc()
1070 * @uses PMA_DBI_free_result()
1071 * @param string|mysql_result $result query or mysql result
1072 * @param string|integer $key field-name or offset
1073 * used as key for array
1074 * @param string|integer $value value-name or offset
1075 * used as value for array
1076 * @param resource $link mysql link
1077 * @param mixed $options
1078 * @return array resultrows or values indexed by $key
1080 function PMA_DBI_fetch_result($result, $key = null, $value = null,
1081 $link = null, $options = 0)
1083 $resultrows = array();
1085 if (is_string($result)) {
1086 $result = PMA_DBI_try_query($result, $link, $options);
1089 // return empty array if result is empty or false
1094 $fetch_function = 'PMA_DBI_fetch_assoc';
1096 // no nested array if only one field is in result
1097 if (null === $key && 1 === PMA_DBI_num_fields($result)) {
1099 $fetch_function = 'PMA_DBI_fetch_row';
1102 // if $key is an integer use non associative mysql fetch function
1104 $fetch_function = 'PMA_DBI_fetch_row';
1107 if (null === $key && null === $value) {
1108 while ($row = $fetch_function($result)) {
1109 $resultrows[] = $row;
1111 } elseif (null === $key) {
1112 while ($row = $fetch_function($result)) {
1113 $resultrows[] = $row[$value];
1115 } elseif (null === $value) {
1116 if (is_array($key)) {
1117 while ($row = $fetch_function($result)) {
1118 $result_target =& $resultrows;
1119 foreach ($key as $key_index) {
1120 if (! isset($result_target[$row[$key_index]])) {
1121 $result_target[$row[$key_index]] = array();
1123 $result_target =& $result_target[$row[$key_index]];
1125 $result_target = $row;
1128 while ($row = $fetch_function($result)) {
1129 $resultrows[$row[$key]] = $row;
1133 if (is_array($key)) {
1134 while ($row = $fetch_function($result)) {
1135 $result_target =& $resultrows;
1136 foreach ($key as $key_index) {
1137 if (! isset($result_target[$row[$key_index]])) {
1138 $result_target[$row[$key_index]] = array();
1140 $result_target =& $result_target[$row[$key_index]];
1142 $result_target = $row[$value];
1145 while ($row = $fetch_function($result)) {
1146 $resultrows[$row[$key]] = $row[$value];
1151 PMA_DBI_free_result($result);
1156 * return default table engine for given database
1158 * @return string default table engine
1160 function PMA_DBI_get_default_engine()
1162 if (PMA_MYSQL_INT_VERSION
> 50002) {
1163 return PMA_DBI_fetch_value('SHOW VARIABLES LIKE \'storage_engine\';', 0, 1);
1165 return PMA_DBI_fetch_value('SHOW VARIABLES LIKE \'table_type\';', 0, 1);
1170 * Get supported SQL compatibility modes
1172 * @return array supported SQL compatibility modes
1174 function PMA_DBI_getCompatibilities()
1176 if (PMA_MYSQL_INT_VERSION
< 40100) {
1179 $compats = array('NONE');
1180 if (PMA_MYSQL_INT_VERSION
>= 40101) {
1181 $compats[] = 'ANSI';
1183 $compats[] = 'MAXDB';
1184 $compats[] = 'MYSQL323';
1185 $compats[] = 'MYSQL40';
1186 $compats[] = 'MSSQL';
1187 $compats[] = 'ORACLE';
1188 // removed; in MySQL 5.0.33, this produces exports that
1189 // can't be read by POSTGRESQL (see our bug #1596328)
1190 //$compats[] = 'POSTGRESQL';
1191 if (PMA_MYSQL_INT_VERSION
>= 50002) {
1192 $compats[] = 'TRADITIONAL';
1199 * returns warnings for last query
1201 * @uses $GLOBALS['userlink']
1202 * @uses PMA_DBI_fetch_result()
1203 * @param resource mysql link $link mysql link resource
1204 * @return array warnings
1206 function PMA_DBI_get_warnings($link = null)
1208 if (PMA_MYSQL_INT_VERSION
< 40100) {
1213 if (isset($GLOBALS['userlink'])) {
1214 $link = $GLOBALS['userlink'];
1220 return PMA_DBI_fetch_result('SHOW WARNINGS', null, null, $link);
1224 * returns true (int > 0) if current user is superuser
1227 * @return integer $is_superuser
1229 function PMA_isSuperuser() {
1230 return PMA_DBI_try_query('SELECT COUNT(*) FROM mysql.user',
1231 $GLOBALS['userlink'], PMA_DBI_QUERY_STORE
);
1236 * returns an array of PROCEDURE or FUNCTION names for a db
1238 * @uses PMA_DBI_free_result()
1239 * @param string $db db name
1240 * @param string $which PROCEDURE | FUNCTION
1241 * @param resource $link mysql link
1243 * @return array the procedure names or function names
1245 function PMA_DBI_get_procedures_or_functions($db, $which, $link = null) {
1247 $shows = PMA_DBI_fetch_result('SHOW ' . $which . ' STATUS;', null, null, $link);
1249 foreach ($shows as $one_show) {
1250 if ($one_show['Db'] == $db && $one_show['Type'] == $which) {
1251 $result[] = $one_show['Name'];
1258 * returns the definition of a specific PROCEDURE or FUNCTION
1260 * @uses PMA_DBI_fetch_value()
1261 * @param string $db db name
1262 * @param string $which PROCEDURE | FUNCTION
1263 * @param string $proc_or_function_name the procedure name or function name
1264 * @param resource $link mysql link
1266 * @return string the procedure's or function's definition
1268 function PMA_DBI_get_procedure_or_function_def($db, $which, $proc_or_function_name, $link = null) {
1270 $returned_field = array('PROCEDURE' => 'Create Procedure', 'FUNCTION' => 'Create Function');
1271 $query = 'SHOW CREATE ' . $which . ' ' . PMA_backquote($db) . '.' . PMA_backquote($proc_or_function_name);
1272 return(PMA_DBI_fetch_value($query, 0, $returned_field[$which]));
1276 * returns details about the TRIGGERs of a specific table
1278 * @uses PMA_DBI_fetch_result()
1279 * @param string $db db name
1280 * @param string $table table name
1282 * @return array information about triggers (may be empty)
1284 function PMA_DBI_get_triggers($db, $table) {
1288 // available in INFORMATION_SCHEMA since MySQL 5.0.10
1289 // Note: in http://dev.mysql.com/doc/refman/5.0/en/faqs-triggers.html
1290 // their example uses WHERE TRIGGER_SCHEMA='dbname' so let's use this
1291 // instead of WHERE EVENT_OBJECT_SCHEMA='dbname'
1292 if (PMA_MYSQL_INT_VERSION
>= 50010) {
1293 $triggers = PMA_DBI_fetch_result("SELECT TRIGGER_SCHEMA, TRIGGER_NAME, EVENT_MANIPULATION, ACTION_TIMING, ACTION_STATEMENT, EVENT_OBJECT_SCHEMA, EVENT_OBJECT_TABLE FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA= '" . PMA_sqlAddslashes($db,true) . "' and EVENT_OBJECT_TABLE = '" . PMA_sqlAddslashes($table, true) . "';");
1297 foreach ($triggers as $trigger) {
1298 $one_result = array();
1299 $one_result['name'] = $trigger['TRIGGER_NAME'];
1300 $one_result['action_timing'] = $trigger['ACTION_TIMING'];
1301 $one_result['event_manipulation'] = $trigger['EVENT_MANIPULATION'];
1303 $one_result['full_trigger_name'] = PMA_backquote($trigger['TRIGGER_SCHEMA']) . '.' . PMA_backquote($trigger['TRIGGER_NAME']);
1304 $one_result['drop'] = 'DROP TRIGGER IF EXISTS ' . $one_result['full_trigger_name'];
1305 $one_result['create'] = 'CREATE TRIGGER ' . $one_result['full_trigger_name'] . ' ' . $trigger['ACTION_TIMING']. ' ' . $trigger['EVENT_MANIPULATION'] . ' ON ' . PMA_backquote($trigger['EVENT_OBJECT_SCHEMA']) . '.' . PMA_backquote($trigger['EVENT_OBJECT_TABLE']) . "\n" . ' FOR EACH ROW ' . $trigger['ACTION_STATEMENT'] . "\n" . $delimiter . "\n";
1307 $result[] = $one_result;