From 66d8a3df0e415c27abe416295c9aca4fd09cdbde Mon Sep 17 00:00:00 2001 From: Matthew Bucci Date: Tue, 16 Jan 2024 21:35:32 -0800 Subject: [PATCH] update sequence handling to support bigserial and serial types --- pg4wp/driver_pgsql.php | 51 +++++++++++++++++----- pg4wp/driver_pgsql_rewrite.php | 2 +- pg4wp/rewriters/CreateTableSQLRewriter.php | 7 ++- tests/parseTest.php | 1 - tests/rewriteTest.php | 50 ++++++++++----------- 5 files changed, 71 insertions(+), 40 deletions(-) diff --git a/pg4wp/driver_pgsql.php b/pg4wp/driver_pgsql.php index 26be48c..06c99d5 100644 --- a/pg4wp/driver_pgsql.php +++ b/pg4wp/driver_pgsql.php @@ -1039,6 +1039,38 @@ function wpsqli_affected_rows(&$connection) return pg_affected_rows($result); } +// Gets the list of sequences from postgres +function wpsqli_get_list_of_sequences(&$connection) +{ + $sql = "SELECT sequencename FROM pg_sequences"; + $result = pg_query($connection, $sql); + if(!$result) { + if (PG4WP_DEBUG || PG4WP_LOG) { + $log = "Unable to get list of sequences\n"; + error_log($log, 3, PG4WP_LOG . 'pg4wp_errors.log'); + } + return []; + } + + $data = pg_fetch_all($result); + return array_column($data, 'sequencename'); +} + +// Get the primary sequence for a table +function wpsqli_get_primary_sequence_for_table(&$connection, $table) +{ + $sequences = wpsqli_get_list_of_sequences($connection); + foreach($sequences as $sequence) { + if (strncmp($sequence, $table, strlen($table)) === 0) { + return $sequence; + } + } + + // Fallback to default if we don't find a sequence + // Note: this will probably fail + return $table . '_seq'; +} + /** * Fetches the ID generated for an AUTO_INCREMENT column by the previous INSERT query. * @@ -1057,19 +1089,13 @@ function wpsqli_insert_id(&$connection = null) $ins_field = $GLOBALS['pg4wp_ins_field']; $table = $GLOBALS['pg4wp_ins_table']; $lastq = $GLOBALS['pg4wp_last_insert']; - $seq = $table . '_seq'; + $seq = wpsqli_get_primary_sequence_for_table($connection, $table); - // Special case for 'term_relationships' table, which does not have a sequence in PostgreSQL. - if ($table == $wpdb->term_relationships) { - // PostgreSQL: Using CURRVAL() to get the current value of the sequence. - $sql = "SELECT CURRVAL('$seq')"; - $res = pg_query($connection, $sql); - if (false !== $res) { - $data = pg_fetch_result($res, 0, 0); - } - } // Special case when using WP_Import plugin where ID is defined in the query itself. - elseif ('post_author' == $ins_field && false !== strpos($lastq, 'ID')) { + if($table == $wpdb->term_relationships) { + $sql = 'NO QUERY'; + $data = 0; + } elseif ('post_author' == $ins_field && false !== strpos($lastq, 'ID')) { // No PostgreSQL specific operation here. $sql = 'ID was in query '; $pattern = '/.+\'(\d+).+$/'; @@ -1080,7 +1106,8 @@ function wpsqli_insert_id(&$connection = null) $GLOBALS['pg4wp_queued_query'] = "SELECT SETVAL('$seq',(SELECT MAX(\"ID\") FROM $table)+1);"; } else { // PostgreSQL: Using CURRVAL() to get the current value of the sequence. - $sql = "SELECT CURRVAL('$seq')"; + // Double quoting is needed to prevent seq from being lowercased automatically + $sql = "SELECT CURRVAL('\"$seq\"')"; $res = pg_query($connection, $sql); if (false !== $res) { $data = pg_fetch_result($res, 0, 0); diff --git a/pg4wp/driver_pgsql_rewrite.php b/pg4wp/driver_pgsql_rewrite.php index 473e895..0292cd0 100644 --- a/pg4wp/driver_pgsql_rewrite.php +++ b/pg4wp/driver_pgsql_rewrite.php @@ -53,7 +53,7 @@ function pg4wp_rewrite($sql) // When installing, the sequence for table terms has to be updated if(defined('WP_INSTALLING') && WP_INSTALLING && false !== strpos($sql, 'INSERT INTO `' . $wpdb->terms . '`')) { - $end .= ';SELECT setval(\'' . $wpdb->terms . '_seq\', (SELECT MAX(term_id) FROM ' . $wpdb->terms . ')+1);'; + $end .= ';SELECT setval(\'' . $wpdb->terms . '_term_id_seq\', (SELECT MAX(term_id) FROM ' . $wpdb->terms . ')+1);'; } break; case 'Insert': diff --git a/pg4wp/rewriters/CreateTableSQLRewriter.php b/pg4wp/rewriters/CreateTableSQLRewriter.php index e7aba47..35c1061 100644 --- a/pg4wp/rewriters/CreateTableSQLRewriter.php +++ b/pg4wp/rewriters/CreateTableSQLRewriter.php @@ -46,6 +46,11 @@ class CreateTableSQLRewriter extends AbstractSQLRewriter preg_match($pattern, $tableSQL, $matches); $table = $matches[1]; + // change all creates into create if not exists + $pattern = "/CREATE TABLE (IF NOT EXISTS )?(\w+)\s*\(/i"; + $replacement = 'CREATE TABLE IF NOT EXISTS $2 ('; + $sql = preg_replace($pattern, $replacement, $sql); + // Remove trailing spaces $sql = trim($sql); @@ -109,7 +114,7 @@ class CreateTableSQLRewriter extends AbstractSQLRewriter $indexName = $table . '_' . $index; // Appending the CREATE INDEX statement to SQL - $sql .= "\nCREATE {$unique}INDEX $indexName ON $table ($columns);"; + $sql .= "\nCREATE {$unique}INDEX IF NOT EXISTS $indexName ON $table ($columns);"; } } // Now remove handled indexes diff --git a/tests/parseTest.php b/tests/parseTest.php index fe40a36..ca58a5f 100644 --- a/tests/parseTest.php +++ b/tests/parseTest.php @@ -33,7 +33,6 @@ final class parseTest extends TestCase $this->assertSame($GLOBALS['pg4wp_ins_field'], "post_author"); } - protected function setUp(): void { global $wpdb; diff --git a/tests/rewriteTest.php b/tests/rewriteTest.php index 985f7d4..786c3a3 100644 --- a/tests/rewriteTest.php +++ b/tests/rewriteTest.php @@ -54,7 +54,7 @@ final class rewriteTest extends TestCase SQL; $expected = <<assertSame(trim($expected), trim($postgresql)); } - + public function test_it_removes_table_charsets() { $sql = <<assertSame(trim($expected), trim($postgresql)); } - + public function test_it_can_create_double_keys_with_length() @@ -359,7 +359,7 @@ final class rewriteTest extends TestCase SQL; $expected = <<assertSame(trim($expected), trim($postgresql)); } - + protected function setUp(): void {