Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/ddl/postgres_sql_generator.php
Go to the documentation of this file.
00001 <?php
00002 
00003 // This file is part of Moodle - http://moodle.org/
00004 //
00005 // Moodle is free software: you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation, either version 3 of the License, or
00008 // (at your option) any later version.
00009 //
00010 // Moodle is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00017 
00018 
00029 defined('MOODLE_INTERNAL') || die();
00030 
00031 require_once($CFG->libdir.'/ddl/sql_generator.php');
00032 
00036 
00037 class postgres_sql_generator extends sql_generator {
00038 
00040 
00041     public $number_type = 'NUMERIC';    // Proper type for NUMBER(x) in this DB
00042 
00043     public $unsigned_allowed = false;    // To define in the generator must handle unsigned information
00044     public $default_for_char = '';      // To define the default to set for NOT NULLs CHARs without default (null=do nothing)
00045 
00046     public $sequence_extra_code = false; //Does the generator need to add extra code to generate the sequence fields
00047     public $sequence_name = 'BIGSERIAL'; //Particular name for inline sequences in this generator
00048     public $sequence_name_small = 'SERIAL'; //Particular name for inline sequences in this generator
00049     public $sequence_only = true; //To avoid to output the rest of the field specs, leaving only the name and the sequence_name variable
00050 
00051     public $enum_inline_code = false; //Does the generator need to add inline code in the column definition
00052 
00053     public $rename_index_sql = 'ALTER TABLE OLDINDEXNAME RENAME TO NEWINDEXNAME'; //SQL sentence to rename one index
00054                                       //TABLENAME, OLDINDEXNAME, NEWINDEXNAME are dynamically replaced
00055 
00056     public $rename_key_sql = null; //SQL sentence to rename one key (PostgreSQL doesn't support this!)
00057                                           //TABLENAME, OLDKEYNAME, NEWKEYNAME are dynamically replaced
00058 
00059     protected $std_strings = null;  // '' or \' quotes
00060 
00066     public function getResetSequenceSQL($table) {
00067 
00068         if ($table instanceof xmldb_table) {
00069             $tablename = $table->getName();
00070         } else {
00071             $tablename = $table;
00072         }
00073 
00074         // From http://www.postgresql.org/docs/7.4/static/sql-altersequence.html
00075         $value = (int)$this->mdb->get_field_sql('SELECT MAX(id) FROM {'.$tablename.'}');
00076         $value++;
00077         return array("ALTER SEQUENCE $this->prefix{$tablename}_id_seq RESTART WITH $value");
00078     }
00079 
00084     public function getCreateTempTableSQL($xmldb_table) {
00085         $this->temptables->add_temptable($xmldb_table->getName());
00086         $sqlarr = $this->getCreateTableSQL($xmldb_table);
00087         $sqlarr = preg_replace('/^CREATE TABLE/', "CREATE TEMPORARY TABLE", $sqlarr);
00088         return $sqlarr;
00089     }
00090 
00095     public function getDropTempTableSQL($xmldb_table) {
00096         $sqlarr = $this->getDropTableSQL($xmldb_table);
00097         $this->temptables->delete_temptable($xmldb_table->getName());
00098         return $sqlarr;
00099     }
00100 
00104     public function getTypeSQL($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
00105 
00106         switch ($xmldb_type) {
00107             case XMLDB_TYPE_INTEGER:    // From http://www.postgresql.org/docs/7.4/interactive/datatype.html
00108                 if (empty($xmldb_length)) {
00109                     $xmldb_length = 10;
00110                 }
00111                 if ($xmldb_length > 9) {
00112                     $dbtype = 'BIGINT';
00113                 } else if ($xmldb_length > 4) {
00114                     $dbtype = 'INTEGER';
00115                 } else {
00116                     $dbtype = 'SMALLINT';
00117                 }
00118                 break;
00119             case XMLDB_TYPE_NUMBER:
00120                 $dbtype = $this->number_type;
00121                 if (!empty($xmldb_length)) {
00122                     $dbtype .= '(' . $xmldb_length;
00123                     if (!empty($xmldb_decimals)) {
00124                         $dbtype .= ',' . $xmldb_decimals;
00125                     }
00126                     $dbtype .= ')';
00127                 }
00128                 break;
00129             case XMLDB_TYPE_FLOAT:
00130                 $dbtype = 'DOUBLE PRECISION';
00131                 if (!empty($xmldb_decimals)) {
00132                     if ($xmldb_decimals < 6) {
00133                         $dbtype = 'REAL';
00134                     }
00135                 }
00136                 break;
00137             case XMLDB_TYPE_CHAR:
00138                 $dbtype = 'VARCHAR';
00139                 if (empty($xmldb_length)) {
00140                     $xmldb_length='255';
00141                 }
00142                 $dbtype .= '(' . $xmldb_length . ')';
00143                 break;
00144             case XMLDB_TYPE_TEXT:
00145                 $dbtype = 'TEXT';
00146                 break;
00147             case XMLDB_TYPE_BINARY:
00148                 $dbtype = 'BYTEA';
00149                 break;
00150             case XMLDB_TYPE_DATETIME:
00151                 $dbtype = 'TIMESTAMP';
00152                 break;
00153         }
00154         return $dbtype;
00155     }
00156 
00160     function getCommentSQL ($xmldb_table) {
00161 
00162         $comment = "COMMENT ON TABLE " . $this->getTableName($xmldb_table);
00163         $comment.= " IS '" . $this->addslashes(substr($xmldb_table->getComment(), 0, 250)) . "'";
00164 
00165         return array($comment);
00166     }
00167 
00171     public function getRenameTableExtraSQL($xmldb_table, $newname) {
00172 
00173         $results = array();
00174 
00175         $newt = new xmldb_table($newname);
00176 
00177         $xmldb_field = new xmldb_field('id'); // Fields having sequences should be exclusively, id.
00178 
00179         $oldseqname = $this->getTableName($xmldb_table) . '_' . $xmldb_field->getName() . '_seq';
00180         $newseqname = $this->getTableName($newt) . '_' . $xmldb_field->getName() . '_seq';
00181 
00183         $results[] = 'ALTER TABLE ' . $oldseqname . ' RENAME TO ' . $newseqname;
00184 
00186         $oldtablename = $this->getTableName($xmldb_table);
00187         $newtablename = $this->getTableName($newt);
00188 
00189         $oldconstraintprefix = $this->getNameForObject($xmldb_table->getName(), '');
00190         $newconstraintprefix = $this->getNameForObject($newt->getName(), '', '');
00191 
00192         if ($constraints = $this->getCheckConstraintsFromDB($xmldb_table)) {
00193             foreach ($constraints as $constraint) {
00195                 $results[] = 'ALTER TABLE ' . $newtablename . ' DROP CONSTRAINT ' . $constraint->name;
00196             }
00197          }
00198 
00199         return $results;
00200     }
00201 
00211     public function getAlterFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause = NULL, $skip_default_clause = NULL, $skip_notnull_clause = NULL) {
00212         $results = array(); 
00213 
00215         $tablename = $xmldb_table->getName();
00216         $fieldname = $xmldb_field->getName();
00217 
00219         $meta = $this->mdb->get_columns($tablename);
00220         $metac = $meta[$xmldb_field->getName()];
00221         $oldmetatype = $metac->meta_type;
00222         $oldlength = $metac->max_length;
00223         $olddecimals = empty($metac->scale) ? null : $metac->scale;
00224         $oldnotnull = empty($metac->not_null) ? false : $metac->not_null;
00225         $olddefault = empty($metac->has_default) ? null : $metac->default_value;
00226 
00227         $typechanged = true;  //By default, assume that the column type has changed
00228         $precisionchanged = true;  //By default, assume that the column precision has changed
00229         $decimalchanged = true;  //By default, assume that the column decimal has changed
00230         $defaultchanged = true;  //By default, assume that the column default has changed
00231         $notnullchanged = true;  //By default, assume that the column notnull has changed
00232 
00234         if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER && $oldmetatype == 'I') ||
00235             ($xmldb_field->getType() == XMLDB_TYPE_NUMBER  && $oldmetatype == 'N') ||
00236             ($xmldb_field->getType() == XMLDB_TYPE_FLOAT   && $oldmetatype == 'F') ||
00237             ($xmldb_field->getType() == XMLDB_TYPE_CHAR    && $oldmetatype == 'C') ||
00238             ($xmldb_field->getType() == XMLDB_TYPE_TEXT    && $oldmetatype == 'X') ||
00239             ($xmldb_field->getType() == XMLDB_TYPE_BINARY  && $oldmetatype == 'B')) {
00240             $typechanged = false;
00241         }
00243         if (($xmldb_field->getType() == XMLDB_TYPE_TEXT) ||
00244             ($xmldb_field->getType() == XMLDB_TYPE_BINARY) ||
00245             ($oldlength == -1) ||
00246             ($xmldb_field->getLength() == $oldlength)) {
00247             $precisionchanged = false;
00248         }
00250         if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER) ||
00251             ($xmldb_field->getType() == XMLDB_TYPE_CHAR) ||
00252             ($xmldb_field->getType() == XMLDB_TYPE_TEXT) ||
00253             ($xmldb_field->getType() == XMLDB_TYPE_BINARY) ||
00254             (!$xmldb_field->getDecimals()) ||
00255             (!$olddecimals) ||
00256             ($xmldb_field->getDecimals() == $olddecimals)) {
00257             $decimalchanged = false;
00258         }
00260         if (($xmldb_field->getDefault() === null && $olddefault === null) ||
00261             ($xmldb_field->getDefault() === $olddefault)) {
00262             $defaultchanged = false;
00263         }
00265         if (($xmldb_field->getNotnull() === $oldnotnull)) {
00266             $notnullchanged = false;
00267         }
00268 
00270         $tablename = $this->getTableName($xmldb_table);
00271         $fieldname = $this->getEncQuoted($xmldb_field->getName());
00272 
00274         $specschanged = $typechanged || $precisionchanged || $decimalchanged;
00275 
00277         if ($specschanged) {
00279             if ($olddefault !== null) {
00280                 $results[] = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' DROP DEFAULT'; 
00281             }
00282             $alterstmt = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $this->getEncQuoted($xmldb_field->getName()) .
00283                          ' TYPE' . $this->getFieldSQL($xmldb_table, $xmldb_field, null, true, true, null, false);
00285             if (($oldmetatype == 'C' || $oldmetatype == 'X') &&
00286                 ($xmldb_field->getType() == XMLDB_TYPE_NUMBER || $xmldb_field->getType() == XMLDB_TYPE_FLOAT)) {
00287                 $alterstmt .= ' USING CAST('.$fieldname.' AS NUMERIC)'; // from char or text to number or float
00288             } else if (($oldmetatype == 'C' || $oldmetatype == 'X') &&
00289                 $xmldb_field->getType() == XMLDB_TYPE_INTEGER) {
00290                 $alterstmt .= ' USING CAST(CAST('.$fieldname.' AS NUMERIC) AS INTEGER)'; // From char to integer
00291             }
00292             $results[] = $alterstmt;
00293         }
00294 
00296         if ($defaultchanged || $specschanged) {
00297             $default_clause = $this->getDefaultClause($xmldb_field);
00298             if ($default_clause) {
00299                 $sql = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' SET' . $default_clause; 
00300                 $results[] = $sql;
00301             } else {
00302                 if (!$specschanged) { 
00303                     $results[] = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' DROP DEFAULT'; 
00304                 }
00305             }
00306         }
00307 
00309         if ($notnullchanged) {
00310             if ($xmldb_field->getNotnull()) {
00311                 $results[] = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' SET NOT NULL';
00312             } else {
00313                 $results[] = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' DROP NOT NULL';
00314             }
00315         }
00316 
00318         return $results;
00319     }
00320 
00327     public function getDropEnumSQL($xmldb_table, $xmldb_field) {
00329         if ($check_constraints = $this->getCheckConstraintsFromDB($xmldb_table, $xmldb_field)) {
00330             $check_constraint = array_shift($check_constraints); 
00331             $constraint_name = strtolower($check_constraint->name); 
00332 
00333             return array('ALTER TABLE ' . $this->getTableName($xmldb_table) .
00334                      ' DROP CONSTRAINT ' . $constraint_name);
00335         } else { 
00336             return array();
00337         }
00338     }
00339 
00344     public function getCreateDefaultSQL($xmldb_table, $xmldb_field) {
00347         return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
00348     }
00349 
00354     public function getDropDefaultSQL($xmldb_table, $xmldb_field) {
00357         return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
00358     }
00359 
00370     public function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) {
00371 
00372         $results = array();
00373 
00374         $tablename = $this->getTableName($xmldb_table);
00375 
00376         if ($constraints = $this->mdb->get_records_sql("SELECT co.conname AS name, co.consrc AS description
00377                                                           FROM pg_constraint co, pg_class cl
00378                                                          WHERE co.conrelid = cl.oid
00379                                                                AND co.contype = 'c' AND cl.relname = ?",
00380                                                        array($tablename))) {
00381             foreach ($constraints as $constraint) {
00382                 $results[$constraint->name] = $constraint;
00383             }
00384         }
00385 
00387         if ($xmldb_field) {
00388             $filtered_results = array();
00389             $filter = $xmldb_field->getName();
00391             foreach ($results as $key => $result) {
00392                 $description = preg_replace('/\("(.*?)"\)/', '($1)', $result->description);// Double quotes out
00393                 $description = preg_replace('/[\(\)]/', '', $description);                 // Parenthesis out
00394                 $description = preg_replace('/::[a-z]+/i', '', $description);              // Casts out
00395                 $description = preg_replace("/({$filter})/i", '@$1@', $description);
00396                 $description = trim(preg_replace('/ or /i', ' OR ', $description));        // Uppercase or & trim
00398                 if (preg_match("/^@{$filter}@/i", $description)) {
00399                     $filtered_results[$key] = $result;
00400                 }
00401             }
00403             $results =  $filtered_results;
00404         }
00405 
00406         return $results;
00407     }
00408 
00409     public function addslashes($s) {
00410         // Postgres is gradually switching to ANSI quotes, we need to check what is expected
00411         if (!isset($this->std_strings)) {
00412             $this->std_strings = ($this->mdb->get_field_sql("select setting from pg_settings where name = 'standard_conforming_strings'") === 'on');
00413         }
00414 
00415         if ($this->std_strings) {
00416             $s = str_replace("'",  "''", $s);
00417         } else {
00418             // do not use php addslashes() because it depends on PHP quote settings!
00419             $s = str_replace('\\','\\\\',$s);
00420             $s = str_replace("\0","\\\0", $s);
00421             $s = str_replace("'",  "\\'", $s);
00422         }
00423 
00424         return $s;
00425     }
00426 
00435 function getSequenceFromDB($xmldb_table) {
00436 
00437     $tablename = $this->getTableName($xmldb_table);
00438     $sequencename = $tablename . '_id_seq';
00439 
00440     if (!$this->mdb->get_record_sql("SELECT *
00441                                        FROM pg_class
00442                                       WHERE relname = ? AND relkind = 'S'",
00443                                     array($sequencename))) {
00444         $sequencename = false;
00445     }
00446 
00447     return $sequencename;
00448 }
00449 
00455     public function isNameInUse($object_name, $type, $table_name) {
00456         switch($type) {
00457             case 'ix':
00458             case 'uix':
00459             case 'seq':
00460                 if ($check = $this->mdb->get_records_sql("SELECT relname
00461                                                             FROM pg_class
00462                                                            WHERE lower(relname) = ?", array(strtolower($object_name)))) {
00463                     return true;
00464                 }
00465                 break;
00466             case 'pk':
00467             case 'uk':
00468             case 'fk':
00469             case 'ck':
00470                 if ($check = $this->mdb->get_records_sql("SELECT conname
00471                                                             FROM pg_constraint
00472                                                            WHERE lower(conname) = ?", array(strtolower($object_name)))) {
00473                     return true;
00474                 }
00475                 break;
00476             case 'trg':
00477                 if ($check = $this->mdb->get_records_sql("SELECT tgname
00478                                                             FROM pg_trigger
00479                                                            WHERE lower(tgname) = ?", array(strtolower($object_name)))) {
00480                     return true;
00481                 }
00482                 break;
00483         }
00484         return false; //No name in use found
00485     }
00486 
00490     public static function getReservedWords() {
00493         $reserved_words = array (
00494             'all', 'analyse', 'analyze', 'and', 'any', 'array', 'as', 'asc',
00495             'asymmetric', 'authorization', 'between', 'binary', 'both', 'case',
00496             'cast', 'check', 'collate', 'column', 'constraint', 'create', 'cross',
00497             'current_date', 'current_role', 'current_time', 'current_timestamp',
00498             'current_user', 'default', 'deferrable', 'desc', 'distinct', 'do',
00499             'else', 'end', 'except', 'false', 'for', 'foreign', 'freeze', 'from',
00500             'full', 'grant', 'group', 'having', 'ilike', 'in', 'initially', 'inner',
00501             'intersect', 'into', 'is', 'isnull', 'join', 'leading', 'left', 'like',
00502             'limit', 'localtime', 'localtimestamp', 'natural', 'new', 'not',
00503             'notnull', 'null', 'off', 'offset', 'old', 'on', 'only', 'or', 'order',
00504             'outer', 'overlaps', 'placing', 'primary', 'references', 'returning', 'right', 'select',
00505             'session_user', 'similar', 'some', 'symmetric', 'table', 'then', 'to',
00506             'trailing', 'true', 'union', 'unique', 'user', 'using', 'verbose',
00507             'when', 'where', 'with'
00508         );
00509         return $reserved_words;
00510     }
00511 }
 All Data Structures Namespaces Files Functions Variables Enumerations