| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: database.pgsql.inc,v 1.68.2.11 2010/12/15 20:41:10 goba Exp $ 3 4 /** 5 * @file 6 * Database interface code for PostgreSQL database servers. 7 */ 8 9 /** 10 * @ingroup database 11 * @{ 12 */ 13 14 /** 15 * Report database status. 16 */ 17 function db_status_report() { 18 $t = get_t(); 19 20 $version = db_version(); 21 22 $form['pgsql'] = array( 23 'title' => $t('PostgreSQL database'), 24 'value' => $version, 25 ); 26 27 if (version_compare($version, DRUPAL_MINIMUM_PGSQL) < 0) { 28 $form['pgsql']['severity'] = REQUIREMENT_ERROR; 29 $form['pgsql']['description'] = $t('Your PostgreSQL Server is too old. Drupal requires at least PostgreSQL %version.', array('%version' => DRUPAL_MINIMUM_PGSQL)); 30 } 31 32 return $form; 33 } 34 35 /** 36 * Returns the version of the database server currently in use. 37 * 38 * @return Database server version 39 */ 40 function db_version() { 41 return db_result(db_query("SHOW SERVER_VERSION")); 42 } 43 44 /** 45 * Initialize a database connection. 46 */ 47 function db_connect($url) { 48 // Check if PostgreSQL support is present in PHP 49 if (!function_exists('pg_connect')) { 50 _db_error_page('Unable to use the PostgreSQL database because the PostgreSQL extension for PHP is not installed. Check your <code>php.ini</code> to see how you can enable it.'); 51 } 52 53 $url = parse_url($url); 54 $conn_string = ''; 55 56 // Decode url-encoded information in the db connection string 57 if (isset($url['user'])) { 58 $conn_string .= ' user='. urldecode($url['user']); 59 } 60 if (isset($url['pass'])) { 61 $conn_string .= ' password='. urldecode($url['pass']); 62 } 63 if (isset($url['host'])) { 64 $conn_string .= ' host='. urldecode($url['host']); 65 } 66 if (isset($url['path'])) { 67 $conn_string .= ' dbname='. substr(urldecode($url['path']), 1); 68 } 69 if (isset($url['port'])) { 70 $conn_string .= ' port='. urldecode($url['port']); 71 } 72 73 // pg_last_error() does not return a useful error message for database 74 // connection errors. We must turn on error tracking to get at a good error 75 // message, which will be stored in $php_errormsg. 76 $track_errors_previous = ini_get('track_errors'); 77 ini_set('track_errors', 1); 78 79 $connection = @pg_connect($conn_string); 80 if (!$connection) { 81 require_once './includes/unicode.inc'; 82 _db_error_page(decode_entities($php_errormsg)); 83 } 84 85 // Restore error tracking setting 86 ini_set('track_errors', $track_errors_previous); 87 88 pg_query($connection, "set client_encoding=\"UTF8\""); 89 return $connection; 90 } 91 92 /** 93 * Runs a basic query in the active database. 94 * 95 * User-supplied arguments to the query should be passed in as separate 96 * parameters so that they can be properly escaped to avoid SQL injection 97 * attacks. 98 * 99 * @param $query 100 * A string containing an SQL query. 101 * @param ... 102 * A variable number of arguments which are substituted into the query 103 * using printf() syntax. Instead of a variable number of query arguments, 104 * you may also pass a single array containing the query arguments. 105 * 106 * Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose 107 * in '') and %%. 108 * 109 * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, 110 * and TRUE values to decimal 1. 111 * 112 * @return 113 * A database query result resource, or FALSE if the query was not 114 * executed correctly. 115 */ 116 function db_query($query) { 117 $args = func_get_args(); 118 array_shift($args); 119 $query = db_prefix_tables($query); 120 if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax 121 $args = $args[0]; 122 } 123 _db_query_callback($args, TRUE); 124 $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); 125 return _db_query($query); 126 } 127 128 /** 129 * Helper function for db_query(). 130 */ 131 function _db_query($query, $debug = 0) { 132 global $active_db, $last_result, $queries; 133 134 if (variable_get('dev_query', 0)) { 135 list($usec, $sec) = explode(' ', microtime()); 136 $timer = (float)$usec + (float)$sec; 137 } 138 139 $last_result = pg_query($active_db, $query); 140 141 if (variable_get('dev_query', 0)) { 142 $bt = debug_backtrace(); 143 $query = $bt[2]['function'] ."\n". $query; 144 list($usec, $sec) = explode(' ', microtime()); 145 $stop = (float)$usec + (float)$sec; 146 $diff = $stop - $timer; 147 $queries[] = array($query, $diff); 148 } 149 150 if ($debug) { 151 print '<p>query: '. $query .'<br />error:'. pg_last_error($active_db) .'</p>'; 152 } 153 154 if ($last_result !== FALSE) { 155 return $last_result; 156 } 157 else { 158 // Indicate to drupal_error_handler that this is a database error. 159 $DB_ERROR} = TRUE; 160 trigger_error(check_plain(pg_last_error($active_db) ."\nquery: ". $query), E_USER_WARNING); 161 return FALSE; 162 } 163 } 164 165 /** 166 * Fetch one result row from the previous query as an object. 167 * 168 * @param $result 169 * A database query result resource, as returned from db_query(). 170 * @return 171 * An object representing the next row of the result, or FALSE. The attributes 172 * of this object are the table fields selected by the query. 173 */ 174 function db_fetch_object($result) { 175 if ($result) { 176 return pg_fetch_object($result); 177 } 178 } 179 180 /** 181 * Fetch one result row from the previous query as an array. 182 * 183 * @param $result 184 * A database query result resource, as returned from db_query(). 185 * @return 186 * An associative array representing the next row of the result, or FALSE. 187 * The keys of this object are the names of the table fields selected by the 188 * query, and the values are the field values for this result row. 189 */ 190 function db_fetch_array($result) { 191 if ($result) { 192 return pg_fetch_assoc($result); 193 } 194 } 195 196 /** 197 * Return an individual result field from the previous query. 198 * 199 * Only use this function if exactly one field is being selected; otherwise, 200 * use db_fetch_object() or db_fetch_array(). 201 * 202 * @param $result 203 * A database query result resource, as returned from db_query(). 204 * @return 205 * The resulting field or FALSE. 206 */ 207 function db_result($result) { 208 if ($result && pg_num_rows($result) > 0) { 209 $array = pg_fetch_row($result); 210 return $array[0]; 211 } 212 return FALSE; 213 } 214 215 /** 216 * Determine whether the previous query caused an error. 217 */ 218 function db_error() { 219 global $active_db; 220 return pg_last_error($active_db); 221 } 222 223 /** 224 * Returns the last insert id. This function is thread safe. 225 * 226 * @param $table 227 * The name of the table you inserted into. 228 * @param $field 229 * The name of the autoincrement field. 230 */ 231 function db_last_insert_id($table, $field) { 232 return db_result(db_query("SELECT CURRVAL('{". db_escape_table($table) ."}_". db_escape_table($field) ."_seq')")); 233 } 234 235 /** 236 * Determine the number of rows changed by the preceding query. 237 */ 238 function db_affected_rows() { 239 global $last_result; 240 return empty($last_result) ? 0 : pg_affected_rows($last_result); 241 } 242 243 /** 244 * Runs a limited-range query in the active database. 245 * 246 * Use this as a substitute for db_query() when a subset of the query 247 * is to be returned. 248 * User-supplied arguments to the query should be passed in as separate 249 * parameters so that they can be properly escaped to avoid SQL injection 250 * attacks. 251 * 252 * @param $query 253 * A string containing an SQL query. 254 * @param ... 255 * A variable number of arguments which are substituted into the query 256 * using printf() syntax. Instead of a variable number of query arguments, 257 * you may also pass a single array containing the query arguments. 258 * Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose 259 * in '') and %%. 260 * 261 * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, 262 * and TRUE values to decimal 1. 263 * 264 * @param $from 265 * The first result row to return. 266 * @param $count 267 * The maximum number of result rows to return. 268 * @return 269 * A database query result resource, or FALSE if the query was not executed 270 * correctly. 271 */ 272 function db_query_range($query) { 273 $args = func_get_args(); 274 $count = array_pop($args); 275 $from = array_pop($args); 276 array_shift($args); 277 278 $query = db_prefix_tables($query); 279 if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax 280 $args = $args[0]; 281 } 282 _db_query_callback($args, TRUE); 283 $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); 284 $query .= ' LIMIT '. (int)$count .' OFFSET '. (int)$from; 285 return _db_query($query); 286 } 287 288 /** 289 * Runs a SELECT query and stores its results in a temporary table. 290 * 291 * Use this as a substitute for db_query() when the results need to stored 292 * in a temporary table. Temporary tables exist for the duration of the page 293 * request. 294 * User-supplied arguments to the query should be passed in as separate parameters 295 * so that they can be properly escaped to avoid SQL injection attacks. 296 * 297 * Note that if you need to know how many results were returned, you should do 298 * a SELECT COUNT(*) on the temporary table afterwards. db_affected_rows() does 299 * not give consistent result across different database types in this case. 300 * 301 * @param $query 302 * A string containing a normal SELECT SQL query. 303 * @param ... 304 * A variable number of arguments which are substituted into the query 305 * using printf() syntax. The query arguments can be enclosed in one 306 * array instead. 307 * Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose 308 * in '') and %%. 309 * 310 * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, 311 * and TRUE values to decimal 1. 312 * 313 * @param $table 314 * The name of the temporary table to select into. This name will not be 315 * prefixed as there is no risk of collision. 316 * @return 317 * A database query result resource, or FALSE if the query was not executed 318 * correctly. 319 */ 320 function db_query_temporary($query) { 321 $args = func_get_args(); 322 $tablename = array_pop($args); 323 array_shift($args); 324 325 $query = preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE '. $tablename .' AS SELECT', db_prefix_tables($query)); 326 if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax 327 $args = $args[0]; 328 } 329 _db_query_callback($args, TRUE); 330 $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); 331 return _db_query($query); 332 } 333 334 /** 335 * Returns a properly formatted Binary Large OBject value. 336 * In case of PostgreSQL encodes data for insert into bytea field. 337 * 338 * @param $data 339 * Data to encode. 340 * @return 341 * Encoded data. 342 */ 343 function db_encode_blob($data) { 344 return "'". pg_escape_bytea($data) ."'"; 345 } 346 347 /** 348 * Returns text from a Binary Large OBject value. 349 * In case of PostgreSQL decodes data after select from bytea field. 350 * 351 * @param $data 352 * Data to decode. 353 * @return 354 * Decoded data. 355 */ 356 function db_decode_blob($data) { 357 return pg_unescape_bytea($data); 358 } 359 360 /** 361 * Prepare user input for use in a database query, preventing SQL injection attacks. 362 * Note: This function requires PostgreSQL 7.2 or later. 363 */ 364 function db_escape_string($text) { 365 return pg_escape_string($text); 366 } 367 368 /** 369 * Lock a table. 370 * This function automatically starts a transaction. 371 */ 372 function db_lock_table($table) { 373 db_query('BEGIN; LOCK TABLE {'. db_escape_table($table) .'} IN EXCLUSIVE MODE'); 374 } 375 376 /** 377 * Unlock all locked tables. 378 * This function automatically commits a transaction. 379 */ 380 function db_unlock_tables() { 381 db_query('COMMIT'); 382 } 383 384 /** 385 * Check if a table exists. 386 * 387 * @param $table 388 * The name of the table. 389 * 390 * @return 391 * TRUE if the table exists, and FALSE if the table does not exist. 392 */ 393 function db_table_exists($table) { 394 return (bool) db_result(db_query("SELECT COUNT(*) FROM pg_class WHERE relname = '{". db_escape_table($table) ."}'")); 395 } 396 397 /** 398 * Check if a column exists in the given table. 399 * 400 * @param $table 401 * The name of the table. 402 * @param $column 403 * The name of the column. 404 * 405 * @return 406 * TRUE if the column exists, and FALSE if the column does not exist. 407 */ 408 function db_column_exists($table, $column) { 409 return (bool) db_result(db_query("SELECT COUNT(pg_attribute.attname) FROM pg_class, pg_attribute WHERE pg_attribute.attrelid = pg_class.oid AND pg_class.relname = '{". db_escape_table($table) ."}' AND attname = '". db_escape_table($column) ."'")); 410 } 411 412 /** 413 * Verify if the database is set up correctly. 414 */ 415 function db_check_setup() { 416 $t = get_t(); 417 418 $encoding = db_result(db_query('SHOW server_encoding')); 419 if (!in_array(strtolower($encoding), array('unicode', 'utf8'))) { 420 drupal_set_message($t('Your PostgreSQL database is set up with the wrong character encoding (%encoding). It is possible it will not work as expected. It is advised to recreate it with UTF-8/Unicode encoding. More information can be found in the <a href="@url">PostgreSQL documentation</a>.', array('%encoding' => $encoding, '@url' => 'http://www.postgresql.org/docs/7.4/interactive/multibyte.html')), 'status'); 421 } 422 } 423 424 /** 425 * @} End of "ingroup database". 426 */ 427 428 /** 429 * @ingroup schemaapi 430 * @{ 431 */ 432 433 /** 434 * This maps a generic data type in combination with its data size 435 * to the engine-specific data type. 436 */ 437 function db_type_map() { 438 // Put :normal last so it gets preserved by array_flip. This makes 439 // it much easier for modules (such as schema.module) to map 440 // database types back into schema types. 441 $map = array( 442 'varchar:normal' => 'varchar', 443 'char:normal' => 'character', 444 445 'text:tiny' => 'text', 446 'text:small' => 'text', 447 'text:medium' => 'text', 448 'text:big' => 'text', 449 'text:normal' => 'text', 450 451 'int:tiny' => 'smallint', 452 'int:small' => 'smallint', 453 'int:medium' => 'int', 454 'int:big' => 'bigint', 455 'int:normal' => 'int', 456 457 'float:tiny' => 'real', 458 'float:small' => 'real', 459 'float:medium' => 'real', 460 'float:big' => 'double precision', 461 'float:normal' => 'real', 462 463 'numeric:normal' => 'numeric', 464 465 'blob:big' => 'bytea', 466 'blob:normal' => 'bytea', 467 468 'datetime:normal' => 'timestamp without time zone', 469 470 'serial:tiny' => 'serial', 471 'serial:small' => 'serial', 472 'serial:medium' => 'serial', 473 'serial:big' => 'bigserial', 474 'serial:normal' => 'serial', 475 ); 476 return $map; 477 } 478 479 /** 480 * Generate SQL to create a new table from a Drupal schema definition. 481 * 482 * @param $name 483 * The name of the table to create. 484 * @param $table 485 * A Schema API table definition array. 486 * @return 487 * An array of SQL statements to create the table. 488 */ 489 function db_create_table_sql($name, $table) { 490 $sql_fields = array(); 491 foreach ($table['fields'] as $field_name => $field) { 492 $sql_fields[] = _db_create_field_sql($field_name, _db_process_field($field)); 493 } 494 495 $sql_keys = array(); 496 if (isset($table['primary key']) && is_array($table['primary key'])) { 497 $sql_keys[] = 'PRIMARY KEY ('. implode(', ', $table['primary key']) .')'; 498 } 499 if (isset($table['unique keys']) && is_array($table['unique keys'])) { 500 foreach ($table['unique keys'] as $key_name => $key) { 501 $sql_keys[] = 'CONSTRAINT {'. $name .'}_'. $key_name .'_key UNIQUE ('. implode(', ', $key) .')'; 502 } 503 } 504 505 $sql = "CREATE TABLE {". $name ."} (\n\t"; 506 $sql .= implode(",\n\t", $sql_fields); 507 if (count($sql_keys) > 0) { 508 $sql .= ",\n\t"; 509 } 510 $sql .= implode(",\n\t", $sql_keys); 511 $sql .= "\n)"; 512 $statements[] = $sql; 513 514 if (isset($table['indexes']) && is_array($table['indexes'])) { 515 foreach ($table['indexes'] as $key_name => $key) { 516 $statements[] = _db_create_index_sql($name, $key_name, $key); 517 } 518 } 519 520 return $statements; 521 } 522 523 function _db_create_index_sql($table, $name, $fields) { 524 $query = 'CREATE INDEX {'. $table .'}_'. $name .'_idx ON {'. $table .'} ('; 525 $query .= _db_create_key_sql($fields) .')'; 526 return $query; 527 } 528 529 function _db_create_key_sql($fields) { 530 $ret = array(); 531 foreach ($fields as $field) { 532 if (is_array($field)) { 533 $ret[] = 'substr('. $field[0] .', 1, '. $field[1] .')'; 534 } 535 else { 536 $ret[] = $field; 537 } 538 } 539 return implode(', ', $ret); 540 } 541 542 function _db_create_keys(&$ret, $table, $new_keys) { 543 if (isset($new_keys['primary key'])) { 544 db_add_primary_key($ret, $table, $new_keys['primary key']); 545 } 546 if (isset($new_keys['unique keys'])) { 547 foreach ($new_keys['unique keys'] as $name => $fields) { 548 db_add_unique_key($ret, $table, $name, $fields); 549 } 550 } 551 if (isset($new_keys['indexes'])) { 552 foreach ($new_keys['indexes'] as $name => $fields) { 553 db_add_index($ret, $table, $name, $fields); 554 } 555 } 556 } 557 558 /** 559 * Set database-engine specific properties for a field. 560 * 561 * @param $field 562 * A field description array, as specified in the schema documentation. 563 */ 564 function _db_process_field($field) { 565 if (!isset($field['size'])) { 566 $field['size'] = 'normal'; 567 } 568 // Set the correct database-engine specific datatype. 569 if (!isset($field['pgsql_type'])) { 570 $map = db_type_map(); 571 $field['pgsql_type'] = $map[$field['type'] .':'. $field['size']]; 572 } 573 if ($field['type'] == 'serial') { 574 unset($field['not null']); 575 } 576 return $field; 577 } 578 579 /** 580 * Create an SQL string for a field to be used in table creation or alteration. 581 * 582 * Before passing a field out of a schema definition into this function it has 583 * to be processed by _db_process_field(). 584 * 585 * @param $name 586 * Name of the field. 587 * @param $spec 588 * The field specification, as per the schema data structure format. 589 */ 590 function _db_create_field_sql($name, $spec) { 591 $sql = $name .' '. $spec['pgsql_type']; 592 593 if ($spec['type'] == 'serial') { 594 unset($spec['not null']); 595 } 596 597 if (in_array($spec['type'], array('varchar', 'char', 'text')) && isset($spec['length'])) { 598 $sql .= '('. $spec['length'] .')'; 599 } 600 elseif (isset($spec['precision']) && isset($spec['scale'])) { 601 $sql .= '('. $spec['precision'] .', '. $spec['scale'] .')'; 602 } 603 604 if (!empty($spec['unsigned'])) { 605 $sql .= " CHECK ($name >= 0)"; 606 } 607 608 if (isset($spec['not null']) && $spec['not null']) { 609 $sql .= ' NOT NULL'; 610 } 611 if (isset($spec['default'])) { 612 $default = is_string($spec['default']) ? "'". $spec['default'] ."'" : $spec['default']; 613 $sql .= " default $default"; 614 } 615 616 return $sql; 617 } 618 619 /** 620 * Rename a table. 621 * 622 * @param $ret 623 * Array to which query results will be added. 624 * @param $table 625 * The table to be renamed. 626 * @param $new_name 627 * The new name for the table. 628 */ 629 function db_rename_table(&$ret, $table, $new_name) { 630 $ret[] = update_sql('ALTER TABLE {'. $table .'} RENAME TO {'. $new_name .'}'); 631 } 632 633 /** 634 * Drop a table. 635 * 636 * @param $ret 637 * Array to which query results will be added. 638 * @param $table 639 * The table to be dropped. 640 */ 641 function db_drop_table(&$ret, $table) { 642 $ret[] = update_sql('DROP TABLE {'. $table .'}'); 643 } 644 645 /** 646 * Add a new field to a table. 647 * 648 * @param $ret 649 * Array to which query results will be added. 650 * @param $table 651 * Name of the table to be altered. 652 * @param $field 653 * Name of the field to be added. 654 * @param $spec 655 * The field specification array, as taken from a schema definition. 656 * The specification may also contain the key 'initial', the newly 657 * created field will be set to the value of the key in all rows. 658 * This is most useful for creating NOT NULL columns with no default 659 * value in existing tables. 660 * @param $new_keys 661 * Optional keys and indexes specification to be created on the 662 * table along with adding the field. The format is the same as a 663 * table specification but without the 'fields' element. If you are 664 * adding a type 'serial' field, you MUST specify at least one key 665 * or index including it in this array. @see db_change_field for more 666 * explanation why. 667 */ 668 function db_add_field(&$ret, $table, $field, $spec, $new_keys = array()) { 669 $fixnull = FALSE; 670 if (!empty($spec['not null']) && !isset($spec['default'])) { 671 $fixnull = TRUE; 672 $spec['not null'] = FALSE; 673 } 674 $query = 'ALTER TABLE {'. $table .'} ADD COLUMN '; 675 $query .= _db_create_field_sql($field, _db_process_field($spec)); 676 $ret[] = update_sql($query); 677 if (isset($spec['initial'])) { 678 // All this because update_sql does not support %-placeholders. 679 $sql = 'UPDATE {'. $table .'} SET '. $field .' = '. db_type_placeholder($spec['type']); 680 $result = db_query($sql, $spec['initial']); 681 $ret[] = array('success' => $result !== FALSE, 'query' => check_plain($sql .' ('. $spec['initial'] .')')); 682 } 683 if ($fixnull) { 684 $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $field SET NOT NULL"); 685 } 686 if (isset($new_keys)) { 687 _db_create_keys($ret, $table, $new_keys); 688 } 689 } 690 691 /** 692 * Drop a field. 693 * 694 * @param $ret 695 * Array to which query results will be added. 696 * @param $table 697 * The table to be altered. 698 * @param $field 699 * The field to be dropped. 700 */ 701 function db_drop_field(&$ret, $table, $field) { 702 $ret[] = update_sql('ALTER TABLE {'. $table .'} DROP COLUMN '. $field); 703 } 704 705 /** 706 * Set the default value for a field. 707 * 708 * @param $ret 709 * Array to which query results will be added. 710 * @param $table 711 * The table to be altered. 712 * @param $field 713 * The field to be altered. 714 * @param $default 715 * Default value to be set. NULL for 'default NULL'. 716 */ 717 function db_field_set_default(&$ret, $table, $field, $default) { 718 if ($default == NULL) { 719 $default = 'NULL'; 720 } 721 else { 722 $default = is_string($default) ? "'$default'" : $default; 723 } 724 725 $ret[] = update_sql('ALTER TABLE {'. $table .'} ALTER COLUMN '. $field .' SET DEFAULT '. $default); 726 } 727 728 /** 729 * Set a field to have no default value. 730 * 731 * @param $ret 732 * Array to which query results will be added. 733 * @param $table 734 * The table to be altered. 735 * @param $field 736 * The field to be altered. 737 */ 738 function db_field_set_no_default(&$ret, $table, $field) { 739 $ret[] = update_sql('ALTER TABLE {'. $table .'} ALTER COLUMN '. $field .' DROP DEFAULT'); 740 } 741 742 /** 743 * Add a primary key. 744 * 745 * @param $ret 746 * Array to which query results will be added. 747 * @param $table 748 * The table to be altered. 749 * @param $fields 750 * Fields for the primary key. 751 */ 752 function db_add_primary_key(&$ret, $table, $fields) { 753 $ret[] = update_sql('ALTER TABLE {'. $table .'} ADD PRIMARY KEY ('. 754 implode(',', $fields) .')'); 755 } 756 757 /** 758 * Drop the primary key. 759 * 760 * @param $ret 761 * Array to which query results will be added. 762 * @param $table 763 * The table to be altered. 764 */ 765 function db_drop_primary_key(&$ret, $table) { 766 $ret[] = update_sql('ALTER TABLE {'. $table .'} DROP CONSTRAINT {'. $table .'}_pkey'); 767 } 768 769 /** 770 * Add a unique key. 771 * 772 * @param $ret 773 * Array to which query results will be added. 774 * @param $table 775 * The table to be altered. 776 * @param $name 777 * The name of the key. 778 * @param $fields 779 * An array of field names. 780 */ 781 function db_add_unique_key(&$ret, $table, $name, $fields) { 782 $name = '{'. $table .'}_'. $name .'_key'; 783 $ret[] = update_sql('ALTER TABLE {'. $table .'} ADD CONSTRAINT '. 784 $name .' UNIQUE ('. implode(',', $fields) .')'); 785 } 786 787 /** 788 * Drop a unique key. 789 * 790 * @param $ret 791 * Array to which query results will be added. 792 * @param $table 793 * The table to be altered. 794 * @param $name 795 * The name of the key. 796 */ 797 function db_drop_unique_key(&$ret, $table, $name) { 798 $name = '{'. $table .'}_'. $name .'_key'; 799 $ret[] = update_sql('ALTER TABLE {'. $table .'} DROP CONSTRAINT '. $name); 800 } 801 802 /** 803 * Add an index. 804 * 805 * @param $ret 806 * Array to which query results will be added. 807 * @param $table 808 * The table to be altered. 809 * @param $name 810 * The name of the index. 811 * @param $fields 812 * An array of field names. 813 */ 814 function db_add_index(&$ret, $table, $name, $fields) { 815 $ret[] = update_sql(_db_create_index_sql($table, $name, $fields)); 816 } 817 818 /** 819 * Drop an index. 820 * 821 * @param $ret 822 * Array to which query results will be added. 823 * @param $table 824 * The table to be altered. 825 * @param $name 826 * The name of the index. 827 */ 828 function db_drop_index(&$ret, $table, $name) { 829 $name = '{'. $table .'}_'. $name .'_idx'; 830 $ret[] = update_sql('DROP INDEX '. $name); 831 } 832 833 /** 834 * Change a field definition. 835 * 836 * IMPORTANT NOTE: To maintain database portability, you have to explicitly 837 * recreate all indices and primary keys that are using the changed field. 838 * 839 * That means that you have to drop all affected keys and indexes with 840 * db_drop_{primary_key,unique_key,index}() before calling db_change_field(). 841 * To recreate the keys and indices, pass the key definitions as the 842 * optional $new_keys argument directly to db_change_field(). 843 * 844 * For example, suppose you have: 845 * @code 846 * $schema['foo'] = array( 847 * 'fields' => array( 848 * 'bar' => array('type' => 'int', 'not null' => TRUE) 849 * ), 850 * 'primary key' => array('bar') 851 * ); 852 * @endcode 853 * and you want to change foo.bar to be type serial, leaving it as the 854 * primary key. The correct sequence is: 855 * @code 856 * db_drop_primary_key($ret, 'foo'); 857 * db_change_field($ret, 'foo', 'bar', 'bar', 858 * array('type' => 'serial', 'not null' => TRUE), 859 * array('primary key' => array('bar'))); 860 * @endcode 861 * 862 * The reasons for this are due to the different database engines: 863 * 864 * On PostgreSQL, changing a field definition involves adding a new field 865 * and dropping an old one which* causes any indices, primary keys and 866 * sequences (from serial-type fields) that use the changed field to be dropped. 867 * 868 * On MySQL, all type 'serial' fields must be part of at least one key 869 * or index as soon as they are created. You cannot use 870 * db_add_{primary_key,unique_key,index}() for this purpose because 871 * the ALTER TABLE command will fail to add the column without a key 872 * or index specification. The solution is to use the optional 873 * $new_keys argument to create the key or index at the same time as 874 * field. 875 * 876 * You could use db_add_{primary_key,unique_key,index}() in all cases 877 * unless you are converting a field to be type serial. You can use 878 * the $new_keys argument in all cases. 879 * 880 * @param $ret 881 * Array to which query results will be added. 882 * @param $table 883 * Name of the table. 884 * @param $field 885 * Name of the field to change. 886 * @param $field_new 887 * New name for the field (set to the same as $field if you don't want to change the name). 888 * @param $spec 889 * The field specification for the new field. 890 * @param $new_keys 891 * Optional keys and indexes specification to be created on the 892 * table along with changing the field. The format is the same as a 893 * table specification but without the 'fields' element. 894 */ 895 function db_change_field(&$ret, $table, $field, $field_new, $spec, $new_keys = array()) { 896 $ret[] = update_sql('ALTER TABLE {'. $table .'} RENAME "'. $field .'" TO "'. $field .'_old"'); 897 $not_null = isset($spec['not null']) ? $spec['not null'] : FALSE; 898 unset($spec['not null']); 899 900 if (!array_key_exists('size', $spec)) { 901 $spec['size'] = 'normal'; 902 } 903 db_add_field($ret, $table, "$field_new", $spec); 904 905 // We need to type cast the new column to best transfer the data 906 // db_type_map will return possiblities that are not 'cast-able' 907 // such as serial - they must be made 'int' instead. 908 $map = db_type_map(); 909 $typecast = $map[$spec['type'] .':'. $spec['size']]; 910 if (in_array($typecast, array('serial', 'bigserial', 'numeric'))) { 911 $typecast = 'int'; 912 } 913 $ret[] = update_sql('UPDATE {'. $table .'} SET '. $field_new .' = CAST('. $field .'_old AS '. $typecast .')'); 914 915 if ($not_null) { 916 $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $field_new SET NOT NULL"); 917 } 918 919 db_drop_field($ret, $table, $field .'_old'); 920 921 if (isset($new_keys)) { 922 _db_create_keys($ret, $table, $new_keys); 923 } 924 } 925 926 /** 927 * @} End of "ingroup schemaapi". 928 */ 929
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |