| [ Index ] |
PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008] |
[Summary view] [Print] [Text view]
1 <?php // $Id: postgres7.class.php,v 1.36 2007/10/10 05:25:28 nicolasconnault Exp $ 2 3 /////////////////////////////////////////////////////////////////////////// 4 // // 5 // NOTICE OF COPYRIGHT // 6 // // 7 // Moodle - Modular Object-Oriented Dynamic Learning Environment // 8 // http://moodle.com // 9 // // 10 // Copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com // 11 // (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com // 12 // // 13 // This program is free software; you can redistribute it and/or modify // 14 // it under the terms of the GNU General Public License as published by // 15 // the Free Software Foundation; either version 2 of the License, or // 16 // (at your option) any later version. // 17 // // 18 // This program is distributed in the hope that it will be useful, // 19 // but WITHOUT ANY WARRANTY; without even the implied warranty of // 20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // 21 // GNU General Public License for more details: // 22 // // 23 // http://www.gnu.org/copyleft/gpl.html // 24 // // 25 /////////////////////////////////////////////////////////////////////////// 26 27 /// This class generate SQL code to be used against PostgreSQL 28 /// It extends XMLDBgenerator so everything can be 29 /// overriden as needed to generate correct SQL. 30 31 class XMLDBpostgres7 extends XMLDBgenerator { 32 33 /// Only set values that are different from the defaults present in XMLDBgenerator 34 35 var $number_type = 'NUMERIC'; // Proper type for NUMBER(x) in this DB 36 37 var $unsigned_allowed = false; // To define in the generator must handle unsigned information 38 var $default_for_char = ''; // To define the default to set for NOT NULLs CHARs without default (null=do nothing) 39 40 var $sequence_extra_code = false; //Does the generator need to add extra code to generate the sequence fields 41 var $sequence_name = 'BIGSERIAL'; //Particular name for inline sequences in this generator 42 var $sequence_name_small = 'SERIAL'; //Particular name for inline sequences in this generator 43 var $sequence_only = true; //To avoid to output the rest of the field specs, leaving only the name and the sequence_name variable 44 45 var $rename_table_extra_code = true; //Does the generator need to add code after table rename 46 47 var $rename_column_extra_code = true; //Does the generator need to add code after column rename 48 49 var $enum_inline_code = false; //Does the generator need to add inline code in the column definition 50 51 var $rename_index_sql = 'ALTER TABLE OLDINDEXNAME RENAME TO NEWINDEXNAME'; //SQL sentence to rename one index 52 //TABLENAME, OLDINDEXNAME, NEWINDEXNAME are dinamically replaced 53 54 var $rename_key_sql = null; //SQL sentence to rename one key (PostgreSQL doesn't support this!) 55 //TABLENAME, OLDKEYNAME, NEWKEYNAME are dinamically replaced 56 57 /** 58 * Creates one new XMLDBpostgres7 59 */ 60 function XMLDBpostgres7() { 61 parent::XMLDBgenerator(); 62 $this->prefix = ''; 63 $this->reserved_words = $this->getReservedWords(); 64 } 65 66 /** 67 * Given one XMLDB Type, lenght and decimals, returns the DB proper SQL type 68 */ 69 function getTypeSQL ($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) { 70 71 switch ($xmldb_type) { 72 case XMLDB_TYPE_INTEGER: // From http://www.postgresql.org/docs/7.4/interactive/datatype.html 73 if (empty($xmldb_length)) { 74 $xmldb_length = 10; 75 } 76 if ($xmldb_length > 9) { 77 $dbtype = 'BIGINT'; 78 } else if ($xmldb_length > 4) { 79 $dbtype = 'INTEGER'; 80 } else { 81 $dbtype = 'SMALLINT'; 82 } 83 break; 84 case XMLDB_TYPE_NUMBER: 85 $dbtype = $this->number_type; 86 if (!empty($xmldb_length)) { 87 $dbtype .= '(' . $xmldb_length; 88 if (!empty($xmldb_decimals)) { 89 $dbtype .= ',' . $xmldb_decimals; 90 } 91 $dbtype .= ')'; 92 } 93 break; 94 case XMLDB_TYPE_FLOAT: 95 $dbtype = 'DOUBLE PRECISION'; 96 if (!empty($xmldb_decimals)) { 97 if ($xmldb_decimals < 6) { 98 $dbtype = 'REAL'; 99 } 100 } 101 break; 102 case XMLDB_TYPE_CHAR: 103 $dbtype = 'VARCHAR'; 104 if (empty($xmldb_length)) { 105 $xmldb_length='255'; 106 } 107 $dbtype .= '(' . $xmldb_length . ')'; 108 break; 109 case XMLDB_TYPE_TEXT: 110 $dbtype = 'TEXT'; 111 break; 112 case XMLDB_TYPE_BINARY: 113 $dbtype = 'BYTEA'; 114 break; 115 case XMLDB_TYPE_DATETIME: 116 $dbtype = 'TIMESTAMP'; 117 break; 118 } 119 return $dbtype; 120 } 121 122 /** 123 * Returns the code needed to create one enum for the xmldb_table and xmldb_field passes 124 */ 125 function getEnumExtraSQL ($xmldb_table, $xmldb_field) { 126 127 $sql = 'CONSTRAINT ' . $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'ck'); 128 $sql.= ' CHECK (' . $this->getEncQuoted($xmldb_field->getName()) . ' IN (' . implode(', ', $xmldb_field->getEnumValues()) . '))'; 129 130 return $sql; 131 } 132 133 /** 134 * Returns the code (in array) needed to add one comment to the table 135 */ 136 function getCommentSQL ($xmldb_table) { 137 138 $comment = "COMMENT ON TABLE " . $this->getTableName($xmldb_table); 139 $comment.= " IS '" . addslashes(substr($xmldb_table->getComment(), 0, 250)) . "'"; 140 141 return array($comment); 142 } 143 144 /** 145 * Returns the code (array of statements) needed to execute extra statements on table rename 146 */ 147 function getRenameTableExtraSQL ($xmldb_table, $newname) { 148 149 $results = array(); 150 151 $newt = new XMLDBTable($newname); 152 153 $xmldb_field = new XMLDBField('id'); // Fields having sequences should be exclusively, id. 154 155 $oldseqname = $this->getTableName($xmldb_table) . '_' . $xmldb_field->getName() . '_seq'; 156 $newseqname = $this->getTableName($newt) . '_' . $xmldb_field->getName() . '_seq'; 157 158 /// Rename de sequence 159 $results[] = 'ALTER TABLE ' . $oldseqname . ' RENAME TO ' . $newseqname; 160 161 /// Rename all the check constraints in the table 162 $oldtablename = $this->getTableName($xmldb_table); 163 $newtablename = $this->getTableName($newt); 164 165 $oldconstraintprefix = $this->getNameForObject($xmldb_table->getName(), ''); 166 $newconstraintprefix = $this->getNameForObject($newt->getName(), '', ''); 167 168 if ($constraints = $this->getCheckConstraintsFromDB($xmldb_table)) { 169 foreach ($constraints as $constraint) { 170 /// Drop the old constraint 171 $results[] = 'ALTER TABLE ' . $newtablename . ' DROP CONSTRAINT ' . $constraint->name; 172 /// Calculate the new constraint name 173 $newconstraintname = str_replace($oldconstraintprefix, $newconstraintprefix, $constraint->name); 174 /// Add the new constraint 175 $results[] = 'ALTER TABLE ' . $newtablename . ' ADD CONSTRAINT ' . $newconstraintname . 176 ' CHECK ' . $constraint->description; 177 } 178 } 179 180 return $results; 181 } 182 183 /** 184 * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to add the field to the table 185 * PostgreSQL is pretty standard but with one severe restriction under 7.4 that forces us to overload 186 * this function: Default clause is not allowed when adding fields. 187 * 188 * This function can be safely removed once min req. for PG will be 8.0 189 */ 190 function getAddFieldSQL($xmldb_table, $xmldb_field) { 191 192 $results = array(); 193 194 $tablename = $this->getTableName($xmldb_table); 195 $fieldname = $this->getEncQuoted($xmldb_field->getName()); 196 197 $defaultvalue = null; 198 199 /// Save old flags 200 $old_skip_default = $this->alter_column_skip_default; 201 $old_skip_notnull = $this->alter_column_skip_notnull; 202 203 /// Prevent default clause and launch parent getAddField() 204 $this->alter_column_skip_default = true; 205 $this->alter_column_skip_notnull = true; 206 $results = parent::getAddFieldSQL($xmldb_table, $xmldb_field); 207 208 /// Re-set old flags 209 $this->alter_column_skip_default = $old_skip_default; 210 $this->alter_column_skip_notnull = $old_skip_notnull; 211 212 /// Add default (only if not skip_default) 213 if (!$this->alter_column_skip_default) { 214 if ($defaultclause = $this->getDefaultClause($xmldb_field)) { 215 $defaultvalue = $this->getDefaultValue($xmldb_field); 216 $results[] = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' SET' . $defaultclause; /// Add default clause 217 } 218 /// Update default value (if exists) to all the records 219 if ($defaultvalue !== null) { 220 $results[] = 'UPDATE ' . $tablename . ' SET ' . $fieldname . '=' . $defaultvalue; 221 } 222 } 223 224 /// Add not null (only if no skip_notnull) 225 if (!$this->alter_column_skip_notnull) { 226 if ($xmldb_field->getNotnull()) { 227 $results[] = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' SET NOT NULL'; /// Add not null 228 } 229 } 230 231 return $results; 232 } 233 234 /** 235 * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to alter the field in the table 236 * PostgreSQL has some severe limits: 237 * - Any change of type or precision requires a new temporary column to be created, values to 238 * be transfered potentially casting them, to apply defaults if the column is not null and 239 * finally, to rename it 240 * - Changes in null/not null require the SET/DROP NOT NULL clause 241 * - Changes in default require the SET/DROP DEFAULT clause 242 */ 243 function getAlterFieldSQL($xmldb_table, $xmldb_field) { 244 245 global $db; 246 247 $results = array(); /// To store all the needed SQL commands 248 249 /// Get the quoted name of the table and field 250 $tablename = $this->getTableName($xmldb_table); 251 $fieldname = $this->getEncQuoted($xmldb_field->getName()); 252 253 /// Take a look to field metadata 254 $meta = array_change_key_case($db->MetaColumns($tablename)); 255 $metac = $meta[$fieldname]; 256 $oldtype = strtolower($metac->type); 257 $oldmetatype = column_type($xmldb_table->getName(), $fieldname); 258 $oldlength = $metac->max_length; 259 $olddecimals = empty($metac->scale) ? null : $metac->scale; 260 $oldnotnull = empty($metac->not_null) ? false : $metac->not_null; 261 $olddefault = empty($metac->has_default) ? null : strtok($metac->default_value, ':'); 262 263 $typechanged = true; //By default, assume that the column type has changed 264 $precisionchanged = true; //By default, assume that the column precision has changed 265 $decimalchanged = true; //By default, assume that the column decimal has changed 266 $defaultchanged = true; //By default, assume that the column default has changed 267 $notnullchanged = true; //By default, assume that the column notnull has changed 268 269 $from_temp_fields = false; //By default don't assume we are going to use temporal fields 270 271 /// Detect if we are changing the type of the column 272 if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER && substr($oldmetatype, 0, 1) == 'I') || 273 ($xmldb_field->getType() == XMLDB_TYPE_NUMBER && $oldmetatype == 'N') || 274 ($xmldb_field->getType() == XMLDB_TYPE_FLOAT && $oldmetatype == 'F') || 275 ($xmldb_field->getType() == XMLDB_TYPE_CHAR && substr($oldmetatype, 0, 1) == 'C') || 276 ($xmldb_field->getType() == XMLDB_TYPE_TEXT && substr($oldmetatype, 0, 1) == 'X') || 277 ($xmldb_field->getType() == XMLDB_TYPE_BINARY && $oldmetatype == 'B')) { 278 $typechanged = false; 279 } 280 /// Detect if we are changing the precision 281 if (($xmldb_field->getType() == XMLDB_TYPE_TEXT) || 282 ($xmldb_field->getType() == XMLDB_TYPE_BINARY) || 283 ($oldlength == -1) || 284 ($xmldb_field->getLength() == $oldlength)) { 285 $precisionchanged = false; 286 } 287 /// Detect if we are changing the decimals 288 if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER) || 289 ($xmldb_field->getType() == XMLDB_TYPE_CHAR) || 290 ($xmldb_field->getType() == XMLDB_TYPE_TEXT) || 291 ($xmldb_field->getType() == XMLDB_TYPE_BINARY) || 292 (!$xmldb_field->getDecimals()) || 293 (!$olddecimals) || 294 ($xmldb_field->getDecimals() == $olddecimals)) { 295 $decimalchanged = false; 296 } 297 /// Detect if we are changing the default 298 if (($xmldb_field->getDefault() === null && $olddefault === null) || 299 ($xmldb_field->getDefault() === $olddefault) || //Check both equality and 300 ("'" . $xmldb_field->getDefault() . "'" === $olddefault)) { //Equality with quotes because ADOdb returns the default with quotes 301 $defaultchanged = false; 302 } 303 /// Detect if we are changing the nullability 304 if (($xmldb_field->getNotnull() === $oldnotnull)) { 305 $notnullchanged = false; 306 } 307 308 /// TODO: Some combinations like 309 /// TODO: integer->integer 310 /// TODO: integer->text 311 /// TODO: number->text 312 /// TODO: text->text 313 /// TODO: do not require the use of temp columns, because PG 8.0 supports them automatically 314 /// TODO: with a simple "alter table zzz alter column yyy type new specs" 315 /// TODO: Must be implemented that way. Eloy 09/2007 316 317 /// If the type or the precision or the decimals have changed, then we need to: 318 /// - create one temp column with the new specs 319 /// - fill the new column with the values from the old one (casting if needed) 320 /// - drop the old column 321 /// - rename the temp column to the original name 322 if ($typechanged || $precisionchanged || $decimalchanged) { 323 $tempcolname = $xmldb_field->getName() . '_alter_column_tmp'; 324 /// Prevent temp field to have both NULL/NOT NULL and DEFAULT constraints 325 $this->alter_column_skip_notnull = true; 326 $this->alter_column_skip_default = true; 327 $xmldb_field->setName($tempcolname); 328 /// Create the temporal column 329 $results = array_merge($results, $this->getAddFieldSQL($xmldb_table, $xmldb_field)); 330 /// Detect some basic casting options 331 if ((substr($oldmetatype, 0, 1) == 'C' && $xmldb_field->getType() == XMLDB_TYPE_NUMBER) || 332 (substr($oldmetatype, 0, 1) == 'C' && $xmldb_field->getType() == XMLDB_TYPE_FLOAT)) { 333 $copyorigin = 'CAST(CAST('.$fieldname.' AS TEXT) AS REAL)'; //From char to number or float 334 } else if ((substr($oldmetatype, 0, 1) == 'C' && $xmldb_field->getType() == XMLDB_TYPE_INTEGER)) { 335 $copyorigin = 'CAST(CAST('.$fieldname.' AS TEXT) AS INTEGER)'; //From char to integer 336 } else { 337 $copyorigin = $fieldname; //Direct copy between columns 338 } 339 /// Copy contents from original col to the temporal one 340 $results[] = 'UPDATE ' . $tablename . ' SET ' . $tempcolname . ' = ' . $copyorigin; 341 /// Drop the old column 342 $xmldb_field->setName($fieldname); //Set back the original field name 343 $results = array_merge($results, $this->getDropFieldSQL($xmldb_table, $xmldb_field)); 344 /// Rename the temp column to the original one 345 $results[] = 'ALTER TABLE ' . $tablename . ' RENAME COLUMN ' . $tempcolname . ' TO ' . $fieldname; 346 /// Mark we have performed one change based in temp fields 347 $from_temp_fields = true; 348 } 349 /// If the default has changed or we have used one temp field 350 if ($defaultchanged || $from_temp_fields) { 351 if ($default_clause = $this->getDefaultClause($xmldb_field)) { 352 $results[] = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' SET' . $default_clause; /// Add default clause 353 } else { 354 if (!$from_temp_fields) { /// Only drop default if we haven't used the temp field, i.e. old column 355 $results[] = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' DROP DEFAULT'; /// Drop default clause 356 } 357 } 358 } 359 /// If the not null has changed or we have used one temp field 360 if ($notnullchanged || $from_temp_fields) { 361 if ($xmldb_field->getNotnull()) { 362 $results[] = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' SET NOT NULL'; 363 } else { 364 $results[] = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' DROP NOT NULL'; 365 } 366 } 367 368 /// Return the results 369 return $results; 370 } 371 372 /** 373 * Returns the code (array of statements) needed to execute extra statements on field rename 374 */ 375 function getRenameFieldExtraSQL ($xmldb_table, $xmldb_field, $newname) { 376 377 $results = array(); 378 379 /// If the field is enum, drop and re-create the check constraint 380 if ($xmldb_field->getEnum()) { 381 /// Drop the current enum 382 $results = array_merge($results, $this->getDropEnumSQL($xmldb_table, $xmldb_field)); 383 /// Change field name (over a clone to avoid some potential problems later) 384 $new_xmldb_field = clone($xmldb_field); 385 $new_xmldb_field->setName($newname); 386 /// Recreate the enum 387 $results = array_merge($results, $this->getCreateEnumSQL($xmldb_table, $new_xmldb_field)); 388 } 389 390 return $results; 391 } 392 393 /** 394 * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its enum 395 * (usually invoked from getModifyEnumSQL() 396 */ 397 function getCreateEnumSQL($xmldb_table, $xmldb_field) { 398 /// All we have to do is to create the check constraint 399 return array('ALTER TABLE ' . $this->getTableName($xmldb_table) . 400 ' ADD ' . $this->getEnumExtraSQL($xmldb_table, $xmldb_field)); 401 } 402 403 /** 404 * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its enum 405 * (usually invoked from getModifyEnumSQL() 406 */ 407 function getDropEnumSQL($xmldb_table, $xmldb_field) { 408 /// Let's introspect to know the real name of the check constraint 409 if ($check_constraints = $this->getCheckConstraintsFromDB($xmldb_table, $xmldb_field)) { 410 $check_constraint = array_shift($check_constraints); /// Get the 1st (should be only one) 411 $constraint_name = strtolower($check_constraint->name); /// Extract the REAL name 412 /// All we have to do is to drop the check constraint 413 return array('ALTER TABLE ' . $this->getTableName($xmldb_table) . 414 ' DROP CONSTRAINT ' . $constraint_name); 415 } else { /// Constraint not found. Nothing to do 416 return array(); 417 } 418 } 419 420 /** 421 * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its default 422 * (usually invoked from getModifyDefaultSQL() 423 */ 424 function getCreateDefaultSQL($xmldb_table, $xmldb_field) { 425 /// Just a wrapper over the getAlterFieldSQL() function for PostgreSQL that 426 /// is capable of handling defaults 427 return $this->getAlterFieldSQL($xmldb_table, $xmldb_field); 428 } 429 430 /** 431 * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its default 432 * (usually invoked from getModifyDefaultSQL() 433 */ 434 function getDropDefaultSQL($xmldb_table, $xmldb_field) { 435 /// Just a wrapper over the getAlterFieldSQL() function for PostgreSQL that 436 /// is capable of handling defaults 437 return $this->getAlterFieldSQL($xmldb_table, $xmldb_field); 438 } 439 440 /** 441 * Given one XMLDBTable returns one array with all the check constrainsts 442 * in the table (fetched from DB) 443 * Optionally the function allows one xmldb_field to be specified in 444 * order to return only the check constraints belonging to one field. 445 * Each element contains the name of the constraint and its description 446 * If no check constraints are found, returns an empty array 447 */ 448 function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) { 449 450 $results = array(); 451 452 $tablename = $this->getTableName($xmldb_table); 453 454 if ($constraints = get_records_sql("SELECT co.conname AS name, co.consrc AS description 455 FROM pg_constraint co, 456 pg_class cl 457 WHERE co.conrelid = cl.oid 458 AND co.contype = 'c' 459 AND cl.relname = '{$tablename}'")) { 460 foreach ($constraints as $constraint) { 461 $results[$constraint->name] = $constraint; 462 } 463 } 464 465 /// Filter by the required field if specified 466 if ($xmldb_field) { 467 $filtered_results = array(); 468 $filter = $xmldb_field->getName(); 469 /// Lets clean a bit each constraint description, looking for the filtered field 470 foreach ($results as $key => $result) { 471 $description = preg_replace('/\("(.*?)"\)/', '($1)', $result->description);// Double quotes out 472 $description = preg_replace('/[\(\)]/', '', $description); // Parenthesis out 473 $description = preg_replace('/::[a-z]+/i', '', $description); // Casts out 474 $description = preg_replace("/({$filter})/i", '@$1@', $description); 475 $description = trim(preg_replace('/ or /i', ' OR ', $description)); // Uppercase or & trim 476 /// description starts by @$filter@ assume it's a constraint beloging to the field 477 if (preg_match("/^@{$filter}@/i", $description)) { 478 $filtered_results[$key] = $result; 479 } 480 } 481 /// Assign filtered results to the final results array 482 $results = $filtered_results; 483 } 484 485 return $results; 486 } 487 488 /** 489 * Given one XMLDBTable returns one string with the sequence of the table 490 * in the table (fetched from DB) 491 * The sequence name for Postgres has one standard name convention: 492 * tablename_fieldname_seq 493 * so we just calculate it and confirm it's present in pg_class 494 * If no sequence is found, returns false 495 */ 496 function getSequenceFromDB($xmldb_table) { 497 498 $tablename = $this->getTableName($xmldb_table); 499 $sequencename = $tablename . '_id_seq'; 500 501 if (!get_record_sql("SELECT * 502 FROM pg_class 503 WHERE relname = '{$sequencename}' 504 AND relkind = 'S'")) { 505 $sequencename = false; 506 } 507 508 return $sequencename; 509 } 510 511 /** 512 * Given one object name and it's type (pk, uk, fk, ck, ix, uix, seq, trg) 513 * return if such name is currently in use (true) or no (false) 514 * (invoked from getNameForObject() 515 */ 516 function isNameInUse($object_name, $type, $table_name) { 517 switch($type) { 518 case 'ix': 519 case 'uix': 520 case 'seq': 521 if ($check = get_records_sql("SELECT relname 522 FROM pg_class 523 WHERE lower(relname) = '" . strtolower($object_name) . "'")) { 524 return true; 525 } 526 break; 527 case 'pk': 528 case 'uk': 529 case 'fk': 530 case 'ck': 531 if ($check = get_records_sql("SELECT conname 532 FROM pg_constraint 533 WHERE lower(conname) = '" . strtolower($object_name) . "'")) { 534 return true; 535 } 536 break; 537 case 'trg': 538 if ($check = get_records_sql("SELECT tgname 539 FROM pg_trigger 540 WHERE lower(tgname) = '" . strtolower($object_name) . "'")) { 541 return true; 542 } 543 break; 544 } 545 return false; //No name in use found 546 } 547 548 /** 549 * Returns an array of reserved words (lowercase) for this DB 550 */ 551 function getReservedWords() { 552 /// This file contains the reserved words for PostgreSQL databases 553 /// http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html 554 $reserved_words = array ( 555 'all', 'analyse', 'analyze', 'and', 'any', 'array', 'as', 'asc', 556 'asymmetric', 'authorization', 'between', 'binary', 'both', 'case', 557 'cast', 'check', 'collate', 'column', 'constraint', 'create', 'cross', 558 'current_date', 'current_role', 'current_time', 'current_timestamp', 559 'current_user', 'default', 'deferrable', 'desc', 'distinct', 'do', 560 'else', 'end', 'except', 'false', 'for', 'foreign', 'freeze', 'from', 561 'full', 'grant', 'group', 'having', 'ilike', 'in', 'initially', 'inner', 562 'intersect', 'into', 'is', 'isnull', 'join', 'leading', 'left', 'like', 563 'limit', 'localtime', 'localtimestamp', 'natural', 'new', 'not', 564 'notnull', 'null', 'off', 'offset', 'old', 'on', 'only', 'or', 'order', 565 'outer', 'overlaps', 'placing', 'primary', 'references', 'right', 'select', 566 'session_user', 'similar', 'some', 'symmetric', 'table', 'then', 'to', 567 'trailing', 'true', 'union', 'unique', 'user', 'using', 'verbose', 568 'when', 'where' 569 ); 570 return $reserved_words; 571 } 572 } 573 574 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Wed Jan 14 11:33:29 2009 | Cross-referenced by PHPXref 0.7 |