PageRenderTime 58ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/ddl/sql_generator.php

https://bitbucket.org/andrewdavidson/sl-clone
PHP | 1418 lines | 682 code | 200 blank | 536 comment | 140 complexity | bf58bfe0c7e90ef4ce6a0e5b2027f82d MD5 | raw file
Possible License(s): AGPL-3.0, MPL-2.0-no-copyleft-exception, LGPL-3.0, Apache-2.0, GPL-3.0, BSD-3-Clause, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. // This file is part of Moodle - http://moodle.org/
  3. //
  4. // Moodle is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // Moodle is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  16. /**
  17. * This class represent the base generator class where all the needed functions to generate proper SQL are defined.
  18. *
  19. * The rest of classes will inherit, by default, the same logic.
  20. * Functions will be overridden as needed to generate correct SQL.
  21. *
  22. * @package core_ddl
  23. * @copyright 1999 onwards Martin Dougiamas http://dougiamas.com
  24. * 2001-3001 Eloy Lafuente (stronk7) http://contiento.com
  25. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  26. */
  27. defined('MOODLE_INTERNAL') || die();
  28. /**
  29. * Abstract sql generator class, base for all db specific implementations.
  30. *
  31. * @package core_ddl
  32. * @copyright 1999 onwards Martin Dougiamas http://dougiamas.com
  33. * 2001-3001 Eloy Lafuente (stronk7) http://contiento.com
  34. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  35. */
  36. abstract class sql_generator {
  37. // Please, avoid editing this defaults in this base class!
  38. // It could change the behaviour of the rest of generators
  39. // that, by default, inherit this configuration.
  40. // To change any of them, do it in extended classes instead.
  41. /** @var string Used to quote names. */
  42. public $quote_string = '"';
  43. /** @var string To be automatically added at the end of each statement. */
  44. public $statement_end = ';';
  45. /** @var bool To decide if we want to quote all the names or only the reserved ones. */
  46. public $quote_all = false;
  47. /** @var bool To create all the integers as NUMBER(x) (also called DECIMAL, NUMERIC...). */
  48. public $integer_to_number = false;
  49. /** @var bool To create all the floats as NUMBER(x) (also called DECIMAL, NUMERIC...). */
  50. public $float_to_number = false;
  51. /** @var string Proper type for NUMBER(x) in this DB. */
  52. public $number_type = 'NUMERIC';
  53. /** @var string To define the default to set for NOT NULLs CHARs without default (null=do nothing).*/
  54. public $default_for_char = null;
  55. /** @var bool To specify if the generator must use some DEFAULT clause to drop defaults.*/
  56. public $drop_default_value_required = false;
  57. /** @var string The DEFAULT clause required to drop defaults.*/
  58. public $drop_default_value = '';
  59. /** @var bool To decide if the default clause of each field must go after the null clause.*/
  60. public $default_after_null = true;
  61. /** @var bool To force the generator if NULL clauses must be specified. It shouldn't be necessary.*/
  62. public $specify_nulls = false;
  63. /** @var string To force primary key names to one string (null=no force).*/
  64. public $primary_key_name = null;
  65. /** @var bool True if the generator builds primary keys.*/
  66. public $primary_keys = true;
  67. /** @var bool True if the generator builds unique keys.*/
  68. public $unique_keys = false;
  69. /** @var bool True if the generator builds foreign keys.*/
  70. public $foreign_keys = false;
  71. /** @var string Template to drop PKs. 'TABLENAME' and 'KEYNAME' will be replaced from this template.*/
  72. public $drop_primary_key = 'ALTER TABLE TABLENAME DROP CONSTRAINT KEYNAME';
  73. /** @var string Template to drop UKs. 'TABLENAME' and 'KEYNAME' will be replaced from this template.*/
  74. public $drop_unique_key = 'ALTER TABLE TABLENAME DROP CONSTRAINT KEYNAME';
  75. /** @var string Template to drop FKs. 'TABLENAME' and 'KEYNAME' will be replaced from this template.*/
  76. public $drop_foreign_key = 'ALTER TABLE TABLENAME DROP CONSTRAINT KEYNAME';
  77. /** @var bool True if the generator needs to add extra code to generate the sequence fields.*/
  78. public $sequence_extra_code = true;
  79. /** @var string The particular name for inline sequences in this generator.*/
  80. public $sequence_name = 'auto_increment';
  81. /** @var string|bool Different name for small (4byte) sequences or false if same.*/
  82. public $sequence_name_small = false;
  83. /**
  84. * @var bool To avoid outputting the rest of the field specs, leaving only the name and the sequence_name returned.
  85. * @see getFieldSQL()
  86. */
  87. public $sequence_only = false;
  88. /** @var bool True if the generator needs to add code for table comments.*/
  89. public $add_table_comments = true;
  90. /** @var bool True if the generator needs to add the after clause for fields.*/
  91. public $add_after_clause = false;
  92. /**
  93. * @var bool True if the generator needs to prepend the prefix to all the key/index/sequence/trigger/check names.
  94. * @see $prefix
  95. */
  96. public $prefix_on_names = true;
  97. /** @var int Maximum length for key/index/sequence/trigger/check names (keep 30 for all!).*/
  98. public $names_max_length = 30;
  99. /** @var string Characters to be used as concatenation operator. If not defined, MySQL CONCAT function will be used.*/
  100. public $concat_character = '||';
  101. /** @var string SQL sentence to rename one table, both 'OLDNAME' and 'NEWNAME' keywords are dynamically replaced.*/
  102. public $rename_table_sql = 'ALTER TABLE OLDNAME RENAME TO NEWNAME';
  103. /** @var string SQL sentence to drop one table where the 'TABLENAME' keyword is dynamically replaced.*/
  104. public $drop_table_sql = 'DROP TABLE TABLENAME';
  105. /** @var string The SQL template to alter columns where the 'TABLENAME' and 'COLUMNSPECS' keywords are dynamically replaced.*/
  106. public $alter_column_sql = 'ALTER TABLE TABLENAME ALTER COLUMN COLUMNSPECS';
  107. /** @var bool The generator will skip the default clause on alter columns.*/
  108. public $alter_column_skip_default = false;
  109. /** @var bool The generator will skip the type clause on alter columns.*/
  110. public $alter_column_skip_type = false;
  111. /** @var bool The generator will skip the null/notnull clause on alter columns.*/
  112. public $alter_column_skip_notnull = false;
  113. /** @var string SQL sentence to rename one column where 'TABLENAME', 'OLDFIELDNAME' and 'NEWFIELDNAME' keywords are dynamically replaced.*/
  114. public $rename_column_sql = 'ALTER TABLE TABLENAME RENAME COLUMN OLDFIELDNAME TO NEWFIELDNAME';
  115. /** @var string SQL sentence to drop one index where 'TABLENAME', 'INDEXNAME' keywords are dynamically replaced.*/
  116. public $drop_index_sql = 'DROP INDEX INDEXNAME';
  117. /** @var string SQL sentence to rename one index where 'TABLENAME', 'OLDINDEXNAME' and 'NEWINDEXNAME' are dynamically replaced.*/
  118. public $rename_index_sql = 'ALTER INDEX OLDINDEXNAME RENAME TO NEWINDEXNAME';
  119. /** @var string SQL sentence to rename one key 'TABLENAME', 'OLDKEYNAME' and 'NEWKEYNAME' are dynamically replaced.*/
  120. public $rename_key_sql = 'ALTER TABLE TABLENAME CONSTRAINT OLDKEYNAME RENAME TO NEWKEYNAME';
  121. /** @var string The prefix to be used for all the DB objects.*/
  122. public $prefix;
  123. /** @var string List of reserved words (in order to quote them properly).*/
  124. public $reserved_words;
  125. /** @var moodle_database The moodle_database instance.*/
  126. public $mdb;
  127. /** @var Control existing temptables.*/
  128. protected $temptables;
  129. /**
  130. * Creates a new sql_generator.
  131. * @param moodle_database $mdb The moodle_database object instance.
  132. * @param moodle_temptables $temptables The optional moodle_temptables instance, null by default.
  133. */
  134. public function __construct($mdb, $temptables = null) {
  135. $this->prefix = $mdb->get_prefix();
  136. $this->reserved_words = $this->getReservedWords();
  137. $this->mdb = $mdb; // this creates circular reference - the other link must be unset when closing db
  138. $this->temptables = $temptables;
  139. }
  140. /**
  141. * Releases all resources.
  142. */
  143. public function dispose() {
  144. $this->mdb = null;
  145. }
  146. /**
  147. * Given one string (or one array), ends it with $statement_end .
  148. *
  149. * @see $statement_end
  150. *
  151. * @param array|string $input SQL statement(s).
  152. * @return array|string
  153. */
  154. public function getEndedStatements($input) {
  155. if (is_array($input)) {
  156. foreach ($input as $key=>$content) {
  157. $input[$key] = $this->getEndedStatements($content);
  158. }
  159. return $input;
  160. } else {
  161. $input = trim($input).$this->statement_end;
  162. return $input;
  163. }
  164. }
  165. /**
  166. * Given one xmldb_table, checks if it exists in DB (true/false).
  167. *
  168. * @param mixed $table The table to be searched (string name or xmldb_table instance).
  169. * @return boolean true/false
  170. */
  171. public function table_exists($table) {
  172. if (is_string($table)) {
  173. $tablename = $table;
  174. } else {
  175. // Calculate the name of the table
  176. $tablename = $table->getName();
  177. }
  178. // get all tables in moodle database
  179. $tables = $this->mdb->get_tables();
  180. $exists = in_array($tablename, $tables);
  181. return $exists;
  182. }
  183. /**
  184. * This function will return the SQL code needed to create db tables and statements.
  185. * @see xmldb_structure
  186. *
  187. * @param xmldb_structure $xmldb_structure An xmldb_structure instance.
  188. * @return array
  189. */
  190. public function getCreateStructureSQL($xmldb_structure) {
  191. $results = array();
  192. if ($tables = $xmldb_structure->getTables()) {
  193. foreach ($tables as $table) {
  194. $results = array_merge($results, $this->getCreateTableSQL($table));
  195. }
  196. }
  197. return $results;
  198. }
  199. /**
  200. * Given one xmldb_table, this returns it's correct name, depending of all the parameterization.
  201. * eg: This appends $prefix to the table name.
  202. *
  203. * @see $prefix
  204. *
  205. * @param xmldb_table $xmldb_table The table whose name we want.
  206. * @param boolean $quoted To specify if the name must be quoted (if reserved word, only!).
  207. * @return string The correct name of the table.
  208. */
  209. public function getTableName(xmldb_table $xmldb_table, $quoted=true) {
  210. // Get the name
  211. $tablename = $this->prefix.$xmldb_table->getName();
  212. // Apply quotes optionally
  213. if ($quoted) {
  214. $tablename = $this->getEncQuoted($tablename);
  215. }
  216. return $tablename;
  217. }
  218. /**
  219. * Given one correct xmldb_table, returns the SQL statements
  220. * to create it (inside one array).
  221. *
  222. * @param xmldb_table $xmldb_table An xmldb_table instance.
  223. * @return array An array of SQL statements, starting with the table creation SQL followed
  224. * by any of its comments, indexes and sequence creation SQL statements.
  225. */
  226. public function getCreateTableSQL($xmldb_table) {
  227. if ($error = $xmldb_table->validateDefinition()) {
  228. throw new coding_exception($error);
  229. }
  230. $results = array(); //Array where all the sentences will be stored
  231. // Table header
  232. $table = 'CREATE TABLE ' . $this->getTableName($xmldb_table) . ' (';
  233. if (!$xmldb_fields = $xmldb_table->getFields()) {
  234. return $results;
  235. }
  236. $sequencefield = null;
  237. // Add the fields, separated by commas
  238. foreach ($xmldb_fields as $xmldb_field) {
  239. if ($xmldb_field->getSequence()) {
  240. $sequencefield = $xmldb_field->getName();
  241. }
  242. $table .= "\n " . $this->getFieldSQL($xmldb_table, $xmldb_field);
  243. $table .= ',';
  244. }
  245. // Add the keys, separated by commas
  246. if ($xmldb_keys = $xmldb_table->getKeys()) {
  247. foreach ($xmldb_keys as $xmldb_key) {
  248. if ($keytext = $this->getKeySQL($xmldb_table, $xmldb_key)) {
  249. $table .= "\nCONSTRAINT " . $keytext . ',';
  250. }
  251. // If the key is XMLDB_KEY_FOREIGN_UNIQUE, create it as UNIQUE too
  252. if ($xmldb_key->getType() == XMLDB_KEY_FOREIGN_UNIQUE) {
  253. //Duplicate the key
  254. $xmldb_key->setType(XMLDB_KEY_UNIQUE);
  255. if ($keytext = $this->getKeySQL($xmldb_table, $xmldb_key)) {
  256. $table .= "\nCONSTRAINT " . $keytext . ',';
  257. }
  258. }
  259. // make sure sequence field is unique
  260. if ($sequencefield and $xmldb_key->getType() == XMLDB_KEY_PRIMARY) {
  261. $fields = $xmldb_key->getFields();
  262. $field = reset($fields);
  263. if ($sequencefield === $field) {
  264. $sequencefield = null;
  265. }
  266. }
  267. }
  268. }
  269. // throw error if sequence field does not have unique key defined
  270. if ($sequencefield) {
  271. throw new ddl_exception('ddsequenceerror', $xmldb_table->getName());
  272. }
  273. // Table footer, trim the latest comma
  274. $table = trim($table,',');
  275. $table .= "\n)";
  276. // Add the CREATE TABLE to results
  277. $results[] = $table;
  278. // Add comments if specified and it exists
  279. if ($this->add_table_comments && $xmldb_table->getComment()) {
  280. $comment = $this->getCommentSQL($xmldb_table);
  281. // Add the COMMENT to results
  282. $results = array_merge($results, $comment);
  283. }
  284. // Add the indexes (each one, one statement)
  285. if ($xmldb_indexes = $xmldb_table->getIndexes()) {
  286. foreach ($xmldb_indexes as $xmldb_index) {
  287. //tables do not exist yet, which means indexed can not exist yet
  288. if ($indextext = $this->getCreateIndexSQL($xmldb_table, $xmldb_index)) {
  289. $results = array_merge($results, $indextext);
  290. }
  291. }
  292. }
  293. // Also, add the indexes needed from keys, based on configuration (each one, one statement)
  294. if ($xmldb_keys = $xmldb_table->getKeys()) {
  295. foreach ($xmldb_keys as $xmldb_key) {
  296. // If we aren't creating the keys OR if the key is XMLDB_KEY_FOREIGN (not underlying index generated
  297. // automatically by the RDBMS) create the underlying (created by us) index (if doesn't exists)
  298. if (!$this->getKeySQL($xmldb_table, $xmldb_key) || $xmldb_key->getType() == XMLDB_KEY_FOREIGN) {
  299. // Create the interim index
  300. $index = new xmldb_index('anyname');
  301. $index->setFields($xmldb_key->getFields());
  302. //tables do not exist yet, which means indexed can not exist yet
  303. $createindex = false; //By default
  304. switch ($xmldb_key->getType()) {
  305. case XMLDB_KEY_UNIQUE:
  306. case XMLDB_KEY_FOREIGN_UNIQUE:
  307. $index->setUnique(true);
  308. $createindex = true;
  309. break;
  310. case XMLDB_KEY_FOREIGN:
  311. $index->setUnique(false);
  312. $createindex = true;
  313. break;
  314. }
  315. if ($createindex) {
  316. if ($indextext = $this->getCreateIndexSQL($xmldb_table, $index)) {
  317. // Add the INDEX to the array
  318. $results = array_merge($results, $indextext);
  319. }
  320. }
  321. }
  322. }
  323. }
  324. // Add sequence extra code if needed
  325. if ($this->sequence_extra_code) {
  326. // Iterate over fields looking for sequences
  327. foreach ($xmldb_fields as $xmldb_field) {
  328. if ($xmldb_field->getSequence()) {
  329. // returns an array of statements needed to create one sequence
  330. $sequence_sentences = $this->getCreateSequenceSQL($xmldb_table, $xmldb_field);
  331. // Add the SEQUENCE to the array
  332. $results = array_merge($results, $sequence_sentences);
  333. }
  334. }
  335. }
  336. return $results;
  337. }
  338. /**
  339. * Given one correct xmldb_index, returns the SQL statements
  340. * needed to create it (in array).
  341. *
  342. * @param xmldb_table $xmldb_table The xmldb_table instance to create the index on.
  343. * @param xmldb_index $xmldb_index The xmldb_index to create.
  344. * @return array An array of SQL statements to create the index.
  345. * @throws coding_exception Thrown if the xmldb_index does not validate with the xmldb_table.
  346. */
  347. public function getCreateIndexSQL($xmldb_table, $xmldb_index) {
  348. if ($error = $xmldb_index->validateDefinition($xmldb_table)) {
  349. throw new coding_exception($error);
  350. }
  351. $unique = '';
  352. $suffix = 'ix';
  353. if ($xmldb_index->getUnique()) {
  354. $unique = ' UNIQUE';
  355. $suffix = 'uix';
  356. }
  357. $index = 'CREATE' . $unique . ' INDEX ';
  358. $index .= $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_index->getFields()), $suffix);
  359. $index .= ' ON ' . $this->getTableName($xmldb_table);
  360. $index .= ' (' . implode(', ', $this->getEncQuoted($xmldb_index->getFields())) . ')';
  361. return array($index);
  362. }
  363. /**
  364. * Given one correct xmldb_field, returns the complete SQL line to create it.
  365. *
  366. * @param xmldb_table $xmldb_table The table related to $xmldb_field.
  367. * @param xmldb_field $xmldb_field The instance of xmldb_field to create the SQL from.
  368. * @param string $skip_type_clause The type clause on alter columns, NULL by default.
  369. * @param string $skip_default_clause The default clause on alter columns, NULL by default.
  370. * @param string $skip_notnull_clause The null/notnull clause on alter columns, NULL by default.
  371. * @param string $specify_nulls_clause To force a specific null clause, NULL by default.
  372. * @param bool $specify_field_name Flag to specify fieldname in return.
  373. * @return string The field generating SQL statement.
  374. * @throws coding_exception Thrown when xmldb_field doesn't validate with the xmldb_table.
  375. */
  376. public function getFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause = NULL, $skip_default_clause = NULL, $skip_notnull_clause = NULL, $specify_nulls_clause = NULL, $specify_field_name = true) {
  377. if ($error = $xmldb_field->validateDefinition($xmldb_table)) {
  378. throw new coding_exception($error);
  379. }
  380. $skip_type_clause = is_null($skip_type_clause) ? $this->alter_column_skip_type : $skip_type_clause;
  381. $skip_default_clause = is_null($skip_default_clause) ? $this->alter_column_skip_default : $skip_default_clause;
  382. $skip_notnull_clause = is_null($skip_notnull_clause) ? $this->alter_column_skip_notnull : $skip_notnull_clause;
  383. $specify_nulls_clause = is_null($specify_nulls_clause) ? $this->specify_nulls : $specify_nulls_clause;
  384. // First of all, convert integers to numbers if defined
  385. if ($this->integer_to_number) {
  386. if ($xmldb_field->getType() == XMLDB_TYPE_INTEGER) {
  387. $xmldb_field->setType(XMLDB_TYPE_NUMBER);
  388. }
  389. }
  390. // Same for floats
  391. if ($this->float_to_number) {
  392. if ($xmldb_field->getType() == XMLDB_TYPE_FLOAT) {
  393. $xmldb_field->setType(XMLDB_TYPE_NUMBER);
  394. }
  395. }
  396. $field = ''; // Let's accumulate the whole expression based on params and settings
  397. // The name
  398. if ($specify_field_name) {
  399. $field .= $this->getEncQuoted($xmldb_field->getName());
  400. }
  401. // The type and length only if we don't want to skip it
  402. if (!$skip_type_clause) {
  403. // The type and length
  404. $field .= ' ' . $this->getTypeSQL($xmldb_field->getType(), $xmldb_field->getLength(), $xmldb_field->getDecimals());
  405. }
  406. // note: unsigned is not supported any more since moodle 2.3, all numbers are signed
  407. // Calculate the not null clause
  408. $notnull = '';
  409. // Only if we don't want to skip it
  410. if (!$skip_notnull_clause) {
  411. if ($xmldb_field->getNotNull()) {
  412. $notnull = ' NOT NULL';
  413. } else {
  414. if ($specify_nulls_clause) {
  415. $notnull = ' NULL';
  416. }
  417. }
  418. }
  419. // Calculate the default clause
  420. $default_clause = '';
  421. if (!$skip_default_clause) { //Only if we don't want to skip it
  422. $default_clause = $this->getDefaultClause($xmldb_field);
  423. }
  424. // Based on default_after_null, set both clauses properly
  425. if ($this->default_after_null) {
  426. $field .= $notnull . $default_clause;
  427. } else {
  428. $field .= $default_clause . $notnull;
  429. }
  430. // The sequence
  431. if ($xmldb_field->getSequence()) {
  432. if($xmldb_field->getLength()<=9 && $this->sequence_name_small) {
  433. $sequencename=$this->sequence_name_small;
  434. } else {
  435. $sequencename=$this->sequence_name;
  436. }
  437. $field .= ' ' . $sequencename;
  438. if ($this->sequence_only) {
  439. // We only want the field name and sequence name to be printed
  440. // so, calculate it and return
  441. $sql = $this->getEncQuoted($xmldb_field->getName()) . ' ' . $sequencename;
  442. return $sql;
  443. }
  444. }
  445. return $field;
  446. }
  447. /**
  448. * Given one correct xmldb_key, returns its specs.
  449. *
  450. * @param xmldb_table $xmldb_table The table related to $xmldb_key.
  451. * @param xmldb_key $xmldb_key The xmldb_key's specifications requested.
  452. * @return string SQL statement about the xmldb_key.
  453. */
  454. public function getKeySQL($xmldb_table, $xmldb_key) {
  455. $key = '';
  456. switch ($xmldb_key->getType()) {
  457. case XMLDB_KEY_PRIMARY:
  458. if ($this->primary_keys) {
  459. if ($this->primary_key_name !== null) {
  460. $key = $this->getEncQuoted($this->primary_key_name);
  461. } else {
  462. $key = $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_key->getFields()), 'pk');
  463. }
  464. $key .= ' PRIMARY KEY (' . implode(', ', $this->getEncQuoted($xmldb_key->getFields())) . ')';
  465. }
  466. break;
  467. case XMLDB_KEY_UNIQUE:
  468. if ($this->unique_keys) {
  469. $key = $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_key->getFields()), 'uk');
  470. $key .= ' UNIQUE (' . implode(', ', $this->getEncQuoted($xmldb_key->getFields())) . ')';
  471. }
  472. break;
  473. case XMLDB_KEY_FOREIGN:
  474. case XMLDB_KEY_FOREIGN_UNIQUE:
  475. if ($this->foreign_keys) {
  476. $key = $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_key->getFields()), 'fk');
  477. $key .= ' FOREIGN KEY (' . implode(', ', $this->getEncQuoted($xmldb_key->getFields())) . ')';
  478. $key .= ' REFERENCES ' . $this->getEncQuoted($this->prefix . $xmldb_key->getRefTable());
  479. $key .= ' (' . implode(', ', $this->getEncQuoted($xmldb_key->getRefFields())) . ')';
  480. }
  481. break;
  482. }
  483. return $key;
  484. }
  485. /**
  486. * Give one xmldb_field, returns the correct "default value" for the current configuration
  487. *
  488. * @param xmldb_field $xmldb_field The field.
  489. * @return The default value of the field.
  490. */
  491. public function getDefaultValue($xmldb_field) {
  492. $default = null;
  493. if ($xmldb_field->getDefault() !== NULL) {
  494. if ($xmldb_field->getType() == XMLDB_TYPE_CHAR ||
  495. $xmldb_field->getType() == XMLDB_TYPE_TEXT) {
  496. if ($xmldb_field->getDefault() === '') { // If passing empty default, use the $default_for_char one instead
  497. $default = "'" . $this->default_for_char . "'";
  498. } else {
  499. $default = "'" . $this->addslashes($xmldb_field->getDefault()) . "'";
  500. }
  501. } else {
  502. $default = $xmldb_field->getDefault();
  503. }
  504. } else {
  505. // We force default '' for not null char columns without proper default
  506. // some day this should be out!
  507. if ($this->default_for_char !== NULL &&
  508. $xmldb_field->getType() == XMLDB_TYPE_CHAR &&
  509. $xmldb_field->getNotNull()) {
  510. $default = "'" . $this->default_for_char . "'";
  511. } else {
  512. // If the DB requires to explicity define some clause to drop one default, do it here
  513. // never applying defaults to TEXT and BINARY fields
  514. if ($this->drop_default_value_required &&
  515. $xmldb_field->getType() != XMLDB_TYPE_TEXT &&
  516. $xmldb_field->getType() != XMLDB_TYPE_BINARY && !$xmldb_field->getNotNull()) {
  517. $default = $this->drop_default_value;
  518. }
  519. }
  520. }
  521. return $default;
  522. }
  523. /**
  524. * Given one xmldb_field, returns the correct "default clause" for the current configuration.
  525. *
  526. * @param xmldb_field $xmldb_field The xmldb_field.
  527. * @return The SQL clause for generating the default value as in $xmldb_field.
  528. */
  529. public function getDefaultClause($xmldb_field) {
  530. $defaultvalue = $this->getDefaultValue ($xmldb_field);
  531. if ($defaultvalue !== null) {
  532. return ' DEFAULT ' . $defaultvalue;
  533. } else {
  534. return null;
  535. }
  536. }
  537. /**
  538. * Given one correct xmldb_table and the new name, returns the SQL statements
  539. * to rename it (inside one array).
  540. *
  541. * @param xmldb_table $xmldb_table The table to rename.
  542. * @param string $newname The new name to rename the table to.
  543. * @return array SQL statement(s) to rename the table.
  544. */
  545. public function getRenameTableSQL($xmldb_table, $newname) {
  546. $results = array(); //Array where all the sentences will be stored
  547. $newt = new xmldb_table($newname); //Temporal table for name calculations
  548. $rename = str_replace('OLDNAME', $this->getTableName($xmldb_table), $this->rename_table_sql);
  549. $rename = str_replace('NEWNAME', $this->getTableName($newt), $rename);
  550. $results[] = $rename;
  551. // Call to getRenameTableExtraSQL() override if needed
  552. $extra_sentences = $this->getRenameTableExtraSQL($xmldb_table, $newname);
  553. $results = array_merge($results, $extra_sentences);
  554. return $results;
  555. }
  556. /**
  557. * Given one correct xmldb_table and the new name, returns the SQL statements
  558. * to drop it (inside one array). Works also for temporary tables.
  559. *
  560. * @param xmldb_table $xmldb_table The table to drop.
  561. * @return array SQL statement(s) for dropping the specified table.
  562. */
  563. public function getDropTableSQL($xmldb_table) {
  564. $results = array(); //Array where all the sentences will be stored
  565. $drop = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->drop_table_sql);
  566. $results[] = $drop;
  567. // call to getDropTableExtraSQL(), override if needed
  568. $extra_sentences = $this->getDropTableExtraSQL($xmldb_table);
  569. $results = array_merge($results, $extra_sentences);
  570. return $results;
  571. }
  572. /**
  573. * Given one xmldb_table and one xmldb_field, return the SQL statements needed to add the field to the table.
  574. *
  575. * @param xmldb_table $xmldb_table The table related to $xmldb_field.
  576. * @param xmldb_field $xmldb_field The instance of xmldb_field to create the SQL from.
  577. * @param string $skip_type_clause The type clause on alter columns, NULL by default.
  578. * @param string $skip_default_clause The default clause on alter columns, NULL by default.
  579. * @param string $skip_notnull_clause The null/notnull clause on alter columns, NULL by default.
  580. * @return array The SQL statement for adding a field to the table.
  581. */
  582. public function getAddFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause = NULL, $skip_default_clause = NULL, $skip_notnull_clause = NULL) {
  583. $skip_type_clause = is_null($skip_type_clause) ? $this->alter_column_skip_type : $skip_type_clause;
  584. $skip_default_clause = is_null($skip_default_clause) ? $this->alter_column_skip_default : $skip_default_clause;
  585. $skip_notnull_clause = is_null($skip_notnull_clause) ? $this->alter_column_skip_notnull : $skip_notnull_clause;
  586. $results = array();
  587. // Get the quoted name of the table and field
  588. $tablename = $this->getTableName($xmldb_table);
  589. // Build the standard alter table add
  590. $sql = $this->getFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause,
  591. $skip_default_clause,
  592. $skip_notnull_clause);
  593. $altertable = 'ALTER TABLE ' . $tablename . ' ADD ' . $sql;
  594. // Add the after clause if necessary
  595. if ($this->add_after_clause && $xmldb_field->getPrevious()) {
  596. $altertable .= ' AFTER ' . $this->getEncQuoted($xmldb_field->getPrevious());
  597. }
  598. $results[] = $altertable;
  599. return $results;
  600. }
  601. /**
  602. * Given one xmldb_table and one xmldb_field, return the SQL statements needed to drop the field from the table.
  603. *
  604. * @param xmldb_table $xmldb_table The table related to $xmldb_field.
  605. * @param xmldb_field $xmldb_field The instance of xmldb_field to create the SQL from.
  606. * @return array The SQL statement for dropping a field from the table.
  607. */
  608. public function getDropFieldSQL($xmldb_table, $xmldb_field) {
  609. $results = array();
  610. // Get the quoted name of the table and field
  611. $tablename = $this->getTableName($xmldb_table);
  612. $fieldname = $this->getEncQuoted($xmldb_field->getName());
  613. // Build the standard alter table drop
  614. $results[] = 'ALTER TABLE ' . $tablename . ' DROP COLUMN ' . $fieldname;
  615. return $results;
  616. }
  617. /**
  618. * Given one xmldb_table and one xmldb_field, return the SQL statements needed to alter the field in the table.
  619. *
  620. * @param xmldb_table $xmldb_table The table related to $xmldb_field.
  621. * @param xmldb_field $xmldb_field The instance of xmldb_field to create the SQL from.
  622. * @param string $skip_type_clause The type clause on alter columns, NULL by default.
  623. * @param string $skip_default_clause The default clause on alter columns, NULL by default.
  624. * @param string $skip_notnull_clause The null/notnull clause on alter columns, NULL by default.
  625. * @return string The field altering SQL statement.
  626. */
  627. public function getAlterFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause = NULL, $skip_default_clause = NULL, $skip_notnull_clause = NULL) {
  628. $skip_type_clause = is_null($skip_type_clause) ? $this->alter_column_skip_type : $skip_type_clause;
  629. $skip_default_clause = is_null($skip_default_clause) ? $this->alter_column_skip_default : $skip_default_clause;
  630. $skip_notnull_clause = is_null($skip_notnull_clause) ? $this->alter_column_skip_notnull : $skip_notnull_clause;
  631. $results = array();
  632. // Get the quoted name of the table and field
  633. $tablename = $this->getTableName($xmldb_table);
  634. $fieldname = $this->getEncQuoted($xmldb_field->getName());
  635. // Build de alter sentence using the alter_column_sql template
  636. $alter = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->alter_column_sql);
  637. $colspec = $this->getFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause,
  638. $skip_default_clause,
  639. $skip_notnull_clause,
  640. true);
  641. $alter = str_replace('COLUMNSPECS', $colspec, $alter);
  642. // Add the after clause if necessary
  643. if ($this->add_after_clause && $xmldb_field->getPrevious()) {
  644. $alter .= ' after ' . $this->getEncQuoted($xmldb_field->getPrevious());
  645. }
  646. // Build the standard alter table modify
  647. $results[] = $alter;
  648. return $results;
  649. }
  650. /**
  651. * Given one xmldb_table and one xmldb_field, return the SQL statements needed to modify the default of the field in the table.
  652. *
  653. * @param xmldb_table $xmldb_table The table related to $xmldb_field.
  654. * @param xmldb_field $xmldb_field The instance of xmldb_field to get the modified default value from.
  655. * @return array The SQL statement for modifying the default value.
  656. */
  657. public function getModifyDefaultSQL($xmldb_table, $xmldb_field) {
  658. $results = array();
  659. // Get the quoted name of the table and field
  660. $tablename = $this->getTableName($xmldb_table);
  661. $fieldname = $this->getEncQuoted($xmldb_field->getName());
  662. // Decide if we are going to create/modify or to drop the default
  663. if ($xmldb_field->getDefault() === null) {
  664. $results = $this->getDropDefaultSQL($xmldb_table, $xmldb_field); //Drop
  665. } else {
  666. $results = $this->getCreateDefaultSQL($xmldb_table, $xmldb_field); //Create/modify
  667. }
  668. return $results;
  669. }
  670. /**
  671. * Given one correct xmldb_field and the new name, returns the SQL statements
  672. * to rename it (inside one array).
  673. *
  674. * @param xmldb_table $xmldb_table The table related to $xmldb_field.
  675. * @param xmldb_field $xmldb_field The instance of xmldb_field to get the renamed field from.
  676. * @param string $newname The new name to rename the field to.
  677. * @return array The SQL statements for renaming the field.
  678. */
  679. public function getRenameFieldSQL($xmldb_table, $xmldb_field, $newname) {
  680. $results = array(); //Array where all the sentences will be stored
  681. // Although this is checked in database_manager::rename_field() - double check
  682. // that we aren't trying to rename one "id" field. Although it could be
  683. // implemented (if adding the necessary code to rename sequences, defaults,
  684. // triggers... and so on under each getRenameFieldExtraSQL() function, it's
  685. // better to forbid it, mainly because this field is the default PK and
  686. // in the future, a lot of FKs can be pointing here. So, this field, more
  687. // or less, must be considered immutable!
  688. if ($xmldb_field->getName() == 'id') {
  689. return array();
  690. }
  691. $rename = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->rename_column_sql);
  692. $rename = str_replace('OLDFIELDNAME', $this->getEncQuoted($xmldb_field->getName()), $rename);
  693. $rename = str_replace('NEWFIELDNAME', $this->getEncQuoted($newname), $rename);
  694. $results[] = $rename;
  695. // Call to getRenameFieldExtraSQL(), override if needed
  696. $extra_sentences = $this->getRenameFieldExtraSQL($xmldb_table, $xmldb_field, $newname);
  697. $results = array_merge($results, $extra_sentences);
  698. return $results;
  699. }
  700. /**
  701. * Given one xmldb_table and one xmldb_key, return the SQL statements needed to add the key to the table
  702. * note that undelying indexes will be added as parametrised by $xxxx_keys and $xxxx_index parameters.
  703. *
  704. * @param xmldb_table $xmldb_table The table related to $xmldb_key.
  705. * @param xmldb_key $xmldb_key The xmldb_key to add.
  706. * @return array SQL statement to add the xmldb_key.
  707. */
  708. public function getAddKeySQL($xmldb_table, $xmldb_key) {
  709. $results = array();
  710. // Just use the CreateKeySQL function
  711. if ($keyclause = $this->getKeySQL($xmldb_table, $xmldb_key)) {
  712. $key = 'ALTER TABLE ' . $this->getTableName($xmldb_table) .
  713. ' ADD CONSTRAINT ' . $keyclause;
  714. $results[] = $key;
  715. }
  716. // If we aren't creating the keys OR if the key is XMLDB_KEY_FOREIGN (not underlying index generated
  717. // automatically by the RDBMS) create the underlying (created by us) index (if doesn't exists)
  718. if (!$keyclause || $xmldb_key->getType() == XMLDB_KEY_FOREIGN) {
  719. // Only if they don't exist
  720. if ($xmldb_key->getType() == XMLDB_KEY_FOREIGN) { //Calculate type of index based on type ok key
  721. $indextype = XMLDB_INDEX_NOTUNIQUE;
  722. } else {
  723. $indextype = XMLDB_INDEX_UNIQUE;
  724. }
  725. $xmldb_index = new xmldb_index('anyname', $indextype, $xmldb_key->getFields());
  726. if (!$this->mdb->get_manager()->index_exists($xmldb_table, $xmldb_index)) {
  727. $results = array_merge($results, $this->getAddIndexSQL($xmldb_table, $xmldb_index));
  728. }
  729. }
  730. // If the key is XMLDB_KEY_FOREIGN_UNIQUE, create it as UNIQUE too
  731. if ($xmldb_key->getType() == XMLDB_KEY_FOREIGN_UNIQUE && $this->unique_keys) {
  732. //Duplicate the key
  733. $xmldb_key->setType(XMLDB_KEY_UNIQUE);
  734. $results = array_merge($results, $this->getAddKeySQL($xmldb_table, $xmldb_key));
  735. }
  736. // Return results
  737. return $results;
  738. }
  739. /**
  740. * Given one xmldb_table and one xmldb_index, return the SQL statements needed to drop the index from the table.
  741. *
  742. * @param xmldb_table $xmldb_table The table related to $xmldb_key.
  743. * @param xmldb_key $xmldb_key The xmldb_key to drop.
  744. * @return array SQL statement to drop the xmldb_key.
  745. */
  746. public function getDropKeySQL($xmldb_table, $xmldb_key) {
  747. $results = array();
  748. // Get the key name (note that this doesn't introspect DB, so could cause some problems sometimes!)
  749. // TODO: We'll need to overwrite the whole getDropKeySQL() method inside each DB to do the proper queries
  750. // against the dictionary or require ADOdb to support it or change the find_key_name() method to
  751. // perform DB introspection directly. But, for now, as we aren't going to enable referential integrity
  752. // it won't be a problem at all
  753. $dbkeyname = $this->mdb->get_manager()->find_key_name($xmldb_table, $xmldb_key);
  754. // Only if such type of key generation is enabled
  755. $dropkey = false;
  756. switch ($xmldb_key->getType()) {
  757. case XMLDB_KEY_PRIMARY:
  758. if ($this->primary_keys) {
  759. $template = $this->drop_primary_key;
  760. $dropkey = true;
  761. }
  762. break;
  763. case XMLDB_KEY_UNIQUE:
  764. if ($this->unique_keys) {
  765. $template = $this->drop_unique_key;
  766. $dropkey = true;
  767. }
  768. break;
  769. case XMLDB_KEY_FOREIGN_UNIQUE:
  770. case XMLDB_KEY_FOREIGN:
  771. if ($this->foreign_keys) {
  772. $template = $this->drop_foreign_key;
  773. $dropkey = true;
  774. }
  775. break;
  776. }
  777. // If we have decided to drop the key, let's do it
  778. if ($dropkey) {
  779. // Replace TABLENAME, CONSTRAINTTYPE and KEYNAME as needed
  780. $dropsql = str_replace('TABLENAME', $this->getTableName($xmldb_table), $template);
  781. $dropsql = str_replace('KEYNAME', $dbkeyname, $dropsql);
  782. $results[] = $dropsql;
  783. }
  784. // If we aren't dropping the keys OR if the key is XMLDB_KEY_FOREIGN (not underlying index generated
  785. // automatically by the RDBMS) drop the underlying (created by us) index (if exists)
  786. if (!$dropkey || $xmldb_key->getType() == XMLDB_KEY_FOREIGN) {
  787. // Only if they exist
  788. $xmldb_index = new xmldb_index('anyname', XMLDB_INDEX_UNIQUE, $xmldb_key->getFields());
  789. if ($this->mdb->get_manager()->index_exists($xmldb_table, $xmldb_index)) {
  790. $results = array_merge($results, $this->getDropIndexSQL($xmldb_table, $xmldb_index));
  791. }
  792. }
  793. // If the key is XMLDB_KEY_FOREIGN_UNIQUE, drop the UNIQUE too
  794. if ($xmldb_key->getType() == XMLDB_KEY_FOREIGN_UNIQUE && $this->unique_keys) {
  795. //Duplicate the key
  796. $xmldb_key->setType(XMLDB_KEY_UNIQUE);
  797. $results = array_merge($results, $this->getDropKeySQL($xmldb_table, $xmldb_key));
  798. }
  799. // Return results
  800. return $results;
  801. }
  802. /**
  803. * Given one xmldb_table and one xmldb_key, return the SQL statements needed to rename the key in the table
  804. * Experimental! Shouldn't be used at all!
  805. *
  806. * @param xmldb_table $xmldb_table The table related to $xmldb_key.
  807. * @param xmldb_key $xmldb_key The xmldb_key to rename.
  808. * @param string $newname The xmldb_key's new name.
  809. * @return array SQL statement to rename the xmldb_key.
  810. */
  811. public function getRenameKeySQL($xmldb_table, $xmldb_key, $newname) {
  812. $results = array();
  813. // Get the real key name
  814. $dbkeyname = $this->mdb->get_manager()->find_key_name($xmldb_table, $xmldb_key);
  815. // Check we are really generating this type of keys
  816. if (($xmldb_key->getType() == XMLDB_KEY_PRIMARY && !$this->primary_keys) ||
  817. ($xmldb_key->getType() == XMLDB_KEY_UNIQUE && !$this->unique_keys) ||
  818. ($xmldb_key->getType() == XMLDB_KEY_FOREIGN && !$this->foreign_keys) ||
  819. ($xmldb_key->getType() == XMLDB_KEY_FOREIGN_UNIQUE && !$this->unique_keys && !$this->foreign_keys)) {
  820. // We aren't generating this type of keys, delegate to child indexes
  821. $xmldb_index = new xmldb_index($xmldb_key->getName());
  822. $xmldb_index->setFields($xmldb_key->getFields());
  823. return $this->getRenameIndexSQL($xmldb_table, $xmldb_index, $newname);
  824. }
  825. // Arrived here so we are working with keys, lets rename them
  826. // Replace TABLENAME and KEYNAME as needed
  827. $renamesql = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->rename_key_sql);
  828. $renamesql = str_replace('OLDKEYNAME', $dbkeyname, $renamesql);
  829. $renamesql = str_replace('NEWKEYNAME', $newname, $renamesql);
  830. // Some DB doesn't support key renaming so this can be empty
  831. if ($renamesql) {
  832. $results[] = $renamesql;
  833. }
  834. return $results;
  835. }
  836. /**
  837. * Given one xmldb_table and one xmldb_index, return the SQL statements needed to add the index to the table.
  838. *
  839. * @param xmldb_table $xmldb_table The xmldb_table instance to add the index on.
  840. * @param xmldb_index $xmldb_index The xmldb_index to add.
  841. * @return array An array of SQL statements to add the index.
  842. */
  843. public function getAddIndexSQL($xmldb_table, $xmldb_index) {
  844. // Just use the CreateIndexSQL function
  845. return $this->getCreateIndexSQL($xmldb_table, $xmldb_index);
  846. }
  847. /**
  848. * Given one xmldb_table and one xmldb_index, return the SQL statements needed to drop the index from the table.
  849. *
  850. * @param xmldb_table $xmldb_table The xmldb_table instance to drop the index on.
  851. * @param xmldb_index $xmldb_index The xmldb_index to drop.
  852. * @return array An array of SQL statements to drop the index.
  853. */
  854. public function getDropIndexSQL($xmldb_table, $xmldb_index) {
  855. $results = array();
  856. // Get the real index name
  857. $dbindexnames = $this->mdb->get_manager()->find_index_name($xmldb_table, $xmldb_index, true);
  858. // Replace TABLENAME and INDEXNAME as needed
  859. if ($dbindexnames) {
  860. foreach ($dbindexnames as $dbindexname) {
  861. $dropsql = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->drop_index_sql);
  862. $dropsql = str_replace('INDEXNAME', $this->getEncQuoted($dbindexname), $dropsql);
  863. $results[] = $dropsql;
  864. }
  865. }
  866. return $results;
  867. }
  868. /**
  869. * Given one xmldb_table and one xmldb_index, return the SQL statements needed to rename the index in the table
  870. * Experimental! Shouldn't be used at all!
  871. *
  872. * @param xmldb_table $xmldb_table The xmldb_table instance to rename the index on.
  873. * @param xmldb_index $xmldb_index The xmldb_index to rename.
  874. * @param string $newname The xmldb_index's new name.
  875. * @return array An array of SQL statements to rename the index.
  876. */
  877. function getRenameIndexSQL($xmldb_table, $xmldb_index, $newname) {
  878. // Some DB doesn't support index renaming (MySQL) so this can be empty
  879. if (empty($this->rename_index_sql)) {
  880. return array();
  881. }
  882. // Get the real index name
  883. $dbindexname = $this->mdb->get_manager()->find_index_name($xmldb_table, $xmldb_index);
  884. // Replace TABLENAME and INDEXNAME as needed
  885. $renamesql = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->rename_index_sql);
  886. $renamesql = str_replace('OLDINDEXNAME', $this->getEncQuoted($dbindexname), $renamesql);
  887. $renamesql = str_replace('NEWINDEXNAME', $this->getEncQuoted($newname), $renamesql);
  888. return array($renamesql);
  889. }
  890. /**
  891. * Given three strings (table name, list of fields (comma separated) and suffix),
  892. * create the proper object name quoting it if necessary.
  893. *
  894. * IMPORTANT: This function must be used to CALCULATE NAMES of objects TO BE CREATED,
  895. * NEVER TO GUESS NAMES of EXISTING objects!!!
  896. *
  897. * @param string $tablename The table name.
  898. * @param string $fields A list of comma separated fields.
  899. * @param string $suffix A suffix for the object name.
  900. * @return string Object's name.
  901. */
  902. public function getNameForObject($tablename, $fields, $suffix='') {
  903. $name = '';
  904. // Implement one basic cache to avoid object name duplication
  905. // along all the request life, but never to return cached results
  906. // We need this because sql statements are created before executing
  907. // them, hence names doesn't exist "physically" yet in DB, so we need
  908. // to known which ones have been used
  909. static $used_names = array();
  910. // Use standard naming. See http://docs.moodle.org/en/XMLDB_key_and_index_naming
  911. $tablearr = explode ('_', $tablename);
  912. foreach ($tablearr as $table) {
  913. $name .= substr(trim($table),0,4);
  914. }
  915. $name .= '_';
  916. $fieldsarr = explode (',', $fields);
  917. foreach ($fieldsarr as $field) {
  918. $name .= substr(trim($field),0,3);
  919. }
  920. // Prepend the prefix
  921. $name = $this->prefix . $name;
  922. $name = substr(trim($name), 0, $this->names_max_length - 1 - strlen($suffix)); //Max names_max_length
  923. // Add the suffix
  924. $namewithsuffix = $name;
  925. if ($suffix) {
  926. $namewithsuffix = $namewithsuffix . '_' . $suffix;
  927. }
  928. // If the calculated name is in the cache, or if we detect it by introspecting the DB let's modify if
  929. if (in_array($namewithsuffix, $used_names) || $this->isNameInUse($namewithsuffix, $suffix, $tablename)) {
  930. $counter = 2;
  931. // If have free space, we add 2
  932. if (strlen($namewithsuffix) < $this->names_max_length) {
  933. $newname = $name . $counter;
  934. // Else replace the last char by 2
  935. } else {
  936. $newname = substr($name, 0, strlen($name)-1) . $counter;
  937. }
  938. $newnamewithsuffix = $newname;
  939. if ($suffix) {
  940. $newnamewithsuffix = $newnamewithsuffix . '_' . $suffix;
  941. }
  942. // Now iterate until not used name is found, incrementing the counter
  943. while (in_array($newnamewithsuffix, $used_names) || $this->isNameInUse($newnamewithsuffix, $suffix, $tablename)) {
  944. $counter++;
  945. $newname = substr($name, 0, strlen($newname)-1) . $counter;
  946. $newnamewithsuffix = $newname;
  947. if ($suffix) {
  948. $newnamewithsuffix = $newnamewithsuffix . '_' . $suffix;
  949. }
  950. }
  951. $namewithsuffix = $newnamewithsuffix;
  952. }
  953. // Add the name to the cache
  954. $used_names[] = $namewithsuffix;
  955. // Quote it if necessary (reserved words)
  956. $namewithsuffix = $this->getEncQuoted($namewithsuffix);
  957. return $namewithsuffix;
  958. }
  959. /**
  960. * Given any string (or one array), enclose it by the proper quotes
  961. * if it's a reserved word
  962. *
  963. * @param string|array $input String to quote.
  964. * @return string Quoted string.
  965. */
  966. public function getEncQuoted($input) {
  967. if (is_array($input)) {
  968. foreach ($input as $key=>$content) {
  969. $input[$key] = $this->getEncQuoted($content);
  970. }
  971. return $input;
  972. } else {
  973. // Always lowercase
  974. $input = strtolower($input);
  975. // if reserved or quote_all or has hyphens, quote it
  976. if ($this->quote_all || in_array($input, $this->reserved_words) || strpos($input, '-') !== false) {
  977. $input = $this->quote_string . $input . $this->quote_string;
  978. }
  979. return $input;
  980. }
  981. }
  982. /**
  983. * Given one XMLDB Statement, build the needed SQL in…

Large files files are truncated, but you can click here to view the full file