schema.inc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. <?php
  2. /**
  3. * @file
  4. * Database schema code for SQLite databases.
  5. */
  6. /**
  7. * @ingroup schemaapi
  8. * @{
  9. */
  10. class DatabaseSchema_sqlite extends DatabaseSchema {
  11. /**
  12. * Override DatabaseSchema::$defaultSchema
  13. */
  14. protected $defaultSchema = 'main';
  15. public function tableExists($table) {
  16. $info = $this->getPrefixInfo($table);
  17. // Don't use {} around sqlite_master table.
  18. return (bool) $this->connection->query('SELECT 1 FROM ' . $info['schema'] . '.sqlite_master WHERE type = :type AND name = :name', array(':type' => 'table', ':name' => $info['table']))->fetchField();
  19. }
  20. public function fieldExists($table, $column) {
  21. $schema = $this->introspectSchema($table);
  22. return !empty($schema['fields'][$column]);
  23. }
  24. /**
  25. * Generate SQL to create a new table from a Drupal schema definition.
  26. *
  27. * @param $name
  28. * The name of the table to create.
  29. * @param $table
  30. * A Schema API table definition array.
  31. * @return
  32. * An array of SQL statements to create the table.
  33. */
  34. public function createTableSql($name, $table) {
  35. $sql = array();
  36. $sql[] = "CREATE TABLE {" . $name . "} (\n" . $this->createColumsSql($name, $table) . "\n);\n";
  37. return array_merge($sql, $this->createIndexSql($name, $table));
  38. }
  39. /**
  40. * Build the SQL expression for indexes.
  41. */
  42. protected function createIndexSql($tablename, $schema) {
  43. $sql = array();
  44. $info = $this->getPrefixInfo($tablename);
  45. if (!empty($schema['unique keys'])) {
  46. foreach ($schema['unique keys'] as $key => $fields) {
  47. $sql[] = 'CREATE UNIQUE INDEX ' . $info['schema'] . '.' . $info['table'] . '_' . $key . ' ON ' . $info['table'] . ' (' . $this->createKeySql($fields) . "); \n";
  48. }
  49. }
  50. if (!empty($schema['indexes'])) {
  51. foreach ($schema['indexes'] as $key => $fields) {
  52. $sql[] = 'CREATE INDEX ' . $info['schema'] . '.' . $info['table'] . '_' . $key . ' ON ' . $info['table'] . ' (' . $this->createKeySql($fields) . "); \n";
  53. }
  54. }
  55. return $sql;
  56. }
  57. /**
  58. * Build the SQL expression for creating columns.
  59. */
  60. protected function createColumsSql($tablename, $schema) {
  61. $sql_array = array();
  62. // Add the SQL statement for each field.
  63. foreach ($schema['fields'] as $name => $field) {
  64. if (isset($field['type']) && $field['type'] == 'serial') {
  65. if (isset($schema['primary key']) && ($key = array_search($name, $schema['primary key'])) !== FALSE) {
  66. unset($schema['primary key'][$key]);
  67. }
  68. }
  69. $sql_array[] = $this->createFieldSql($name, $this->processField($field));
  70. }
  71. // Process keys.
  72. if (!empty($schema['primary key'])) {
  73. $sql_array[] = " PRIMARY KEY (" . $this->createKeySql($schema['primary key']) . ")";
  74. }
  75. return implode(", \n", $sql_array);
  76. }
  77. /**
  78. * Build the SQL expression for keys.
  79. */
  80. protected function createKeySql($fields) {
  81. $return = array();
  82. foreach ($fields as $field) {
  83. if (is_array($field)) {
  84. $return[] = $field[0];
  85. }
  86. else {
  87. $return[] = $field;
  88. }
  89. }
  90. return implode(', ', $return);
  91. }
  92. /**
  93. * Set database-engine specific properties for a field.
  94. *
  95. * @param $field
  96. * A field description array, as specified in the schema documentation.
  97. */
  98. protected function processField($field) {
  99. if (!isset($field['size'])) {
  100. $field['size'] = 'normal';
  101. }
  102. // Set the correct database-engine specific datatype.
  103. // In case one is already provided, force it to uppercase.
  104. if (isset($field['sqlite_type'])) {
  105. $field['sqlite_type'] = drupal_strtoupper($field['sqlite_type']);
  106. }
  107. else {
  108. $map = $this->getFieldTypeMap();
  109. $field['sqlite_type'] = $map[$field['type'] . ':' . $field['size']];
  110. }
  111. if (isset($field['type']) && $field['type'] == 'serial') {
  112. $field['auto_increment'] = TRUE;
  113. }
  114. return $field;
  115. }
  116. /**
  117. * Create an SQL string for a field to be used in table creation or alteration.
  118. *
  119. * Before passing a field out of a schema definition into this function it has
  120. * to be processed by db_processField().
  121. *
  122. * @param $name
  123. * Name of the field.
  124. * @param $spec
  125. * The field specification, as per the schema data structure format.
  126. */
  127. protected function createFieldSql($name, $spec) {
  128. if (!empty($spec['auto_increment'])) {
  129. $sql = $name . " INTEGER PRIMARY KEY AUTOINCREMENT";
  130. if (!empty($spec['unsigned'])) {
  131. $sql .= ' CHECK (' . $name . '>= 0)';
  132. }
  133. }
  134. else {
  135. $sql = $name . ' ' . $spec['sqlite_type'];
  136. if (in_array($spec['sqlite_type'], array('VARCHAR', 'TEXT')) && isset($spec['length'])) {
  137. $sql .= '(' . $spec['length'] . ')';
  138. }
  139. if (isset($spec['not null'])) {
  140. if ($spec['not null']) {
  141. $sql .= ' NOT NULL';
  142. }
  143. else {
  144. $sql .= ' NULL';
  145. }
  146. }
  147. if (!empty($spec['unsigned'])) {
  148. $sql .= ' CHECK (' . $name . '>= 0)';
  149. }
  150. if (isset($spec['default'])) {
  151. if (is_string($spec['default'])) {
  152. $spec['default'] = "'" . $spec['default'] . "'";
  153. }
  154. $sql .= ' DEFAULT ' . $spec['default'];
  155. }
  156. if (empty($spec['not null']) && !isset($spec['default'])) {
  157. $sql .= ' DEFAULT NULL';
  158. }
  159. }
  160. return $sql;
  161. }
  162. /**
  163. * This maps a generic data type in combination with its data size
  164. * to the engine-specific data type.
  165. */
  166. public function getFieldTypeMap() {
  167. // Put :normal last so it gets preserved by array_flip. This makes
  168. // it much easier for modules (such as schema.module) to map
  169. // database types back into schema types.
  170. // $map does not use drupal_static as its value never changes.
  171. static $map = array(
  172. 'varchar:normal' => 'VARCHAR',
  173. 'char:normal' => 'CHAR',
  174. 'text:tiny' => 'TEXT',
  175. 'text:small' => 'TEXT',
  176. 'text:medium' => 'TEXT',
  177. 'text:big' => 'TEXT',
  178. 'text:normal' => 'TEXT',
  179. 'serial:tiny' => 'INTEGER',
  180. 'serial:small' => 'INTEGER',
  181. 'serial:medium' => 'INTEGER',
  182. 'serial:big' => 'INTEGER',
  183. 'serial:normal' => 'INTEGER',
  184. 'int:tiny' => 'INTEGER',
  185. 'int:small' => 'INTEGER',
  186. 'int:medium' => 'INTEGER',
  187. 'int:big' => 'INTEGER',
  188. 'int:normal' => 'INTEGER',
  189. 'float:tiny' => 'FLOAT',
  190. 'float:small' => 'FLOAT',
  191. 'float:medium' => 'FLOAT',
  192. 'float:big' => 'FLOAT',
  193. 'float:normal' => 'FLOAT',
  194. 'numeric:normal' => 'NUMERIC',
  195. 'blob:big' => 'BLOB',
  196. 'blob:normal' => 'BLOB',
  197. );
  198. return $map;
  199. }
  200. public function renameTable($table, $new_name) {
  201. if (!$this->tableExists($table)) {
  202. throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot rename @table to @table_new: table @table doesn't exist.", array('@table' => $table, '@table_new' => $new_name)));
  203. }
  204. if ($this->tableExists($new_name)) {
  205. throw new DatabaseSchemaObjectExistsException(t("Cannot rename @table to @table_new: table @table_new already exists.", array('@table' => $table, '@table_new' => $new_name)));
  206. }
  207. $schema = $this->introspectSchema($table);
  208. // SQLite doesn't allow you to rename tables outside of the current
  209. // database. So the syntax '...RENAME TO database.table' would fail.
  210. // So we must determine the full table name here rather than surrounding
  211. // the table with curly braces incase the db_prefix contains a reference
  212. // to a database outside of our existing database.
  213. $info = $this->getPrefixInfo($new_name);
  214. $this->connection->query('ALTER TABLE {' . $table . '} RENAME TO ' . $info['table']);
  215. // Drop the indexes, there is no RENAME INDEX command in SQLite.
  216. if (!empty($schema['unique keys'])) {
  217. foreach ($schema['unique keys'] as $key => $fields) {
  218. $this->dropIndex($table, $key);
  219. }
  220. }
  221. if (!empty($schema['indexes'])) {
  222. foreach ($schema['indexes'] as $index => $fields) {
  223. $this->dropIndex($table, $index);
  224. }
  225. }
  226. // Recreate the indexes.
  227. $statements = $this->createIndexSql($new_name, $schema);
  228. foreach ($statements as $statement) {
  229. $this->connection->query($statement);
  230. }
  231. }
  232. public function dropTable($table) {
  233. if (!$this->tableExists($table)) {
  234. return FALSE;
  235. }
  236. $this->connection->tableDropped = TRUE;
  237. $this->connection->query('DROP TABLE {' . $table . '}');
  238. return TRUE;
  239. }
  240. public function addField($table, $field, $specification, $keys_new = array()) {
  241. if (!$this->tableExists($table)) {
  242. throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add field @table.@field: table doesn't exist.", array('@field' => $field, '@table' => $table)));
  243. }
  244. if ($this->fieldExists($table, $field)) {
  245. throw new DatabaseSchemaObjectExistsException(t("Cannot add field @table.@field: field already exists.", array('@field' => $field, '@table' => $table)));
  246. }
  247. // SQLite doesn't have a full-featured ALTER TABLE statement. It only
  248. // supports adding new fields to a table, in some simple cases. In most
  249. // cases, we have to create a new table and copy the data over.
  250. if (empty($keys_new) && (empty($specification['not null']) || isset($specification['default']))) {
  251. // When we don't have to create new keys and we are not creating a
  252. // NOT NULL column without a default value, we can use the quicker version.
  253. $query = 'ALTER TABLE {' . $table . '} ADD ' . $this->createFieldSql($field, $this->processField($specification));
  254. $this->connection->query($query);
  255. // Apply the initial value if set.
  256. if (isset($specification['initial'])) {
  257. $this->connection->update($table)
  258. ->fields(array($field => $specification['initial']))
  259. ->execute();
  260. }
  261. }
  262. else {
  263. // We cannot add the field directly. Use the slower table alteration
  264. // method, starting from the old schema.
  265. $old_schema = $this->introspectSchema($table);
  266. $new_schema = $old_schema;
  267. // Add the new field.
  268. $new_schema['fields'][$field] = $specification;
  269. // Build the mapping between the old fields and the new fields.
  270. $mapping = array();
  271. if (isset($specification['initial'])) {
  272. // If we have a initial value, copy it over.
  273. $mapping[$field] = array(
  274. 'expression' => ':newfieldinitial',
  275. 'arguments' => array(':newfieldinitial' => $specification['initial']),
  276. );
  277. }
  278. else {
  279. // Else use the default of the field.
  280. $mapping[$field] = NULL;
  281. }
  282. // Add the new indexes.
  283. $new_schema += $keys_new;
  284. $this->alterTable($table, $old_schema, $new_schema, $mapping);
  285. }
  286. }
  287. /**
  288. * Create a table with a new schema containing the old content.
  289. *
  290. * As SQLite does not support ALTER TABLE (with a few exceptions) it is
  291. * necessary to create a new table and copy over the old content.
  292. *
  293. * @param $table
  294. * Name of the table to be altered.
  295. * @param $old_schema
  296. * The old schema array for the table.
  297. * @param $new_schema
  298. * The new schema array for the table.
  299. * @param $mapping
  300. * An optional mapping between the fields of the old specification and the
  301. * fields of the new specification. An associative array, whose keys are
  302. * the fields of the new table, and values can take two possible forms:
  303. * - a simple string, which is interpreted as the name of a field of the
  304. * old table,
  305. * - an associative array with two keys 'expression' and 'arguments',
  306. * that will be used as an expression field.
  307. */
  308. protected function alterTable($table, $old_schema, $new_schema, array $mapping = array()) {
  309. $i = 0;
  310. do {
  311. $new_table = $table . '_' . $i++;
  312. } while ($this->tableExists($new_table));
  313. $this->createTable($new_table, $new_schema);
  314. // Build a SQL query to migrate the data from the old table to the new.
  315. $select = $this->connection->select($table);
  316. // Complete the mapping.
  317. $possible_keys = array_keys($new_schema['fields']);
  318. $mapping += array_combine($possible_keys, $possible_keys);
  319. // Now add the fields.
  320. foreach ($mapping as $field_alias => $field_source) {
  321. // Just ignore this field (ie. use it's default value).
  322. if (!isset($field_source)) {
  323. continue;
  324. }
  325. if (is_array($field_source)) {
  326. $select->addExpression($field_source['expression'], $field_alias, $field_source['arguments']);
  327. }
  328. else {
  329. $select->addField($table, $field_source, $field_alias);
  330. }
  331. }
  332. // Execute the data migration query.
  333. $this->connection->insert($new_table)
  334. ->from($select)
  335. ->execute();
  336. $old_count = $this->connection->query('SELECT COUNT(*) FROM {' . $table . '}')->fetchField();
  337. $new_count = $this->connection->query('SELECT COUNT(*) FROM {' . $new_table . '}')->fetchField();
  338. if ($old_count == $new_count) {
  339. $this->dropTable($table);
  340. $this->renameTable($new_table, $table);
  341. }
  342. }
  343. /**
  344. * Find out the schema of a table.
  345. *
  346. * This function uses introspection methods provided by the database to
  347. * create a schema array. This is useful, for example, during update when
  348. * the old schema is not available.
  349. *
  350. * @param $table
  351. * Name of the table.
  352. * @return
  353. * An array representing the schema, from drupal_get_schema().
  354. * @see drupal_get_schema()
  355. */
  356. protected function introspectSchema($table) {
  357. $mapped_fields = array_flip($this->getFieldTypeMap());
  358. $schema = array(
  359. 'fields' => array(),
  360. 'primary key' => array(),
  361. 'unique keys' => array(),
  362. 'indexes' => array(),
  363. );
  364. $info = $this->getPrefixInfo($table);
  365. $result = $this->connection->query('PRAGMA ' . $info['schema'] . '.table_info(' . $info['table'] . ')');
  366. foreach ($result as $row) {
  367. if (preg_match('/^([^(]+)\((.*)\)$/', $row->type, $matches)) {
  368. $type = $matches[1];
  369. $length = $matches[2];
  370. }
  371. else {
  372. $type = $row->type;
  373. $length = NULL;
  374. }
  375. if (isset($mapped_fields[$type])) {
  376. list($type, $size) = explode(':', $mapped_fields[$type]);
  377. $schema['fields'][$row->name] = array(
  378. 'type' => $type,
  379. 'size' => $size,
  380. 'not null' => !empty($row->notnull),
  381. 'default' => trim($row->dflt_value, "'"),
  382. );
  383. if ($length) {
  384. $schema['fields'][$row->name]['length'] = $length;
  385. }
  386. if ($row->pk) {
  387. $schema['primary key'][] = $row->name;
  388. }
  389. }
  390. else {
  391. new Exception("Unable to parse the column type " . $row->type);
  392. }
  393. }
  394. $indexes = array();
  395. $result = $this->connection->query('PRAGMA ' . $info['schema'] . '.index_list(' . $info['table'] . ')');
  396. foreach ($result as $row) {
  397. if (strpos($row->name, 'sqlite_autoindex_') !== 0) {
  398. $indexes[] = array(
  399. 'schema_key' => $row->unique ? 'unique keys' : 'indexes',
  400. 'name' => $row->name,
  401. );
  402. }
  403. }
  404. foreach ($indexes as $index) {
  405. $name = $index['name'];
  406. // Get index name without prefix.
  407. $index_name = substr($name, strlen($info['table']) + 1);
  408. $result = $this->connection->query('PRAGMA ' . $info['schema'] . '.index_info(' . $name . ')');
  409. foreach ($result as $row) {
  410. $schema[$index['schema_key']][$index_name][] = $row->name;
  411. }
  412. }
  413. return $schema;
  414. }
  415. public function dropField($table, $field) {
  416. if (!$this->fieldExists($table, $field)) {
  417. return FALSE;
  418. }
  419. $old_schema = $this->introspectSchema($table);
  420. $new_schema = $old_schema;
  421. unset($new_schema['fields'][$field]);
  422. foreach ($new_schema['indexes'] as $index => $fields) {
  423. foreach ($fields as $key => $field_name) {
  424. if ($field_name == $field) {
  425. unset($new_schema['indexes'][$index][$key]);
  426. }
  427. }
  428. // If this index has no more fields then remove it.
  429. if (empty($new_schema['indexes'][$index])) {
  430. unset($new_schema['indexes'][$index]);
  431. }
  432. }
  433. $this->alterTable($table, $old_schema, $new_schema);
  434. return TRUE;
  435. }
  436. public function changeField($table, $field, $field_new, $spec, $keys_new = array()) {
  437. if (!$this->fieldExists($table, $field)) {
  438. throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot change the definition of field @table.@name: field doesn't exist.", array('@table' => $table, '@name' => $field)));
  439. }
  440. if (($field != $field_new) && $this->fieldExists($table, $field_new)) {
  441. throw new DatabaseSchemaObjectExistsException(t("Cannot rename field @table.@name to @name_new: target field already exists.", array('@table' => $table, '@name' => $field, '@name_new' => $field_new)));
  442. }
  443. $old_schema = $this->introspectSchema($table);
  444. $new_schema = $old_schema;
  445. // Map the old field to the new field.
  446. if ($field != $field_new) {
  447. $mapping[$field_new] = $field;
  448. }
  449. else {
  450. $mapping = array();
  451. }
  452. // Remove the previous definition and swap in the new one.
  453. unset($new_schema['fields'][$field]);
  454. $new_schema['fields'][$field_new] = $spec;
  455. // Map the former indexes to the new column name.
  456. $new_schema['primary key'] = $this->mapKeyDefinition($new_schema['primary key'], $mapping);
  457. foreach (array('unique keys', 'indexes') as $k) {
  458. foreach ($new_schema[$k] as &$key_definition) {
  459. $key_definition = $this->mapKeyDefinition($key_definition, $mapping);
  460. }
  461. }
  462. // Add in the keys from $keys_new.
  463. if (isset($keys_new['primary key'])) {
  464. $new_schema['primary key'] = $keys_new['primary key'];
  465. }
  466. foreach (array('unique keys', 'indexes') as $k) {
  467. if (!empty($keys_new[$k])) {
  468. $new_schema[$k] = $keys_new[$k] + $new_schema[$k];
  469. }
  470. }
  471. $this->alterTable($table, $old_schema, $new_schema, $mapping);
  472. }
  473. /**
  474. * Utility method: rename columns in an index definition according to a new mapping.
  475. *
  476. * @param $key_definition
  477. * The key definition.
  478. * @param $mapping
  479. * The new mapping.
  480. */
  481. protected function mapKeyDefinition(array $key_definition, array $mapping) {
  482. foreach ($key_definition as &$field) {
  483. // The key definition can be an array($field, $length).
  484. if (is_array($field)) {
  485. $field = &$field[0];
  486. }
  487. if (isset($mapping[$field])) {
  488. $field = $mapping[$field];
  489. }
  490. }
  491. return $key_definition;
  492. }
  493. public function addIndex($table, $name, $fields) {
  494. if (!$this->tableExists($table)) {
  495. throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add index @name to table @table: table doesn't exist.", array('@table' => $table, '@name' => $name)));
  496. }
  497. if ($this->indexExists($table, $name)) {
  498. throw new DatabaseSchemaObjectExistsException(t("Cannot add index @name to table @table: index already exists.", array('@table' => $table, '@name' => $name)));
  499. }
  500. $schema['indexes'][$name] = $fields;
  501. $statements = $this->createIndexSql($table, $schema);
  502. foreach ($statements as $statement) {
  503. $this->connection->query($statement);
  504. }
  505. }
  506. public function indexExists($table, $name) {
  507. $info = $this->getPrefixInfo($table);
  508. return $this->connection->query('PRAGMA ' . $info['schema'] . '.index_info(' . $info['table'] . '_' . $name . ')')->fetchField() != '';
  509. }
  510. public function dropIndex($table, $name) {
  511. if (!$this->indexExists($table, $name)) {
  512. return FALSE;
  513. }
  514. $info = $this->getPrefixInfo($table);
  515. $this->connection->query('DROP INDEX ' . $info['schema'] . '.' . $info['table'] . '_' . $name);
  516. return TRUE;
  517. }
  518. public function addUniqueKey($table, $name, $fields) {
  519. if (!$this->tableExists($table)) {
  520. throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add unique key @name to table @table: table doesn't exist.", array('@table' => $table, '@name' => $name)));
  521. }
  522. if ($this->indexExists($table, $name)) {
  523. throw new DatabaseSchemaObjectExistsException(t("Cannot add unique key @name to table @table: unique key already exists.", array('@table' => $table, '@name' => $name)));
  524. }
  525. $schema['unique keys'][$name] = $fields;
  526. $statements = $this->createIndexSql($table, $schema);
  527. foreach ($statements as $statement) {
  528. $this->connection->query($statement);
  529. }
  530. }
  531. public function dropUniqueKey($table, $name) {
  532. if (!$this->indexExists($table, $name)) {
  533. return FALSE;
  534. }
  535. $info = $this->getPrefixInfo($table);
  536. $this->connection->query('DROP INDEX ' . $info['schema'] . '.' . $info['table'] . '_' . $name);
  537. return TRUE;
  538. }
  539. public function addPrimaryKey($table, $fields) {
  540. if (!$this->tableExists($table)) {
  541. throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add primary key to table @table: table doesn't exist.", array('@table' => $table)));
  542. }
  543. $old_schema = $this->introspectSchema($table);
  544. $new_schema = $old_schema;
  545. if (!empty($new_schema['primary key'])) {
  546. throw new DatabaseSchemaObjectExistsException(t("Cannot add primary key to table @table: primary key already exists.", array('@table' => $table)));
  547. }
  548. $new_schema['primary key'] = $fields;
  549. $this->alterTable($table, $old_schema, $new_schema);
  550. }
  551. public function dropPrimaryKey($table) {
  552. $old_schema = $this->introspectSchema($table);
  553. $new_schema = $old_schema;
  554. if (empty($new_schema['primary key'])) {
  555. return FALSE;
  556. }
  557. unset($new_schema['primary key']);
  558. $this->alterTable($table, $old_schema, $new_schema);
  559. return TRUE;
  560. }
  561. public function fieldSetDefault($table, $field, $default) {
  562. if (!$this->fieldExists($table, $field)) {
  563. throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot set default value of field @table.@field: field doesn't exist.", array('@table' => $table, '@field' => $field)));
  564. }
  565. $old_schema = $this->introspectSchema($table);
  566. $new_schema = $old_schema;
  567. $new_schema['fields'][$field]['default'] = $default;
  568. $this->alterTable($table, $old_schema, $new_schema);
  569. }
  570. public function fieldSetNoDefault($table, $field) {
  571. if (!$this->fieldExists($table, $field)) {
  572. throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot remove default value of field @table.@field: field doesn't exist.", array('@table' => $table, '@field' => $field)));
  573. }
  574. $old_schema = $this->introspectSchema($table);
  575. $new_schema = $old_schema;
  576. unset($new_schema['fields'][$field]['default']);
  577. $this->alterTable($table, $old_schema, $new_schema);
  578. }
  579. /**
  580. * {@inheritdoc}
  581. */
  582. public function findTables($table_expression) {
  583. // Don't add the prefix, $table_expression already includes the prefix.
  584. $info = $this->getPrefixInfo($table_expression, FALSE);
  585. // Can't use query placeholders for the schema because the query would have
  586. // to be :prefixsqlite_master, which does not work.
  587. $result = db_query("SELECT name FROM " . $info['schema'] . ".sqlite_master WHERE type = :type AND name LIKE :table_name", array(
  588. ':type' => 'table',
  589. ':table_name' => $info['table'],
  590. ));
  591. return $result->fetchAllKeyed(0, 0);
  592. }
  593. /**
  594. * {@inheritdoc}
  595. */
  596. public function findTablesD8($table_expression) {
  597. $tables = array();
  598. // The SQLite implementation doesn't need to use the same filtering strategy
  599. // as the parent one because individually prefixed tables live in their own
  600. // schema (database), which means that neither the main database nor any
  601. // attached one will contain a prefixed table name, so we just need to loop
  602. // over all known schemas and filter by the user-supplied table expression.
  603. $attached_dbs = $this->connection->getAttachedDatabases();
  604. foreach ($attached_dbs as $schema) {
  605. // Can't use query placeholders for the schema because the query would
  606. // have to be :prefixsqlite_master, which does not work. We also need to
  607. // ignore the internal SQLite tables.
  608. $result = db_query("SELECT name FROM " . $schema . ".sqlite_master WHERE type = :type AND name LIKE :table_name AND name NOT LIKE :pattern", array(
  609. ':type' => 'table',
  610. ':table_name' => $table_expression,
  611. ':pattern' => 'sqlite_%',
  612. ));
  613. $tables += $result->fetchAllKeyed(0, 0);
  614. }
  615. return $tables;
  616. }
  617. }