00001 <?php
00002
00003
00017 function db_status_report() {
00018 $t = get_t();
00019
00020 $version = db_version();
00021
00022 $form['pgsql'] = array(
00023 'title' => $t('PostgreSQL database'),
00024 'value' => $version,
00025 );
00026
00027 if (version_compare($version, DRUPAL_MINIMUM_PGSQL) < 0) {
00028 $form['pgsql']['severity'] = REQUIREMENT_ERROR;
00029 $form['pgsql']['description'] = $t('Your PostgreSQL Server is too old. Drupal requires at least PostgreSQL %version.', array('%version' => DRUPAL_MINIMUM_PGSQL));
00030 }
00031
00032 return $form;
00033 }
00034
00040 function db_version() {
00041 return db_result(db_query("SHOW SERVER_VERSION"));
00042 }
00043
00047 function db_connect(a>) {
00048
00049 if (!function_exists('pg_connect')) {
00050 _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.');
00051 }
00052
00053 a> = parse_url(a>);
00054 $conn_string = '';
00055
00056
00057 if (isset(a>['user'])) {
00058 $conn_string .= ' user=' . urldecode(a>['user']);
00059 }
00060 if (isset(a>['pass'])) {
00061 $conn_string .= ' password=' . urldecode(a>['pass']);
00062 }
00063 if (isset(a>['host'])) {
00064 $conn_string .= ' host=' . urldecode(a>['host']);
00065 }
00066 if (isset(a>['path'])) {
00067 $conn_string .= ' dbname=' . substr(urldecode(a>['path']), 1);
00068 }
00069 if (isset(a>['port'])) {
00070 $conn_string .= ' port=' . urldecode(a>['port']);
00071 }
00072
00073
00074
00075
00076 $track_errors_previous = ini_get('track_errors');
00077 ini_set('track_errors', 1);
00078
00079 $connection = @pg_connect($conn_string);
00080 if (!$connection) {
00081 require_once './includes/unicode.inc';
00082 _db_error_page(decode_entities($php_errormsg));
00083 }
00084
00085
00086 ini_set('track_errors', $track_errors_previous);
00087
00088 return $connection;
00089 }
00090
00115 function db_query($query) {
00116 $args = func_get_args();
00117 array_shift($args);
00118 $query = db_prefix_tables($query);
00119 if (isset($args[0]) and is_array($args[0])) {
00120 $args = $args[0];
00121 }
00122 _db_query_callback($args, TRUE);
00123 $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
00124 return _db_query($query);
00125 }
00126
00130 function _db_query($query, $debug = 0) {
00131 global $active_db, $last_result, $queries;
00132
00133 if (variable_get('dev_query', 0)) {
00134 list($usec, $sec) = explode(' ', microtime());
00135 $timer = (float)$usec + (float)$sec;
00136 }
00137
00138 $last_result = pg_query($active_db, $query);
00139
00140 if (variable_get('dev_query', 0)) {
00141 $bt = debug_backtrace();
00142 $query = $bt[2]['function'] . "\n" . $query;
00143 list($usec, $sec) = explode(' ', microtime());
00144 $stop = (float)$usec + (float)$sec;
00145 $diff = $stop - $timer;
00146 $queries[] = array($query, $diff);
00147 }
00148
00149 if ($debug) {
00150 print '<p>query: ' . $query . '<br />error:' . pg_last_error($active_db) . '</p>';
00151 }
00152
00153 if ($last_result !== FALSE) {
00154 return $last_result;
00155 }
00156 else {
00157
00158 ${DB_ERROR} = TRUE;
00159 trigger_error(check_plain(pg_last_error($active_db) . "\nquery: " . $query), E_USER_WARNING);
00160 return FALSE;
00161 }
00162 }
00163
00173 function db_fetch_object($result) {
00174 if ($result) {
00175 return pg_fetch_object($result);
00176 }
00177 }
00178
00189 function db_fetch_array($result) {
00190 if ($result) {
00191 return pg_fetch_assoc($result);
00192 }
00193 }
00194
00206 function db_result($result) {
00207 if ($result && pg_num_rows($result) > 0) {
00208 $array = pg_fetch_row($result);
00209 return $array[0];
00210 }
00211 return FALSE;
00212 }
00213
00217 function db_error() {
00218 global $active_db;
00219 return pg_last_error($active_db);
00220 }
00221
00230 function db_last_insert_id($table, $field) {
00231 return db_result(db_query("SELECT CURRVAL('{" . db_escape_table($table) . "}_" . db_escape_table($field) . "_seq')"));
00232 }
00233
00237 function db_affected_rows() {
00238 global $last_result;
00239 return empty($last_result) ? 0 : pg_affected_rows($last_result);
00240 }
00241
00271 function db_query_range($query) {
00272 $args = func_get_args();
00273 $count = array_pop($args);
00274 $from = array_pop($args);
00275 array_shift($args);
00276
00277 $query = db_prefix_tables($query);
00278 if (isset($args[0]) and is_array($args[0])) {
00279 $args = $args[0];
00280 }
00281 _db_query_callback($args, TRUE);
00282 $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
00283 $query .= ' LIMIT ' . (int)$count . ' OFFSET ' . (int)$from;
00284 return _db_query($query);
00285 }
00286
00319 function db_query_temporary($query) {
00320 $args = func_get_args();
00321 $tablename = array_pop($args);
00322 array_shift($args);
00323
00324 $query = preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE ' . $tablename . ' AS SELECT', db_prefix_tables($query));
00325 if (isset($args[0]) and is_array($args[0])) {
00326 $args = $args[0];
00327 }
00328 _db_query_callback($args, TRUE);
00329 $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
00330 return _db_query($query);
00331 }
00332
00342 function db_encode_blob($data) {
00343 return "'" . pg_escape_bytea($data) . "'";
00344 }
00345
00355 function db_decode_blob($data) {
00356 return pg_unescape_bytea($data);
00357 }
00358
00363 function db_escape_string($text) {
00364 return pg_escape_string($text);
00365 }
00366
00371 function db_lock_table($table) {
00372 db_query('BEGIN; LOCK TABLE {' . db_escape_table($table) . '} IN EXCLUSIVE MODE');
00373 }
00374
00379 function db_unlock_tables() {
00380 db_query('COMMIT');
00381 }
00382
00386 function db_table_exists($table) {
00387 return (bool) db_result(db_query("SELECT COUNT(*) FROM pg_class WHERE relname = '{" . db_escape_table($table) . "}'"));
00388 }
00389
00393 function db_column_exists($table, $column) {
00394 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) . "'"));
00395 }
00396
00400 function db_check_setup() {
00401 $t = get_t();
00402
00403 $encoding = db_result(db_query('SHOW server_encoding'));
00404 if (!in_array(strtolower($encoding), array('unicode', 'utf8'))) {
00405 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');
00406 }
00407 }
00408
00420 function db_distinct_field($table, $field, $query) {
00421 $field_to_select = 'DISTINCT ON (' . $table . '.' . $field . ") $table.$field";
00422
00423 $query = preg_replace('/(SELECT.*)(?:' . $table . '\.|\s)(?<!DISTINCT\()(?<!DISTINCT\(' . $table . '\.)' . $field . '(.*FROM )/AUsi', '\1 ' . $field_to_select . '\2', $query);
00424 $query = preg_replace('/(ORDER BY )(?!' . $table . '\.' . $field . ')/', '\1' . "$table.$field, ", $query);
00425 return $query;
00426 }
00427
00441 function db_type_map() {
00442
00443
00444
00445 $map = array(
00446 'varchar:normal' => 'varchar',
00447 'char:normal' => 'character',
00448
00449 'text:tiny' => 'text',
00450 'text:small' => 'text',
00451 'text:medium' => 'text',
00452 'text:big' => 'text',
00453 'text:normal' => 'text',
00454
00455 'int:tiny' => 'smallint',
00456 'int:small' => 'smallint',
00457 'int:medium' => 'int',
00458 'int:big' => 'bigint',
00459 'int:normal' => 'int',
00460
00461 'float:tiny' => 'real',
00462 'float:small' => 'real',
00463 'float:medium' => 'real',
00464 'float:big' => 'double precision',
00465 'float:normal' => 'real',
00466
00467 'numeric:normal' => 'numeric',
00468
00469 'blob:big' => 'bytea',
00470 'blob:normal' => 'bytea',
00471
00472 'datetime:normal' => 'timestamp',
00473
00474 'serial:tiny' => 'serial',
00475 'serial:small' => 'serial',
00476 'serial:medium' => 'serial',
00477 'serial:big' => 'bigserial',
00478 'serial:normal' => 'serial',
00479 );
00480 return $map;
00481 }
00482
00493 function db_create_table_sql($name, $table) {
00494 $sql_fields = array();
00495 foreach ($table['fields'] as $field_name => $field) {
00496 $sql_fields[] = _db_create_field_sql($field_name, _db_process_field($field));
00497 }
00498
00499 $sql_keys = array();
00500 if (isset($table['primary key']) && is_array($table['primary key'])) {
00501 $sql_keys[] = 'PRIMARY KEY (' . implode(', ', $table['primary key']) . ')';
00502 }
00503 if (isset($table['unique keys']) && is_array($table['unique keys'])) {
00504 foreach ($table['unique keys'] as $key_name => $key) {
00505 $sql_keys[] = 'CONSTRAINT {' . $name . '}_' . $key_name . '_key UNIQUE (' . implode(', ', $key) . ')';
00506 }
00507 }
00508
00509 $sql = "CREATE TABLE {" . $name . "} (\n\t";
00510 $sql .= implode(",\n\t", $sql_fields);
00511 if (count($sql_keys) > 0) {
00512 $sql .= ",\n\t";
00513 }
00514 $sql .= implode(",\n\t", $sql_keys);
00515 $sql .= "\n)";
00516 $statements[] = $sql;
00517
00518 if (isset($table['indexes']) && is_array($table['indexes'])) {
00519 foreach ($table['indexes'] as $key_name => $key) {
00520 $statements[] = _db_create_index_sql($name, $key_name, $key);
00521 }
00522 }
00523
00524 return $statements;
00525 }
00526
00527 function _db_create_index_sql($table, $name, $fields) {
00528 $query = 'CREATE INDEX {' . $table . '}_' . $name . '_idx ON {' . $table . '} (';
00529 $query .= _db_create_key_sql($fields) . ')';
00530 return $query;
00531 }
00532
00533 function _db_create_key_sql($fields) {
00534 $ret = array();
00535 foreach ($fields as $field) {
00536 if (is_array($field)) {
00537 $ret[] = 'substr(' . $field[0] . ', 1, ' . $field[1] . ')';
00538 }
00539 else {
00540 $ret[] = $field;
00541 }
00542 }
00543 return implode(', ', $ret);
00544 }
00545
00546 function _db_create_keys(&$ret, $table, $new_keys) {
00547 if (isset($new_keys['primary key'])) {
00548 db_add_primary_key($ret, $table, $new_keys['primary key']);
00549 }
00550 if (isset($new_keys['unique keys'])) {
00551 foreach ($new_keys['unique keys'] as $name => $fields) {
00552 db_add_unique_key($ret, $table, $name, $fields);
00553 }
00554 }
00555 if (isset($new_keys['indexes'])) {
00556 foreach ($new_keys['indexes'] as $name => $fields) {
00557 db_add_index($ret, $table, $name, $fields);
00558 }
00559 }
00560 }
00561
00568 function _db_process_field($field) {
00569 if (!isset($field['size'])) {
00570 $field['size'] = 'normal';
00571 }
00572
00573 if (!isset($field['pgsql_type'])) {
00574 $map = db_type_map();
00575 $field['pgsql_type'] = $map[$field['type'] . ':' . $field['size']];
00576 }
00577 if ($field['type'] == 'serial') {
00578 unset($field['not null']);
00579 }
00580 return $field;
00581 }
00582
00594 function _db_create_field_sql($name, $spec) {
00595 $sql = $name . ' ' . $spec['pgsql_type'];
00596
00597 if ($spec['type'] == 'serial') {
00598 unset($spec['not null']);
00599 }
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609 if (!empty($spec['unsigned'])) {
00610 switch ($spec['type']) {
00611 case 'int':
00612 $sql .= '_unsigned';
00613 break;
00614 case 'serial':
00615 case 'float':
00616 $sql .= " CHECK ($name >= 0)";
00617 break;
00618 case 'numeric':
00619
00620 break;
00621 default:
00622
00623 break;
00624 }
00625 }
00626
00627 if (!empty($spec['length'])) {
00628 $sql .= '(' . $spec['length'] . ')';
00629 }
00630 elseif (isset($spec['precision']) && isset($spec['scale'])) {
00631 $sql .= '(' . $spec['precision'] . ', ' . $spec['scale'] . ')';
00632 }
00633
00634
00635 if ($spec['type'] == 'numeric' && !empty($spec['unsigned'])) {
00636 $sql .= " CHECK ($name >= 0)";
00637 }
00638
00639 if (isset($spec['not null']) && $spec['not null']) {
00640 $sql .= ' NOT NULL';
00641 }
00642 if (isset($spec['default'])) {
00643 $default = is_string($spec['default']) ? "'" . $spec['default'] . "'" : $spec['default'];
00644 $sql .= " default $default";
00645 }
00646
00647 return $sql;
00648 }
00649
00660 function db_rename_table(&$ret, $table, $new_name) {
00661 $ret[] = update_sql('ALTER TABLE {' . $table . '} RENAME TO {' . $new_name . '}');
00662 }
00663
00672 function db_drop_table(&$ret, $table) {
00673 $ret[] = update_sql('DROP TABLE {' . $table . '}');
00674 }
00675
00699 function db_add_field(&$ret, $table, $field, $spec, $new_keys = array()) {
00700 $fixnull = FALSE;
00701 if (!empty($spec['not null']) && !isset($spec['default'])) {
00702 $fixnull = TRUE;
00703 $spec['not null'] = FALSE;
00704 }
00705 $query = 'ALTER TABLE {' . $table . '} ADD COLUMN ';
00706 $query .= _db_create_field_sql($field, _db_process_field($spec));
00707 $ret[] = update_sql($query);
00708 if (isset($spec['initial'])) {
00709
00710 $sql = 'UPDATE {' . $table . '} SET ' . $field . ' = ' . db_type_placeholder($spec['type']);
00711 $result = db_query($sql, $spec['initial']);
00712 $ret[] = array('success' => $result !== FALSE, 'query' => check_plain($sql . ' (' . $spec['initial'] . ')'));
00713 }
00714 if ($fixnull) {
00715 $ret[] = update_sql("ALTER TABLE {" . $table . "} ALTER $field SET NOT NULL");
00716 }
00717 if (isset($new_keys)) {
00718 _db_create_keys($ret, $table, $new_keys);
00719 }
00720 }
00721
00732 function db_drop_field(&$ret, $table, $field) {
00733 $ret[] = update_sql('ALTER TABLE {' . $table . '} DROP COLUMN ' . $field);
00734 }
00735
00748 function db_field_set_default(&$ret, $table, $field, $default) {
00749 if ($default == NULL) {
00750 $default = 'NULL';
00751 }
00752 else {
00753 $default = is_string($default) ? "'$default'" : $default;
00754 }
00755
00756 $ret[] = update_sql('ALTER TABLE {' . $table . '} ALTER COLUMN ' . $field . ' SET DEFAULT ' . $default);
00757 }
00758
00769 function db_field_set_no_default(&$ret, $table, $field) {
00770 $ret[] = update_sql('ALTER TABLE {' . $table . '} ALTER COLUMN ' . $field . ' DROP DEFAULT');
00771 }
00772
00783 function db_add_primary_key(&$ret, $table, $fields) {
00784 $ret[] = update_sql('ALTER TABLE {' . $table . '} ADD PRIMARY KEY (' .
00785 implode(',', $fields) . ')');
00786 }
00787
00796 function db_drop_primary_key(&$ret, $table) {
00797 $ret[] = update_sql('ALTER TABLE {' . $table . '} DROP CONSTRAINT {' . $table . '}_pkey');
00798 }
00799
00812 function db_add_unique_key(&$ret, $table, $name, $fields) {
00813 $name = '{' . $table . '}_' . $name . '_key';
00814 $ret[] = update_sql('ALTER TABLE {' . $table . '} ADD CONSTRAINT ' .
00815 $name . ' UNIQUE (' . implode(',', $fields) . ')');
00816 }
00817
00828 function db_drop_unique_key(&$ret, $table, $name) {
00829 $name = '{' . $table . '}_' . $name . '_key';
00830 $ret[] = update_sql('ALTER TABLE {' . $table . '} DROP CONSTRAINT ' . $name);
00831 }
00832
00845 function db_add_index(&$ret, $table, $name, $fields) {
00846 $ret[] = update_sql(_db_create_index_sql($table, $name, $fields));
00847 }
00848
00859 function db_drop_index(&$ret, $table, $name) {
00860 $name = '{' . $table . '}_' . $name . '_idx';
00861 $ret[] = update_sql('DROP INDEX ' . $name);
00862 }
00863
00926 function db_change_field(&$ret, $table, $field, $field_new, $spec, $new_keys = array()) {
00927 $ret[] = update_sql("ALTER TABLE {" . $table . "} RENAME $field TO " . $field . "_old");
00928 $not_null = isset($spec['not null']) ? $spec['not null'] : FALSE;
00929 unset($spec['not null']);
00930
00931 db_add_field($ret, $table, "$field_new", $spec);
00932
00933 $ret[] = update_sql("UPDATE {" . $table . "} SET $field_new = " . $field . "_old");
00934
00935 if ($not_null) {
00936 $ret[] = update_sql("ALTER TABLE {" . $table . "} ALTER $field_new SET NOT NULL");
00937 }
00938
00939 db_drop_field($ret, $table, $field . '_old');
00940
00941 if (isset($new_keys)) {
00942 _db_create_keys($ret, $table, $new_keys);
00943 }
00944 }
00945