dbdelta.php 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075
  1. <?php
  2. /**
  3. * Test dbDelta()
  4. *
  5. * @group upgrade
  6. * @group dbdelta
  7. */
  8. class Tests_dbDelta extends WP_UnitTestCase {
  9. /**
  10. * The maximum size of an index with utf8mb4 collation and charset with a standard
  11. * byte limit of 767. floor(767/4) = 191 characters.
  12. */
  13. protected $max_index_length = 191;
  14. /**
  15. * Database engine used for creating tables.
  16. *
  17. * Prior to MySQL 5.7, InnoDB did not support FULLTEXT indexes, so MyISAM is used instead.
  18. */
  19. protected $db_engine = '';
  20. /**
  21. * Display width for BIGINT data type.
  22. *
  23. * Prior to MySQL 8.0.17, default width of 20 digits was used: BIGINT(20).
  24. * Since MySQL 8.0.17, display width for integer data types is no longer supported.
  25. */
  26. protected $bigint_display_width = '';
  27. /**
  28. * Make sure the upgrade code is loaded before the tests are run.
  29. */
  30. public static function setUpBeforeClass() {
  31. parent::setUpBeforeClass();
  32. require_once ABSPATH . 'wp-admin/includes/upgrade.php';
  33. }
  34. /**
  35. * Create a custom table to be used in each test.
  36. */
  37. public function setUp() {
  38. global $wpdb;
  39. $db_version = $wpdb->db_version();
  40. if ( version_compare( $db_version, '5.7', '<' ) ) {
  41. // Prior to MySQL 5.7, InnoDB did not support FULLTEXT indexes, so MyISAM is used instead.
  42. $this->db_engine = 'ENGINE=MyISAM';
  43. }
  44. if ( version_compare( $db_version, '8.0.17', '<' ) ) {
  45. // Prior to MySQL 8.0.17, default width of 20 digits was used: BIGINT(20).
  46. $this->bigint_display_width = '(20)';
  47. }
  48. $wpdb->query(
  49. $wpdb->prepare(
  50. "
  51. CREATE TABLE {$wpdb->prefix}dbdelta_test (" .
  52. // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
  53. "id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  54. column_1 varchar(255) NOT NULL,
  55. column_2 text,
  56. column_3 blob,
  57. PRIMARY KEY (id),
  58. KEY key_1 (column_1(%d)),
  59. KEY compound_key (id,column_1(%d)),
  60. FULLTEXT KEY fulltext_key (column_1)" .
  61. // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
  62. ") {$this->db_engine}
  63. ",
  64. $this->max_index_length,
  65. $this->max_index_length
  66. )
  67. );
  68. // This has to be called after the `CREATE TABLE` above as the `_create_temporary_tables` filter
  69. // causes it to create a temporary table, and a temporary table cannot use a FULLTEXT index.
  70. parent::setUp();
  71. }
  72. /**
  73. * Delete the custom table on teardown.
  74. */
  75. public function tearDown() {
  76. global $wpdb;
  77. parent::tearDown();
  78. // This has to be called after the parent `tearDown()` method.
  79. $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}dbdelta_test" );
  80. }
  81. /**
  82. * Test table creation.
  83. */
  84. public function test_creating_a_table() {
  85. remove_filter( 'query', array( $this, '_create_temporary_tables' ) );
  86. remove_filter( 'query', array( $this, '_drop_temporary_tables' ) );
  87. global $wpdb;
  88. $updates = dbDelta(
  89. "CREATE TABLE {$wpdb->prefix}dbdelta_create_test (
  90. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  91. column_1 varchar(255) NOT NULL,
  92. PRIMARY KEY (id)
  93. );"
  94. );
  95. $expected = array(
  96. "{$wpdb->prefix}dbdelta_create_test" => "Created table {$wpdb->prefix}dbdelta_create_test",
  97. );
  98. $this->assertSame( $expected, $updates );
  99. $this->assertSame(
  100. "{$wpdb->prefix}dbdelta_create_test",
  101. $wpdb->get_var(
  102. $wpdb->prepare(
  103. 'SHOW TABLES LIKE %s',
  104. $wpdb->esc_like( "{$wpdb->prefix}dbdelta_create_test" )
  105. )
  106. )
  107. );
  108. $wpdb->query( "DROP TABLE {$wpdb->prefix}dbdelta_create_test" );
  109. }
  110. /**
  111. * Test that it does nothing for an existing table.
  112. */
  113. public function test_existing_table() {
  114. global $wpdb;
  115. $updates = dbDelta(
  116. "
  117. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  118. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  119. column_1 varchar(255) NOT NULL,
  120. PRIMARY KEY (id),
  121. KEY key_1 (column_1($this->max_index_length)),
  122. KEY compound_key (id,column_1($this->max_index_length))
  123. )
  124. "
  125. );
  126. $this->assertSame( array(), $updates );
  127. }
  128. /**
  129. * Test the column type is updated.
  130. */
  131. public function test_column_type_change() {
  132. global $wpdb;
  133. // id: bigint => int(11)
  134. $updates = dbDelta(
  135. "
  136. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  137. id int(11) NOT NULL AUTO_INCREMENT,
  138. column_1 varchar(255) NOT NULL,
  139. PRIMARY KEY (id),
  140. KEY key_1 (column_1($this->max_index_length)),
  141. KEY compound_key (id,column_1($this->max_index_length))
  142. )
  143. "
  144. );
  145. $this->assertSame(
  146. array(
  147. "{$wpdb->prefix}dbdelta_test.id"
  148. => "Changed type of {$wpdb->prefix}dbdelta_test.id from bigint{$this->bigint_display_width} to int(11)",
  149. ),
  150. $updates
  151. );
  152. }
  153. /**
  154. * Test new column added.
  155. */
  156. public function test_column_added() {
  157. global $wpdb;
  158. $updates = dbDelta(
  159. "
  160. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  161. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  162. column_1 varchar(255) NOT NULL,
  163. extra_col longtext,
  164. PRIMARY KEY (id),
  165. KEY key_1 (column_1($this->max_index_length)),
  166. KEY compound_key (id,column_1($this->max_index_length))
  167. )
  168. "
  169. );
  170. $this->assertSame(
  171. array(
  172. "{$wpdb->prefix}dbdelta_test.extra_col"
  173. => "Added column {$wpdb->prefix}dbdelta_test.extra_col",
  174. ),
  175. $updates
  176. );
  177. $this->assertTableHasColumn( 'column_1', $wpdb->prefix . 'dbdelta_test' );
  178. $this->assertTableHasPrimaryKey( 'id', $wpdb->prefix . 'dbdelta_test' );
  179. }
  180. /**
  181. * Test that it does nothing when a column is removed.
  182. *
  183. * @ticket 26801
  184. */
  185. public function test_columns_arent_removed() {
  186. global $wpdb;
  187. // No column column_1.
  188. $updates = dbDelta(
  189. "
  190. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  191. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  192. PRIMARY KEY (id),
  193. KEY key_1 (column_1($this->max_index_length)),
  194. KEY compound_key (id,column_1($this->max_index_length))
  195. )
  196. "
  197. );
  198. $this->assertSame( array(), $updates );
  199. $this->assertTableHasColumn( 'column_1', $wpdb->prefix . 'dbdelta_test' );
  200. }
  201. /**
  202. * Test that nothing happens with $execute is false.
  203. */
  204. public function test_no_execution() {
  205. global $wpdb;
  206. // Added column extra_col.
  207. $updates = dbDelta(
  208. "
  209. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  210. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  211. column_1 varchar(255) NOT NULL,
  212. extra_col longtext,
  213. PRIMARY KEY (id),
  214. KEY key_1 (column_1({$this->max_index_length})),
  215. KEY compound_key (id,column_1($this->max_index_length))
  216. )
  217. ",
  218. false // Don't execute.
  219. );
  220. $this->assertSame(
  221. array(
  222. "{$wpdb->prefix}dbdelta_test.extra_col"
  223. => "Added column {$wpdb->prefix}dbdelta_test.extra_col",
  224. ),
  225. $updates
  226. );
  227. $this->assertTableHasNotColumn( 'extra_col', $wpdb->prefix . 'dbdelta_test' );
  228. }
  229. /**
  230. * Test inserting into the database
  231. */
  232. public function test_insert_into_table() {
  233. global $wpdb;
  234. $insert = dbDelta(
  235. "INSERT INTO {$wpdb->prefix}dbdelta_test (column_1) VALUES ('wcphilly2015')"
  236. );
  237. $this->assertSame(
  238. array(),
  239. $insert
  240. );
  241. $this->assertTableRowHasValue( 'column_1', 'wcphilly2015', $wpdb->prefix . 'dbdelta_test' );
  242. }
  243. /**
  244. * Test that FULLTEXT indexes are detected.
  245. *
  246. * @ticket 14445
  247. */
  248. public function test_fulltext_index() {
  249. global $wpdb;
  250. $updates = dbDelta(
  251. "
  252. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  253. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  254. column_1 varchar(255) NOT NULL,
  255. PRIMARY KEY (id),
  256. KEY key_1 (column_1($this->max_index_length)),
  257. KEY compound_key (id,column_1($this->max_index_length)),
  258. FULLTEXT KEY fulltext_key (column_1)
  259. )
  260. ",
  261. false
  262. );
  263. $this->assertEmpty( $updates );
  264. }
  265. //
  266. // Assertions.
  267. //
  268. /**
  269. * Assert that a table has a row with a value in a field.
  270. *
  271. * @param string $column The field name.
  272. * @param string $value The field value.
  273. * @param string $table The database table name.
  274. */
  275. protected function assertTableRowHasValue( $column, $value, $table ) {
  276. global $wpdb;
  277. // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
  278. $table_row = $wpdb->get_row( "select $column from {$table} where $column = '$value'" );
  279. $expected = (object) array(
  280. $column => $value,
  281. );
  282. $this->assertEquals( $expected, $table_row );
  283. }
  284. /**
  285. * Assert that a table has a column.
  286. *
  287. * @param string $column The field name.
  288. * @param string $table The database table name.
  289. */
  290. protected function assertTableHasColumn( $column, $table ) {
  291. global $wpdb;
  292. // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
  293. $table_fields = $wpdb->get_results( "DESCRIBE $table" );
  294. $this->assertCount( 1, wp_list_filter( $table_fields, array( 'Field' => $column ) ) );
  295. }
  296. /**
  297. * Assert that a table has a primary key.
  298. *
  299. * Checks for single-column primary keys. May not work for multi-column primary keys.
  300. *
  301. * @param string $column The column for the primary key.
  302. * @param string $table The database table name.
  303. */
  304. protected function assertTableHasPrimaryKey( $column, $table ) {
  305. global $wpdb;
  306. // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
  307. $table_indices = $wpdb->get_results( "SHOW INDEX FROM $table" );
  308. $this->assertCount(
  309. 1,
  310. wp_list_filter(
  311. $table_indices,
  312. array(
  313. 'Key_name' => 'PRIMARY',
  314. 'Column_name' => $column,
  315. ),
  316. 'AND'
  317. )
  318. );
  319. }
  320. /**
  321. * Assert that a table doesn't have a column.
  322. *
  323. * @param string $column The field name.
  324. * @param string $table The database table name.
  325. */
  326. protected function assertTableHasNotColumn( $column, $table ) {
  327. global $wpdb;
  328. // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
  329. $table_fields = $wpdb->get_results( "DESCRIBE $table" );
  330. $this->assertCount( 0, wp_list_filter( $table_fields, array( 'Field' => $column ) ) );
  331. }
  332. /**
  333. * @ticket 31869
  334. */
  335. function test_truncated_index() {
  336. global $wpdb;
  337. if ( ! $wpdb->has_cap( 'utf8mb4' ) ) {
  338. $this->markTestSkipped( 'This test requires utf8mb4 support in MySQL.' );
  339. }
  340. // This table needs to be actually created.
  341. remove_filter( 'query', array( $this, '_create_temporary_tables' ) );
  342. remove_filter( 'query', array( $this, '_drop_temporary_tables' ) );
  343. $table_name = "{$wpdb->prefix}test_truncated_index";
  344. $create = "
  345. CREATE TABLE $table_name (
  346. a varchar(255) COLLATE utf8mb4_unicode_ci,
  347. KEY a_key (a)
  348. ) ENGINE=InnoDB ROW_FORMAT=DYNAMIC";
  349. // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
  350. $wpdb->query( $create );
  351. // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
  352. $index = $wpdb->get_row( "SHOW INDEXES FROM $table_name WHERE Key_name='a_key';" );
  353. $actual = dbDelta( $create, false );
  354. // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
  355. $wpdb->query( "DROP TABLE IF EXISTS $table_name;" );
  356. if ( 191 !== $index->Sub_part ) {
  357. $this->markTestSkipped( 'This test requires the index to be truncated.' );
  358. }
  359. $this->assertSame( array(), $actual );
  360. }
  361. /**
  362. * @ticket 36748
  363. */
  364. function test_dont_downsize_text_fields() {
  365. global $wpdb;
  366. $result = dbDelta(
  367. "
  368. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  369. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  370. column_1 varchar(255) NOT NULL,
  371. column_2 tinytext,
  372. column_3 blob,
  373. PRIMARY KEY (id),
  374. KEY key_1 (column_1({$this->max_index_length})),
  375. KEY compound_key (id,column_1($this->max_index_length)),
  376. FULLTEXT KEY fulltext_key (column_1)
  377. ) {$this->db_engine}
  378. ",
  379. false
  380. );
  381. $this->assertSame( array(), $result );
  382. }
  383. /**
  384. * @ticket 36748
  385. */
  386. function test_dont_downsize_blob_fields() {
  387. global $wpdb;
  388. $result = dbDelta(
  389. "
  390. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  391. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  392. column_1 varchar(255) NOT NULL,
  393. column_2 text,
  394. column_3 tinyblob,
  395. PRIMARY KEY (id),
  396. KEY key_1 (column_1({$this->max_index_length})),
  397. KEY compound_key (id,column_1($this->max_index_length)),
  398. FULLTEXT KEY fulltext_key (column_1)
  399. ) {$this->db_engine}
  400. ",
  401. false
  402. );
  403. $this->assertSame( array(), $result );
  404. }
  405. /**
  406. * @ticket 36748
  407. */
  408. function test_upsize_text_fields() {
  409. global $wpdb;
  410. $result = dbDelta(
  411. "
  412. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  413. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  414. column_1 varchar(255) NOT NULL,
  415. column_2 bigtext,
  416. column_3 blob,
  417. PRIMARY KEY (id),
  418. KEY key_1 (column_1({$this->max_index_length})),
  419. KEY compound_key (id,column_1($this->max_index_length)),
  420. FULLTEXT KEY fulltext_key (column_1)
  421. ) {$this->db_engine}
  422. ",
  423. false
  424. );
  425. $this->assertSame(
  426. array(
  427. "{$wpdb->prefix}dbdelta_test.column_2"
  428. => "Changed type of {$wpdb->prefix}dbdelta_test.column_2 from text to bigtext",
  429. ),
  430. $result
  431. );
  432. }
  433. /**
  434. * @ticket 36748
  435. */
  436. function test_upsize_blob_fields() {
  437. global $wpdb;
  438. $result = dbDelta(
  439. "
  440. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  441. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  442. column_1 varchar(255) NOT NULL,
  443. column_2 text,
  444. column_3 mediumblob,
  445. PRIMARY KEY (id),
  446. KEY key_1 (column_1({$this->max_index_length})),
  447. KEY compound_key (id,column_1($this->max_index_length)),
  448. FULLTEXT KEY fulltext_key (column_1)
  449. ) {$this->db_engine}
  450. ",
  451. false
  452. );
  453. $this->assertSame(
  454. array(
  455. "{$wpdb->prefix}dbdelta_test.column_3"
  456. => "Changed type of {$wpdb->prefix}dbdelta_test.column_3 from blob to mediumblob",
  457. ),
  458. $result
  459. );
  460. }
  461. /**
  462. * @ticket 20263
  463. */
  464. function test_query_with_backticks_does_not_throw_an_undefined_index_warning() {
  465. global $wpdb;
  466. $schema = "
  467. CREATE TABLE {$wpdb->prefix}dbdelta_test2 (
  468. `id` bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  469. `column_1` varchar(255) NOT NULL,
  470. PRIMARY KEY (id),
  471. KEY compound_key (id,column_1($this->max_index_length))
  472. )
  473. ";
  474. // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
  475. $wpdb->query( $schema );
  476. $updates = dbDelta( $schema, false );
  477. $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}dbdelta_test2" );
  478. $this->assertEmpty( $updates );
  479. }
  480. /**
  481. * @ticket 36948
  482. */
  483. function test_spatial_indices() {
  484. global $wpdb;
  485. $db_version = $wpdb->db_version();
  486. if ( version_compare( $db_version, '5.4', '<' ) ) {
  487. $this->markTestSkipped( 'Spatial indices require MySQL 5.4 and above.' );
  488. }
  489. $geomcollection_name = 'geomcollection';
  490. if ( version_compare( $db_version, '8.0.11', '<' ) ) {
  491. // Prior to MySQL 8.0.11, GeometryCollection data type name was used.
  492. $geomcollection_name = 'geometrycollection';
  493. }
  494. $schema =
  495. "
  496. CREATE TABLE {$wpdb->prefix}spatial_index_test (
  497. non_spatial bigint{$this->bigint_display_width} unsigned NOT NULL,
  498. spatial_value {$geomcollection_name} NOT NULL,
  499. KEY non_spatial (non_spatial),
  500. SPATIAL KEY spatial_key (spatial_value)
  501. ) {$this->db_engine};
  502. ";
  503. // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
  504. $wpdb->query( $schema );
  505. $updates = dbDelta( $schema, false );
  506. $this->assertEmpty( $updates );
  507. $schema =
  508. "
  509. CREATE TABLE {$wpdb->prefix}spatial_index_test (
  510. non_spatial bigint{$this->bigint_display_width} unsigned NOT NULL,
  511. spatial_value {$geomcollection_name} NOT NULL,
  512. spatial_value2 {$geomcollection_name} NOT NULL,
  513. KEY non_spatial (non_spatial),
  514. SPATIAL KEY spatial_key (spatial_value)
  515. SPATIAL KEY spatial_key2 (spatial_value2)
  516. ) {$this->db_engine};
  517. ";
  518. $updates = dbDelta( $schema, false );
  519. $this->assertSame(
  520. array(
  521. "{$wpdb->prefix}spatial_index_test.spatial_value2" => "Added column {$wpdb->prefix}spatial_index_test.spatial_value2",
  522. "Added index {$wpdb->prefix}spatial_index_test SPATIAL KEY `spatial_key2` (`spatial_value2`)",
  523. ),
  524. $updates
  525. );
  526. $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}spatial_index_test" );
  527. }
  528. /**
  529. * @ticket 20263
  530. */
  531. function test_query_with_backticks_does_not_cause_a_query_to_alter_all_columns_and_indices_to_run_even_if_none_have_changed() {
  532. global $wpdb;
  533. $schema = "
  534. CREATE TABLE {$wpdb->prefix}dbdelta_test2 (
  535. `id` bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  536. `references` varchar(255) NOT NULL,
  537. PRIMARY KEY (`id`),
  538. KEY `compound_key` (`id`,`references`($this->max_index_length))
  539. )
  540. ";
  541. // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
  542. $wpdb->query( $schema );
  543. $updates = dbDelta( $schema );
  544. $table_indices = $wpdb->get_results( "SHOW INDEX FROM {$wpdb->prefix}dbdelta_test2" );
  545. $compound_key_index = wp_list_filter( $table_indices, array( 'Key_name' => 'compound_key' ) );
  546. $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}dbdelta_test2" );
  547. $this->assertCount( 2, $compound_key_index );
  548. $this->assertEmpty( $updates );
  549. }
  550. /**
  551. * @ticket 20263
  552. */
  553. function test_index_with_a_reserved_keyword_can_be_created() {
  554. global $wpdb;
  555. $updates = dbDelta(
  556. "
  557. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  558. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  559. column_1 varchar(255) NOT NULL,
  560. column_2 text,
  561. column_3 blob,
  562. `references` varchar(255) NOT NULL,
  563. PRIMARY KEY (id),
  564. KEY key_1 (column_1($this->max_index_length)),
  565. KEY compound_key (id , column_1($this->max_index_length)),
  566. KEY compound_key2 (id,`references`($this->max_index_length)),
  567. FULLTEXT KEY fulltext_key (column_1)
  568. ) {$this->db_engine}
  569. "
  570. );
  571. $table_indices = $wpdb->get_results( "SHOW INDEX FROM {$wpdb->prefix}dbdelta_test" );
  572. $this->assertCount( 2, wp_list_filter( $table_indices, array( 'Key_name' => 'compound_key2' ), 'AND' ) );
  573. $this->assertSame(
  574. array(
  575. "{$wpdb->prefix}dbdelta_test.references" => "Added column {$wpdb->prefix}dbdelta_test.references",
  576. 0 => "Added index {$wpdb->prefix}dbdelta_test KEY `compound_key2` (`id`,`references`($this->max_index_length))",
  577. ),
  578. $updates
  579. );
  580. }
  581. /**
  582. * @ticket 20263
  583. */
  584. function test_wp_get_db_schema_does_no_alter_queries_on_existing_install() {
  585. $updates = dbDelta( wp_get_db_schema() );
  586. $this->assertEmpty( $updates );
  587. }
  588. /**
  589. * @ticket 20263
  590. */
  591. function test_key_and_index_and_fulltext_key_and_fulltext_index_and_unique_key_and_unique_index_indicies() {
  592. global $wpdb;
  593. $schema = "
  594. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  595. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  596. column_1 varchar(255) NOT NULL,
  597. column_2 text,
  598. column_3 blob,
  599. PRIMARY KEY (id),
  600. KEY key_1 (column_1($this->max_index_length)),
  601. KEY compound_key (id,column_1($this->max_index_length)),
  602. FULLTEXT KEY fulltext_key (column_1),
  603. INDEX key_2 (column_1($this->max_index_length)),
  604. UNIQUE KEY key_3 (column_1($this->max_index_length)),
  605. UNIQUE INDEX key_4 (column_1($this->max_index_length)),
  606. FULLTEXT INDEX key_5 (column_1),
  607. ) {$this->db_engine}
  608. ";
  609. $creates = dbDelta( $schema );
  610. $this->assertSame(
  611. array(
  612. 0 => "Added index {$wpdb->prefix}dbdelta_test KEY `key_2` (`column_1`($this->max_index_length))",
  613. 1 => "Added index {$wpdb->prefix}dbdelta_test UNIQUE KEY `key_3` (`column_1`($this->max_index_length))",
  614. 2 => "Added index {$wpdb->prefix}dbdelta_test UNIQUE KEY `key_4` (`column_1`($this->max_index_length))",
  615. 3 => "Added index {$wpdb->prefix}dbdelta_test FULLTEXT KEY `key_5` (`column_1`)",
  616. ),
  617. $creates
  618. );
  619. $updates = dbDelta( $schema );
  620. $this->assertEmpty( $updates );
  621. }
  622. /**
  623. * @ticket 20263
  624. */
  625. function test_index_and_key_are_synonyms_and_do_not_recreate_indices() {
  626. global $wpdb;
  627. $updates = dbDelta(
  628. "
  629. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  630. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  631. column_1 varchar(255) NOT NULL,
  632. column_2 text,
  633. column_3 blob,
  634. PRIMARY KEY (id),
  635. INDEX key_1 (column_1($this->max_index_length)),
  636. INDEX compound_key (id,column_1($this->max_index_length)),
  637. FULLTEXT INDEX fulltext_key (column_1)
  638. ) {$this->db_engine}
  639. "
  640. );
  641. $this->assertEmpty( $updates );
  642. }
  643. /**
  644. * @ticket 20263
  645. */
  646. function test_indices_with_prefix_limits_are_created_and_do_not_recreate_indices() {
  647. global $wpdb;
  648. $schema = "
  649. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  650. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  651. column_1 varchar(255) NOT NULL,
  652. column_2 text,
  653. column_3 blob,
  654. PRIMARY KEY (id),
  655. KEY key_1 (column_1($this->max_index_length)),
  656. KEY compound_key (id,column_1($this->max_index_length)),
  657. FULLTEXT KEY fulltext_key (column_1),
  658. KEY key_2 (column_1(10)),
  659. KEY key_3 (column_2(100),column_1(10)),
  660. ) {$this->db_engine}
  661. ";
  662. $creates = dbDelta( $schema );
  663. $this->assertSame(
  664. array(
  665. 0 => "Added index {$wpdb->prefix}dbdelta_test KEY `key_2` (`column_1`(10))",
  666. 1 => "Added index {$wpdb->prefix}dbdelta_test KEY `key_3` (`column_2`(100),`column_1`(10))",
  667. ),
  668. $creates
  669. );
  670. $updates = dbDelta( $schema );
  671. $this->assertEmpty( $updates );
  672. }
  673. /**
  674. * @ticket 34959
  675. */
  676. function test_index_col_names_with_order_do_not_recreate_indices() {
  677. global $wpdb;
  678. $updates = dbDelta(
  679. "
  680. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  681. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  682. column_1 varchar(255) NOT NULL,
  683. column_2 text,
  684. column_3 blob,
  685. PRIMARY KEY (id),
  686. KEY key_1 (column_1($this->max_index_length) DESC),
  687. KEY compound_key (id,column_1($this->max_index_length) ASC),
  688. FULLTEXT KEY fulltext_key (column_1)
  689. ) {$this->db_engine}
  690. "
  691. );
  692. $this->assertEmpty( $updates );
  693. }
  694. /**
  695. * @ticket 34873
  696. */
  697. function test_primary_key_with_single_space_does_not_recreate_index() {
  698. global $wpdb;
  699. $updates = dbDelta(
  700. "
  701. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  702. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  703. column_1 varchar(255) NOT NULL,
  704. column_2 text,
  705. column_3 blob,
  706. PRIMARY KEY (id),
  707. KEY key_1 (column_1($this->max_index_length)),
  708. KEY compound_key (id,column_1($this->max_index_length)),
  709. FULLTEXT KEY fulltext_key (column_1)
  710. ) {$this->db_engine}
  711. "
  712. );
  713. $this->assertEmpty( $updates );
  714. }
  715. /**
  716. * @ticket 34869
  717. */
  718. function test_index_definitions_with_spaces_do_not_recreate_indices() {
  719. global $wpdb;
  720. $updates = dbDelta(
  721. "
  722. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  723. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  724. column_1 varchar(255) NOT NULL,
  725. column_2 text,
  726. column_3 blob,
  727. PRIMARY KEY (id),
  728. KEY key_1 ( column_1($this->max_index_length)),
  729. KEY compound_key (id, column_1($this->max_index_length)),
  730. FULLTEXT KEY fulltext_key (column_1)
  731. ) {$this->db_engine}
  732. "
  733. );
  734. $this->assertEmpty( $updates );
  735. }
  736. /**
  737. * @ticket 34871
  738. */
  739. function test_index_types_are_not_case_sensitive_and_do_not_recreate_indices() {
  740. global $wpdb;
  741. $updates = dbDelta(
  742. "
  743. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  744. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  745. column_1 varchar(255) NOT NULL,
  746. column_2 text,
  747. column_3 blob,
  748. PRIMARY KEY (id),
  749. key key_1 (column_1($this->max_index_length)),
  750. key compound_key (id,column_1($this->max_index_length)),
  751. FULLTEXT KEY fulltext_key (column_1)
  752. ) {$this->db_engine}
  753. "
  754. );
  755. $this->assertEmpty( $updates );
  756. }
  757. /**
  758. * @ticket 34874
  759. */
  760. function test_key_names_are_not_case_sensitive_and_do_not_recreate_indices() {
  761. global $wpdb;
  762. $updates = dbDelta(
  763. "
  764. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  765. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  766. column_1 varchar(255) NOT NULL,
  767. column_2 text,
  768. column_3 blob,
  769. PRIMARY KEY (id),
  770. KEY KEY_1 (column_1($this->max_index_length)),
  771. KEY compOUND_key (id,column_1($this->max_index_length)),
  772. FULLTEXT KEY FULLtext_kEY (column_1)
  773. ) {$this->db_engine}
  774. ",
  775. false
  776. );
  777. $this->assertEmpty( $updates );
  778. }
  779. /**
  780. * @ticket 34870
  781. */
  782. function test_unchanged_key_lengths_do_not_recreate_index() {
  783. global $wpdb;
  784. $updates = dbDelta(
  785. "
  786. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  787. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  788. column_1 varchar(255) NOT NULL,
  789. column_2 text,
  790. column_3 blob,
  791. PRIMARY KEY (id),
  792. KEY key_1 (column_1({$this->max_index_length})),
  793. KEY compound_key (id,column_1($this->max_index_length)),
  794. FULLTEXT KEY fulltext_key (column_1)
  795. ) {$this->db_engine}
  796. ",
  797. false
  798. );
  799. $this->assertEmpty( $updates );
  800. }
  801. /**
  802. * @ticket 34870
  803. */
  804. function test_changed_key_lengths_do_not_recreate_index() {
  805. global $wpdb;
  806. $updates = dbDelta(
  807. "
  808. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  809. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  810. column_1 varchar(255) NOT NULL,
  811. column_2 text,
  812. column_3 blob,
  813. PRIMARY KEY (id),
  814. KEY key_1 (column_1($this->max_index_length)),
  815. KEY compound_key (id,column_1($this->max_index_length)),
  816. KEY changing_key_length (column_1(20)),
  817. FULLTEXT KEY fulltext_key (column_1)
  818. ) {$this->db_engine}
  819. "
  820. );
  821. $this->assertSame(
  822. array(
  823. "Added index {$wpdb->prefix}dbdelta_test KEY `changing_key_length` (`column_1`(20))",
  824. ),
  825. $updates
  826. );
  827. $updates = dbDelta(
  828. "
  829. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  830. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  831. column_1 varchar(255) NOT NULL,
  832. column_2 text,
  833. column_3 blob,
  834. PRIMARY KEY (id),
  835. KEY key_1 (column_1($this->max_index_length)),
  836. KEY compound_key (id,column_1($this->max_index_length)),
  837. KEY changing_key_length (column_1(50)),
  838. FULLTEXT KEY fulltext_key (column_1)
  839. ) {$this->db_engine}
  840. "
  841. );
  842. $this->assertEmpty( $updates );
  843. $updates = dbDelta(
  844. "
  845. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  846. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  847. column_1 varchar(255) NOT NULL,
  848. column_2 text,
  849. column_3 blob,
  850. PRIMARY KEY (id),
  851. KEY key_1 (column_1($this->max_index_length)),
  852. KEY compound_key (id,column_1($this->max_index_length)),
  853. KEY changing_key_length (column_1(1)),
  854. FULLTEXT KEY fulltext_key (column_1)
  855. ) {$this->db_engine}
  856. "
  857. );
  858. $this->assertEmpty( $updates );
  859. $updates = dbDelta(
  860. "
  861. CREATE TABLE {$wpdb->prefix}dbdelta_test (
  862. id bigint{$this->bigint_display_width} NOT NULL AUTO_INCREMENT,
  863. column_1 varchar(255) NOT NULL,
  864. column_2 text,
  865. column_3 blob,
  866. PRIMARY KEY (id),
  867. KEY key_1 (column_1),
  868. KEY compound_key (id,column_1),
  869. KEY changing_key_length (column_1),
  870. FULLTEXT KEY fulltext_key (column_1)
  871. ) {$this->db_engine}
  872. "
  873. );
  874. $this->assertEmpty( $updates );
  875. }
  876. /**
  877. * @ticket 31679
  878. */
  879. function test_column_type_change_with_hyphens_in_name() {
  880. global $wpdb;
  881. $schema = "
  882. CREATE TABLE {$wpdb->prefix}dbdelta_test2 (
  883. `foo-bar` varchar(255) DEFAULT NULL
  884. )
  885. ";
  886. // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
  887. $wpdb->query( $schema );
  888. $schema_update = "
  889. CREATE TABLE {$wpdb->prefix}dbdelta_test2 (
  890. `foo-bar` text DEFAULT NULL
  891. )
  892. ";
  893. $updates = dbDelta( $schema_update );
  894. $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}dbdelta_test2" );
  895. $this->assertSame(
  896. array(
  897. "{$wpdb->prefix}dbdelta_test2.foo-bar" => "Changed type of {$wpdb->prefix}dbdelta_test2.foo-bar from varchar(255) to text",
  898. ),
  899. $updates
  900. );
  901. }
  902. }