database.mysql-common.inc

Functions shared between mysql and mysqli database engines.

File

drupal-6.x/includes/database.mysql-common.inc
View source
  1. <?php
  2. /**
  3. * @file
  4. * Functions shared between mysql and mysqli database engines.
  5. */
  6. /**
  7. * Runs a basic query in the active database.
  8. *
  9. * User-supplied arguments to the query should be passed in as separate
  10. * parameters so that they can be properly escaped to avoid SQL injection
  11. * attacks.
  12. *
  13. * @param $query
  14. * A string containing an SQL query.
  15. * @param ...
  16. * A variable number of arguments which are substituted into the query
  17. * using printf() syntax. Instead of a variable number of query arguments,
  18. * you may also pass a single array containing the query arguments.
  19. *
  20. * Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose
  21. * in '') and %%.
  22. *
  23. * NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
  24. * and TRUE values to decimal 1.
  25. *
  26. * @return
  27. * Successful SELECT, SHOW, DESCRIBE, EXPLAIN, or other queries which return a
  28. * set of results will return a database query result resource. Other
  29. * successful queries will return TRUE and failing queries will return FALSE.
  30. */
  31. function db_query($query) {
  32. $args = func_get_args();
  33. array_shift($args);
  34. $query = db_prefix_tables($query);
  35. if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax
  36. $args = $args[0];
  37. }
  38. _db_query_callback($args, TRUE);
  39. $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
  40. return _db_query($query);
  41. }
  42. /**
  43. * @ingroup schemaapi
  44. * @{
  45. */
  46. /**
  47. * Generate SQL to create a new table from a Drupal schema definition.
  48. *
  49. * @param $name
  50. * The name of the table to create.
  51. * @param $table
  52. * A Schema API table definition array.
  53. * @return
  54. * An array of SQL statements to create the table.
  55. */
  56. function db_create_table_sql($name, $table) {
  57. if (empty($table['mysql_suffix'])) {
  58. $table['mysql_suffix'] = '/*!40100 DEFAULT CHARACTER SET utf8';
  59. // By default, MySQL uses the default collation for new tables, which is
  60. // 'utf8_general_ci' for utf8. If an alternate collation has been set, it
  61. // needs to be explicitly specified.
  62. // @see db_connect()
  63. $collation = (!empty($table['collation']) ? $table['collation'] : (!empty($GLOBALS['db_collation']) ? $GLOBALS['db_collation'] : ''));
  64. if ($collation) {
  65. $table['mysql_suffix'] .= ' COLLATE ' . $collation;
  66. }
  67. $table['mysql_suffix'] .= ' */';
  68. }
  69. $sql = "CREATE TABLE {". $name ."} (\n";
  70. // Add the SQL statement for each field.
  71. foreach ($table['fields'] as $field_name => $field) {
  72. $sql .= _db_create_field_sql($field_name, _db_process_field($field)) .", \n";
  73. }
  74. // Process keys & indexes.
  75. $keys = _db_create_keys_sql($table);
  76. if (count($keys)) {
  77. $sql .= implode(", \n", $keys) .", \n";
  78. }
  79. // Remove the last comma and space.
  80. $sql = substr($sql, 0, -3) ."\n) ";
  81. $sql .= $table['mysql_suffix'];
  82. return array($sql);
  83. }
  84. function _db_create_keys_sql($spec) {
  85. $keys = array();
  86. if (!empty($spec['primary key'])) {
  87. $keys[] = 'PRIMARY KEY ('. _db_create_key_sql($spec['primary key']) .')';
  88. }
  89. if (!empty($spec['unique keys'])) {
  90. foreach ($spec['unique keys'] as $key => $fields) {
  91. $keys[] = 'UNIQUE KEY '. $key .' ('. _db_create_key_sql($fields) .')';
  92. }
  93. }
  94. if (!empty($spec['indexes'])) {
  95. foreach ($spec['indexes'] as $index => $fields) {
  96. $keys[] = 'INDEX '. $index .' ('. _db_create_key_sql($fields) .')';
  97. }
  98. }
  99. return $keys;
  100. }
  101. function _db_create_key_sql($fields) {
  102. $ret = array();
  103. foreach ($fields as $field) {
  104. if (is_array($field)) {
  105. $ret[] = $field[0] .'('. $field[1] .')';
  106. }
  107. else {
  108. $ret[] = $field;
  109. }
  110. }
  111. return implode(', ', $ret);
  112. }
  113. /**
  114. * Set database-engine specific properties for a field.
  115. *
  116. * @param $field
  117. * A field description array, as specified in the schema documentation.
  118. */
  119. function _db_process_field($field) {
  120. if (!isset($field['size'])) {
  121. $field['size'] = 'normal';
  122. }
  123. // Set the correct database-engine specific datatype.
  124. if (!isset($field['mysql_type'])) {
  125. $map = db_type_map();
  126. $field['mysql_type'] = $map[$field['type'] .':'. $field['size']];
  127. }
  128. if ($field['type'] == 'serial') {
  129. $field['auto_increment'] = TRUE;
  130. }
  131. return $field;
  132. }
  133. /**
  134. * Create an SQL string for a field to be used in table creation or alteration.
  135. *
  136. * Before passing a field out of a schema definition into this function it has
  137. * to be processed by _db_process_field().
  138. *
  139. * @param $name
  140. * Name of the field.
  141. * @param $spec
  142. * The field specification, as per the schema data structure format.
  143. */
  144. function _db_create_field_sql($name, $spec) {
  145. $sql = "`". $name ."` ". $spec['mysql_type'];
  146. if (in_array($spec['type'], array('varchar', 'char', 'text')) && isset($spec['length'])) {
  147. $sql .= '('. $spec['length'] .')';
  148. }
  149. elseif (isset($spec['precision']) && isset($spec['scale'])) {
  150. $sql .= '('. $spec['precision'] .', '. $spec['scale'] .')';
  151. }
  152. if (!empty($spec['unsigned'])) {
  153. $sql .= ' unsigned';
  154. }
  155. if (!empty($spec['not null'])) {
  156. $sql .= ' NOT NULL';
  157. }
  158. if (!empty($spec['auto_increment'])) {
  159. $sql .= ' auto_increment';
  160. }
  161. if (isset($spec['default'])) {
  162. if (is_string($spec['default'])) {
  163. $spec['default'] = "'". $spec['default'] ."'";
  164. }
  165. $sql .= ' DEFAULT '. $spec['default'];
  166. }
  167. if (empty($spec['not null']) && !isset($spec['default'])) {
  168. $sql .= ' DEFAULT NULL';
  169. }
  170. return $sql;
  171. }
  172. /**
  173. * This maps a generic data type in combination with its data size
  174. * to the engine-specific data type.
  175. */
  176. function db_type_map() {
  177. // Put :normal last so it gets preserved by array_flip. This makes
  178. // it much easier for modules (such as schema.module) to map
  179. // database types back into schema types.
  180. $map = array(
  181. 'varchar:normal' => 'VARCHAR',
  182. 'char:normal' => 'CHAR',
  183. 'text:tiny' => 'TINYTEXT',
  184. 'text:small' => 'TINYTEXT',
  185. 'text:medium' => 'MEDIUMTEXT',
  186. 'text:big' => 'LONGTEXT',
  187. 'text:normal' => 'TEXT',
  188. 'serial:tiny' => 'TINYINT',
  189. 'serial:small' => 'SMALLINT',
  190. 'serial:medium' => 'MEDIUMINT',
  191. 'serial:big' => 'BIGINT',
  192. 'serial:normal' => 'INT',
  193. 'int:tiny' => 'TINYINT',
  194. 'int:small' => 'SMALLINT',
  195. 'int:medium' => 'MEDIUMINT',
  196. 'int:big' => 'BIGINT',
  197. 'int:normal' => 'INT',
  198. 'float:tiny' => 'FLOAT',
  199. 'float:small' => 'FLOAT',
  200. 'float:medium' => 'FLOAT',
  201. 'float:big' => 'DOUBLE',
  202. 'float:normal' => 'FLOAT',
  203. 'numeric:normal' => 'DECIMAL',
  204. 'blob:big' => 'LONGBLOB',
  205. 'blob:normal' => 'BLOB',
  206. 'datetime:normal' => 'DATETIME',
  207. );
  208. return $map;
  209. }
  210. /**
  211. * Rename a table.
  212. *
  213. * @param $ret
  214. * Array to which query results will be added.
  215. * @param $table
  216. * The table to be renamed.
  217. * @param $new_name
  218. * The new name for the table.
  219. */
  220. function db_rename_table(&$ret, $table, $new_name) {
  221. $ret[] = update_sql('ALTER TABLE {'. $table .'} RENAME TO {'. $new_name .'}');
  222. }
  223. /**
  224. * Drop a table.
  225. *
  226. * @param $ret
  227. * Array to which query results will be added.
  228. * @param $table
  229. * The table to be dropped.
  230. */
  231. function db_drop_table(&$ret, $table) {
  232. $ret[] = update_sql('DROP TABLE {'. $table .'}');
  233. }
  234. /**
  235. * Add a new field to a table.
  236. *
  237. * @param $ret
  238. * Array to which query results will be added.
  239. * @param $table
  240. * Name of the table to be altered.
  241. * @param $field
  242. * Name of the field to be added.
  243. * @param $spec
  244. * The field specification array, as taken from a schema definition.
  245. * The specification may also contain the key 'initial', the newly
  246. * created field will be set to the value of the key in all rows.
  247. * This is most useful for creating NOT NULL columns with no default
  248. * value in existing tables.
  249. * @param $keys_new
  250. * Optional keys and indexes specification to be created on the
  251. * table along with adding the field. The format is the same as a
  252. * table specification but without the 'fields' element. If you are
  253. * adding a type 'serial' field, you MUST specify at least one key
  254. * or index including it in this array. See db_change_field() for more
  255. * explanation why.
  256. */
  257. function db_add_field(&$ret, $table, $field, $spec, $keys_new = array()) {
  258. $fixnull = FALSE;
  259. if (!empty($spec['not null']) && !isset($spec['default'])) {
  260. $fixnull = TRUE;
  261. $spec['not null'] = FALSE;
  262. }
  263. $query = 'ALTER TABLE {'. $table .'} ADD ';
  264. $query .= _db_create_field_sql($field, _db_process_field($spec));
  265. if (count($keys_new)) {
  266. $query .= ', ADD '. implode(', ADD ', _db_create_keys_sql($keys_new));
  267. }
  268. $ret[] = update_sql($query);
  269. if (isset($spec['initial'])) {
  270. // All this because update_sql does not support %-placeholders.
  271. $sql = 'UPDATE {'. $table .'} SET '. $field .' = '. db_type_placeholder($spec['type']);
  272. $result = db_query($sql, $spec['initial']);
  273. $ret[] = array('success' => $result !== FALSE, 'query' => check_plain($sql .' ('. $spec['initial'] .')'));
  274. }
  275. if ($fixnull) {
  276. $spec['not null'] = TRUE;
  277. db_change_field($ret, $table, $field, $field, $spec);
  278. }
  279. }
  280. /**
  281. * Drop a field.
  282. *
  283. * @param $ret
  284. * Array to which query results will be added.
  285. * @param $table
  286. * The table to be altered.
  287. * @param $field
  288. * The field to be dropped.
  289. */
  290. function db_drop_field(&$ret, $table, $field) {
  291. $ret[] = update_sql('ALTER TABLE {'. $table .'} DROP '. $field);
  292. }
  293. /**
  294. * Set the default value for a field.
  295. *
  296. * @param $ret
  297. * Array to which query results will be added.
  298. * @param $table
  299. * The table to be altered.
  300. * @param $field
  301. * The field to be altered.
  302. * @param $default
  303. * Default value to be set. NULL for 'default NULL'.
  304. */
  305. function db_field_set_default(&$ret, $table, $field, $default) {
  306. if ($default === NULL) {
  307. $default = 'NULL';
  308. }
  309. else {
  310. $default = is_string($default) ? "'$default'" : $default;
  311. }
  312. $ret[] = update_sql('ALTER TABLE {'. $table .'} ALTER COLUMN '. $field .' SET DEFAULT '. $default);
  313. }
  314. /**
  315. * Set a field to have no default value.
  316. *
  317. * @param $ret
  318. * Array to which query results will be added.
  319. * @param $table
  320. * The table to be altered.
  321. * @param $field
  322. * The field to be altered.
  323. */
  324. function db_field_set_no_default(&$ret, $table, $field) {
  325. $ret[] = update_sql('ALTER TABLE {'. $table .'} ALTER COLUMN '. $field .' DROP DEFAULT');
  326. }
  327. /**
  328. * Add a primary key.
  329. *
  330. * @param $ret
  331. * Array to which query results will be added.
  332. * @param $table
  333. * The table to be altered.
  334. * @param $fields
  335. * Fields for the primary key.
  336. */
  337. function db_add_primary_key(&$ret, $table, $fields) {
  338. $ret[] = update_sql('ALTER TABLE {'. $table .'} ADD PRIMARY KEY ('.
  339. _db_create_key_sql($fields) .')');
  340. }
  341. /**
  342. * Drop the primary key.
  343. *
  344. * @param $ret
  345. * Array to which query results will be added.
  346. * @param $table
  347. * The table to be altered.
  348. */
  349. function db_drop_primary_key(&$ret, $table) {
  350. $ret[] = update_sql('ALTER TABLE {'. $table .'} DROP PRIMARY KEY');
  351. }
  352. /**
  353. * Add a unique key.
  354. *
  355. * @param $ret
  356. * Array to which query results will be added.
  357. * @param $table
  358. * The table to be altered.
  359. * @param $name
  360. * The name of the key.
  361. * @param $fields
  362. * An array of field names.
  363. */
  364. function db_add_unique_key(&$ret, $table, $name, $fields) {
  365. $ret[] = update_sql('ALTER TABLE {'. $table .'} ADD UNIQUE KEY '.
  366. $name .' ('. _db_create_key_sql($fields) .')');
  367. }
  368. /**
  369. * Drop a unique key.
  370. *
  371. * @param $ret
  372. * Array to which query results will be added.
  373. * @param $table
  374. * The table to be altered.
  375. * @param $name
  376. * The name of the key.
  377. */
  378. function db_drop_unique_key(&$ret, $table, $name) {
  379. $ret[] = update_sql('ALTER TABLE {'. $table .'} DROP KEY '. $name);
  380. }
  381. /**
  382. * Add an index.
  383. *
  384. * @param $ret
  385. * Array to which query results will be added.
  386. * @param $table
  387. * The table to be altered.
  388. * @param $name
  389. * The name of the index.
  390. * @param $fields
  391. * An array of field names.
  392. */
  393. function db_add_index(&$ret, $table, $name, $fields) {
  394. $query = 'ALTER TABLE {'. $table .'} ADD INDEX '. $name .' ('. _db_create_key_sql($fields) .')';
  395. $ret[] = update_sql($query);
  396. }
  397. /**
  398. * Drop an index.
  399. *
  400. * @param $ret
  401. * Array to which query results will be added.
  402. * @param $table
  403. * The table to be altered.
  404. * @param $name
  405. * The name of the index.
  406. */
  407. function db_drop_index(&$ret, $table, $name) {
  408. $ret[] = update_sql('ALTER TABLE {'. $table .'} DROP INDEX '. $name);
  409. }
  410. /**
  411. * Change a field definition.
  412. *
  413. * IMPORTANT NOTE: To maintain database portability, you have to explicitly
  414. * recreate all indices and primary keys that are using the changed field.
  415. *
  416. * That means that you have to drop all affected keys and indexes with
  417. * db_drop_{primary_key,unique_key,index}() before calling db_change_field().
  418. * To recreate the keys and indices, pass the key definitions as the
  419. * optional $keys_new argument directly to db_change_field().
  420. *
  421. * For example, suppose you have:
  422. * @code
  423. * $schema['foo'] = array(
  424. * 'fields' => array(
  425. * 'bar' => array('type' => 'int', 'not null' => TRUE)
  426. * ),
  427. * 'primary key' => array('bar')
  428. * );
  429. * @endcode
  430. * and you want to change foo.bar to be type serial, leaving it as the
  431. * primary key. The correct sequence is:
  432. * @code
  433. * db_drop_primary_key($ret, 'foo');
  434. * db_change_field($ret, 'foo', 'bar', 'bar',
  435. * array('type' => 'serial', 'not null' => TRUE),
  436. * array('primary key' => array('bar')));
  437. * @endcode
  438. *
  439. * The reasons for this are due to the different database engines:
  440. *
  441. * On PostgreSQL, changing a field definition involves adding a new field
  442. * and dropping an old one which* causes any indices, primary keys and
  443. * sequences (from serial-type fields) that use the changed field to be dropped.
  444. *
  445. * On MySQL, all type 'serial' fields must be part of at least one key
  446. * or index as soon as they are created. You cannot use
  447. * db_add_{primary_key,unique_key,index}() for this purpose because
  448. * the ALTER TABLE command will fail to add the column without a key
  449. * or index specification. The solution is to use the optional
  450. * $keys_new argument to create the key or index at the same time as
  451. * field.
  452. *
  453. * You could use db_add_{primary_key,unique_key,index}() in all cases
  454. * unless you are converting a field to be type serial. You can use
  455. * the $keys_new argument in all cases.
  456. *
  457. * @param $ret
  458. * Array to which query results will be added.
  459. * @param $table
  460. * Name of the table.
  461. * @param $field
  462. * Name of the field to change.
  463. * @param $field_new
  464. * New name for the field (set to the same as $field if you don't want to change the name).
  465. * @param $spec
  466. * The field specification for the new field.
  467. * @param $keys_new
  468. * Optional keys and indexes specification to be created on the
  469. * table along with changing the field. The format is the same as a
  470. * table specification but without the 'fields' element.
  471. */
  472. function db_change_field(&$ret, $table, $field, $field_new, $spec, $keys_new = array()) {
  473. $sql = 'ALTER TABLE {'. $table .'} CHANGE `'. $field .'` '.
  474. _db_create_field_sql($field_new, _db_process_field($spec));
  475. if (count($keys_new)) {
  476. $sql .= ', ADD '. implode(', ADD ', _db_create_keys_sql($keys_new));
  477. }
  478. $ret[] = update_sql($sql);
  479. }
  480. /**
  481. * Returns the last insert id.
  482. *
  483. * @param $table
  484. * The name of the table you inserted into.
  485. * @param $field
  486. * The name of the autoincrement field.
  487. */
  488. function db_last_insert_id($table, $field) {
  489. return db_result(db_query('SELECT LAST_INSERT_ID()'));
  490. }