From 804c63752c6d3679d6a106dd3f5c1aedaf6a68bc Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Wed, 25 Dec 2024 08:41:49 +0500 Subject: [PATCH 001/137] Fix issue #762 --- src/Schema/AbstractSchema.php | 38 +++++++++++++++++++++++++++++++ src/Schema/SchemaInterface.php | 28 +++++++++++++++++++++++ tests/Common/CommonSchemaTest.php | 33 +++++++++++++++++++++++++++ tests/Db/Schema/SchemaTest.php | 14 ++++++++++++ 4 files changed, 113 insertions(+) diff --git a/src/Schema/AbstractSchema.php b/src/Schema/AbstractSchema.php index 78b42cc95..5a52d9322 100644 --- a/src/Schema/AbstractSchema.php +++ b/src/Schema/AbstractSchema.php @@ -574,4 +574,42 @@ public function getViewNames(string $schema = '', bool $refresh = false): array return (array) $this->viewNames[$schema]; } + + /** + * @param string $tableName The table name. + * @param string $schema The schema of the tables. + * @return bool + * @throws Throwable + */ + public function hasTableName(string $tableName, string $schema = ''): bool + { + $tables = $this->getTableNames($schema); + + return in_array($tableName, $tables); + } + + /** + * @param string $schema The schema name. + * @return bool + * @throws Throwable + */ + public function hasSchemaName(string $schema): bool + { + $schemas = $this->getSchemaNames(); + + return in_array($schema, $schemas); + } + + /** + * @param string $viewName The view name. + * @param string $schema The schema of the views. + * @return bool + * @throws Throwable + */ + public function hasViewName(string $viewName, string $schema = ''): bool + { + $views = $this->getViewNames($schema); + + return in_array($viewName, $views); + } } diff --git a/src/Schema/SchemaInterface.php b/src/Schema/SchemaInterface.php index 2632f16e4..9f05ec54d 100644 --- a/src/Schema/SchemaInterface.php +++ b/src/Schema/SchemaInterface.php @@ -416,4 +416,32 @@ public function enableCache(bool $value): void; * @return array All view names in the database. */ public function getViewNames(string $schema = '', bool $refresh = false): array; + + /** + * Determines if a specified table exists in the database. + * + * @param string $tableName The table name to search for + * @param string $schema The schema of the tables. Defaults to empty string, meaning the current or default schema + * name. If not empty, the table will be searched in the specified schema. + * @return bool Whether table exists or not + */ + public function hasTableName(string $tableName, string $schema = ''): bool; + + /** + * Determines if a specified schema exists in the database. + * + * @param string $schema The table name to search for + * @return bool Whether schema exists or not + */ + public function hasSchemaName(string $schema): bool; + + /** + * Determines if a specified view exists in the database. + * + * @param string $viewName The table name to search for + * @param string $schema The schema of the tables. Defaults to empty string, meaning the current or default schema + * name. If not empty, the table will be searched in the specified schema. + * @return bool Whether view exists or not + */ + public function hasViewName(string $viewName, string $schema = ''): bool; } diff --git a/tests/Common/CommonSchemaTest.php b/tests/Common/CommonSchemaTest.php index bbf5447da..5e6ce718d 100644 --- a/tests/Common/CommonSchemaTest.php +++ b/tests/Common/CommonSchemaTest.php @@ -405,6 +405,27 @@ public function testGetTableNames(array $pdoAttributes): void $db->close(); } + public function testHasTableName(array $pdoAttributes): void + { + $db = $this->getConnection(true); + + foreach ($pdoAttributes as $name => $value) { + if ($name === PDO::ATTR_EMULATE_PREPARES) { + continue; + } + + $db->getPDO()?->setAttribute($name, $value); + } + + $schema = $db->getSchema(); + + $this->assertTrue($schema->hasTableName('customer')); + $this->assertTrue($schema->hasTableName('category')); + $this->assertFalse($schema->hasTableName('no_such_table')); + + $db->close(); + } + /** * @dataProvider \Yiisoft\Db\Tests\Provider\SchemaProvider::tableSchema */ @@ -482,6 +503,18 @@ public function testGetViewNames(): void $db->close(); } + public function hasViewName(): void + { + $db = $this->getConnection(true); + + $schema = $db->getSchema(); + + $this->assertTrue($schema->hasViewName('animal_view')); + $this->assertFalse($schema->hasViewName('no_such_view')); + + $db->close(); + } + public function testNegativeDefaultValues(): void { $db = $this->getConnection(true); diff --git a/tests/Db/Schema/SchemaTest.php b/tests/Db/Schema/SchemaTest.php index 365a97d72..e4e7453ca 100644 --- a/tests/Db/Schema/SchemaTest.php +++ b/tests/Db/Schema/SchemaTest.php @@ -202,6 +202,20 @@ public function testGetSchemaNamesWithSchema(): void $this->assertSame(['dbo', 'public'], $schema->getSchemaNames()); } + public function testHasSchemaName(): void + { + $db = $this->getConnection(); + + $schema = $db->getSchema(); + Assert::setInaccessibleProperty($schema, 'schemaNames', ['dbo', 'public']); + + $this->assertTrue($schema->hasSchemaName('dbo')); + $this->assertTrue($schema->hasSchemaName('public')); + $this->assertFalse($schema->hasSchemaName('no_such_schema')); + + $db->close(); + } + /** * @throws NotSupportedException */ From 13f23c726a67393b19130aa6c4b0c987b9b275c1 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Wed, 25 Dec 2024 14:57:23 +0500 Subject: [PATCH 002/137] Fix issue #762 --- src/Schema/AbstractSchema.php | 14 +++----------- src/Schema/SchemaInterface.php | 6 +++--- tests/Common/CommonSchemaTest.php | 14 +++++++------- tests/Db/Schema/SchemaTest.php | 8 ++++---- 4 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/Schema/AbstractSchema.php b/src/Schema/AbstractSchema.php index 5a52d9322..264c8902d 100644 --- a/src/Schema/AbstractSchema.php +++ b/src/Schema/AbstractSchema.php @@ -576,12 +576,9 @@ public function getViewNames(string $schema = '', bool $refresh = false): array } /** - * @param string $tableName The table name. - * @param string $schema The schema of the tables. - * @return bool * @throws Throwable */ - public function hasTableName(string $tableName, string $schema = ''): bool + public function hasTable(string $tableName, string $schema = ''): bool { $tables = $this->getTableNames($schema); @@ -589,11 +586,9 @@ public function hasTableName(string $tableName, string $schema = ''): bool } /** - * @param string $schema The schema name. - * @return bool * @throws Throwable */ - public function hasSchemaName(string $schema): bool + public function hasSchema(string $schema): bool { $schemas = $this->getSchemaNames(); @@ -601,12 +596,9 @@ public function hasSchemaName(string $schema): bool } /** - * @param string $viewName The view name. - * @param string $schema The schema of the views. - * @return bool * @throws Throwable */ - public function hasViewName(string $viewName, string $schema = ''): bool + public function hasView(string $viewName, string $schema = ''): bool { $views = $this->getViewNames($schema); diff --git a/src/Schema/SchemaInterface.php b/src/Schema/SchemaInterface.php index 9f05ec54d..422518564 100644 --- a/src/Schema/SchemaInterface.php +++ b/src/Schema/SchemaInterface.php @@ -425,7 +425,7 @@ public function getViewNames(string $schema = '', bool $refresh = false): array; * name. If not empty, the table will be searched in the specified schema. * @return bool Whether table exists or not */ - public function hasTableName(string $tableName, string $schema = ''): bool; + public function hasTable(string $tableName, string $schema = ''): bool; /** * Determines if a specified schema exists in the database. @@ -433,7 +433,7 @@ public function hasTableName(string $tableName, string $schema = ''): bool; * @param string $schema The table name to search for * @return bool Whether schema exists or not */ - public function hasSchemaName(string $schema): bool; + public function hasSchema(string $schema): bool; /** * Determines if a specified view exists in the database. @@ -443,5 +443,5 @@ public function hasSchemaName(string $schema): bool; * name. If not empty, the table will be searched in the specified schema. * @return bool Whether view exists or not */ - public function hasViewName(string $viewName, string $schema = ''): bool; + public function hasView(string $viewName, string $schema = ''): bool; } diff --git a/tests/Common/CommonSchemaTest.php b/tests/Common/CommonSchemaTest.php index 5e6ce718d..1541dde65 100644 --- a/tests/Common/CommonSchemaTest.php +++ b/tests/Common/CommonSchemaTest.php @@ -405,7 +405,7 @@ public function testGetTableNames(array $pdoAttributes): void $db->close(); } - public function testHasTableName(array $pdoAttributes): void + public function testHasTable(array $pdoAttributes): void { $db = $this->getConnection(true); @@ -419,9 +419,9 @@ public function testHasTableName(array $pdoAttributes): void $schema = $db->getSchema(); - $this->assertTrue($schema->hasTableName('customer')); - $this->assertTrue($schema->hasTableName('category')); - $this->assertFalse($schema->hasTableName('no_such_table')); + $this->assertTrue($schema->hasTable('customer')); + $this->assertTrue($schema->hasTable('category')); + $this->assertFalse($schema->hasTable('no_such_table')); $db->close(); } @@ -503,14 +503,14 @@ public function testGetViewNames(): void $db->close(); } - public function hasViewName(): void + public function hasView(): void { $db = $this->getConnection(true); $schema = $db->getSchema(); - $this->assertTrue($schema->hasViewName('animal_view')); - $this->assertFalse($schema->hasViewName('no_such_view')); + $this->assertTrue($schema->hasView('animal_view')); + $this->assertFalse($schema->hasView('no_such_view')); $db->close(); } diff --git a/tests/Db/Schema/SchemaTest.php b/tests/Db/Schema/SchemaTest.php index e4e7453ca..60cd54cb0 100644 --- a/tests/Db/Schema/SchemaTest.php +++ b/tests/Db/Schema/SchemaTest.php @@ -202,16 +202,16 @@ public function testGetSchemaNamesWithSchema(): void $this->assertSame(['dbo', 'public'], $schema->getSchemaNames()); } - public function testHasSchemaName(): void + public function testHasSchema(): void { $db = $this->getConnection(); $schema = $db->getSchema(); Assert::setInaccessibleProperty($schema, 'schemaNames', ['dbo', 'public']); - $this->assertTrue($schema->hasSchemaName('dbo')); - $this->assertTrue($schema->hasSchemaName('public')); - $this->assertFalse($schema->hasSchemaName('no_such_schema')); + $this->assertTrue($schema->hasSchema('dbo')); + $this->assertTrue($schema->hasSchema('public')); + $this->assertFalse($schema->hasSchema('no_such_schema')); $db->close(); } From fd253ea6f1f18ba27b5c86a3cdd9224aa017681a Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Wed, 25 Dec 2024 14:59:03 +0500 Subject: [PATCH 003/137] Fix issue #762 --- tests/Common/CommonSchemaTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Common/CommonSchemaTest.php b/tests/Common/CommonSchemaTest.php index 1541dde65..6429691b0 100644 --- a/tests/Common/CommonSchemaTest.php +++ b/tests/Common/CommonSchemaTest.php @@ -503,7 +503,7 @@ public function testGetViewNames(): void $db->close(); } - public function hasView(): void + public function testHasView(): void { $db = $this->getConnection(true); From 966e2149e2ddb06d8cde3c0490781d38f386aa5c Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Wed, 25 Dec 2024 20:58:06 +0500 Subject: [PATCH 004/137] Fix issue #762 --- src/Schema/AbstractSchema.php | 12 ++++++------ src/Schema/SchemaInterface.php | 15 ++++++++++++--- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/Schema/AbstractSchema.php b/src/Schema/AbstractSchema.php index 264c8902d..890835e1c 100644 --- a/src/Schema/AbstractSchema.php +++ b/src/Schema/AbstractSchema.php @@ -578,9 +578,9 @@ public function getViewNames(string $schema = '', bool $refresh = false): array /** * @throws Throwable */ - public function hasTable(string $tableName, string $schema = ''): bool + public function hasTable(string $tableName, string $schema = '', bool $refresh = false): bool { - $tables = $this->getTableNames($schema); + $tables = $this->getTableNames($schema, $refresh); return in_array($tableName, $tables); } @@ -588,9 +588,9 @@ public function hasTable(string $tableName, string $schema = ''): bool /** * @throws Throwable */ - public function hasSchema(string $schema): bool + public function hasSchema(string $schema, bool $refresh = false): bool { - $schemas = $this->getSchemaNames(); + $schemas = $this->getSchemaNames($refresh); return in_array($schema, $schemas); } @@ -598,9 +598,9 @@ public function hasSchema(string $schema): bool /** * @throws Throwable */ - public function hasView(string $viewName, string $schema = ''): bool + public function hasView(string $viewName, string $schema = '', bool $refresh = false): bool { - $views = $this->getViewNames($schema); + $views = $this->getViewNames($schema, $refresh); return in_array($viewName, $views); } diff --git a/src/Schema/SchemaInterface.php b/src/Schema/SchemaInterface.php index 422518564..2d4216127 100644 --- a/src/Schema/SchemaInterface.php +++ b/src/Schema/SchemaInterface.php @@ -423,17 +423,23 @@ public function getViewNames(string $schema = '', bool $refresh = false): array; * @param string $tableName The table name to search for * @param string $schema The schema of the tables. Defaults to empty string, meaning the current or default schema * name. If not empty, the table will be searched in the specified schema. + * @param bool $refresh Whether to fetch the latest available table names. If this is false, view names fetched + * before (if available) will be returned. + * * @return bool Whether table exists or not */ - public function hasTable(string $tableName, string $schema = ''): bool; + public function hasTable(string $tableName, string $schema = '', bool $refresh = false): bool; /** * Determines if a specified schema exists in the database. * * @param string $schema The table name to search for + * @param bool $refresh Whether to fetch the latest available schema names. If this is false, view names fetched + * before (if available) will be returned. + * * @return bool Whether schema exists or not */ - public function hasSchema(string $schema): bool; + public function hasSchema(string $schema, bool $refresh = false): bool; /** * Determines if a specified view exists in the database. @@ -441,7 +447,10 @@ public function hasSchema(string $schema): bool; * @param string $viewName The table name to search for * @param string $schema The schema of the tables. Defaults to empty string, meaning the current or default schema * name. If not empty, the table will be searched in the specified schema. + * @param bool $refresh Whether to fetch the latest available view names. If this is false, view names fetched + * before (if available) will be returned. + * * @return bool Whether view exists or not */ - public function hasView(string $viewName, string $schema = ''): bool; + public function hasView(string $viewName, string $schema = '', bool $refresh = false): bool; } From 7a5d737fbfe94b2e60a0914992ccd78add2ef737 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 26 Dec 2024 05:11:54 +0500 Subject: [PATCH 005/137] Update src/Schema/SchemaInterface.php Co-authored-by: Alexander Makarov --- src/Schema/SchemaInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Schema/SchemaInterface.php b/src/Schema/SchemaInterface.php index 2d4216127..0ff924dfe 100644 --- a/src/Schema/SchemaInterface.php +++ b/src/Schema/SchemaInterface.php @@ -420,7 +420,7 @@ public function getViewNames(string $schema = '', bool $refresh = false): array; /** * Determines if a specified table exists in the database. * - * @param string $tableName The table name to search for + * @param string $tableName The table name to search for. * @param string $schema The schema of the tables. Defaults to empty string, meaning the current or default schema * name. If not empty, the table will be searched in the specified schema. * @param bool $refresh Whether to fetch the latest available table names. If this is false, view names fetched From 1e281ab1437f30a677cdbcffc872d419abdc8522 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 26 Dec 2024 05:26:43 +0500 Subject: [PATCH 006/137] Fix issue #762 --- src/Schema/SchemaInterface.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Schema/SchemaInterface.php b/src/Schema/SchemaInterface.php index 0ff924dfe..febf59045 100644 --- a/src/Schema/SchemaInterface.php +++ b/src/Schema/SchemaInterface.php @@ -420,37 +420,37 @@ public function getViewNames(string $schema = '', bool $refresh = false): array; /** * Determines if a specified table exists in the database. * - * @param string $tableName The table name to search for. + * @param string $tableName The table name to search for * @param string $schema The schema of the tables. Defaults to empty string, meaning the current or default schema * name. If not empty, the table will be searched in the specified schema. * @param bool $refresh Whether to fetch the latest available table names. If this is false, view names fetched * before (if available) will be returned. * - * @return bool Whether table exists or not + * @return bool Whether table exists. */ public function hasTable(string $tableName, string $schema = '', bool $refresh = false): bool; /** * Determines if a specified schema exists in the database. * - * @param string $schema The table name to search for + * @param string $schema The schema name to search for * @param bool $refresh Whether to fetch the latest available schema names. If this is false, view names fetched * before (if available) will be returned. * - * @return bool Whether schema exists or not + * @return bool Whether schema exists. */ public function hasSchema(string $schema, bool $refresh = false): bool; /** * Determines if a specified view exists in the database. * - * @param string $viewName The table name to search for + * @param string $viewName The view name to search for * @param string $schema The schema of the tables. Defaults to empty string, meaning the current or default schema * name. If not empty, the table will be searched in the specified schema. * @param bool $refresh Whether to fetch the latest available view names. If this is false, view names fetched * before (if available) will be returned. * - * @return bool Whether view exists or not + * @return bool Whether view exists. */ public function hasView(string $viewName, string $schema = '', bool $refresh = false): bool; } From 2514ee081fa7f4eceb5c0408c318f142075bc476 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Sat, 4 Jan 2025 20:24:36 +0500 Subject: [PATCH 007/137] Changelog update --- tests/Common/CommonSchemaTest.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/Common/CommonSchemaTest.php b/tests/Common/CommonSchemaTest.php index 6429691b0..cc311286b 100644 --- a/tests/Common/CommonSchemaTest.php +++ b/tests/Common/CommonSchemaTest.php @@ -405,15 +405,16 @@ public function testGetTableNames(array $pdoAttributes): void $db->close(); } + /** + * @dataProvider \Yiisoft\Db\Tests\Provider\SchemaProvider::pdoAttributes + * + * @throws NotSupportedException + */ public function testHasTable(array $pdoAttributes): void { $db = $this->getConnection(true); foreach ($pdoAttributes as $name => $value) { - if ($name === PDO::ATTR_EMULATE_PREPARES) { - continue; - } - $db->getPDO()?->setAttribute($name, $value); } From c43d104d85230c63961675ae6ef428be33ac2b2e Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Sun, 5 Jan 2025 09:08:01 +0500 Subject: [PATCH 008/137] Removed redundant PHPDoc block --- tests/Common/CommonSchemaTest.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/Common/CommonSchemaTest.php b/tests/Common/CommonSchemaTest.php index cc311286b..737f2f478 100644 --- a/tests/Common/CommonSchemaTest.php +++ b/tests/Common/CommonSchemaTest.php @@ -405,11 +405,6 @@ public function testGetTableNames(array $pdoAttributes): void $db->close(); } - /** - * @dataProvider \Yiisoft\Db\Tests\Provider\SchemaProvider::pdoAttributes - * - * @throws NotSupportedException - */ public function testHasTable(array $pdoAttributes): void { $db = $this->getConnection(true); From 64f818c651c2ded43b3f71d230899e655f160c39 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Sun, 5 Jan 2025 09:15:01 +0500 Subject: [PATCH 009/137] Returned PHPDoc block to fix automated tests --- tests/Common/CommonSchemaTest.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/Common/CommonSchemaTest.php b/tests/Common/CommonSchemaTest.php index 737f2f478..cc311286b 100644 --- a/tests/Common/CommonSchemaTest.php +++ b/tests/Common/CommonSchemaTest.php @@ -405,6 +405,11 @@ public function testGetTableNames(array $pdoAttributes): void $db->close(); } + /** + * @dataProvider \Yiisoft\Db\Tests\Provider\SchemaProvider::pdoAttributes + * + * @throws NotSupportedException + */ public function testHasTable(array $pdoAttributes): void { $db = $this->getConnection(true); From 219c7c6f6970224df848dd80f28aecf243c4e821 Mon Sep 17 00:00:00 2001 From: Sergei Tigrov Date: Sun, 5 Jan 2025 11:18:35 +0700 Subject: [PATCH 010/137] Update tests/Common/CommonSchemaTest.php --- tests/Common/CommonSchemaTest.php | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/tests/Common/CommonSchemaTest.php b/tests/Common/CommonSchemaTest.php index cc311286b..03b877e92 100644 --- a/tests/Common/CommonSchemaTest.php +++ b/tests/Common/CommonSchemaTest.php @@ -405,19 +405,10 @@ public function testGetTableNames(array $pdoAttributes): void $db->close(); } - /** - * @dataProvider \Yiisoft\Db\Tests\Provider\SchemaProvider::pdoAttributes - * - * @throws NotSupportedException - */ - public function testHasTable(array $pdoAttributes): void + public function testHasTable(): void { $db = $this->getConnection(true); - foreach ($pdoAttributes as $name => $value) { - $db->getPDO()?->setAttribute($name, $value); - } - $schema = $db->getSchema(); $this->assertTrue($schema->hasTable('customer')); From 23c9235728139a5288f24e1f50efe7376539919b Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Sun, 5 Jan 2025 09:20:42 +0500 Subject: [PATCH 011/137] Removed redundant PHPDoc block --- tests/Common/CommonSchemaTest.php | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/tests/Common/CommonSchemaTest.php b/tests/Common/CommonSchemaTest.php index cc311286b..03b877e92 100644 --- a/tests/Common/CommonSchemaTest.php +++ b/tests/Common/CommonSchemaTest.php @@ -405,19 +405,10 @@ public function testGetTableNames(array $pdoAttributes): void $db->close(); } - /** - * @dataProvider \Yiisoft\Db\Tests\Provider\SchemaProvider::pdoAttributes - * - * @throws NotSupportedException - */ - public function testHasTable(array $pdoAttributes): void + public function testHasTable(): void { $db = $this->getConnection(true); - foreach ($pdoAttributes as $name => $value) { - $db->getPDO()?->setAttribute($name, $value); - } - $schema = $db->getSchema(); $this->assertTrue($schema->hasTable('customer')); From 028baf80199bc2c79ab6740aa5a15cff62e38b3a Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Sun, 5 Jan 2025 10:45:40 +0500 Subject: [PATCH 012/137] Fixed hasSchema tests --- tests/Common/CommonSchemaTest.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/Common/CommonSchemaTest.php b/tests/Common/CommonSchemaTest.php index 03b877e92..a91ec4f69 100644 --- a/tests/Common/CommonSchemaTest.php +++ b/tests/Common/CommonSchemaTest.php @@ -415,6 +415,10 @@ public function testHasTable(): void $this->assertTrue($schema->hasTable('category')); $this->assertFalse($schema->hasTable('no_such_table')); + $this->assertTrue($schema->hasTable('customer', '', true)); + $this->assertTrue($schema->hasTable('category', '', true)); + $this->assertFalse($schema->hasTable('no_such_table', '', true)); + $db->close(); } @@ -504,6 +508,9 @@ public function testHasView(): void $this->assertTrue($schema->hasView('animal_view')); $this->assertFalse($schema->hasView('no_such_view')); + $this->assertTrue($schema->hasView('animal_view', '', true)); + $this->assertFalse($schema->hasView('no_such_view', '', true)); + $db->close(); } From e42d4b67dd4d9be428173f46257fe74abc24b933 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Sun, 5 Jan 2025 11:11:33 +0500 Subject: [PATCH 013/137] Fixed hasSchema tests & formatting --- CHANGELOG.md | 1 + src/Schema/SchemaInterface.php | 10 +++++----- tests/Common/CommonSchemaTest.php | 9 +++++++++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f488b79a..a5f9bd28e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## 2.0.0 under development +- Enh #762: Add methods `SchemaInterface::hasSchema()`, `SchemaInterface::hasTable()`, `SchemaInterface::hasView()` (@evil1) - Enh #820: Support `Traversable` values for `AbstractDMLQueryBuilder::batchInsert()` method with empty columns (@Tigrov) - Enh #815: Refactor `Query::column()` method (@Tigrov) - Enh #816: Allow scalar values for `$columns` parameter of `Query::select()` and `Query::addSelect()` methods (@Tigrov) diff --git a/src/Schema/SchemaInterface.php b/src/Schema/SchemaInterface.php index febf59045..ca64365e9 100644 --- a/src/Schema/SchemaInterface.php +++ b/src/Schema/SchemaInterface.php @@ -422,9 +422,9 @@ public function getViewNames(string $schema = '', bool $refresh = false): array; * * @param string $tableName The table name to search for * @param string $schema The schema of the tables. Defaults to empty string, meaning the current or default schema - * name. If not empty, the table will be searched in the specified schema. + * name. If not empty, the table will be searched in the specified schema. * @param bool $refresh Whether to fetch the latest available table names. If this is false, view names fetched - * before (if available) will be returned. + * before (if available) will be returned. * * @return bool Whether table exists. */ @@ -435,7 +435,7 @@ public function hasTable(string $tableName, string $schema = '', bool $refresh = * * @param string $schema The schema name to search for * @param bool $refresh Whether to fetch the latest available schema names. If this is false, view names fetched - * before (if available) will be returned. + * before (if available) will be returned. * * @return bool Whether schema exists. */ @@ -446,9 +446,9 @@ public function hasSchema(string $schema, bool $refresh = false): bool; * * @param string $viewName The view name to search for * @param string $schema The schema of the tables. Defaults to empty string, meaning the current or default schema - * name. If not empty, the table will be searched in the specified schema. + * name. If not empty, the table will be searched in the specified schema. * @param bool $refresh Whether to fetch the latest available view names. If this is false, view names fetched - * before (if available) will be returned. + * before (if available) will be returned. * * @return bool Whether view exists. */ diff --git a/tests/Common/CommonSchemaTest.php b/tests/Common/CommonSchemaTest.php index a91ec4f69..1c321da3b 100644 --- a/tests/Common/CommonSchemaTest.php +++ b/tests/Common/CommonSchemaTest.php @@ -419,6 +419,11 @@ public function testHasTable(): void $this->assertTrue($schema->hasTable('category', '', true)); $this->assertFalse($schema->hasTable('no_such_table', '', true)); + if ($db->getDriverName() !== 'sqlite') { + $this->assertFalse($schema->hasTable('customer', 'no_such_schema', true)); + $this->assertFalse($schema->hasTable('category', 'no_such_schema', true)); + } + $db->close(); } @@ -511,6 +516,10 @@ public function testHasView(): void $this->assertTrue($schema->hasView('animal_view', '', true)); $this->assertFalse($schema->hasView('no_such_view', '', true)); + if ($db->getDriverName() !== 'sqlite') { + $this->assertFalse($schema->hasView('animal_view', 'no_such_schema', true)); + } + $db->close(); } From c19ffde8db96a2b31584f2bba0a4ae4d29ebc19c Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Sun, 5 Jan 2025 11:15:09 +0500 Subject: [PATCH 014/137] Fixed hasSchema tests & formatting --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5f9bd28e..f003da6fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## 2.0.0 under development -- Enh #762: Add methods `SchemaInterface::hasSchema()`, `SchemaInterface::hasTable()`, `SchemaInterface::hasView()` (@evil1) +- Enh #913: Add methods `SchemaInterface::hasSchema()`, `SchemaInterface::hasTable()`, `SchemaInterface::hasView()` (@evil1) - Enh #820: Support `Traversable` values for `AbstractDMLQueryBuilder::batchInsert()` method with empty columns (@Tigrov) - Enh #815: Refactor `Query::column()` method (@Tigrov) - Enh #816: Allow scalar values for `$columns` parameter of `Query::select()` and `Query::addSelect()` methods (@Tigrov) From 3203b8b263b725e4bcef4a0f9d22a4011214d0c5 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Sun, 5 Jan 2025 11:19:48 +0500 Subject: [PATCH 015/137] Fixed hasSchema tests & formatting --- CHANGELOG.md | 2 +- tests/Common/CommonSchemaTest.php | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f003da6fc..acfffb5ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## 2.0.0 under development -- Enh #913: Add methods `SchemaInterface::hasSchema()`, `SchemaInterface::hasTable()`, `SchemaInterface::hasView()` (@evil1) +- New #913: Add methods `SchemaInterface::hasSchema()`, `SchemaInterface::hasTable()`, `SchemaInterface::hasView()` (@evil1) - Enh #820: Support `Traversable` values for `AbstractDMLQueryBuilder::batchInsert()` method with empty columns (@Tigrov) - Enh #815: Refactor `Query::column()` method (@Tigrov) - Enh #816: Allow scalar values for `$columns` parameter of `Query::select()` and `Query::addSelect()` methods (@Tigrov) diff --git a/tests/Common/CommonSchemaTest.php b/tests/Common/CommonSchemaTest.php index 1c321da3b..a91ec4f69 100644 --- a/tests/Common/CommonSchemaTest.php +++ b/tests/Common/CommonSchemaTest.php @@ -419,11 +419,6 @@ public function testHasTable(): void $this->assertTrue($schema->hasTable('category', '', true)); $this->assertFalse($schema->hasTable('no_such_table', '', true)); - if ($db->getDriverName() !== 'sqlite') { - $this->assertFalse($schema->hasTable('customer', 'no_such_schema', true)); - $this->assertFalse($schema->hasTable('category', 'no_such_schema', true)); - } - $db->close(); } @@ -516,10 +511,6 @@ public function testHasView(): void $this->assertTrue($schema->hasView('animal_view', '', true)); $this->assertFalse($schema->hasView('no_such_view', '', true)); - if ($db->getDriverName() !== 'sqlite') { - $this->assertFalse($schema->hasView('animal_view', 'no_such_schema', true)); - } - $db->close(); } From 4d6074fee608ef93a1b9a16971d278acfc7126f4 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Sun, 5 Jan 2025 21:36:32 +0500 Subject: [PATCH 016/137] Fixed hasView and hasTable tests tests --- src/Query/AbstractQueryStatement.php | 35 ++++++++++++++++++++++++++++ tests/Common/CommonSchemaTest.php | 12 ++++++---- 2 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 src/Query/AbstractQueryStatement.php diff --git a/src/Query/AbstractQueryStatement.php b/src/Query/AbstractQueryStatement.php new file mode 100644 index 000000000..d8e1d361d --- /dev/null +++ b/src/Query/AbstractQueryStatement.php @@ -0,0 +1,35 @@ +sql; + } + + public function setSql(string $sql): static + { + $this->sql = $this->getQueryBuilder()->quoter()->quoteSql($sql); + return $this; + } +} diff --git a/tests/Common/CommonSchemaTest.php b/tests/Common/CommonSchemaTest.php index a91ec4f69..7c1453f56 100644 --- a/tests/Common/CommonSchemaTest.php +++ b/tests/Common/CommonSchemaTest.php @@ -415,9 +415,9 @@ public function testHasTable(): void $this->assertTrue($schema->hasTable('category')); $this->assertFalse($schema->hasTable('no_such_table')); - $this->assertTrue($schema->hasTable('customer', '', true)); - $this->assertTrue($schema->hasTable('category', '', true)); - $this->assertFalse($schema->hasTable('no_such_table', '', true)); + $db->createCommand()->dropTable('customer')->execute(); + + $this->assertFalse($schema->hasTable('customer', '', true)); $db->close(); } @@ -508,8 +508,10 @@ public function testHasView(): void $this->assertTrue($schema->hasView('animal_view')); $this->assertFalse($schema->hasView('no_such_view')); - $this->assertTrue($schema->hasView('animal_view', '', true)); - $this->assertFalse($schema->hasView('no_such_view', '', true)); + $db->createCommand()->dropView('animal_view')->execute(); + + $this->assertTrue($schema->hasView('animal_view')); + $this->assertFalse($schema->hasView('animal_view', '', true)); $db->close(); } From 0beb7a20d08292aaeef69001c2f5fd9a3ff865bc Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 7 Jan 2025 21:09:16 +0500 Subject: [PATCH 017/137] Removed accidental file from the commit --- src/Query/AbstractQueryStatement.php | 35 ---------------------------- 1 file changed, 35 deletions(-) delete mode 100644 src/Query/AbstractQueryStatement.php diff --git a/src/Query/AbstractQueryStatement.php b/src/Query/AbstractQueryStatement.php deleted file mode 100644 index d8e1d361d..000000000 --- a/src/Query/AbstractQueryStatement.php +++ /dev/null @@ -1,35 +0,0 @@ -sql; - } - - public function setSql(string $sql): static - { - $this->sql = $this->getQueryBuilder()->quoter()->quoteSql($sql); - return $this; - } -} From c770c9beb8845ac2d3d200c574646f247e12ea93 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Wed, 26 Mar 2025 14:43:21 +0500 Subject: [PATCH 018/137] Replace customer table with category for testing --- tests/Common/CommonSchemaTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Common/CommonSchemaTest.php b/tests/Common/CommonSchemaTest.php index 7c1453f56..41be1d996 100644 --- a/tests/Common/CommonSchemaTest.php +++ b/tests/Common/CommonSchemaTest.php @@ -415,9 +415,9 @@ public function testHasTable(): void $this->assertTrue($schema->hasTable('category')); $this->assertFalse($schema->hasTable('no_such_table')); - $db->createCommand()->dropTable('customer')->execute(); + $db->createCommand()->dropTable('category')->execute(); - $this->assertFalse($schema->hasTable('customer', '', true)); + $this->assertFalse($schema->hasTable('category', '', true)); $db->close(); } From 43ef361cefa5c7500db590258cc08458dc742914 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Wed, 26 Mar 2025 14:46:28 +0500 Subject: [PATCH 019/137] Replace table name for testing --- tests/Common/CommonSchemaTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Common/CommonSchemaTest.php b/tests/Common/CommonSchemaTest.php index 1fb76f9e9..338cfea7d 100644 --- a/tests/Common/CommonSchemaTest.php +++ b/tests/Common/CommonSchemaTest.php @@ -411,13 +411,13 @@ public function testHasTable(): void $schema = $db->getSchema(); - $this->assertTrue($schema->hasTable('customer')); + $this->assertTrue($schema->hasTable('order')); $this->assertTrue($schema->hasTable('category')); $this->assertFalse($schema->hasTable('no_such_table')); - $db->createCommand()->dropTable('category')->execute(); + $db->createCommand()->dropTable('order')->execute(); - $this->assertFalse($schema->hasTable('category', '', true)); + $this->assertFalse($schema->hasTable('order', '', true)); $db->close(); } From 87ba24cb92a8b1d3c0cd77704f49d392542a5773 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Wed, 26 Mar 2025 14:54:42 +0500 Subject: [PATCH 020/137] Replace table name for testing --- tests/Common/CommonSchemaTest.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/Common/CommonSchemaTest.php b/tests/Common/CommonSchemaTest.php index 338cfea7d..394806f5e 100644 --- a/tests/Common/CommonSchemaTest.php +++ b/tests/Common/CommonSchemaTest.php @@ -19,6 +19,7 @@ use Yiisoft\Db\Exception\InvalidCallException; use Yiisoft\Db\Exception\InvalidConfigException; use Yiisoft\Db\Exception\NotSupportedException; +use Yiisoft\Db\Schema\Column\ColumnBuilder; use Yiisoft\Db\Schema\TableSchemaInterface; use Yiisoft\Db\Tests\AbstractSchemaTest; use Yiisoft\Db\Tests\Support\AnyCaseValue; @@ -411,13 +412,20 @@ public function testHasTable(): void $schema = $db->getSchema(); + $tempTableName = 'testTemporaryTable'; + $db->createCommand()->createTable($tempTableName, [ + 'id' => ColumnBuilder::primaryKey(), + 'name' => ColumnBuilder::string()->notNull(), + ])->execute(); + $this->assertTrue($schema->hasTable('order')); $this->assertTrue($schema->hasTable('category')); + $this->assertTrue($schema->hasTable($tempTableName)); $this->assertFalse($schema->hasTable('no_such_table')); - $db->createCommand()->dropTable('order')->execute(); + $db->createCommand()->dropTable($tempTableName)->execute(); - $this->assertFalse($schema->hasTable('order', '', true)); + $this->assertFalse($schema->hasTable($tempTableName, '', true)); $db->close(); } From 1828d680aec5c407c22329d0b1b63f74568a24c2 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 10:51:12 +0500 Subject: [PATCH 021/137] Replace dropTable() method call with raw SQL query --- tests/Common/CommonSchemaTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Common/CommonSchemaTest.php b/tests/Common/CommonSchemaTest.php index 394806f5e..c3e0235b6 100644 --- a/tests/Common/CommonSchemaTest.php +++ b/tests/Common/CommonSchemaTest.php @@ -423,8 +423,9 @@ public function testHasTable(): void $this->assertTrue($schema->hasTable($tempTableName)); $this->assertFalse($schema->hasTable('no_such_table')); - $db->createCommand()->dropTable($tempTableName)->execute(); + $db->createCommand('DROP TABLE ' . $db->getQuoter()->quoteTableName($tempTableName))->execute(); + $this->assertTrue($schema->hasTable($tempTableName)); $this->assertFalse($schema->hasTable($tempTableName, '', true)); $db->close(); From b34c105329db47a04ebe79648d94c0fda4789ae3 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 11:23:36 +0500 Subject: [PATCH 022/137] Update UPGRADE docs --- UPGRADE.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/UPGRADE.md b/UPGRADE.md index a38216a74..ab3639b34 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -124,7 +124,10 @@ Each table column has its own class in the `Yiisoft\Db\Schema\Column` namespace - `QueryBuilderInterface::prepareValue()` - converts a value to its SQL representation; - `QueryBuilderInterface::getColumnFactory()` - returns the column factory object for concrete DBMS; - `QueryBuilderInterface::getServerInfo()` - returns `ServerInfoInterface` instance which provides server information; -- `LikeConditionInterface::getCaseSensitive()` - returns whether the comparison is case-sensitive. +- `LikeConditionInterface::getCaseSensitive()` - returns whether the comparison is case-sensitive; +- `SchemaInterface::hasTable()` - returns whether the specified table exists in database; +- `SchemaInterface::hasSchema()` - returns whether the specified schema exists in database; +- `SchemaInterface::hasView()` - returns whether the specified view exists in database; ### Remove methods From d126e1f72ea1ea065bbe74e8bcf78d83ce170f51 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 14:41:52 +0500 Subject: [PATCH 023/137] Test for 65535 records limit --- tests/AbstractCommandTest.php | 41 +++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index 899e8757f..019e613d7 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -14,6 +14,7 @@ use Yiisoft\Db\Profiler\Context\CommandContext; use Yiisoft\Db\Profiler\ContextInterface; use Yiisoft\Db\Profiler\ProfilerInterface; +use Yiisoft\Db\Schema\Column\ColumnBuilder; use Yiisoft\Db\Tests\Support\DbHelper; use Yiisoft\Db\Tests\Support\TestTrait; @@ -277,4 +278,44 @@ public function end(string $token, ContextInterface|array $context = []): void $db->createCommand($sql)->execute(); } + + public function testBindParamsOverflowIssue(): void + { + $db = $this->getConnection(); + $db->open(); + + $tempTableName = 'testTempTable'; + $db->createCommand()->createTable($tempTableName, [ + 'id' => ColumnBuilder::primaryKey(), + 'first_name' => ColumnBuilder::string()->notNull(), + 'last_name' => ColumnBuilder::string()->notNull(), + 'birth_date' => ColumnBuilder::date(), + 'country' => ColumnBuilder::string(), + 'city' => ColumnBuilder::string(), + 'address' => ColumnBuilder::string(), + ])->execute(); + + $personData = [ + 'first_name' => 'IVAN', + 'last_name' => 'PUPKIN', + 'birth_date' => '1983-08-08', + 'country' => 'Kazakhstan', + 'city' => 'Almaty', + 'address' => '7, Gagarin street, apartment 10', + ]; + + $insertData = []; + for ($i = 0; $i < 10000; $i++) { + $insertData[] = $personData; + } + + $command = $db->createCommand(); + $command->insertBatch($tempTableName, $insertData)->execute(); + + $this->expectException(\PDOException::class); + $this->expectExceptionMessageMatches('/General error\w+number of parameters must be between \d+ and \d+/ui'); + + $db->createCommand()->dropTable($tempTableName)->execute(); + $db->close(); + } } From 020c3f3be1f10855d9f3f830eb872a5b5473098b Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 14:46:29 +0500 Subject: [PATCH 024/137] Test for 65535 records limit --- tests/AbstractCommandTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index 019e613d7..cec001df3 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -312,8 +312,10 @@ public function testBindParamsOverflowIssue(): void $command = $db->createCommand(); $command->insertBatch($tempTableName, $insertData)->execute(); - $this->expectException(\PDOException::class); - $this->expectExceptionMessageMatches('/General error\w+number of parameters must be between \d+ and \d+/ui'); + if ($db->getDriverName() === 'pgsql') { + $this->expectException(\PDOException::class); + $this->expectExceptionMessageMatches('/General error\w+number of parameters must be between \d+ and \d+/ui'); + } $db->createCommand()->dropTable($tempTableName)->execute(); $db->close(); From f723c72f5e920e6ce84306c57fc0a2605eb1ac07 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 14:53:15 +0500 Subject: [PATCH 025/137] Test for 65535 records limit --- tests/AbstractCommandTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index cec001df3..cfea086f4 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -317,6 +317,9 @@ public function testBindParamsOverflowIssue(): void $this->expectExceptionMessageMatches('/General error\w+number of parameters must be between \d+ and \d+/ui'); } + $countSql = 'SELECT COUNT(*) FROM ' . $db->getQuoter()->quoteTableName($tempTableName); + $this->assertEquals(10000, $db->createCommand($countSql)->queryScalar()); + $db->createCommand()->dropTable($tempTableName)->execute(); $db->close(); } From 4b5d89cdded467b7298be5a916261f7ee5f206e6 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 14:59:41 +0500 Subject: [PATCH 026/137] Test for 65535 records limit --- tests/AbstractCommandTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index cfea086f4..943f14189 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -309,8 +309,7 @@ public function testBindParamsOverflowIssue(): void $insertData[] = $personData; } - $command = $db->createCommand(); - $command->insertBatch($tempTableName, $insertData)->execute(); + $db->createCommand()->insertBatch($tempTableName, $insertData)->execute(); if ($db->getDriverName() === 'pgsql') { $this->expectException(\PDOException::class); From 397303316168f33cacc5178096e425c6052c6215 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 15:10:57 +0500 Subject: [PATCH 027/137] Test for 65535 records limit --- tests/AbstractCommandTest.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index 943f14189..2ad607c1a 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -311,9 +311,13 @@ public function testBindParamsOverflowIssue(): void $db->createCommand()->insertBatch($tempTableName, $insertData)->execute(); - if ($db->getDriverName() === 'pgsql') { + if ($db->getDriverName() === 'pgsql' || $db->getDriverName() === 'sqlite') { $this->expectException(\PDOException::class); - $this->expectExceptionMessageMatches('/General error\w+number of parameters must be between \d+ and \d+/ui'); + if ($db->getDriverName() === 'pgsql') { + $this->expectExceptionMessageMatches('/General error:\w+number of parameters must be between \d+ and \d+/ui'); + } elseif ($db->getDriverName() === 'sqlite') { + $this->expectExceptionMessageMatches('/General error:\w+too many SQL variables'); + } } $countSql = 'SELECT COUNT(*) FROM ' . $db->getQuoter()->quoteTableName($tempTableName); From 449714d14f6a455e8c57f9159eef74ffc60fe4c8 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 15:13:10 +0500 Subject: [PATCH 028/137] Test for 65535 records limit --- tests/AbstractCommandTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index 2ad607c1a..051aa468d 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -316,7 +316,7 @@ public function testBindParamsOverflowIssue(): void if ($db->getDriverName() === 'pgsql') { $this->expectExceptionMessageMatches('/General error:\w+number of parameters must be between \d+ and \d+/ui'); } elseif ($db->getDriverName() === 'sqlite') { - $this->expectExceptionMessageMatches('/General error:\w+too many SQL variables'); + $this->expectExceptionMessageMatches('/General error:\w+too many SQL variables/ui'); } } From e2672249ba4ae7299bcce6788189b99ab39f7a4e Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 15:29:58 +0500 Subject: [PATCH 029/137] Test for 65535 records limit --- tests/AbstractCommandTest.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index 051aa468d..3a4c9f786 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -311,14 +311,14 @@ public function testBindParamsOverflowIssue(): void $db->createCommand()->insertBatch($tempTableName, $insertData)->execute(); - if ($db->getDriverName() === 'pgsql' || $db->getDriverName() === 'sqlite') { - $this->expectException(\PDOException::class); - if ($db->getDriverName() === 'pgsql') { - $this->expectExceptionMessageMatches('/General error:\w+number of parameters must be between \d+ and \d+/ui'); - } elseif ($db->getDriverName() === 'sqlite') { - $this->expectExceptionMessageMatches('/General error:\w+too many SQL variables/ui'); - } - } +// if ($db->getDriverName() === 'pgsql' || $db->getDriverName() === 'sqlite') { +// $this->expectException(\PDOException::class); +// if ($db->getDriverName() === 'pgsql') { +// $this->expectExceptionMessageMatches('/General error:\w+number of parameters must be between \d+ and \d+/ui'); +// } elseif ($db->getDriverName() === 'sqlite') { +// $this->expectExceptionMessageMatches('/General error:\w+too many SQL variables/ui'); +// } +// } $countSql = 'SELECT COUNT(*) FROM ' . $db->getQuoter()->quoteTableName($tempTableName); $this->assertEquals(10000, $db->createCommand($countSql)->queryScalar()); From 4b3bc67a6a64eb8dbad1d9692cde8e6571a5b7b7 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 15:32:58 +0500 Subject: [PATCH 030/137] Test for 65535 records limit --- tests/AbstractCommandTest.php | 92 +++++++++++++++++------------------ 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index 3a4c9f786..3fdc48e72 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -279,51 +279,51 @@ public function end(string $token, ContextInterface|array $context = []): void $db->createCommand($sql)->execute(); } - public function testBindParamsOverflowIssue(): void - { - $db = $this->getConnection(); - $db->open(); - - $tempTableName = 'testTempTable'; - $db->createCommand()->createTable($tempTableName, [ - 'id' => ColumnBuilder::primaryKey(), - 'first_name' => ColumnBuilder::string()->notNull(), - 'last_name' => ColumnBuilder::string()->notNull(), - 'birth_date' => ColumnBuilder::date(), - 'country' => ColumnBuilder::string(), - 'city' => ColumnBuilder::string(), - 'address' => ColumnBuilder::string(), - ])->execute(); - - $personData = [ - 'first_name' => 'IVAN', - 'last_name' => 'PUPKIN', - 'birth_date' => '1983-08-08', - 'country' => 'Kazakhstan', - 'city' => 'Almaty', - 'address' => '7, Gagarin street, apartment 10', - ]; - - $insertData = []; - for ($i = 0; $i < 10000; $i++) { - $insertData[] = $personData; - } - - $db->createCommand()->insertBatch($tempTableName, $insertData)->execute(); - -// if ($db->getDriverName() === 'pgsql' || $db->getDriverName() === 'sqlite') { -// $this->expectException(\PDOException::class); -// if ($db->getDriverName() === 'pgsql') { -// $this->expectExceptionMessageMatches('/General error:\w+number of parameters must be between \d+ and \d+/ui'); -// } elseif ($db->getDriverName() === 'sqlite') { -// $this->expectExceptionMessageMatches('/General error:\w+too many SQL variables/ui'); -// } +// public function testBindParamsOverflowIssue(): void +// { +// $db = $this->getConnection(); +// $db->open(); +// +// $tempTableName = 'testTempTable'; +// $db->createCommand()->createTable($tempTableName, [ +// 'id' => ColumnBuilder::primaryKey(), +// 'first_name' => ColumnBuilder::string()->notNull(), +// 'last_name' => ColumnBuilder::string()->notNull(), +// 'birth_date' => ColumnBuilder::date(), +// 'country' => ColumnBuilder::string(), +// 'city' => ColumnBuilder::string(), +// 'address' => ColumnBuilder::string(), +// ])->execute(); +// +// $personData = [ +// 'first_name' => 'IVAN', +// 'last_name' => 'PUPKIN', +// 'birth_date' => '1983-08-08', +// 'country' => 'Kazakhstan', +// 'city' => 'Almaty', +// 'address' => '7, Gagarin street, apartment 10', +// ]; +// +// $insertData = []; +// for ($i = 0; $i < 10000; $i++) { +// $insertData[] = $personData; // } - - $countSql = 'SELECT COUNT(*) FROM ' . $db->getQuoter()->quoteTableName($tempTableName); - $this->assertEquals(10000, $db->createCommand($countSql)->queryScalar()); - - $db->createCommand()->dropTable($tempTableName)->execute(); - $db->close(); - } +// +// $db->createCommand()->insertBatch($tempTableName, $insertData)->execute(); +// +//// if ($db->getDriverName() === 'pgsql' || $db->getDriverName() === 'sqlite') { +//// $this->expectException(\PDOException::class); +//// if ($db->getDriverName() === 'pgsql') { +//// $this->expectExceptionMessageMatches('/General error:\w+number of parameters must be between \d+ and \d+/ui'); +//// } elseif ($db->getDriverName() === 'sqlite') { +//// $this->expectExceptionMessageMatches('/General error:\w+too many SQL variables/ui'); +//// } +//// } +// +// $countSql = 'SELECT COUNT(*) FROM ' . $db->getQuoter()->quoteTableName($tempTableName); +// $this->assertEquals(10000, $db->createCommand($countSql)->queryScalar()); +// +// $db->createCommand()->dropTable($tempTableName)->execute(); +// $db->close(); +// } } From eabb05bab3343be862775f9f5b5ceb713dd7d12f Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 15:48:20 +0500 Subject: [PATCH 031/137] Test for 65535 records limit --- tests/AbstractCommandTest.php | 86 +++++++++++++++++------------------ 1 file changed, 41 insertions(+), 45 deletions(-) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index 3fdc48e72..636bde85c 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -279,51 +279,47 @@ public function end(string $token, ContextInterface|array $context = []): void $db->createCommand($sql)->execute(); } -// public function testBindParamsOverflowIssue(): void -// { -// $db = $this->getConnection(); -// $db->open(); -// -// $tempTableName = 'testTempTable'; -// $db->createCommand()->createTable($tempTableName, [ -// 'id' => ColumnBuilder::primaryKey(), -// 'first_name' => ColumnBuilder::string()->notNull(), -// 'last_name' => ColumnBuilder::string()->notNull(), -// 'birth_date' => ColumnBuilder::date(), -// 'country' => ColumnBuilder::string(), -// 'city' => ColumnBuilder::string(), -// 'address' => ColumnBuilder::string(), -// ])->execute(); -// -// $personData = [ -// 'first_name' => 'IVAN', -// 'last_name' => 'PUPKIN', -// 'birth_date' => '1983-08-08', -// 'country' => 'Kazakhstan', -// 'city' => 'Almaty', -// 'address' => '7, Gagarin street, apartment 10', -// ]; -// -// $insertData = []; -// for ($i = 0; $i < 10000; $i++) { -// $insertData[] = $personData; -// } -// -// $db->createCommand()->insertBatch($tempTableName, $insertData)->execute(); -// -//// if ($db->getDriverName() === 'pgsql' || $db->getDriverName() === 'sqlite') { -//// $this->expectException(\PDOException::class); -//// if ($db->getDriverName() === 'pgsql') { -//// $this->expectExceptionMessageMatches('/General error:\w+number of parameters must be between \d+ and \d+/ui'); -//// } elseif ($db->getDriverName() === 'sqlite') { -//// $this->expectExceptionMessageMatches('/General error:\w+too many SQL variables/ui'); -//// } -//// } -// + public function testBindParamsOverflowIssue(): void + { + $db = $this->getConnection(); + + if ($db->getDriverName() !== 'pgsql') { + $this->markTestSkipped('Test is intended for use with pgsql database.'); + } + + $tempTableName = 'testTempTable'; + $db->createCommand()->createTable($tempTableName, [ + 'id' => ColumnBuilder::primaryKey(), + 'first_name' => ColumnBuilder::string()->notNull(), + 'last_name' => ColumnBuilder::string()->notNull(), + 'birth_date' => ColumnBuilder::date(), + 'country' => ColumnBuilder::string(), + 'city' => ColumnBuilder::string(), + 'address' => ColumnBuilder::string(), + ])->execute(); + + $personData = [ + 'first_name' => 'IVAN', + 'last_name' => 'PUPKIN', + 'birth_date' => '1983-08-08', + 'country' => 'Kazakhstan', + 'city' => 'Almaty', + 'address' => '7, Gagarin street, apartment 10', + ]; + + $insertData = []; + for ($i = 0; $i < 10000; $i++) { + $insertData[] = $personData; + } + + $db->createCommand()->insertBatch($tempTableName, $insertData)->execute(); + + $this->expectException(\PDOException::class); + $this->expectExceptionMessageMatches('/General error:\w+number of parameters must be between \d+ and \d+/ui'); + // $countSql = 'SELECT COUNT(*) FROM ' . $db->getQuoter()->quoteTableName($tempTableName); // $this->assertEquals(10000, $db->createCommand($countSql)->queryScalar()); -// -// $db->createCommand()->dropTable($tempTableName)->execute(); -// $db->close(); -// } + + $db->createCommand()->dropTable($tempTableName)->execute(); + } } From d8979b170efbe5afc3b998a97d23535e942d8209 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 15:56:59 +0500 Subject: [PATCH 032/137] Close DB connection after test --- tests/AbstractCommandTest.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index 636bde85c..f1239a5cf 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -49,6 +49,7 @@ public function testAutoQuoting(): void ), $command->getSql(), ); + $db->close(); } /** @@ -70,6 +71,7 @@ public function testConstruct(): void $this->assertSame($sql, $command->getSql()); $this->assertSame([':name' => 'John Doe'], $command->getParams()); + $db->close(); } /** @@ -107,6 +109,7 @@ public function testGetParams(): void $this->assertContainsOnlyInstancesOf(ParamInterface::class, $bindedValues); $this->assertCount(3, $bindedValues); $this->assertEquals($param, $bindedValues['int']); + $db->close(); } /** @@ -128,6 +131,7 @@ public function testGetRawSql(string $sql, array $params, string $expectedRawSql $command = $db->createCommand($sql, $params); $this->assertSame($expectedRawSql, $command->getRawSql()); + $db->close(); } /** @@ -149,6 +153,7 @@ public function testGetSetSql(): void SQL; $command->setSql($sql2); $this->assertSame($sql2, $command->getSql()); + $db->close(); } /** @@ -175,6 +180,7 @@ public function testPrepareCancel(): void $command->cancel(); $this->assertNull($command->getPdoStatement()); + $db->close(); } /** @@ -194,6 +200,7 @@ public function testSetRawSql(): void ); $this->assertSame('SELECT 123', $command->getRawSql()); + $db->close(); } /** @@ -212,6 +219,7 @@ public function testSetSql(): void ); $this->assertSame('SELECT 123', $command->getSql()); + $db->close(); } /** @@ -237,6 +245,7 @@ public function testProfiler(?string $sql = null): void $db->setProfiler($profiler); $db->createCommand($sql)->execute(); + $db->close(); } /** @@ -277,6 +286,7 @@ public function end(string $token, ContextInterface|array $context = []): void $db->setProfiler($profiler); $db->createCommand($sql)->execute(); + $db->close(); } public function testBindParamsOverflowIssue(): void @@ -321,5 +331,6 @@ public function testBindParamsOverflowIssue(): void // $this->assertEquals(10000, $db->createCommand($countSql)->queryScalar()); $db->createCommand()->dropTable($tempTableName)->execute(); + $db->close(); } } From c1bf4f80817e19f4ced4316d31dd992b2c9e306e Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 16:05:13 +0500 Subject: [PATCH 033/137] Close all DB connection after tests --- tests/Common/CommonCommandTest.php | 9 +++++++ tests/Db/Command/CommandTest.php | 40 ++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/tests/Common/CommonCommandTest.php b/tests/Common/CommonCommandTest.php index f84896572..a30ff02b1 100644 --- a/tests/Common/CommonCommandTest.php +++ b/tests/Common/CommonCommandTest.php @@ -1099,6 +1099,7 @@ public function testExecute(): void $this->expectExceptionMessage($message); $command->execute(); + $db->close(); } /** @@ -1470,6 +1471,7 @@ public function testInsertSelectFailed(array|ExpressionInterface|string $invalid $this->expectExceptionMessage('Expected select query object with enumerated (named) parameters'); $command->insert('{{customer}}', $query)->execute(); + $db->close(); } /** @@ -1524,6 +1526,7 @@ public function testIntegrityViolation(): void ); $command->execute(); $command->execute(); + $db->close(); } /** @@ -1616,6 +1619,7 @@ public function testQuery(): void $this->expectException(Exception::class); $command->query(); + $db->close(); } /** @@ -2045,6 +2049,7 @@ protected function internalExecute(): void }; $command->prepare(); + $db->close(); } /** @@ -2099,6 +2104,7 @@ public function testDecimalValue(): void $phpTypecastValue = $column->phpTypecast($result['total']); $this->assertSame($decimalValue, $phpTypecastValue); + $db->close(); } public function testInsertWithReturningPksEmptyValues() @@ -2113,6 +2119,7 @@ public function testInsertWithReturningPksEmptyValues() }; $this->assertSame($expected, $pkValues); + $db->close(); } public function testInsertWithReturningPksEmptyValuesAndNoPk() @@ -2122,6 +2129,7 @@ public function testInsertWithReturningPksEmptyValuesAndNoPk() $pkValues = $db->createCommand()->insertWithReturningPks('negative_default_values', []); $this->assertSame([], $pkValues); + $db->close(); } public function testUuid(): void @@ -2212,5 +2220,6 @@ public function testJsonTable(): void $value = (new Query($db))->select('json_col')->from('json_table')->where(['id' => 1])->scalar(); $this->assertSame('{"a":1,"b":2}', str_replace(' ', '', $value)); + $db->close(); } } diff --git a/tests/Db/Command/CommandTest.php b/tests/Db/Command/CommandTest.php index 62cbfae36..32ef6863b 100644 --- a/tests/Db/Command/CommandTest.php +++ b/tests/Db/Command/CommandTest.php @@ -42,6 +42,7 @@ public function testAddCheck(): void ), $sql, ); + $db->close(); } /** @dataProvider \Yiisoft\Db\Tests\Provider\CommandProvider::columnTypes */ @@ -63,6 +64,7 @@ public function testAddColumn(ColumnInterface|string $type): void ), $sql, ); + $db->close(); } public function testAddCommentOnColumn(): void @@ -81,6 +83,7 @@ public function testAddCommentOnColumn(): void ), $sql, ); + $db->close(); } public function testAddCommentOnTable(): void @@ -99,6 +102,7 @@ public function testAddCommentOnTable(): void ), $sql, ); + $db->close(); } public function testAddDefaultValue(): void @@ -113,6 +117,7 @@ public function testAddDefaultValue(): void ); $command->addDefaultValue('table', 'name', 'column', 'value'); + $db->close(); } /** @@ -135,6 +140,7 @@ public function testAddForeignKeySql( $sql = $command->addForeignKey($tableName, $name, $columns, $referenceTable, $referenceColumns, $delete, $update)->getSql(); $this->assertSame($expected, $sql); + $db->close(); } /** @@ -149,6 +155,7 @@ public function testAddPrimaryKeySql(string $name, string $tableName, array|stri $this->assertSame($expected, $sql); + $db->close(); } /** @@ -162,6 +169,7 @@ public function testAddUniqueSql(string $name, string $tableName, array|string $ $sql = $command->addUnique($tableName, $name, $column)->getSql(); $this->assertSame($expected, $sql); + $db->close(); } public function testAlterColumn(): void @@ -180,6 +188,7 @@ public function testAlterColumn(): void ), $sql, ); + $db->close(); } public function testBatchInsert(): void @@ -199,6 +208,7 @@ public function testBatchInsert(): void ], $command->getParams() ); + $db->close(); } /** @@ -219,6 +229,7 @@ public function testCreateIndexSql( $sql = $command->createIndex($table, $name, $column, $indexType, $indexMethod)->getSql(); $this->assertSame($expected, $sql); + $db->close(); } public function testCheckIntegrity(): void @@ -233,6 +244,7 @@ public function testCheckIntegrity(): void ); $command->checkIntegrity('schema', 'table')->execute(); + $db->close(); } public function testCreateTable(): void @@ -269,6 +281,7 @@ public function testCreateTable(): void $sql = $command->createTable('test_table', $columns, $options)->getSql(); Assert::equalsWithoutLE($expected, $sql); + $db->close(); } public function testCreateView(): void @@ -293,6 +306,7 @@ public function testCreateView(): void ), $sql, ); + $db->close(); } public function testDelete(): void @@ -311,6 +325,7 @@ public function testDelete(): void ), $sql, ); + $db->close(); } public function testDropCheck(): void @@ -329,6 +344,7 @@ public function testDropCheck(): void ), $sql, ); + $db->close(); } public function testDropColumn(): void @@ -347,6 +363,7 @@ public function testDropColumn(): void ), $sql, ); + $db->close(); } public function testDropCommentFromColumn(): void @@ -365,6 +382,7 @@ public function testDropCommentFromColumn(): void ), $sql, ); + $db->close(); } public function testDropCommentFromTable(): void @@ -383,6 +401,7 @@ public function testDropCommentFromTable(): void ), $sql, ); + $db->close(); } public function testDropDefaultValue(): void @@ -397,6 +416,7 @@ public function testDropDefaultValue(): void ); $command->dropDefaultValue('table', 'column'); + $db->close(); } public function testDropForeingKey(): void @@ -415,6 +435,7 @@ public function testDropForeingKey(): void ), $sql, ); + $db->close(); } public function testDropIndex(): void @@ -433,6 +454,7 @@ public function testDropIndex(): void ), $sql, ); + $db->close(); } public function testDropPrimaryKey(): void @@ -451,6 +473,7 @@ public function testDropPrimaryKey(): void ), $sql, ); + $db->close(); } public function testDropView(): void @@ -469,6 +492,7 @@ public function testDropView(): void ), $sql, ); + $db->close(); } #[DataProviderExternal(CommandProvider::class, 'dropTable')] @@ -490,6 +514,7 @@ public function testDropTable(string $expected, ?bool $ifExists, ?bool $cascade) $expectedSql = DbHelper::replaceQuotes($expected, $db->getDriverName()); $this->assertSame($expectedSql, $command->getSql()); + $db->close(); } public function testDropUnique(): void @@ -508,6 +533,7 @@ public function testDropUnique(): void ), $sql, ); + $db->close(); } public function testExecute(): void @@ -522,6 +548,7 @@ public function testExecute(): void ); $command->createTable('customer', ['id' => 'pk'])->execute(); + $db->close(); } public function testInsert(): void @@ -543,6 +570,7 @@ public function testInsert(): void ], $command->getParams(), ); + $db->close(); } public function testQuery(): void @@ -562,6 +590,7 @@ public function testQuery(): void ); $command->query(); + $db->close(); } public function testQueryAll(): void @@ -581,6 +610,7 @@ public function testQueryAll(): void ); $command->queryAll(); + $db->close(); } public function testQueryColumn(): void @@ -600,6 +630,7 @@ public function testQueryColumn(): void ); $command->queryColumn(); + $db->close(); } public function testQueryOne(): void @@ -617,6 +648,7 @@ public function testQueryOne(): void ); $command->setSql($sql)->queryOne(); + $db->close(); } public function testQueryScalar(): void @@ -634,6 +666,7 @@ public function testQueryScalar(): void ); $this->assertEquals(1, $command->setSql($sql)->queryScalar()); + $db->close(); } public function testRenameColumn(): void @@ -651,6 +684,7 @@ public function testRenameColumn(): void ), $sql, ); + $db->close(); } public function testRenameTable(): void @@ -668,6 +702,7 @@ public function testRenameTable(): void ), $sql, ); + $db->close(); } public function testResetSequence(): void @@ -680,6 +715,7 @@ public function testResetSequence(): void ); $db->createCommand()->resetSequence('table', 5); + $db->close(); } public function testSetRetryHandler(): void @@ -691,6 +727,7 @@ public function testSetRetryHandler(): void $command->setRetryHandler($handler); $this->assertSame($handler, Assert::getInaccessibleProperty($command, 'retryHandler')); + $db->close(); } public function testTruncateTable(): void @@ -709,6 +746,7 @@ public function testTruncateTable(): void ), $sql, ); + $db->close(); } public function testUpdate(): void @@ -720,6 +758,7 @@ public function testUpdate(): void $this->assertSame('UPDATE [table] SET [name]=:qp0 WHERE [id]=:qp1', $command->getSql()); $this->assertSame([':qp0' => 'John', ':qp1' => 1], $command->getParams()); + $db->close(); } public function testUpsert(): void @@ -734,6 +773,7 @@ public function testUpsert(): void ); $command->upsert('{{table}}', []); + $db->close(); } public function testProfiler(?string $sql = null): void From a808c98f3d70a6adea108d810c65a9156c0f7bc2 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 16:10:57 +0500 Subject: [PATCH 034/137] Close all DB connection after tests --- tests/Db/Query/QueryTest.php | 5 +++++ tests/Db/QueryBuilder/QueryBuilderTest.php | 19 +++++++++++++++++++ tests/Db/Schema/SchemaTest.php | 17 +++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/tests/Db/Query/QueryTest.php b/tests/Db/Query/QueryTest.php index ca85c071f..0595e68f3 100644 --- a/tests/Db/Query/QueryTest.php +++ b/tests/Db/Query/QueryTest.php @@ -37,6 +37,7 @@ public function testColumn(): void ); (new Query($db))->select('name')->from('customer')->orderBy(['id' => SORT_DESC])->column(); + $db->close(); } /** @@ -54,6 +55,7 @@ public function testCount(): void ); (new Query($db))->from('customer')->count(); + $db->close(); } public function testExists(): void @@ -66,6 +68,7 @@ public function testExists(): void ); (new Query($db))->from('customer')->where(['status' => 2])->exists(); + $db->close(); } /** @@ -86,6 +89,7 @@ public function testLimitOffsetWithExpression(): void ); $query->column(); + $db->close(); } /** @@ -103,6 +107,7 @@ public function testOne(): void ); (new Query($db))->from('customer')->where(['status' => 2])->one(); + $db->close(); } public function testColumnWithIndexBy(): void diff --git a/tests/Db/QueryBuilder/QueryBuilderTest.php b/tests/Db/QueryBuilder/QueryBuilderTest.php index 8ace1896e..d72d8ca2b 100644 --- a/tests/Db/QueryBuilder/QueryBuilderTest.php +++ b/tests/Db/QueryBuilder/QueryBuilderTest.php @@ -47,6 +47,7 @@ public function testAddDefaultValue(): void ); $qb->addDefaultValue('table', 'name', 'column', 'value'); + $db->close(); } /** @@ -67,6 +68,8 @@ public function testBatchInsert( $this->assertSame($expected, $qb->insertBatch($table, $rows, $columns, $params)); $this->assertSame($expectedParams, $params); } catch (InvalidArgumentException|Exception) { + } finally { + $db->close(); } } @@ -82,6 +85,7 @@ public function testBuildJoinException(): void $qb = $db->getQueryBuilder(); $params = []; $qb->buildJoin(['admin_profile', 'admin_user.id = admin_profile.user_id'], $params); + $db->close(); } /** @@ -98,6 +102,7 @@ public function testCheckIntegrity(): void $qb = $db->getQueryBuilder(); $qb->checkIntegrity('schema', 'table'); + $db->close(); } public function testCreateTable(): void @@ -132,6 +137,7 @@ public function testCreateTable(): void ], ), ); + $db->close(); } /** @@ -151,6 +157,7 @@ public function testCreateView(): void SQL, $qb->createView('testCreateView', $subQuery) ); + $db->close(); } /** @@ -168,6 +175,7 @@ public function testDropDefaultValue(): void ); $qb->dropDefaultValue('T_constraints_1', 'CN_pk'); + $db->close(); } /** @@ -183,6 +191,7 @@ public function testGetExpressionBuilderException(): void }; $qb = $db->getQueryBuilder(); $qb->getExpressionBuilder($expression); + $db->close(); } /** @@ -202,6 +211,7 @@ public function testInsert( $this->assertSame($expectedSQL, $qb->insert($table, $columns, $params)); $this->assertEquals($expectedParams, $params); + $db->close(); } /** @@ -224,6 +234,7 @@ public function testInsertWithReturningPks( ); $qb->insertWithReturningPks($table, $columns, $params); + $db->close(); } /** @@ -241,6 +252,7 @@ public function testResetSequence(): void ); $qb->resetSequence('T_constraints_1', 'id'); + $db->close(); } /** @@ -264,6 +276,7 @@ public function testUpdate( $this->assertSame($expectedSql, $sql); $this->assertEquals($expectedParams, $params); + $db->close(); } /** @@ -290,6 +303,7 @@ public function testUpsert( ); $db->getQueryBuilder()->upsert($table, $insertColumns, $updateColumns, $actualParams); + $db->close(); } /** @@ -309,6 +323,7 @@ public function testUpsertExecute( $actualParams = []; $actualSQL = $db->getQueryBuilder()->upsert($table, $insertColumns, $updateColumns, $actualParams); + $db->close(); } public function testPrepareValueClosedResource(): void @@ -322,6 +337,7 @@ public function testPrepareValueClosedResource(): void fclose($resource); $qb->prepareValue($resource); + $db->close(); } public function testPrepareValueNonStreamResource(): void @@ -332,6 +348,7 @@ public function testPrepareValueNonStreamResource(): void $this->expectExceptionObject(new InvalidArgumentException('Supported only stream resource type.')); $qb->prepareValue(stream_context_create()); + $db->close(); } public function testGetServerInfo(): void @@ -340,6 +357,7 @@ public function testGetServerInfo(): void $qb = $db->getQueryBuilder(); $this->assertInstanceOf(ServerInfoInterface::class, $qb->getServerInfo()); + $db->close(); } public function testJsonColumn(): void @@ -371,5 +389,6 @@ public function testJsonColumn(): void ), $qb->alterColumn('json_table', 'json_col', $column), ); + $db->close(); } } diff --git a/tests/Db/Schema/SchemaTest.php b/tests/Db/Schema/SchemaTest.php index 60cd54cb0..6d2f05cd6 100644 --- a/tests/Db/Schema/SchemaTest.php +++ b/tests/Db/Schema/SchemaTest.php @@ -42,6 +42,7 @@ public function testFindTableNames(): void $this->expectExceptionMessage('Yiisoft\Db\Tests\Support\Stub\Schema does not support fetching all table names.'); Assert::invokeMethod($schema, 'findTableNames', ['dbo']); + $db->close(); } /** @@ -54,6 +55,7 @@ public function testFindViewNames(): void $schema = $db->getSchema(); $this->assertSame([], Assert::invokeMethod($schema, 'findViewNames', ['dbo'])); + $db->close(); } /** @@ -83,6 +85,7 @@ public function testGetSchemaChecks(): void $this->assertIsArray($checks); $this->assertContainsOnlyInstancesOf(CheckConstraint::class, $checks); } + $db->close(); } /** @@ -112,6 +115,7 @@ public function testGetSchemaDefaultValues(): void $this->assertIsArray($defaultValues); $this->assertContainsOnlyInstancesOf(DefaultValueConstraint::class, $defaultValues); } + $db->close(); } /** @@ -142,6 +146,7 @@ public function testGetSchemaForeignKeys(): void $this->assertIsArray($foreignKeys); $this->assertContainsOnlyInstancesOf(ForeignKeyConstraint::class, $foreignKeys); } + $db->close(); } /** @@ -172,6 +177,7 @@ public function testGetSchemaIndexes(): void $this->assertIsArray($indexes); $this->assertContainsOnlyInstancesOf(IndexConstraint::class, $indexes); } + $db->close(); } public function testGetSchemaNames(): void @@ -186,6 +192,7 @@ public function testGetSchemaNames(): void ); $schema->getSchemaNames(); + $db->close(); } /** @@ -200,6 +207,7 @@ public function testGetSchemaNamesWithSchema(): void Assert::setInaccessibleProperty($schema, 'schemaNames', ['dbo', 'public']); $this->assertSame(['dbo', 'public'], $schema->getSchemaNames()); + $db->close(); } public function testHasSchema(): void @@ -234,6 +242,7 @@ public function testGetSchemaPrimaryKeys(): void $this->assertIsArray($tablePks); $this->assertContainsOnlyInstancesOf(Constraint::class, $tablePks); + $db->close(); } /** @@ -258,6 +267,7 @@ public function testGetSchemaUniques(): void $this->assertIsArray($uniques); $this->assertContainsOnlyInstancesOf(Constraint::class, $uniques); } + $db->close(); } public function getTableSchema(): void @@ -278,6 +288,7 @@ public function getTableSchema(): void $this->assertSame('T_constraints_1', $table->getFullName()); $this->assertSame(['C_id'], $table->getPrimaryKey()); $this->assertSame(['C_id', 'C_not_null', 'C_check', 'C_default', 'C_unique'], $table->getColumnNames()); + $db->close(); } /** @@ -300,6 +311,7 @@ public function testGetTableSchemas(): void foreach ($tables as $table) { $this->assertInstanceOf(TableSchemaInterface::class, $table); } + $db->close(); } public function testGetViewNames(): void @@ -309,6 +321,7 @@ public function testGetViewNames(): void $schema = $db->getSchema(); $this->assertSame([], $schema->getViewNames()); + $db->close(); } public function testRefreshTableSchema(): void @@ -331,6 +344,7 @@ public function testRefreshTableSchema(): void $refreshedTable = $schemaMock->getTableSchema('T_constraints_1'); $this->assertNotSame($noCacheTable, $refreshedTable); + $db->close(); } public function testRefreshTableSchemaWithSchemaCaseDisabled(): void @@ -353,6 +367,7 @@ public function testRefreshTableSchemaWithSchemaCaseDisabled(): void $refreshedTable = $schemaMock->getTableSchema('T_constraints_1'); $this->assertNotSame($noCacheTable, $refreshedTable); + $db->close(); } /** @@ -368,6 +383,7 @@ public function testResolveTableName(): void $this->expectExceptionMessage('Yiisoft\Db\Tests\Support\Stub\Schema does not support resolving table names.'); Assert::invokeMethod($schema, 'resolveTableName', ['customer']); + $db->close(); } /** @@ -388,6 +404,7 @@ public function testSetTableMetadata(): void Assert::invokeMethod($schema, 'setTableMetadata', ['T_constraints_1', 'checks', $checkConstraint]); $this->assertSame($checkConstraint, $schema->getTableChecks('T_constraints_1')); + $db->close(); } private function createTableSchemaStub(): TableSchemaInterface From d9c59e7bdccb43bf6632d39baf08e50890786eec Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 17:13:16 +0500 Subject: [PATCH 035/137] Close all DB connection after tests --- tests/AbstractConnectionTest.php | 8 +++ tests/AbstractPdoConnectionTest.php | 11 +++- tests/AbstractQueryBuilderTest.php | 93 +++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 1 deletion(-) diff --git a/tests/AbstractConnectionTest.php b/tests/AbstractConnectionTest.php index 5c214e04a..48a007252 100644 --- a/tests/AbstractConnectionTest.php +++ b/tests/AbstractConnectionTest.php @@ -37,6 +37,7 @@ public function testCreateBatchQueryResult(): void $query = (new Query($db))->from('customer'); $this->assertInstanceOf(BatchQueryResult::class, $db->createBatchQueryResult($query)); + $db->close(); } /** @@ -56,6 +57,7 @@ public function testCreateCommand(): void $this->assertSame($sql, $command->getSql()); $this->assertSame($params, $command->getParams()); + $db->close(); } public function testGetDriverName(): void @@ -63,6 +65,7 @@ public function testGetDriverName(): void $db = $this->getConnection(); $this->assertSame($this->getDriverName(), $db->getDriverName()); + $db->close(); } /** @@ -84,6 +87,7 @@ function (PdoConnectionInterface $db) { $db->beginTransaction(); } ); + $db->close(); } public function testNotProfiler(): void @@ -101,6 +105,7 @@ public function testNotProfiler(): void $db->setProfiler(null); $this->assertNull(Assert::getInaccessibleProperty($db, 'profiler')); + $db->close(); } public function testProfiler(): void @@ -128,6 +133,7 @@ public function end(string $token, ContextInterface|array $context = []): void }; $db->setProfiler($profiler); $db->open(); + $db->close(); } public function testSetTablePrefix(): void @@ -137,6 +143,7 @@ public function testSetTablePrefix(): void $db->setTablePrefix('pre_'); $this->assertSame('pre_', $db->getTablePrefix()); + $db->close(); } public function testSerialized(): void @@ -151,6 +158,7 @@ public function testSerialized(): void $this->assertNull($unserialized->getPDO()); $this->assertEquals(123, $unserialized->createCommand('SELECT 123')->queryScalar()); $this->assertNotNull($connection->getPDO()); + $connection->close(); } private function getProfiler(): ProfilerInterface diff --git a/tests/AbstractPdoConnectionTest.php b/tests/AbstractPdoConnectionTest.php index 5dc21f364..c3a6bd32a 100644 --- a/tests/AbstractPdoConnectionTest.php +++ b/tests/AbstractPdoConnectionTest.php @@ -27,13 +27,17 @@ public function testClone(): void $this->assertNotSame($db, $db2); $this->assertNull($db2->getTransaction()); $this->assertNull($db2->getPDO()); + $db->close(); + $db2->close(); } public function testGetDriver(): void { - $driver = $this->getConnection()->getDriver(); + $db = $this->getConnection(); + $driver = $db->getDriver(); $this->assertInstanceOf(PdoDriverInterface::class, $driver); + $db->close(); } public function testGetServerInfo(): void @@ -41,6 +45,7 @@ public function testGetServerInfo(): void $db = $this->getConnection(); $this->assertInstanceOf(PdoServerInfo::class, $db->getServerInfo()); + $db->close(); } /** @@ -72,6 +77,7 @@ public function testOpenClose(): void $this->expectExceptionMessage('could not find driver'); $db->open(); + $db->close(); } /** @@ -107,6 +113,7 @@ public function testOpenCloseWithLogger(): void $this->expectExceptionMessage('could not find driver'); $db->open(); + $db->close(); } public function testQuoteValueNotString(): void @@ -116,6 +123,7 @@ public function testQuoteValueNotString(): void $value = $db->quoteValue(1); $this->assertSame(1, $value); + $db->close(); } public function testSetEmulatePrepare(): void @@ -127,6 +135,7 @@ public function testSetEmulatePrepare(): void $db->setEmulatePrepare(true); $this->assertTrue($db->getEmulatePrepare()); + $db->close(); } protected function getLogger(): LoggerInterface|MockObject diff --git a/tests/AbstractQueryBuilderTest.php b/tests/AbstractQueryBuilderTest.php index fb8c2f0b6..798666ef7 100644 --- a/tests/AbstractQueryBuilderTest.php +++ b/tests/AbstractQueryBuilderTest.php @@ -55,6 +55,7 @@ public function testAddCheck(): void ), $sql, ); + $db->close(); } /** @dataProvider \Yiisoft\Db\Tests\Provider\QueryBuilderProvider::columnTypes */ @@ -74,6 +75,7 @@ public function testAddColumn(ColumnInterface|string $type): void ), $sql, ); + $db->close(); } /** @@ -95,6 +97,7 @@ public function testAddCommentOnColumn(): void ), $sql, ); + $db->close(); } /** @@ -116,6 +119,7 @@ public function testAddCommentOnTable(): void ), $sql, ); + $db->close(); } /** @@ -138,6 +142,7 @@ public function testAddDefaultValue(): void ), $sql, ); + $db->close(); } /** @@ -162,6 +167,7 @@ public function testAddForeignKey( $sql = $qb->addForeignKey($table, $name, $columns, $refTable, $refColumns, $delete, $update); $this->assertSame($expected, $sql); + $db->close(); } /** @@ -175,6 +181,7 @@ public function testAddPrimaryKey(string $name, string $table, array|string $col $sql = $qb->addPrimaryKey($table, $name, $columns); $this->assertSame($expected, $sql); + $db->close(); } /** @@ -188,6 +195,7 @@ public function testAddUnique(string $name, string $table, array|string $columns $sql = $qb->addUnique($table, $name, $columns); $this->assertSame($expected, $sql); + $db->close(); } #[DataProviderExternal(QueryBuilderProvider::class, 'alterColumn')] @@ -196,6 +204,7 @@ public function testAlterColumn(string|ColumnInterface $type, string $expected): $qb = $this->getConnection()->getQueryBuilder(); $this->assertSame($expected, $qb->alterColumn('foo1', 'bar', $type)); + $db->close(); } /** @@ -221,6 +230,7 @@ public function testBatchInsert( $this->assertSame($expected, $sql); $this->assertSame($expectedParams, $params); + $db->close(); } #[DataProviderExternal(QueryBuilderProvider::class, 'buildCondition')] @@ -242,6 +252,7 @@ public function testBuildCondition( $sql ); $this->assertEquals($expectedParams, $params); + $db->close(); } /** @@ -255,6 +266,7 @@ public function testBuildColumnsWithString(): void $qb = $db->getQueryBuilder(); $this->assertSame('(id)', $qb->buildColumns('(id)')); + $db->close(); } /** @@ -271,6 +283,7 @@ public function testBuildColumnsWithArray(): void DbHelper::replaceQuotes('[[id]], [[name]], [[email]], [[address]], [[status]]', $db->getDriverName()), $qb->buildColumns(['id', 'name', 'email', 'address', 'status']), ); + $db->close(); } /** @@ -290,6 +303,7 @@ public function testBuildColumnsWithExpression(): void ), $qb->buildColumns(['id', 'name', 'email', 'address', 'status', new Expression('COUNT(*)')]), ); + $db->close(); } /** @@ -320,6 +334,7 @@ public function testBuildIssue15653(): void $sql, ); $this->assertSame([':qp0' => '1', ':qp1' => '0'], $params); + $db->close(); } /** @@ -346,6 +361,7 @@ public function testBuildFilterCondition(array $condition, string $expected, arr $sql, ); $this->assertSame($expectedParams, $params); + $db->close(); } /** @@ -370,6 +386,7 @@ public function testBuildFrom(): void ), $qb->buildFrom($query->getFrom(), $params), ); + $db->close(); } /** @@ -393,6 +410,7 @@ public function testBuildGroupBy(): void ), $qb->buildGroupBy($query->getGroupBy(), $params), ); + $db->close(); } /** @@ -418,6 +436,7 @@ public function testBuildHaving(): void ), $qb->buildHaving($query->getHaving(), $params), ); + $db->close(); } /** @@ -442,6 +461,7 @@ public function testBuildJoin(): void ), $qb->buildJoin($query->getJoins(), $params), ); + $db->close(); } #[DataProviderExternal(QueryBuilderProvider::class, 'buildLikeCondition')] @@ -472,6 +492,7 @@ public function testBuildLikeCondition( $this->assertSame($expectedParams[$name], $value); } } + $db->close(); } public function testBuildLimit(): void @@ -482,6 +503,7 @@ public function testBuildLimit(): void $query = (new Query($db))->from('admin_user')->limit(10); $this->assertSame('LIMIT 10', $qb->buildLimit($query->getLimit(), 0)); + $db->close(); } public function testBuildLimitOffset(): void @@ -492,6 +514,7 @@ public function testBuildLimitOffset(): void $query = (new Query($db))->from('admin_user')->limit(10)->offset(5); $this->assertSame('LIMIT 10 OFFSET 5', $qb->buildLimit($query->getLimit(), $query->getOffset())); + $db->close(); } /** @@ -515,6 +538,7 @@ public function testBuildOrderBy(): void ), $qb->buildOrderBy($query->getOrderBy(), $params), ); + $db->close(); } /** @@ -551,6 +575,7 @@ public function testBuildOrderByAndLimit(): void $query->getOffset(), ), ); + $db->close(); } /** @@ -576,6 +601,7 @@ public function testBuildSelect(): void ), $qb->buildSelect($query->getSelect(), $params), ); + $db->close(); } /** @@ -600,6 +626,7 @@ public function testBuildSelectWithAlias(): void ), $qb->buildSelect(['id as a'], $params), ); + $db->close(); } /** @@ -625,6 +652,7 @@ public function testBuildSelectWithDistinct(): void ), $qb->buildSelect($query->getSelect(), $params, true), ); + $db->close(); } /** @@ -650,6 +678,7 @@ public function testBuildUnion(): void ), $qb->buildUnion($query->getUnions(), $params), ); + $db->close(); } /** @@ -675,6 +704,7 @@ public function testBuildWithQueries(): void ), $qb->buildWithQueries($query->getWithQueries(), $params), ); + $db->close(); } /** @@ -722,6 +752,7 @@ public function testBuildWithComplexSelect(): void $sql, ); $this->assertEmpty($params); + $db->close(); } /** @@ -746,6 +777,7 @@ public function testBuildWithFrom( $this->assertSame($expectedSql, $sql); $this->assertSame($expectedParams, $params); + $db->close(); } /** @@ -774,6 +806,7 @@ public function testBuildWithFromAliasesNoExist(): void ); $this->assertSame([], $params); + $db->close(); } /** @@ -822,6 +855,7 @@ public function testBuildWithFromIndexHint(): void ); $this->assertEmpty($params); + $db->close(); } /** @@ -889,6 +923,7 @@ public function testBuildWithFromSubquery(): void $sql, ); $this->assertEmpty($params); + $db->close(); } /** @@ -973,6 +1008,7 @@ public function testBuildWithGroupBy(): void $sql, ); $this->assertSame([':to' => 4], $params); + $db->close(); } /** @@ -998,6 +1034,7 @@ public function testBuildWithLimit(): void ); $this->assertSame([], $params); + $db->close(); } /** @@ -1022,6 +1059,7 @@ public function testBuildWithOffset(): void $sql, ); $this->assertSame([], $params); + $db->close(); } /** @@ -1106,6 +1144,7 @@ public function testBuildWithOrderBy(): void $sql, ); $this->assertSame([':to' => 4], $params); + $db->close(); } /** @@ -1140,6 +1179,7 @@ public function testBuildWithQuery(): void ); $this->assertSame([], $params); + $db->close(); } /** @@ -1171,6 +1211,7 @@ public function testBuildWithQueryRecursive(): void $this->assertSame($expected, $sql); $this->assertSame([], $params); + $db->close(); } /** @dataProvider \Yiisoft\Db\Tests\Provider\QueryBuilderProvider::cteAliases */ @@ -1193,6 +1234,7 @@ public function testBuildWithQueryAlias($alias, $expected) $this->assertSame($expectedSql, $sql); $this->assertSame([], $params); + $db->close(); } /** @@ -1256,6 +1298,7 @@ public function testBuildWithSelectExpression(): void $sql, ); $this->assertSame([':len' => 4], $params); + $db->close(); } /** @@ -1284,6 +1327,7 @@ public function testBuildWithSelectSubquery(): void $sql, ); $this->assertEmpty($params); + $db->close(); } /** @@ -1309,6 +1353,7 @@ public function testBuildWithSelectOption(): void $this->assertSame($expected, $sql); $this->assertSame([], $params); + $db->close(); } /** @@ -1351,6 +1396,7 @@ public function testBuildWithSetSeparator(): void $sql, ); $this->assertEmpty($params); + $db->close(); } /** @@ -1386,6 +1432,7 @@ public function testBuildWithUnion(): void $sql, ); $this->assertSame([], $params); + $db->close(); } /** @@ -1411,6 +1458,7 @@ public function testBuildWithWhereExists(string $cond, string $expectedQuerySql) $this->assertSame($expectedQuerySql, $actualQuerySql); $this->assertSame($expectedQueryParams, $actualQueryParams); + $db->close(); } /** @@ -1447,6 +1495,7 @@ public function testBuildWithWhereExistsArrayParameters(): void $sql, ); $this->assertSame([':qp0' => 6, ':qp1' => 210, ':qp2' => 'asd'], $params); + $db->close(); } /** @@ -1483,6 +1532,7 @@ public function testBuildWithWhereExistsWithParameters(): void $sql, ); $this->assertSame([':some_value' => 'asd', ':merchant_id' => 6], $params); + $db->close(); } /** @@ -1532,6 +1582,7 @@ public function testsCreateConditionFromArray(): void ['a = 1', ['or', 'b = 2', ['and', 'c = 3', ['or', 'd = 4', 'e = 5']]]], $condition->getExpressions(), ); + $db->close(); } public function testCreateOverlapsConditionFromArray(): void @@ -1550,6 +1601,7 @@ public function testCreateOverlapsConditionFromArray(): void $this->assertInstanceOf(JsonOverlapsCondition::class, $condition); $this->assertSame('column', $condition->getColumn()); $this->assertSame([1, 2, 3], $condition->getValues()); + $db->close(); } public function testCreateOverlapsConditionFromArrayWithInvalidOperandsCount(): void @@ -1561,6 +1613,7 @@ public function testCreateOverlapsConditionFromArrayWithInvalidOperandsCount(): $this->expectExceptionMessage('Operator "JSON OVERLAPS" requires two operands.'); $qb->createConditionFromArray(['json overlaps', 'column']); + $db->close(); } public function testCreateOverlapsConditionFromArrayWithInvalidColumn(): void @@ -1572,6 +1625,7 @@ public function testCreateOverlapsConditionFromArrayWithInvalidColumn(): void $this->expectExceptionMessage('Operator "JSON OVERLAPS" requires column to be string or ExpressionInterface.'); $qb->createConditionFromArray(['json overlaps', ['column'], [1, 2, 3]]); + $db->close(); } public function testCreateOverlapsConditionFromArrayWithInvalidValues(): void @@ -1583,6 +1637,7 @@ public function testCreateOverlapsConditionFromArrayWithInvalidValues(): void $this->expectExceptionMessage('Operator "JSON OVERLAPS" requires values to be iterable or ExpressionInterface.'); $qb->createConditionFromArray(['json overlaps', 'column', 1]); + $db->close(); } /** @@ -1595,6 +1650,7 @@ public function testCreateIndex(string $sql, Closure $builder): void $qb = $db->getQueryBuilder(); $this->assertSame($db->getQuoter()->quoteSql($sql), $builder($qb)); + $db->close(); } /** @@ -1617,6 +1673,7 @@ public function testCreateView(): void DbHelper::replaceQuotes($expected, $db->getDriverName()), $qb->createView('animal_view', (new Query($db))->select('1')), ); + $db->close(); } /** @@ -1635,6 +1692,7 @@ public function testDelete(string $table, array|string $condition, string $expec $this->assertSame($expectedSQL, $actualSQL); $this->assertSame($expectedParams, $actualParams); + $db->close(); } public function testDropCheck(): void @@ -1652,6 +1710,7 @@ public function testDropCheck(): void ), $qb->dropCheck('T_constraints_1', 'CN_check'), ); + $db->close(); } public function testDropColumn(): void @@ -1669,6 +1728,7 @@ public function testDropColumn(): void ), $qb->dropColumn('customer', 'id'), ); + $db->close(); } public function testDropCommentFromColumn(): void @@ -1686,6 +1746,7 @@ public function testDropCommentFromColumn(): void ), $qb->dropCommentFromColumn('customer', 'id'), ); + $db->close(); } public function testDropCommentFromTable(): void @@ -1703,6 +1764,7 @@ public function testDropCommentFromTable(): void ), $qb->dropCommentFromTable('customer'), ); + $db->close(); } /** @@ -1724,6 +1786,7 @@ public function testDropDefaultValue(): void ), $qb->dropDefaultValue('T_constraints_1', 'CN_pk'), ); + $db->close(); } public function testDropForeignKey(): void @@ -1741,6 +1804,7 @@ public function testDropForeignKey(): void ), $qb->dropForeignKey('T_constraints_3', 'CN_constraints_3'), ); + $db->close(); } public function testDropIndex(): void @@ -1758,6 +1822,7 @@ public function testDropIndex(): void ), $qb->dropIndex('T_constraints_2', 'CN_constraints_2_single'), ); + $db->close(); } public function testDropPrimaryKey(): void @@ -1775,6 +1840,7 @@ public function testDropPrimaryKey(): void ), $qb->dropPrimaryKey('T_constraints_1', 'CN_pk'), ); + $db->close(); } public static function dataDropTable(): iterable @@ -1809,6 +1875,7 @@ public function testDropTable(string $expected, ?bool $ifExists, ?bool $cascade) $expectedSql = DbHelper::replaceQuotes($expected, $db->getDriverName()); $this->assertSame($expectedSql, $sql); + $db->close(); } public function testDropUnique(): void @@ -1826,6 +1893,7 @@ public function testDropUnique(): void ), $qb->dropUnique('test_uq', 'test_uq_constraint'), ); + $db->close(); } public function testDropView(): void @@ -1843,6 +1911,7 @@ public function testDropView(): void ), $qb->dropview('animal_view'), ); + $db->close(); } /** @@ -1860,6 +1929,7 @@ public function testGetExpressionBuilder(): void ExpressionBuilderInterface::class, $qb->getExpressionBuilder($simpleCondition), ); + $db->close(); } /** @@ -1883,6 +1953,7 @@ public function testInsert( $this->assertSame($expectedSQL, $qb->insert($table, $columns, $params)); $this->assertEquals($expectedParams, $params); + $db->close(); } /** @@ -1901,6 +1972,7 @@ public function testInsertWithReturningPks( $this->assertSame($expectedSQL, $qb->insertWithReturningPks($table, $columns, $params)); $this->assertSame($expectedParams, $params); + $db->close(); } public function testQuoter(): void @@ -1910,6 +1982,7 @@ public function testQuoter(): void $qb = $db->getQueryBuilder(); $this->assertInstanceOf(QuoterInterface::class, $qb->getQuoter()); + $db->close(); } public function testRenameColumn(): void @@ -1928,6 +2001,7 @@ public function testRenameColumn(): void ), $sql, ); + $db->close(); } public function testRenameTable(): void @@ -1946,6 +2020,7 @@ public function testRenameTable(): void ), $sql, ); + $db->close(); } /** @@ -1971,6 +2046,7 @@ public function testResetSequence(): void SQL, $qb->resetSequence('item', 3), ); + $db->close(); } /** @@ -1995,6 +2071,7 @@ public function testResetSequenceNoAssociatedException(): void } $qb->resetSequence('type'); + $db->close(); } /** @@ -2017,6 +2094,7 @@ public function testResetSequenceTableNoExistException(): void } $qb->resetSequence('noExist', 1); + $db->close(); } /** @@ -2030,6 +2108,7 @@ public function testSelectExists(string $sql, string $expected): void $sqlSelectExist = $qb->selectExists($sql); $this->assertSame($expected, $sqlSelectExist); + $db->close(); } /** @@ -2090,6 +2169,7 @@ public function testSelectExpression(): void $this->assertSame($expected, $sql); $this->assertSame([':len' => 4], $params); + $db->close(); } /** @@ -2116,6 +2196,7 @@ public function testSelectSubquery(): void $this->assertSame($expected, $sql); $this->assertEmpty($params); + $db->close(); } /** @dataProvider \Yiisoft\Db\Tests\Provider\QueryBuilderProvider::selectScalar */ @@ -2134,6 +2215,7 @@ public function testSelectScalar(array|bool|float|int|string $columns, string $e $this->assertSame($expected, $sql); $this->assertEmpty($params); + $db->close(); } public function testSetConditionClasses(): void @@ -2146,6 +2228,7 @@ public function testSetConditionClasses(): void $conditionClasses = Assert::getInaccessibleProperty($dqlBuilder, 'conditionClasses'); $this->assertSame(stdClass::class, $conditionClasses['stdClass']); + $db->close(); } public function testSetExpressionBuilder(): void @@ -2158,6 +2241,7 @@ public function testSetExpressionBuilder(): void $expressionBuilders = Assert::getInaccessibleProperty($dqlBuilder, 'expressionBuilders'); $this->assertSame(stdClass::class, $expressionBuilders['stdClass']); + $db->close(); } /** @@ -2199,6 +2283,7 @@ public function testSetSeparator(): void $sql, ); $this->assertEmpty($params); + $db->close(); } public function testTruncateTable(): void @@ -2229,6 +2314,7 @@ public function testTruncateTable(): void ), $sql, ); + $db->close(); } /** @@ -2253,6 +2339,7 @@ public function testUpdate( $this->assertSame($expectedSql, $sql); $this->assertEquals($expectedParams, $params); + $db->close(); } /** @@ -2278,6 +2365,7 @@ public function testUpsert( $this->assertSame($expectedSQL, $actualSQL); $this->assertSame($expectedParams, $actualParams); + $db->close(); } /** @@ -2312,6 +2400,7 @@ public function testUpsertExecute( $command = $db->createCommand($actualSQL, $actualParams); $command->execute(); + $db->close(); } /** @@ -2343,6 +2432,7 @@ public function testOverrideParameters1(): void ), $command->getRawSql() ); + $db->close(); } /** @@ -2374,6 +2464,7 @@ public function testOverrideParameters2(): void ), $command->getRawSql() ); + $db->close(); } #[DataProviderExternal(QueryBuilderProvider::class, 'buildColumnDefinition')] @@ -2395,6 +2486,7 @@ public function testPrepareParam(string $expected, mixed $value, int $type): voi $param = new Param($value, $type); $this->assertSame($expected, $qb->prepareParam($param)); + $db->close(); } #[DataProviderExternal(QueryBuilderProvider::class, 'prepareValue')] @@ -2404,5 +2496,6 @@ public function testPrepareValue(string $expected, mixed $value): void $qb = $db->getQueryBuilder(); $this->assertSame($expected, $qb->prepareValue($value)); + $db->close(); } } From 1503a9271a446f685b6b4a3b9aec514af4e6ecf8 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 17:16:45 +0500 Subject: [PATCH 036/137] Close all DB connection after tests --- tests/AbstractQueryBuilderTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/AbstractQueryBuilderTest.php b/tests/AbstractQueryBuilderTest.php index 798666ef7..82f120c87 100644 --- a/tests/AbstractQueryBuilderTest.php +++ b/tests/AbstractQueryBuilderTest.php @@ -204,7 +204,6 @@ public function testAlterColumn(string|ColumnInterface $type, string $expected): $qb = $this->getConnection()->getQueryBuilder(); $this->assertSame($expected, $qb->alterColumn('foo1', 'bar', $type)); - $db->close(); } /** From f44b96850ed2c3521a7d364d3c196643ba5c57f3 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 17:24:42 +0500 Subject: [PATCH 037/137] Close all DB connection after tests --- tests/AbstractQueryGetTableAliasTest.php | 9 +++++ tests/AbstractQueryTest.php | 46 +++++++++++++++++++++--- tests/AbstractQuoterTest.php | 7 ++++ tests/AbstractSchemaTest.php | 3 ++ 4 files changed, 61 insertions(+), 4 deletions(-) diff --git a/tests/AbstractQueryGetTableAliasTest.php b/tests/AbstractQueryGetTableAliasTest.php index 169b616f0..59067f535 100644 --- a/tests/AbstractQueryGetTableAliasTest.php +++ b/tests/AbstractQueryGetTableAliasTest.php @@ -36,6 +36,7 @@ public function testAliasesFromString(): void ], $tables, ); + $db->close(); } /** @@ -53,6 +54,7 @@ public function testGetTableNamesIsFromAliasedSubquery(): void $tables = $query->getTablesUsedInFrom(); $this->assertSame($expected, $tables); + $db->close(); } /** @@ -68,6 +70,7 @@ public function testNamesIsFromAliasedArrayWithExpression(): void $tables = $query->getTablesUsedInFrom(); $this->assertSame(['{{x}}' => $expression], $tables); + $db->close(); } public function testNamesIsFromAliasedExpression(): void @@ -84,6 +87,7 @@ public function testNamesIsFromAliasedExpression(): void $tables = $query->getTablesUsedInFrom(); $this->assertSame(['{{x}}' => $expression], $tables); + $db->close(); } /** @@ -102,6 +106,7 @@ public function testNamesIsFromArrayWithAlias(): void ['{{prf}}' => '{{profile}}', '{{usr}}' => '{{user}}', '{{a b}}' => '{{c d}}', '{{p}}' => '{{post}}'], $tables, ); + $db->close(); } /** @@ -116,6 +121,7 @@ public function testNamesIsFromArrayWithoutAlias(): void $tables = $query->getTablesUsedInFrom(); $this->assertSame(['{{profile}}' => '{{profile}}', '{{user}}' => '{{user}}'], $tables); + $db->close(); } /** @@ -132,6 +138,7 @@ public function testNamesIsFromPrefixedTableName(): void $tables = $query->getTablesUsedInFrom(); $this->assertSame(['{{%order_item}}' => '{{%order_item}}'], $tables); + $db->close(); } /** @@ -155,6 +162,7 @@ public function testNamesIsFromString(): void ], $tables, ); + $db->close(); } /** @@ -171,5 +179,6 @@ public function testNamesIsFromTableNameWithDatabase(): void $tables = $query->getTablesUsedInFrom(); $this->assertSame(['{{tickets.workflows}}' => '{{tickets.workflows}}'], $tables); + $db->close(); } } diff --git a/tests/AbstractQueryTest.php b/tests/AbstractQueryTest.php index a068e8715..f7483d757 100644 --- a/tests/AbstractQueryTest.php +++ b/tests/AbstractQueryTest.php @@ -28,6 +28,7 @@ public function testAddGroupByExpression(): void $query->addGroupBy($expression); $this->assertSame([$expression], $query->getGroupBy()); + $db->close(); } public function testAddOrderByEmpty(): void @@ -38,6 +39,7 @@ public function testAddOrderByEmpty(): void $query->addOrderBy([]); $this->assertSame([], $query->getOrderBy()); + $db->close(); } public function testAddParamsWithNameInt(): void @@ -49,6 +51,7 @@ public function testAddParamsWithNameInt(): void $query->addParams([2 => 'test']); $this->assertSame([1 => 'value', 2 => 'test'], $query->getParams()); + $db->close(); } /** @@ -90,6 +93,7 @@ public function testAndFilterCompare(): void $query->andFilterCompare('value', '<=100'); $this->assertSame($condition, $query->getWhere()); + $db->close(); } /** @@ -108,6 +112,7 @@ public function testAndFilterHaving(): void $query->andFilterHaving(['>', 'id', 2]); $this->assertSame(['and', ['>', 'id', 1], ['>', 'id', 2]], $query->getHaving()); + $db->close(); } /** @@ -122,6 +127,7 @@ public function testAndFilterHavingWithHashFormat(): void $this->assertInstanceOf(QueryInterface::class, $result); $this->assertSame(['status' => 1], $query->getHaving()); + $db->close(); } /** @@ -157,6 +163,7 @@ public function testCount(): void $count = (new Query($db))->from('customer')->orderBy('id')->limit(1)->count(); $this->assertEquals(3, $count); + $db->close(); } /** @@ -206,6 +213,7 @@ public function testEmulateExecution(): void $column = (new Query($db))->select(['id'])->from('customer')->emulateExecution()->column(); $this->assertSame([], $column); + $db->close(); } /** @@ -227,6 +235,7 @@ public function testFilterHavingWithHashFormat(): void $query->orFilterHaving(['name' => '']); $this->assertSame(['id' => 0], $query->getHaving()); + $db->close(); } /** @@ -277,6 +286,7 @@ public function testFilterHavingWithOperatorFormat(): void $query->andFilterHaving(['or', ['eq', 'id', null], ['eq', 'id', []]]); $this->assertSame($condition, $query->getHaving()); + $db->close(); } /** @@ -292,6 +302,7 @@ public function testFilterRecursively(): void ); $this->assertSame(['and', ['id' => 1]], $query->getWhere()); + $db->close(); } /** @@ -313,6 +324,7 @@ public function testFilterWhereWithHashFormat(): void $query->orFilterWhere(['name' => '']); $this->assertSame(['id' => 0], $query->getWhere()); + $db->close(); } /** @@ -363,6 +375,7 @@ public function testFilterWhereWithOperatorFormat(): void $query->andFilterWhere(['or', ['eq', 'id', null], ['eq', 'id', []]]); $this->assertSame($condition, $query->getWhere()); + $db->close(); } public function testFrom(): void @@ -373,6 +386,7 @@ public function testFrom(): void $query->from('user'); $this->assertSame(['user'], $query->getFrom()); + $db->close(); } public function testFromTableIsArrayWithExpression(): void @@ -386,6 +400,7 @@ public function testFromTableIsArrayWithExpression(): void $this->assertIsArray($from); $this->assertInstanceOf(ExpressionInterface::class, $from[0]); + $db->close(); } public function testGroup(): void @@ -404,6 +419,7 @@ public function testGroup(): void $query->addGroupBy('age'); $this->assertSame(['team', 'company', 'age'], $query->getGroupBy()); + $db->close(); } public function testHaving(): void @@ -423,6 +439,7 @@ public function testHaving(): void $query->orHaving('age = :age', [':age' => '30']); $this->assertSame(['or', ['and', 'id = :id', 'name = :name'], 'age = :age'], $query->getHaving()); $this->assertSame([':id' => 1, ':name' => 'something', ':age' => '30'], $query->getParams()); + $db->close(); } public function testJoin(): void @@ -440,6 +457,7 @@ public function testJoin(): void [['INNER JOIN', 'profile', 'user.id = profile.user_id'], ['LEFT JOIN', 'order', 'user.id = order.user_id']], $query->getJoins() ); + $db->close(); } public function testLimitOffset(): void @@ -451,6 +469,7 @@ public function testLimitOffset(): void $this->assertSame(10, $query->getLimit()); $this->assertSame(5, $query->getOffset()); + $db->close(); } /** @@ -464,6 +483,7 @@ public function testOrFilterHavingHashFormat(): void $query->orFilterHaving(['status' => 1]); $this->assertSame(['status' => 1], $query->getHaving()); + $db->close(); } /** @@ -477,6 +497,7 @@ public function testOrFilterWhereHashFormat(): void $query->orFilterWhere(['status' => 1]); $this->assertSame(['status' => 1], $query->getWhere()); + $db->close(); } public function testOrder(): void @@ -515,6 +536,7 @@ public function testOrder(): void $query->addOrderBy($expression2); $this->assertSame([$expression1, $expression2], $query->getOrderBy()); + $db->close(); } public function testRightJoin(): void @@ -525,6 +547,7 @@ public function testRightJoin(): void $query->rightJoin('profile', 'user.id = profile.user_id'); $this->assertSame([['RIGHT JOIN', 'profile', 'user.id = profile.user_id']], $query->getJoins()); + $db->close(); } public function testSelect(): void @@ -668,6 +691,7 @@ public function testSelect(): void $query->addSelect(['float' => 12.34]); $this->assertSame([1, true, 'float' => 12.34], $query->getSelect()); + $db->close(); } public function testSetJoin(): void @@ -687,6 +711,7 @@ public function testSetJoin(): void ], $query->getJoins() ); + $db->close(); } public function testSetUnion(): void @@ -697,6 +722,7 @@ public function testSetUnion(): void $query->setUnions(['SELECT * FROM table1', 'SELECT * FROM table2']); $this->assertSame(['SELECT * FROM table1', 'SELECT * FROM table2'], $query->getUnions()); + $db->close(); } public function testShouldEmulateExecution(): void @@ -710,6 +736,7 @@ public function testShouldEmulateExecution(): void $query->emulateExecution(); $this->assertTrue($query->shouldEmulateExecution()); + $db->close(); } public function testWhere(): void @@ -731,6 +758,7 @@ public function testWhere(): void $this->assertSame(['or', ['and', 'id = :id', 'name = :name'], 'age = :age'], $query->getWhere()); $this->assertSame([':id' => 1, ':name' => 'something', ':age' => '30'], $query->getParams()); + $db->close(); } public function testWithQueries(): void @@ -741,6 +769,7 @@ public function testWithQueries(): void $query->withQueries(['query1', 'query2']); $this->assertSame(['query1', 'query2'], $query->getWithQueries()); + $db->close(); } public function testColumnWithIndexBy(): void @@ -773,6 +802,7 @@ public function testColumnWithIndexBy(): void ->where(['id' => null]); $this->assertSame([], $query->column()); + $db->close(); } /** @@ -780,11 +810,13 @@ public function testColumnWithIndexBy(): void */ public function testFilterCondition(array|string $condition, array|string|null $expected): void { - $query = (new Query($this->getConnection())); + $db = $this->getConnection(); + $query = (new Query($db)); $this->assertNull($query->getWhere()); $query->filterWhere($condition); $this->assertEquals($expected, $query->getWhere()); + $db->close(); } /** @@ -792,11 +824,13 @@ public function testFilterCondition(array|string $condition, array|string|null $ */ public function testNormalizeOrderBy(array|string|Expression $columns, array|string $expected): void { - $query = (new Query($this->getConnection())); + $db = $this->getConnection(); + $query = (new Query($db)); $this->assertEquals([], $query->getOrderBy()); $query->orderBy($columns); $this->assertEquals($expected, $query->getOrderBy()); + $db->close(); } /** @@ -804,17 +838,20 @@ public function testNormalizeOrderBy(array|string|Expression $columns, array|str */ public function testNormalizeSelect(array|bool|float|int|string|ExpressionInterface $columns, array|string $expected): void { - $query = (new Query($this->getConnection())); + $db = $this->getConnection(); + $query = (new Query($db)); $this->assertEquals([], $query->getSelect()); $query->select($columns); $this->assertEquals($expected, $query->getSelect()); + $db->close(); } public function testCountGreaterThanPhpIntMax(): void { + $db = $this->getConnection(); $query = $this->getMockBuilder(Query::class) - ->setConstructorArgs([$this->getConnection()]) + ->setConstructorArgs([$db]) ->onlyMethods(['queryScalar']) ->getMock(); @@ -823,5 +860,6 @@ public function testCountGreaterThanPhpIntMax(): void ->willReturn('12345678901234567890'); $this->assertSame('12345678901234567890', $query->count()); + $db->close(); } } diff --git a/tests/AbstractQuoterTest.php b/tests/AbstractQuoterTest.php index e98a3ab07..0c731b373 100644 --- a/tests/AbstractQuoterTest.php +++ b/tests/AbstractQuoterTest.php @@ -19,6 +19,7 @@ public function testEnsureColumnName(string $columnName, string $expected): void $db = $this->getConnection(); $this->assertSame($expected, $db->getQuoter()->ensureColumnName($columnName)); + $db->close(); } /** @@ -29,6 +30,7 @@ public function testEnsureNameQuoted(string $name, string $expected): void $db = $this->getConnection(); $this->assertSame($expected, $db->getQuoter()->ensureNameQuoted($name)); + $db->close(); } /** @@ -41,6 +43,7 @@ public function testGetRawTableName(string $tableName, string $expected, string $db->setTablePrefix($tablePrefix); $this->assertSame($expected, $db->getQuoter()->getRawTableName($tableName)); + $db->close(); } /** @@ -51,6 +54,7 @@ public function testGetTableNameParts(string $tableName, string ...$expected): v $db = $this->getConnection(); $this->assertSame($expected, array_reverse($db->getQuoter()->getTableNameParts($tableName))); + $db->close(); } /** @@ -61,6 +65,7 @@ public function testQuoteColumnName(string $columnName, string $expected): void $db = $this->getConnection(); $this->assertSame($expected, $db->getQuoter()->quoteColumnName($columnName)); + $db->close(); } /** @@ -81,6 +86,7 @@ public function testQuoteSimpleColumnName( $unQuoted = $quoter->unquoteSimpleColumnName($quoted); $this->assertSame($expectedUnQuotedColumnName, $unQuoted); + $db->close(); } /** @@ -98,5 +104,6 @@ public function testQuoteTableName(string $tableName, string $expected): void $unQuoted = $quoter->unquoteSimpleTableName($quoter->quoteTableName($tableName)); $this->assertSame($expected, $unQuoted); + $db->close(); } } diff --git a/tests/AbstractSchemaTest.php b/tests/AbstractSchemaTest.php index db453111e..634ecd5d1 100644 --- a/tests/AbstractSchemaTest.php +++ b/tests/AbstractSchemaTest.php @@ -24,6 +24,7 @@ public function testGetDefaultSchema(): void $schema = $db->getSchema(); $this->assertNull($schema->getDefaultSchema()); + $db->close(); } public function testGetDataType(): void @@ -53,6 +54,7 @@ public function testGetDataType(): void } fclose($fp); + $db->close(); } public function testRefresh(): void @@ -64,5 +66,6 @@ public function testRefresh(): void $this->assertSame([], Assert::getInaccessibleProperty($schema, 'tableMetadata')); $this->assertSame([], Assert::getInaccessibleProperty($schema, 'tableNames')); + $db->close(); } } From 2dd73a08e7381115448268a7e014ea93e1ae0bd5 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 17:41:38 +0500 Subject: [PATCH 038/137] Close all DB connection after tests --- tests/AbstractCommandTest.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index f1239a5cf..2f1ae2f56 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -297,6 +297,15 @@ public function testBindParamsOverflowIssue(): void $this->markTestSkipped('Test is intended for use with pgsql database.'); } + $skipVersions = ['12']; + $dbmsVersion = $db->getServerInfo()->getVersion(); + if (preg_match('/^(\d+)\.(\d+)/ui', $dbmsVersion, $matches)) { + $dbmsVersion = $matches[1]; + } + if (in_array($dbmsVersion, $skipVersions)) { + $this->markTestSkipped('Test is not applicable to pgsql v' . $dbmsVersion); + } + $tempTableName = 'testTempTable'; $db->createCommand()->createTable($tempTableName, [ 'id' => ColumnBuilder::primaryKey(), From ead13113a39b7f44119ffa9282c06094d90a40ac Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 17:46:40 +0500 Subject: [PATCH 039/137] Close all DB connection after tests --- tests/AbstractCommandTest.php | 2 +- tests/Db/Schema/SchemaTest.php | 14 -------------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index 2f1ae2f56..0044cb48a 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -297,7 +297,7 @@ public function testBindParamsOverflowIssue(): void $this->markTestSkipped('Test is intended for use with pgsql database.'); } - $skipVersions = ['12']; + $skipVersions = ['11', '12', '16']; $dbmsVersion = $db->getServerInfo()->getVersion(); if (preg_match('/^(\d+)\.(\d+)/ui', $dbmsVersion, $matches)) { $dbmsVersion = $matches[1]; diff --git a/tests/Db/Schema/SchemaTest.php b/tests/Db/Schema/SchemaTest.php index 64f7cc10f..6d2f05cd6 100644 --- a/tests/Db/Schema/SchemaTest.php +++ b/tests/Db/Schema/SchemaTest.php @@ -224,20 +224,6 @@ public function testHasSchema(): void $db->close(); } - public function testHasSchema(): void - { - $db = $this->getConnection(); - - $schema = $db->getSchema(); - Assert::setInaccessibleProperty($schema, 'schemaNames', ['dbo', 'public']); - - $this->assertTrue($schema->hasSchema('dbo')); - $this->assertTrue($schema->hasSchema('public')); - $this->assertFalse($schema->hasSchema('no_such_schema')); - - $db->close(); - } - /** * @throws NotSupportedException */ From fc6d7888d32c61550343ff2edc510ab3efeb4570 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 17:51:04 +0500 Subject: [PATCH 040/137] Close all DB connection after tests --- tests/AbstractCommandTest.php | 20 ++++++++++---------- tests/Db/Connection/ConnectionTest.php | 1 + 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index 0044cb48a..52b4114a3 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -297,14 +297,14 @@ public function testBindParamsOverflowIssue(): void $this->markTestSkipped('Test is intended for use with pgsql database.'); } - $skipVersions = ['11', '12', '16']; - $dbmsVersion = $db->getServerInfo()->getVersion(); - if (preg_match('/^(\d+)\.(\d+)/ui', $dbmsVersion, $matches)) { - $dbmsVersion = $matches[1]; - } - if (in_array($dbmsVersion, $skipVersions)) { - $this->markTestSkipped('Test is not applicable to pgsql v' . $dbmsVersion); - } +// $skipVersions = ['11', '12', '16']; +// $dbmsVersion = $db->getServerInfo()->getVersion(); +// if (preg_match('/^(\d+)\.(\d+)/ui', $dbmsVersion, $matches)) { +// $dbmsVersion = $matches[1]; +// } +// if (in_array($dbmsVersion, $skipVersions)) { +// $this->markTestSkipped('Test is not applicable to pgsql v' . $dbmsVersion); +// } $tempTableName = 'testTempTable'; $db->createCommand()->createTable($tempTableName, [ @@ -331,11 +331,11 @@ public function testBindParamsOverflowIssue(): void $insertData[] = $personData; } - $db->createCommand()->insertBatch($tempTableName, $insertData)->execute(); - $this->expectException(\PDOException::class); $this->expectExceptionMessageMatches('/General error:\w+number of parameters must be between \d+ and \d+/ui'); + $db->createCommand()->insertBatch($tempTableName, $insertData)->execute(); + // $countSql = 'SELECT COUNT(*) FROM ' . $db->getQuoter()->quoteTableName($tempTableName); // $this->assertEquals(10000, $db->createCommand($countSql)->queryScalar()); diff --git a/tests/Db/Connection/ConnectionTest.php b/tests/Db/Connection/ConnectionTest.php index 6a3599292..d07ac8841 100644 --- a/tests/Db/Connection/ConnectionTest.php +++ b/tests/Db/Connection/ConnectionTest.php @@ -22,6 +22,7 @@ public function testGetTableSchema(): void $db = $this->getConnection(); $this->assertNull($db->getTableSchema('non_existing_table')); + $db->close(); } public function testSerialized(): void From 915c3e0e4647a73de45b3d6e2312d5e3bd65be74 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 17:57:52 +0500 Subject: [PATCH 041/137] Close all DB connection after tests --- tests/AbstractCommandTest.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index 52b4114a3..de7ae287f 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -331,15 +331,15 @@ public function testBindParamsOverflowIssue(): void $insertData[] = $personData; } - $this->expectException(\PDOException::class); - $this->expectExceptionMessageMatches('/General error:\w+number of parameters must be between \d+ and \d+/ui'); - - $db->createCommand()->insertBatch($tempTableName, $insertData)->execute(); - -// $countSql = 'SELECT COUNT(*) FROM ' . $db->getQuoter()->quoteTableName($tempTableName); -// $this->assertEquals(10000, $db->createCommand($countSql)->queryScalar()); - - $db->createCommand()->dropTable($tempTableName)->execute(); - $db->close(); + try { + $db->createCommand()->insertBatch($tempTableName, $insertData)->execute(); + $countSql = 'SELECT COUNT(*) FROM ' . $db->getQuoter()->quoteTableName($tempTableName); + $this->assertEquals(10000, $db->createCommand($countSql)->queryScalar()); + } catch (\PDOException $ex) { + // $this->expectExceptionMessageMatches('/General error:\w+number of parameters must be between \d+ and \d+/ui'); + } finally { + $db->createCommand()->dropTable($tempTableName)->execute(); + $db->close(); + } } } From e6be6891e6ffe6767bc5e09b44c35cee12a7dc1f Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 18:00:56 +0500 Subject: [PATCH 042/137] Close all DB connection after tests --- tests/AbstractCommandTest.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index de7ae287f..ff38813cc 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -333,13 +333,12 @@ public function testBindParamsOverflowIssue(): void try { $db->createCommand()->insertBatch($tempTableName, $insertData)->execute(); - $countSql = 'SELECT COUNT(*) FROM ' . $db->getQuoter()->quoteTableName($tempTableName); - $this->assertEquals(10000, $db->createCommand($countSql)->queryScalar()); } catch (\PDOException $ex) { // $this->expectExceptionMessageMatches('/General error:\w+number of parameters must be between \d+ and \d+/ui'); - } finally { - $db->createCommand()->dropTable($tempTableName)->execute(); - $db->close(); } + $countSql = 'SELECT COUNT(*) FROM ' . $db->getQuoter()->quoteTableName($tempTableName); + $this->assertEquals(10000, $db->createCommand($countSql)->queryScalar()); + $db->createCommand()->dropTable($tempTableName)->execute(); + $db->close(); } } From ecce7a3c21cc96a4dea42a7ef8e84a830cf1e582 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 18:08:47 +0500 Subject: [PATCH 043/137] Close all DB connection after tests --- tests/AbstractCommandTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index ff38813cc..f323a24a9 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -331,11 +331,11 @@ public function testBindParamsOverflowIssue(): void $insertData[] = $personData; } - try { - $db->createCommand()->insertBatch($tempTableName, $insertData)->execute(); - } catch (\PDOException $ex) { - // $this->expectExceptionMessageMatches('/General error:\w+number of parameters must be between \d+ and \d+/ui'); - } + $db->createCommand()->insertBatch($tempTableName, $insertData)->execute(); +// try { +// } catch (\PDOException $ex) { +// // $this->expectExceptionMessageMatches('/General error:\w+number of parameters must be between \d+ and \d+/ui'); +// } $countSql = 'SELECT COUNT(*) FROM ' . $db->getQuoter()->quoteTableName($tempTableName); $this->assertEquals(10000, $db->createCommand($countSql)->queryScalar()); $db->createCommand()->dropTable($tempTableName)->execute(); From 0c933d40c85fe2c3e5bc5acf78623877975f2e25 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 18:14:26 +0500 Subject: [PATCH 044/137] Close all DB connection after tests --- tests/AbstractCommandTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index f323a24a9..cd404b412 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -327,7 +327,7 @@ public function testBindParamsOverflowIssue(): void ]; $insertData = []; - for ($i = 0; $i < 10000; $i++) { + for ($i = 0; $i < 11000; $i++) { $insertData[] = $personData; } From ff0e7af40ceb8cc2cd6d0aafc1a947aff3e6f104 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 18:18:32 +0500 Subject: [PATCH 045/137] Close all DB connection after tests --- tests/AbstractCommandTest.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index cd404b412..a2430542e 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -326,16 +326,17 @@ public function testBindParamsOverflowIssue(): void 'address' => '7, Gagarin street, apartment 10', ]; + //generate 66 000 params (6 fields x 11000 lines) $insertData = []; for ($i = 0; $i < 11000; $i++) { $insertData[] = $personData; } + $this->expectException(\PDOException::class); + $this->expectExceptionMessageMatches('/General error:\w+number of parameters must be between \d+ and \d+/ui'); + $db->createCommand()->insertBatch($tempTableName, $insertData)->execute(); -// try { -// } catch (\PDOException $ex) { -// // $this->expectExceptionMessageMatches('/General error:\w+number of parameters must be between \d+ and \d+/ui'); -// } + $countSql = 'SELECT COUNT(*) FROM ' . $db->getQuoter()->quoteTableName($tempTableName); $this->assertEquals(10000, $db->createCommand($countSql)->queryScalar()); $db->createCommand()->dropTable($tempTableName)->execute(); From 0064ea4873c90940ce7ec4030de7e892cc8102ae Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 18:21:48 +0500 Subject: [PATCH 046/137] Close all DB connection after tests --- tests/AbstractCommandTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index a2430542e..3742abe4e 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -9,6 +9,7 @@ use Yiisoft\Db\Command\Param; use Yiisoft\Db\Command\ParamInterface; use Yiisoft\Db\Exception\Exception; +use Yiisoft\Db\Exception\IntegrityException; use Yiisoft\Db\Exception\InvalidConfigException; use Yiisoft\Db\Exception\NotSupportedException; use Yiisoft\Db\Profiler\Context\CommandContext; @@ -332,7 +333,7 @@ public function testBindParamsOverflowIssue(): void $insertData[] = $personData; } - $this->expectException(\PDOException::class); + $this->expectException(IntegrityException::class); $this->expectExceptionMessageMatches('/General error:\w+number of parameters must be between \d+ and \d+/ui'); $db->createCommand()->insertBatch($tempTableName, $insertData)->execute(); From 133ea38211fc2ef615737b14cd8552b9ea665a87 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 28 Mar 2025 18:24:48 +0500 Subject: [PATCH 047/137] Close all DB connection after tests --- tests/AbstractCommandTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index 3742abe4e..14a37f307 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -334,7 +334,7 @@ public function testBindParamsOverflowIssue(): void } $this->expectException(IntegrityException::class); - $this->expectExceptionMessageMatches('/General error:\w+number of parameters must be between \d+ and \d+/ui'); + $this->expectExceptionMessageMatches('/General error: \d+ number of parameters must be between \d+ and \d+/ui'); $db->createCommand()->insertBatch($tempTableName, $insertData)->execute(); From 082d0555f36eb8055c575398280dffd97ef35673 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Sat, 29 Mar 2025 21:50:17 +0500 Subject: [PATCH 048/137] New object for handling multiple commands --- src/Command/AbstractCommand.php | 1 + src/Command/CommandsCollection.php | 111 +++++++++++++++++++++++++ src/Connection/AbstractConnection.php | 15 ++++ src/Connection/ConnectionInterface.php | 13 +++ tests/AbstractCommandTest.php | 2 +- 5 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 src/Command/CommandsCollection.php diff --git a/src/Command/AbstractCommand.php b/src/Command/AbstractCommand.php index 68b06c438..eaca59ff3 100644 --- a/src/Command/AbstractCommand.php +++ b/src/Command/AbstractCommand.php @@ -208,6 +208,7 @@ public function batchInsert(string $table, array $columns, iterable $rows): stat public function insertBatch(string $table, iterable $rows, array $columns = []): static { + //mark this as deprecated and remove in future versions $table = $this->getQueryBuilder()->getQuoter()->getRawTableName($table); $params = []; diff --git a/src/Command/CommandsCollection.php b/src/Command/CommandsCollection.php new file mode 100644 index 000000000..f9a748424 --- /dev/null +++ b/src/Command/CommandsCollection.php @@ -0,0 +1,111 @@ +position = 0; + } + + function current(): CommandInterface { + return $this->commands[$this->position]; + } + + function key(): int { + return $this->position; + } + + function next(): void { + ++$this->position; + } + + function valid(): bool { + return isset($this->commands[$this->position]); + } + + function count(): int + { + return count($this->commands); + } + + /** + * @throws InvalidConfigException + * @throws Exception + */ + public function insertBatch(string $table, array $rows, array $columns = []): static + { + $table = $this->connection->getQuoter()->getRawTableName($table); + + $columnsCount = count($columns); + if ($columnsCount === 0 && count($rows) > 0) { + $columnsCount = count(array_keys($rows[array_key_first($rows)])); + } + + $maxParamsQty = $this->connection->getParamsLimit(); + $totalInsertedParams = $columnsCount * count($rows); + + if (!empty($maxParamsQty) && $totalInsertedParams > $maxParamsQty) { + $chunkSize = (int)floor($maxParamsQty / $columnsCount); + $rowChunks = array_chunk($rows, $chunkSize); + foreach ($rowChunks as $rowChunk) { + $this->commands[] = $this->createInsertBatchCommand($table, $rowChunk, $columns); + } + } else { + $this->commands[] = $this->createInsertBatchCommand($table, $rows, $columns); + } + + return $this; + } + + /** + * @throws InvalidConfigException + * @throws Exception + */ + private function createInsertBatchCommand(string $table, array $rows, array $columns = []): CommandInterface + { + $command = $this->connection->createCommand(); + $params = []; + $sql = $this->connection->getQueryBuilder()->insertBatch($table, $rows, $columns, $params); + + $command->setRawSql($sql); + $command->bindValues($params); + + return $command; + } + + /** + * @throws \Throwable + * @throws Exception + */ + public function execute(): int + { + $total = 0; + foreach ($this->commands as $command) { + $total += $command->execute(); + } + + return $total; + } +} diff --git a/src/Connection/AbstractConnection.php b/src/Connection/AbstractConnection.php index cd9f11679..70cfed93a 100644 --- a/src/Connection/AbstractConnection.php +++ b/src/Connection/AbstractConnection.php @@ -6,6 +6,7 @@ use Closure; use Throwable; +use Yiisoft\Db\Command\CommandsCollection; use Yiisoft\Db\Query\BatchQueryResult; use Yiisoft\Db\Query\BatchQueryResultInterface; use Yiisoft\Db\Query\QueryInterface; @@ -117,4 +118,18 @@ protected function rollbackTransactionOnLevel(TransactionInterface $transaction, } } } + + public function getParamsLimit(): int + { + //must be overriden in a DBMS package which has a limit + if ($this->getDriverName() === 'pgsql') { + return 65535; + } + return 0; + } + + public function createCommandsCollection(): CommandsCollection + { + return new CommandsCollection($this); + } } diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index 10c605a78..4d2587afe 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -7,6 +7,7 @@ use Closure; use Throwable; use Yiisoft\Db\Command\CommandInterface; +use Yiisoft\Db\Command\CommandsCollection; use Yiisoft\Db\Exception\Exception; use Yiisoft\Db\Exception\InvalidCallException; use Yiisoft\Db\Exception\InvalidConfigException; @@ -228,4 +229,16 @@ public function setTablePrefix(string $value): void; * @psalm-param Closure(ConnectionInterface):mixed|Closure(ConnectionInterface):void $closure */ public function transaction(Closure $closure, ?string $isolationLevel = null): mixed; + + /** + * Returns maximum number of bound params for a DBMS. Default 0 - means unlimited. + * @return int + */ + public function getParamsLimit(): int; + + /** + * Creates commands collection used for `insertBatch()` + * @return CommandsCollection + */ + public function createCommandsCollection(): CommandsCollection; } diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index 14a37f307..405b81cc4 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -336,7 +336,7 @@ public function testBindParamsOverflowIssue(): void $this->expectException(IntegrityException::class); $this->expectExceptionMessageMatches('/General error: \d+ number of parameters must be between \d+ and \d+/ui'); - $db->createCommand()->insertBatch($tempTableName, $insertData)->execute(); + $db->createCommandsCollection()->insertBatch($tempTableName, $insertData)->execute(); $countSql = 'SELECT COUNT(*) FROM ' . $db->getQuoter()->quoteTableName($tempTableName); $this->assertEquals(10000, $db->createCommand($countSql)->queryScalar()); From f4fff70735003b5af08c87e6cdd2a4df44bf713c Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Sat, 29 Mar 2025 21:55:42 +0500 Subject: [PATCH 049/137] New object for handling multiple commands --- tests/AbstractCommandTest.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index 405b81cc4..14ea2a106 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -333,13 +333,10 @@ public function testBindParamsOverflowIssue(): void $insertData[] = $personData; } - $this->expectException(IntegrityException::class); - $this->expectExceptionMessageMatches('/General error: \d+ number of parameters must be between \d+ and \d+/ui'); - $db->createCommandsCollection()->insertBatch($tempTableName, $insertData)->execute(); $countSql = 'SELECT COUNT(*) FROM ' . $db->getQuoter()->quoteTableName($tempTableName); - $this->assertEquals(10000, $db->createCommand($countSql)->queryScalar()); + $this->assertEquals(11000, $db->createCommand($countSql)->queryScalar()); $db->createCommand()->dropTable($tempTableName)->execute(); $db->close(); } From 4be947f46374146b57c608ce6408256b71dfefc8 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Mon, 31 Mar 2025 10:31:07 +0300 Subject: [PATCH 050/137] Update src/Command/CommandsCollection.php --- src/Command/CommandsCollection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Command/CommandsCollection.php b/src/Command/CommandsCollection.php index f9a748424..768a72762 100644 --- a/src/Command/CommandsCollection.php +++ b/src/Command/CommandsCollection.php @@ -10,7 +10,7 @@ class CommandsCollection implements Iterator, Countable { /** - * @var int Current iterator position + * @var int Current iterator position. */ private int $position = 0; /** From 3d1b474cd1773140bf29f8b652616bcda32dec06 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Mon, 31 Mar 2025 10:31:15 +0300 Subject: [PATCH 051/137] Update src/Command/CommandsCollection.php --- src/Command/CommandsCollection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Command/CommandsCollection.php b/src/Command/CommandsCollection.php index 768a72762..e8deb4cc2 100644 --- a/src/Command/CommandsCollection.php +++ b/src/Command/CommandsCollection.php @@ -14,7 +14,7 @@ class CommandsCollection implements Iterator, Countable */ private int $position = 0; /** - * @var CommandInterface[] Command of the collection + * @var CommandInterface[] Commands of the collection. */ private array $commands = []; From 221543cadbbd9f02f14aafe0aeac4d2af785d661 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Mon, 31 Mar 2025 10:31:23 +0300 Subject: [PATCH 052/137] Update src/Command/CommandsCollection.php --- src/Command/CommandsCollection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Command/CommandsCollection.php b/src/Command/CommandsCollection.php index e8deb4cc2..f78a499e3 100644 --- a/src/Command/CommandsCollection.php +++ b/src/Command/CommandsCollection.php @@ -19,7 +19,7 @@ class CommandsCollection implements Iterator, Countable private array $commands = []; /** - * @param ConnectionInterface $connection Connection to a database + * @param ConnectionInterface $connection Connection to a database. */ public function __construct(private readonly ConnectionInterface $connection) { From 7a54d2f3331dd3cf879badfb3ea666ac561244d5 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Mon, 31 Mar 2025 10:31:34 +0300 Subject: [PATCH 053/137] Update src/Connection/ConnectionInterface.php --- src/Connection/ConnectionInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index 4d2587afe..6d84edeb4 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -231,7 +231,7 @@ public function setTablePrefix(string $value): void; public function transaction(Closure $closure, ?string $isolationLevel = null): mixed; /** - * Returns maximum number of bound params for a DBMS. Default 0 - means unlimited. + * Returns maximum number of bound parameters for a DBMS. Default is 0 which means unlimited. * @return int */ public function getParamsLimit(): int; From 22a1906d8dd567f16877c9f6f705e9b5f80e697f Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 12:58:22 +0500 Subject: [PATCH 054/137] Move BatchCommand into CommandInterface --- src/Command/AbstractCommand.php | 50 ++++++++++++++++--- ...ommandsCollection.php => BatchCommand.php} | 33 +----------- src/Command/CommandInterface.php | 2 +- src/Connection/AbstractConnection.php | 6 +-- src/Connection/ConnectionInterface.php | 8 +-- tests/AbstractCommandTest.php | 26 +++++----- 6 files changed, 64 insertions(+), 61 deletions(-) rename src/Command/{CommandsCollection.php => BatchCommand.php} (57%) diff --git a/src/Command/AbstractCommand.php b/src/Command/AbstractCommand.php index eaca59ff3..512eb373e 100644 --- a/src/Command/AbstractCommand.php +++ b/src/Command/AbstractCommand.php @@ -206,18 +206,54 @@ public function batchInsert(string $table, array $columns, iterable $rows): stat return $this->insertBatch($table, $rows, $columns); } - public function insertBatch(string $table, iterable $rows, array $columns = []): static + private function iterableToArray(iterable $iterable): array + { + $data = []; + foreach ($iterable as $row) { + $rowData = []; + foreach ($row as $column => $value) { + if (!is_array($value) && is_iterable($value)) { + $rowData[$column] = $this->iterableToArray($value); + } else { + $rowData[$column] = $value; + } + } + $data[] = $rowData; + } + + return $data; + } + + public function insertBatch(string $table, iterable $rows, array $columns = []): BatchCommand { - //mark this as deprecated and remove in future versions $table = $this->getQueryBuilder()->getQuoter()->getRawTableName($table); - $params = []; - $sql = $this->getQueryBuilder()->insertBatch($table, $rows, $columns, $params); + if (is_array($rows)) { + $data = $rows; + } else { + $data = $this->iterableToArray($rows); + } - $this->setRawSql($sql); - $this->bindValues($params); + $columnsCount = count($columns); + if ($columnsCount === 0 && count($data)) { + $columnsCount = count(array_keys($data[array_key_first($data)])); + } - return $this; + $maxParamsQty = $this->db->getParamsLimit(); + $totalInsertedParams = $columnsCount * count($data); + + $batchCommand = new BatchCommand($this->db); + if (!empty($maxParamsQty) && $totalInsertedParams > $maxParamsQty) { + $chunkSize = (int)floor($maxParamsQty / $columnsCount); + $rowChunks = array_chunk($data, $chunkSize); + foreach ($rowChunks as $rowChunk) { + $batchCommand->addInsertBatchCommand($table, $rowChunk, $columns); + } + } else { + $batchCommand->addInsertBatchCommand($table, $data, $columns); + } + + return $batchCommand; } abstract public function bindValue(int|string $name, mixed $value, ?int $dataType = null): static; diff --git a/src/Command/CommandsCollection.php b/src/Command/BatchCommand.php similarity index 57% rename from src/Command/CommandsCollection.php rename to src/Command/BatchCommand.php index f9a748424..438b6eda6 100644 --- a/src/Command/CommandsCollection.php +++ b/src/Command/BatchCommand.php @@ -7,7 +7,7 @@ use Yiisoft\Db\Exception\Exception; use Yiisoft\Db\Exception\InvalidConfigException; -class CommandsCollection implements Iterator, Countable +final class BatchCommand implements Iterator, Countable { /** * @var int Current iterator position @@ -54,36 +54,7 @@ function count(): int * @throws InvalidConfigException * @throws Exception */ - public function insertBatch(string $table, array $rows, array $columns = []): static - { - $table = $this->connection->getQuoter()->getRawTableName($table); - - $columnsCount = count($columns); - if ($columnsCount === 0 && count($rows) > 0) { - $columnsCount = count(array_keys($rows[array_key_first($rows)])); - } - - $maxParamsQty = $this->connection->getParamsLimit(); - $totalInsertedParams = $columnsCount * count($rows); - - if (!empty($maxParamsQty) && $totalInsertedParams > $maxParamsQty) { - $chunkSize = (int)floor($maxParamsQty / $columnsCount); - $rowChunks = array_chunk($rows, $chunkSize); - foreach ($rowChunks as $rowChunk) { - $this->commands[] = $this->createInsertBatchCommand($table, $rowChunk, $columns); - } - } else { - $this->commands[] = $this->createInsertBatchCommand($table, $rows, $columns); - } - - return $this; - } - - /** - * @throws InvalidConfigException - * @throws Exception - */ - private function createInsertBatchCommand(string $table, array $rows, array $columns = []): CommandInterface + public function addInsertBatchCommand(string $table, array $rows, array $columns = []): CommandInterface { $command = $this->connection->createCommand(); $params = []; diff --git a/src/Command/CommandInterface.php b/src/Command/CommandInterface.php index 6208fd90f..4fe9a07fc 100644 --- a/src/Command/CommandInterface.php +++ b/src/Command/CommandInterface.php @@ -201,7 +201,7 @@ public function alterColumn(string $table, string $column, ColumnInterface|strin * * Note: The method will quote the `table` and `column` parameters before using them in the generated SQL. */ - public function insertBatch(string $table, iterable $rows, array $columns = []): static; + public function insertBatch(string $table, iterable $rows, array $columns = []): BatchCommand; /** * Binds a parameter to the SQL statement to be executed. diff --git a/src/Connection/AbstractConnection.php b/src/Connection/AbstractConnection.php index 70cfed93a..2eeb9f0d3 100644 --- a/src/Connection/AbstractConnection.php +++ b/src/Connection/AbstractConnection.php @@ -6,7 +6,7 @@ use Closure; use Throwable; -use Yiisoft\Db\Command\CommandsCollection; +use Yiisoft\Db\Command\BatchCommand; use Yiisoft\Db\Query\BatchQueryResult; use Yiisoft\Db\Query\BatchQueryResultInterface; use Yiisoft\Db\Query\QueryInterface; @@ -128,8 +128,8 @@ public function getParamsLimit(): int return 0; } - public function createCommandsCollection(): CommandsCollection + public function createCommandsCollection(): BatchCommand { - return new CommandsCollection($this); + return new BatchCommand($this); } } diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index 4d2587afe..19aecfdf9 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -7,7 +7,7 @@ use Closure; use Throwable; use Yiisoft\Db\Command\CommandInterface; -use Yiisoft\Db\Command\CommandsCollection; +use Yiisoft\Db\Command\BatchCommand; use Yiisoft\Db\Exception\Exception; use Yiisoft\Db\Exception\InvalidCallException; use Yiisoft\Db\Exception\InvalidConfigException; @@ -235,10 +235,4 @@ public function transaction(Closure $closure, ?string $isolationLevel = null): m * @return int */ public function getParamsLimit(): int; - - /** - * Creates commands collection used for `insertBatch()` - * @return CommandsCollection - */ - public function createCommandsCollection(): CommandsCollection; } diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index 14ea2a106..ed7ab86f6 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -10,6 +10,7 @@ use Yiisoft\Db\Command\ParamInterface; use Yiisoft\Db\Exception\Exception; use Yiisoft\Db\Exception\IntegrityException; +use Yiisoft\Db\Exception\InvalidArgumentException; use Yiisoft\Db\Exception\InvalidConfigException; use Yiisoft\Db\Exception\NotSupportedException; use Yiisoft\Db\Profiler\Context\CommandContext; @@ -290,6 +291,13 @@ public function end(string $token, ContextInterface|array $context = []): void $db->close(); } + /** + * @throws InvalidArgumentException + * @throws NotSupportedException + * @throws Exception + * @throws Throwable + * @throws InvalidConfigException + */ public function testBindParamsOverflowIssue(): void { $db = $this->getConnection(); @@ -298,15 +306,6 @@ public function testBindParamsOverflowIssue(): void $this->markTestSkipped('Test is intended for use with pgsql database.'); } -// $skipVersions = ['11', '12', '16']; -// $dbmsVersion = $db->getServerInfo()->getVersion(); -// if (preg_match('/^(\d+)\.(\d+)/ui', $dbmsVersion, $matches)) { -// $dbmsVersion = $matches[1]; -// } -// if (in_array($dbmsVersion, $skipVersions)) { -// $this->markTestSkipped('Test is not applicable to pgsql v' . $dbmsVersion); -// } - $tempTableName = 'testTempTable'; $db->createCommand()->createTable($tempTableName, [ 'id' => ColumnBuilder::primaryKey(), @@ -328,15 +327,18 @@ public function testBindParamsOverflowIssue(): void ]; //generate 66 000 params (6 fields x 11000 lines) + $generateRowsCount = 11000; $insertData = []; - for ($i = 0; $i < 11000; $i++) { + for ($i = 0; $i < $generateRowsCount; $i++) { $insertData[] = $personData; } - $db->createCommandsCollection()->insertBatch($tempTableName, $insertData)->execute(); + $batchCommand = $db->createCommand()->insertBatch($tempTableName, $insertData); + $insertedRowsCount = $batchCommand->execute(); $countSql = 'SELECT COUNT(*) FROM ' . $db->getQuoter()->quoteTableName($tempTableName); - $this->assertEquals(11000, $db->createCommand($countSql)->queryScalar()); + $this->assertEquals($insertedRowsCount, $insertedRowsCount); + $this->assertEquals($generateRowsCount, $db->createCommand($countSql)->queryScalar()); $db->createCommand()->dropTable($tempTableName)->execute(); $db->close(); } From 951c0f709b292537611557556a516bb654fd7d7b Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 12:59:39 +0500 Subject: [PATCH 055/137] Move BatchCommand into CommandInterface --- src/Command/AbstractCommand.php | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/src/Command/AbstractCommand.php b/src/Command/AbstractCommand.php index 512eb373e..cd53d2cc1 100644 --- a/src/Command/AbstractCommand.php +++ b/src/Command/AbstractCommand.php @@ -206,24 +206,6 @@ public function batchInsert(string $table, array $columns, iterable $rows): stat return $this->insertBatch($table, $rows, $columns); } - private function iterableToArray(iterable $iterable): array - { - $data = []; - foreach ($iterable as $row) { - $rowData = []; - foreach ($row as $column => $value) { - if (!is_array($value) && is_iterable($value)) { - $rowData[$column] = $this->iterableToArray($value); - } else { - $rowData[$column] = $value; - } - } - $data[] = $rowData; - } - - return $data; - } - public function insertBatch(string $table, iterable $rows, array $columns = []): BatchCommand { $table = $this->getQueryBuilder()->getQuoter()->getRawTableName($table); @@ -231,7 +213,7 @@ public function insertBatch(string $table, iterable $rows, array $columns = []): if (is_array($rows)) { $data = $rows; } else { - $data = $this->iterableToArray($rows); + $data = iterator_to_array($rows); } $columnsCount = count($columns); From 87ff7b5d6620cac167b745b5fcc482a7f3db3dee Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 13:12:14 +0500 Subject: [PATCH 056/137] Adjusted batch insert test according to a new design --- src/Command/AbstractCommand.php | 11 +++++++---- src/Command/CommandInterface.php | 3 ++- tests/Db/Command/CommandTest.php | 10 +++++++--- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/Command/AbstractCommand.php b/src/Command/AbstractCommand.php index cd53d2cc1..a45fb6e28 100644 --- a/src/Command/AbstractCommand.php +++ b/src/Command/AbstractCommand.php @@ -206,7 +206,7 @@ public function batchInsert(string $table, array $columns, iterable $rows): stat return $this->insertBatch($table, $rows, $columns); } - public function insertBatch(string $table, iterable $rows, array $columns = []): BatchCommand + public function insertBatch(string $table, iterable $rows, array $columns = [], int $rowsAtOnceLimit = 0): BatchCommand { $table = $this->getQueryBuilder()->getQuoter()->getRawTableName($table); @@ -221,12 +221,15 @@ public function insertBatch(string $table, iterable $rows, array $columns = []): $columnsCount = count(array_keys($data[array_key_first($data)])); } - $maxParamsQty = $this->db->getParamsLimit(); + $maxParamsLimit = $this->db->getParamsLimit(); + if (!empty($maxParamsLimit) && !empty($rowsAtOnceLimit) && $rowsAtOnceLimit > $maxParamsLimit) { + $maxParamsLimit = $rowsAtOnceLimit; + } $totalInsertedParams = $columnsCount * count($data); $batchCommand = new BatchCommand($this->db); - if (!empty($maxParamsQty) && $totalInsertedParams > $maxParamsQty) { - $chunkSize = (int)floor($maxParamsQty / $columnsCount); + if (!empty($maxParamsLimit) && $totalInsertedParams > $maxParamsLimit) { + $chunkSize = (int)floor($maxParamsLimit / $columnsCount); $rowChunks = array_chunk($data, $chunkSize); foreach ($rowChunks as $rowChunk) { $batchCommand->addInsertBatchCommand($table, $rowChunk, $columns); diff --git a/src/Command/CommandInterface.php b/src/Command/CommandInterface.php index 4fe9a07fc..c558c2c55 100644 --- a/src/Command/CommandInterface.php +++ b/src/Command/CommandInterface.php @@ -193,6 +193,7 @@ public function alterColumn(string $table, string $column, ColumnInterface|strin * @param string $table The name of the table to insert new rows into. * @param iterable $rows The rows to be batch inserted into the table. * @param string[] $columns The column names. + * @param int $rowsAtOnceLimit Limit number of rows inserted at once. Default 0 - means maximum allowed by DBMS. * * @throws Exception * @throws InvalidArgumentException @@ -201,7 +202,7 @@ public function alterColumn(string $table, string $column, ColumnInterface|strin * * Note: The method will quote the `table` and `column` parameters before using them in the generated SQL. */ - public function insertBatch(string $table, iterable $rows, array $columns = []): BatchCommand; + public function insertBatch(string $table, iterable $rows, array $columns = [], int $rowsAtOnceLimit = 0): BatchCommand; /** * Binds a parameter to the SQL statement to be executed. diff --git a/tests/Db/Command/CommandTest.php b/tests/Db/Command/CommandTest.php index 32ef6863b..94cdf6293 100644 --- a/tests/Db/Command/CommandTest.php +++ b/tests/Db/Command/CommandTest.php @@ -196,9 +196,13 @@ public function testBatchInsert(): void $db = $this->getConnection(); $command = $db->createCommand(); - $command->insertBatch('table', [['value1', 'value2'], ['value3', 'value4']], ['column1', 'column2']); + $batchCommands = $command->insertBatch('table', [['value1', 'value2'], ['value3', 'value4']], ['column1', 'column2']); - $this->assertSame('INSERT INTO [table] ([column1], [column2]) VALUES (:qp0, :qp1), (:qp2, :qp3)', $command->getSql()); + $this->assertSame(1, count($batchCommands)); + + $batchCommands->next(); + $firstCommand = $batchCommands->current(); + $this->assertSame('INSERT INTO [table] ([column1], [column2]) VALUES (:qp0, :qp1), (:qp2, :qp3)', $firstCommand->getSql()); $this->assertSame( [ ':qp0' => 'value1', @@ -206,7 +210,7 @@ public function testBatchInsert(): void ':qp2' => 'value3', ':qp3' => 'value4', ], - $command->getParams() + $firstCommand->getParams() ); $db->close(); } From 48df33f0e8c0e99e3d5770fcfb4ed044db1b9312 Mon Sep 17 00:00:00 2001 From: evil1 <5018681+evil1@users.noreply.github.com> Date: Tue, 1 Apr 2025 08:13:01 +0000 Subject: [PATCH 057/137] Apply Rector changes (CI) --- src/Debug/CommandInterfaceProxy.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Debug/CommandInterfaceProxy.php b/src/Debug/CommandInterfaceProxy.php index 85677e1bd..45a6d75a5 100644 --- a/src/Debug/CommandInterfaceProxy.php +++ b/src/Debug/CommandInterfaceProxy.php @@ -101,7 +101,7 @@ public function alterColumn(string $table, string $column, ColumnInterface|strin /** * @psalm-suppress MixedArgument */ - public function insertBatch(string $table, iterable $rows, array $columns = []): static + public function insertBatch(string $table, iterable $rows, array $columns = [], int $rowsAtOnceLimit = 0): static { return new self($this->decorated->{__FUNCTION__}(...func_get_args()), $this->collector); } From 281f2ae4ba2019a7733c7a7d5dba67520434c0d5 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 13:45:16 +0500 Subject: [PATCH 058/137] Adjusted batch insert test according to a new design --- src/Command/BatchCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Command/BatchCommand.php b/src/Command/BatchCommand.php index 72da2ed75..5b3e8247f 100644 --- a/src/Command/BatchCommand.php +++ b/src/Command/BatchCommand.php @@ -54,7 +54,7 @@ function count(): int * @throws InvalidConfigException * @throws Exception */ - public function addInsertBatchCommand(string $table, array $rows, array $columns = []): CommandInterface + public function addInsertBatchCommand(string $table, array $rows, array $columns = []): void { $command = $this->connection->createCommand(); $params = []; @@ -63,7 +63,7 @@ public function addInsertBatchCommand(string $table, array $rows, array $columns $command->setRawSql($sql); $command->bindValues($params); - return $command; + $this->commands[] = $command; } /** From 703ca43423bd491b644df8212853da99130e840f Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 13:48:54 +0500 Subject: [PATCH 059/137] Adjusted batch insert test according to a new design --- tests/Db/Command/CommandTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Db/Command/CommandTest.php b/tests/Db/Command/CommandTest.php index 94cdf6293..40316d272 100644 --- a/tests/Db/Command/CommandTest.php +++ b/tests/Db/Command/CommandTest.php @@ -200,7 +200,6 @@ public function testBatchInsert(): void $this->assertSame(1, count($batchCommands)); - $batchCommands->next(); $firstCommand = $batchCommands->current(); $this->assertSame('INSERT INTO [table] ([column1], [column2]) VALUES (:qp0, :qp1), (:qp2, :qp3)', $firstCommand->getSql()); $this->assertSame( @@ -210,7 +209,7 @@ public function testBatchInsert(): void ':qp2' => 'value3', ':qp3' => 'value4', ], - $firstCommand->getParams() + $command->getParams() ); $db->close(); } From f58ce6f66aa96c8fa2b1393aaef9a8a8dd4cb6bf Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 13:51:08 +0500 Subject: [PATCH 060/137] Adjusted batch insert test according to a new design --- src/Command/BatchCommand.php | 8 ++++---- tests/Db/Command/CommandTest.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Command/BatchCommand.php b/src/Command/BatchCommand.php index 5b3e8247f..3351a8d24 100644 --- a/src/Command/BatchCommand.php +++ b/src/Command/BatchCommand.php @@ -19,9 +19,9 @@ final class BatchCommand implements Iterator, Countable private array $commands = []; /** - * @param ConnectionInterface $connection Connection to a database. + * @param ConnectionInterface $db Connection to a database. */ - public function __construct(private readonly ConnectionInterface $connection) + public function __construct(private readonly ConnectionInterface $db) { } @@ -56,9 +56,9 @@ function count(): int */ public function addInsertBatchCommand(string $table, array $rows, array $columns = []): void { - $command = $this->connection->createCommand(); + $command = $this->db->createCommand(); $params = []; - $sql = $this->connection->getQueryBuilder()->insertBatch($table, $rows, $columns, $params); + $sql = $this->db->getQueryBuilder()->insertBatch($table, $rows, $columns, $params); $command->setRawSql($sql); $command->bindValues($params); diff --git a/tests/Db/Command/CommandTest.php b/tests/Db/Command/CommandTest.php index 40316d272..fb65127d3 100644 --- a/tests/Db/Command/CommandTest.php +++ b/tests/Db/Command/CommandTest.php @@ -209,7 +209,7 @@ public function testBatchInsert(): void ':qp2' => 'value3', ':qp3' => 'value4', ], - $command->getParams() + $firstCommand->getParams() ); $db->close(); } From a684cc0f40e5d21be215792220bcb98a4c88b17b Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 15:42:30 +0500 Subject: [PATCH 061/137] Adjusted batch insert test according to a new design --- src/Command/AbstractCommand.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Command/AbstractCommand.php b/src/Command/AbstractCommand.php index a45fb6e28..137b8d7b4 100644 --- a/src/Command/AbstractCommand.php +++ b/src/Command/AbstractCommand.php @@ -218,7 +218,12 @@ public function insertBatch(string $table, iterable $rows, array $columns = [], $columnsCount = count($columns); if ($columnsCount === 0 && count($data)) { - $columnsCount = count(array_keys($data[array_key_first($data)])); + $firstRow = $data[array_key_first($data)]; + if (is_object($firstRow)) { + $columnsCount = count(array_keys(get_object_vars($firstRow))); + } else { + $columnsCount = count(array_keys($firstRow)); + } } $maxParamsLimit = $this->db->getParamsLimit(); From 4139d816a5dcf770fdda1705df82729b9ee97e27 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 15:49:48 +0500 Subject: [PATCH 062/137] Adjusted batch insert test according to a new design --- tests/Common/CommonCommandTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Common/CommonCommandTest.php b/tests/Common/CommonCommandTest.php index a30ff02b1..43e95f0c4 100644 --- a/tests/Common/CommonCommandTest.php +++ b/tests/Common/CommonCommandTest.php @@ -421,13 +421,13 @@ public function testBatchInsertWithDuplicates(): void $db = $this->getConnection(true); $command = $db->createCommand(); - $command->insertBatch( + $batchCommand = $command->insertBatch( '{{customer}}', [['t1@example.com', 'test_name', 'test_address']], ['email', 'name', 'address'], ); - $this->assertSame(1, $command->execute()); + $this->assertSame(1, $batchCommand->execute()); $result = (new Query($db)) ->select(['email', 'name', 'address']) @@ -458,9 +458,9 @@ public function testBatchInsertWithManyData(): void $values[$i] = ['t' . $i . '@any.com', 't' . $i, 't' . $i . ' address']; } - $command->insertBatch('{{customer}}', $values, ['email', 'name', 'address']); + $batchCommand = $command->insertBatch('{{customer}}', $values, ['email', 'name', 'address']); - $this->assertSame($attemptsInsertRows, $command->execute()); + $this->assertSame($attemptsInsertRows, $batchCommand->execute()); $insertedRowsCount = (new Query($db))->from('{{customer}}')->count(); From 9e3507c229563c2fb073134728ceb2c58a582207 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 16:19:45 +0500 Subject: [PATCH 063/137] Adjusted batch insert test according to a new design --- src/Command/AbstractCommand.php | 9 +-------- src/QueryBuilder/AbstractDMLQueryBuilder.php | 2 +- src/QueryBuilder/DMLQueryBuilderInterface.php | 13 +++++++++++++ 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/Command/AbstractCommand.php b/src/Command/AbstractCommand.php index 137b8d7b4..ae7cb67bd 100644 --- a/src/Command/AbstractCommand.php +++ b/src/Command/AbstractCommand.php @@ -216,15 +216,8 @@ public function insertBatch(string $table, iterable $rows, array $columns = [], $data = iterator_to_array($rows); } + $columns = $this->getQueryBuilder()->extractColumnNames($data, $columns); $columnsCount = count($columns); - if ($columnsCount === 0 && count($data)) { - $firstRow = $data[array_key_first($data)]; - if (is_object($firstRow)) { - $columnsCount = count(array_keys(get_object_vars($firstRow))); - } else { - $columnsCount = count(array_keys($firstRow)); - } - } $maxParamsLimit = $this->db->getParamsLimit(); if (!empty($maxParamsLimit) && !empty($rowsAtOnceLimit) && $rowsAtOnceLimit > $maxParamsLimit) { diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index c28368ed4..4e79a6ff5 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -225,7 +225,7 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array * * @psalm-param Iterator|non-empty-array> $rows */ - protected function extractColumnNames(array|Iterator $rows, array $columns): array + public function extractColumnNames(array|Iterator $rows, array $columns): array { $columns = $this->getNormalizeColumnNames($columns); diff --git a/src/QueryBuilder/DMLQueryBuilderInterface.php b/src/QueryBuilder/DMLQueryBuilderInterface.php index 463d7ccd9..3643ccdd3 100644 --- a/src/QueryBuilder/DMLQueryBuilderInterface.php +++ b/src/QueryBuilder/DMLQueryBuilderInterface.php @@ -4,6 +4,7 @@ namespace Yiisoft\Db\QueryBuilder; +use Iterator; use JsonException; use Yiisoft\Db\Connection\ConnectionInterface; use Yiisoft\Db\Exception\Exception; @@ -227,4 +228,16 @@ public function upsert( bool|array $updateColumns, array &$params ): string; + + /** + * Extract column names from columns and rows. + * + * @param array[]|Iterator $rows The rows to be batch inserted into the table. + * @param string[] $columns The column names. + * + * @return string[] The column names. + * + * @psalm-param Iterator|non-empty-array> $rows + */ + public function extractColumnNames(array|Iterator $rows, array $columns): array; } From 5d43b04c846c2643ecdd219759773d716366a43e Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 16:22:56 +0500 Subject: [PATCH 064/137] Adjusted batch insert test according to a new design --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 4e79a6ff5..8c0e4edaa 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -225,7 +225,7 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array * * @psalm-param Iterator|non-empty-array> $rows */ - public function extractColumnNames(array|Iterator $rows, array $columns): array + final public function extractColumnNames(array|Iterator $rows, array $columns): array { $columns = $this->getNormalizeColumnNames($columns); From 32d8d7eba37c9184c9fce0ae3e28ca7b117aa6e4 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 16:30:59 +0500 Subject: [PATCH 065/137] Adjusted batch insert test according to a new design --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 10 ---------- src/QueryBuilder/AbstractQueryBuilder.php | 6 ++++++ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 8c0e4edaa..b52584331 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -215,16 +215,6 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array return $values; } - /** - * Extract column names from columns and rows. - * - * @param array[]|Iterator $rows The rows to be batch inserted into the table. - * @param string[] $columns The column names. - * - * @return string[] The column names. - * - * @psalm-param Iterator|non-empty-array> $rows - */ final public function extractColumnNames(array|Iterator $rows, array $columns): array { $columns = $this->getNormalizeColumnNames($columns); diff --git a/src/QueryBuilder/AbstractQueryBuilder.php b/src/QueryBuilder/AbstractQueryBuilder.php index c3bffadca..751b5cb27 100644 --- a/src/QueryBuilder/AbstractQueryBuilder.php +++ b/src/QueryBuilder/AbstractQueryBuilder.php @@ -4,6 +4,7 @@ namespace Yiisoft\Db\QueryBuilder; +use Iterator; use Yiisoft\Db\Command\CommandInterface; use Yiisoft\Db\Constant\DataType; use Yiisoft\Db\Command\ParamInterface; @@ -495,4 +496,9 @@ protected function prepareBinary(string $binary): string { return '0x' . bin2hex($binary); } + + public function extractColumnNames(array|Iterator $rows, array $columns): array + { + return $this->dmlBuilder->extractColumnNames($rows, $columns); + } } From 61001684abad3a274762540fc148c214d51ad99e Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 16:36:37 +0500 Subject: [PATCH 066/137] Adjusted batch insert test according to a new design --- tests/Common/CommonCommandTest.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/Common/CommonCommandTest.php b/tests/Common/CommonCommandTest.php index 43e95f0c4..3ede01724 100644 --- a/tests/Common/CommonCommandTest.php +++ b/tests/Common/CommonCommandTest.php @@ -322,13 +322,15 @@ public function testBatchInsert( $db = $this->getConnection(true); $command = $db->createCommand(); - $command->insertBatch($table, $values, $columns); + $batchCommand = $command->insertBatch($table, $values, $columns); - $this->assertSame($expected, $command->getSql()); - $this->assertSame($expectedParams, $command->getParams()); + $firstCommand = $batchCommand->current(); - $command->prepare(false); - $command->execute(); + $this->assertSame($expected, $firstCommand->getSql()); + $this->assertSame($expectedParams, $firstCommand->getParams()); + + $firstCommand->prepare(false); + $batchCommand->execute(); $this->assertEquals($insertedRow, (new Query($db))->from($table)->count()); From b48e8e241c3853c50cacca525118380a32fa3048 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 16:41:37 +0500 Subject: [PATCH 067/137] Adjusted batch insert test according to a new design --- tests/Common/CommonCommandTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Common/CommonCommandTest.php b/tests/Common/CommonCommandTest.php index 3ede01724..f179505d9 100644 --- a/tests/Common/CommonCommandTest.php +++ b/tests/Common/CommonCommandTest.php @@ -486,9 +486,9 @@ static function () { } )(); $command = $db->createCommand(); - $command->insertBatch('{{customer}}', $rows, ['email', 'name', 'address']); + $batchCommand = $command->insertBatch('{{customer}}', $rows, ['email', 'name', 'address']); - $this->assertSame(1, $command->execute()); + $this->assertSame(1, $batchCommand->execute()); $db->close(); } From 31a09b401c67fb737225835d8756e400d68f6f05 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 17:32:39 +0500 Subject: [PATCH 068/137] Adjusted batch insert test according to a new design --- src/Command/AbstractCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Command/AbstractCommand.php b/src/Command/AbstractCommand.php index ae7cb67bd..2f845243b 100644 --- a/src/Command/AbstractCommand.php +++ b/src/Command/AbstractCommand.php @@ -201,7 +201,7 @@ public function alterColumn(string $table, string $column, ColumnInterface|strin * * @deprecated Use {@see insertBatch()} instead. It will be removed in version 3.0.0. */ - public function batchInsert(string $table, array $columns, iterable $rows): static + public function batchInsert(string $table, array $columns, iterable $rows): BatchCommand { return $this->insertBatch($table, $rows, $columns); } From a3202bd9f8fbc465d03ac09a0769af39d4728e45 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 17:38:18 +0500 Subject: [PATCH 069/137] Adjusted batch insert test according to a new design --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 2 +- src/QueryBuilder/AbstractQueryBuilder.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index b52584331..a466abaf3 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -215,7 +215,7 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array return $values; } - final public function extractColumnNames(array|Iterator $rows, array $columns): array + public function extractColumnNames(array|Iterator $rows, array $columns): array { $columns = $this->getNormalizeColumnNames($columns); diff --git a/src/QueryBuilder/AbstractQueryBuilder.php b/src/QueryBuilder/AbstractQueryBuilder.php index 751b5cb27..1cb3050cf 100644 --- a/src/QueryBuilder/AbstractQueryBuilder.php +++ b/src/QueryBuilder/AbstractQueryBuilder.php @@ -497,7 +497,7 @@ protected function prepareBinary(string $binary): string return '0x' . bin2hex($binary); } - public function extractColumnNames(array|Iterator $rows, array $columns): array + public function extractColumnNames(iterable $rows, array $columns): array { return $this->dmlBuilder->extractColumnNames($rows, $columns); } From 4eed6d30328deb6f70796b46c435539d455a252b Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 17:44:47 +0500 Subject: [PATCH 070/137] Adjusted batch insert test according to a new design --- src/Command/AbstractCommand.php | 10 ++++++++-- src/Driver/Pdo/AbstractPdoCommand.php | 6 ++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Command/AbstractCommand.php b/src/Command/AbstractCommand.php index 2f845243b..a661702ed 100644 --- a/src/Command/AbstractCommand.php +++ b/src/Command/AbstractCommand.php @@ -6,6 +6,7 @@ use Closure; use Throwable; +use Yiisoft\Db\Connection\ConnectionInterface; use Yiisoft\Db\Exception\Exception; use Yiisoft\Db\Query\Data\DataReaderInterface; use Yiisoft\Db\Query\QueryInterface; @@ -219,13 +220,13 @@ public function insertBatch(string $table, iterable $rows, array $columns = [], $columns = $this->getQueryBuilder()->extractColumnNames($data, $columns); $columnsCount = count($columns); - $maxParamsLimit = $this->db->getParamsLimit(); + $maxParamsLimit = $this->getConnection()->getParamsLimit(); if (!empty($maxParamsLimit) && !empty($rowsAtOnceLimit) && $rowsAtOnceLimit > $maxParamsLimit) { $maxParamsLimit = $rowsAtOnceLimit; } $totalInsertedParams = $columnsCount * count($data); - $batchCommand = new BatchCommand($this->db); + $batchCommand = new BatchCommand($this->getConnection()); if (!empty($maxParamsLimit) && $totalInsertedParams > $maxParamsLimit) { $chunkSize = (int)floor($maxParamsLimit / $columnsCount); $rowChunks = array_chunk($data, $chunkSize); @@ -541,6 +542,11 @@ public function upsert( return $this->setSql($sql)->bindValues($params); } + /** + * @return ConnectionInterface The query builder instance. + */ + abstract protected function getConnection(): ConnectionInterface; + /** * @return QueryBuilderInterface The query builder instance. */ diff --git a/src/Driver/Pdo/AbstractPdoCommand.php b/src/Driver/Pdo/AbstractPdoCommand.php index bfcb018b5..7ce3e6131 100644 --- a/src/Driver/Pdo/AbstractPdoCommand.php +++ b/src/Driver/Pdo/AbstractPdoCommand.php @@ -14,6 +14,7 @@ use Yiisoft\Db\Command\AbstractCommand; use Yiisoft\Db\Command\Param; use Yiisoft\Db\Command\ParamInterface; +use Yiisoft\Db\Connection\ConnectionInterface; use Yiisoft\Db\Exception\ConvertException; use Yiisoft\Db\Exception\Exception; use Yiisoft\Db\Exception\InvalidParamException; @@ -166,6 +167,11 @@ protected function bindPendingParams(): void } } + protected function getConnection(): ConnectionInterface + { + return $this->db; + } + protected function getQueryBuilder(): QueryBuilderInterface { return $this->db->getQueryBuilder(); From b1ec11efcfe1fe5c0bd842d1aa536ded67e28d43 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 17:54:06 +0500 Subject: [PATCH 071/137] Adjusted batch insert test according to a new design --- src/Debug/CommandInterfaceProxy.php | 5 +++-- src/Debug/ConnectionInterfaceProxy.php | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Debug/CommandInterfaceProxy.php b/src/Debug/CommandInterfaceProxy.php index 45a6d75a5..e827d6e7d 100644 --- a/src/Debug/CommandInterfaceProxy.php +++ b/src/Debug/CommandInterfaceProxy.php @@ -6,6 +6,7 @@ use Closure; use Throwable; +use Yiisoft\Db\Command\BatchCommand; use Yiisoft\Db\Command\CommandInterface; use Yiisoft\Db\Query\Data\DataReaderInterface; use Yiisoft\Db\Query\QueryInterface; @@ -101,9 +102,9 @@ public function alterColumn(string $table, string $column, ColumnInterface|strin /** * @psalm-suppress MixedArgument */ - public function insertBatch(string $table, iterable $rows, array $columns = [], int $rowsAtOnceLimit = 0): static + public function insertBatch(string $table, iterable $rows, array $columns = [], int $rowsAtOnceLimit = 0): BatchCommand { - return new self($this->decorated->{__FUNCTION__}(...func_get_args()), $this->collector); + return $this->decorated->{__FUNCTION__}(...func_get_args()); } /** diff --git a/src/Debug/ConnectionInterfaceProxy.php b/src/Debug/ConnectionInterfaceProxy.php index 3fde6420b..7835a2c65 100644 --- a/src/Debug/ConnectionInterfaceProxy.php +++ b/src/Debug/ConnectionInterfaceProxy.php @@ -163,4 +163,9 @@ public function getDriverName(): string { return $this->connection->getDriverName(); } + + public function getParamsLimit(): int + { + return $this->connection->getParamsLimit(); + } } From fdf306618ceba27a12991117d3c3d7e05ccc93fd Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 18:09:12 +0500 Subject: [PATCH 072/137] Adjusted batch insert test according to a new design --- src/Command/BatchCommand.php | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Command/BatchCommand.php b/src/Command/BatchCommand.php index 3351a8d24..4676e6f3e 100644 --- a/src/Command/BatchCommand.php +++ b/src/Command/BatchCommand.php @@ -5,8 +5,15 @@ use Countable; use Yiisoft\Db\Connection\ConnectionInterface; use Yiisoft\Db\Exception\Exception; +use Yiisoft\Db\Exception\InvalidArgumentException; use Yiisoft\Db\Exception\InvalidConfigException; +use Yiisoft\Db\QueryBuilder\DMLQueryBuilderInterface; +/** + * Object used as batch commands container + * + * @psalm-import-type BatchValues from DMLQueryBuilderInterface + */ final class BatchCommand implements Iterator, Countable { /** @@ -51,10 +58,21 @@ function count(): int } /** + * Adds batch insert commands into execution queue + * + * @param string $table The name of the table to insert new rows into. + * @param iterable $rows The rows to be batch inserted into the table. + * @param string[] $columns The column names. + * + * @throws Exception + * @throws InvalidArgumentException + * + * @psalm-param BatchValues $rows + * * @throws InvalidConfigException * @throws Exception */ - public function addInsertBatchCommand(string $table, array $rows, array $columns = []): void + public function addInsertBatchCommand(string $table, iterable $rows, array $columns = []): void { $command = $this->db->createCommand(); $params = []; From 05e72b0cd2b0e78199615964648311c4308b17c9 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 18:13:59 +0500 Subject: [PATCH 073/137] Adjusted batch insert test according to a new design --- src/Debug/CommandInterfaceProxy.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Debug/CommandInterfaceProxy.php b/src/Debug/CommandInterfaceProxy.php index e827d6e7d..1721c5238 100644 --- a/src/Debug/CommandInterfaceProxy.php +++ b/src/Debug/CommandInterfaceProxy.php @@ -99,9 +99,6 @@ public function alterColumn(string $table, string $column, ColumnInterface|strin return new self($this->decorated->{__FUNCTION__}(...func_get_args()), $this->collector); } - /** - * @psalm-suppress MixedArgument - */ public function insertBatch(string $table, iterable $rows, array $columns = [], int $rowsAtOnceLimit = 0): BatchCommand { return $this->decorated->{__FUNCTION__}(...func_get_args()); From aa8ef7980a2941286bcc3b316f61a74c3ddbb241 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 18:22:12 +0500 Subject: [PATCH 074/137] Adjusted batch insert test according to a new design --- src/Command/BatchCommand.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Command/BatchCommand.php b/src/Command/BatchCommand.php index 4676e6f3e..abebbcaaa 100644 --- a/src/Command/BatchCommand.php +++ b/src/Command/BatchCommand.php @@ -12,6 +12,8 @@ /** * Object used as batch commands container * + * @implements Iterator + * * @psalm-import-type BatchValues from DMLQueryBuilderInterface */ final class BatchCommand implements Iterator, Countable From 0fcdee0016ddaaa3261f8372988c87e884e59d12 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 18:27:41 +0500 Subject: [PATCH 075/137] Adjusted batch insert test according to a new design --- src/Debug/CommandInterfaceProxy.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Debug/CommandInterfaceProxy.php b/src/Debug/CommandInterfaceProxy.php index 1721c5238..46e37bd70 100644 --- a/src/Debug/CommandInterfaceProxy.php +++ b/src/Debug/CommandInterfaceProxy.php @@ -99,6 +99,9 @@ public function alterColumn(string $table, string $column, ColumnInterface|strin return new self($this->decorated->{__FUNCTION__}(...func_get_args()), $this->collector); } + /** + * @psalm-suppress MixedReturnStatement + */ public function insertBatch(string $table, iterable $rows, array $columns = [], int $rowsAtOnceLimit = 0): BatchCommand { return $this->decorated->{__FUNCTION__}(...func_get_args()); From 0d57a8c1ef144bcb7f00804c45e92be8b31577f6 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 18:49:53 +0500 Subject: [PATCH 076/137] Adjusted batch insert test according to a new design --- src/Command/AbstractCommand.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Command/AbstractCommand.php b/src/Command/AbstractCommand.php index a661702ed..bee781ff2 100644 --- a/src/Command/AbstractCommand.php +++ b/src/Command/AbstractCommand.php @@ -210,6 +210,7 @@ public function batchInsert(string $table, array $columns, iterable $rows): Batc public function insertBatch(string $table, iterable $rows, array $columns = [], int $rowsAtOnceLimit = 0): BatchCommand { $table = $this->getQueryBuilder()->getQuoter()->getRawTableName($table); + $batchCommand = new BatchCommand($this->getConnection()); if (is_array($rows)) { $data = $rows; @@ -217,6 +218,9 @@ public function insertBatch(string $table, iterable $rows, array $columns = [], $data = iterator_to_array($rows); } + if (empty($data)) { + return $batchCommand; + } $columns = $this->getQueryBuilder()->extractColumnNames($data, $columns); $columnsCount = count($columns); @@ -226,7 +230,6 @@ public function insertBatch(string $table, iterable $rows, array $columns = [], } $totalInsertedParams = $columnsCount * count($data); - $batchCommand = new BatchCommand($this->getConnection()); if (!empty($maxParamsLimit) && $totalInsertedParams > $maxParamsLimit) { $chunkSize = (int)floor($maxParamsLimit / $columnsCount); $rowChunks = array_chunk($data, $chunkSize); From 5a576f6e40a6cb881cd096ff413658f2be8b9547 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 19:07:11 +0500 Subject: [PATCH 077/137] Adjusted batch insert test according to a new design --- src/Command/BatchCommand.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Command/BatchCommand.php b/src/Command/BatchCommand.php index abebbcaaa..e77ae7034 100644 --- a/src/Command/BatchCommand.php +++ b/src/Command/BatchCommand.php @@ -1,4 +1,5 @@ position = 0; } - function current(): CommandInterface { + public function current(): CommandInterface { return $this->commands[$this->position]; } @@ -46,15 +47,15 @@ function key(): int { return $this->position; } - function next(): void { + public function next(): void { ++$this->position; } - function valid(): bool { + public function valid(): bool { return isset($this->commands[$this->position]); } - function count(): int + public function count(): int { return count($this->commands); } From 1dc68256825aa6be0c48e82b1d48a365bf79f357 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 19:08:09 +0500 Subject: [PATCH 078/137] Adjusted batch insert test according to a new design --- src/Command/BatchCommand.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Command/BatchCommand.php b/src/Command/BatchCommand.php index e77ae7034..6dd35043b 100644 --- a/src/Command/BatchCommand.php +++ b/src/Command/BatchCommand.php @@ -35,23 +35,28 @@ public function __construct(private readonly ConnectionInterface $db) { } - public function rewind(): void { + public function rewind(): void + { $this->position = 0; } - public function current(): CommandInterface { + public function current(): CommandInterface + { return $this->commands[$this->position]; } - function key(): int { + function key(): int + { return $this->position; } - public function next(): void { + public function next(): void + { ++$this->position; } - public function valid(): bool { + public function valid(): bool + { return isset($this->commands[$this->position]); } From 05ad7a705f59cf965810412f9626424f88ae17b2 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 19:12:50 +0500 Subject: [PATCH 079/137] Adjusted batch insert test according to a new design --- src/Command/BatchCommand.php | 2 +- src/Connection/ConnectionInterface.php | 1 - src/QueryBuilder/AbstractQueryBuilder.php | 1 - tests/AbstractCommandTest.php | 1 - tests/Db/Command/CommandTest.php | 2 +- 5 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Command/BatchCommand.php b/src/Command/BatchCommand.php index 6dd35043b..2b05c9438 100644 --- a/src/Command/BatchCommand.php +++ b/src/Command/BatchCommand.php @@ -45,7 +45,7 @@ public function current(): CommandInterface return $this->commands[$this->position]; } - function key(): int + public function key(): int { return $this->position; } diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index 0fbd11496..4f082584e 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -7,7 +7,6 @@ use Closure; use Throwable; use Yiisoft\Db\Command\CommandInterface; -use Yiisoft\Db\Command\BatchCommand; use Yiisoft\Db\Exception\Exception; use Yiisoft\Db\Exception\InvalidCallException; use Yiisoft\Db\Exception\InvalidConfigException; diff --git a/src/QueryBuilder/AbstractQueryBuilder.php b/src/QueryBuilder/AbstractQueryBuilder.php index 1cb3050cf..444f5a187 100644 --- a/src/QueryBuilder/AbstractQueryBuilder.php +++ b/src/QueryBuilder/AbstractQueryBuilder.php @@ -4,7 +4,6 @@ namespace Yiisoft\Db\QueryBuilder; -use Iterator; use Yiisoft\Db\Command\CommandInterface; use Yiisoft\Db\Constant\DataType; use Yiisoft\Db\Command\ParamInterface; diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index ed7ab86f6..acf1fc3f9 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -9,7 +9,6 @@ use Yiisoft\Db\Command\Param; use Yiisoft\Db\Command\ParamInterface; use Yiisoft\Db\Exception\Exception; -use Yiisoft\Db\Exception\IntegrityException; use Yiisoft\Db\Exception\InvalidArgumentException; use Yiisoft\Db\Exception\InvalidConfigException; use Yiisoft\Db\Exception\NotSupportedException; diff --git a/tests/Db/Command/CommandTest.php b/tests/Db/Command/CommandTest.php index fb65127d3..2974c817c 100644 --- a/tests/Db/Command/CommandTest.php +++ b/tests/Db/Command/CommandTest.php @@ -198,7 +198,7 @@ public function testBatchInsert(): void $command = $db->createCommand(); $batchCommands = $command->insertBatch('table', [['value1', 'value2'], ['value3', 'value4']], ['column1', 'column2']); - $this->assertSame(1, count($batchCommands)); + $this->assertSame(1, $batchCommands); $firstCommand = $batchCommands->current(); $this->assertSame('INSERT INTO [table] ([column1], [column2]) VALUES (:qp0, :qp1), (:qp2, :qp3)', $firstCommand->getSql()); From 08e1b721f23b5c459b64f0948017d0250fb93443 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 19:13:40 +0500 Subject: [PATCH 080/137] Fix CI styling --- src/Command/BatchCommand.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Command/BatchCommand.php b/src/Command/BatchCommand.php index 2b05c9438..bacb0f863 100644 --- a/src/Command/BatchCommand.php +++ b/src/Command/BatchCommand.php @@ -1,5 +1,7 @@ Date: Tue, 1 Apr 2025 19:26:18 +0500 Subject: [PATCH 081/137] Fix CI styling --- tests/Db/Command/CommandTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Db/Command/CommandTest.php b/tests/Db/Command/CommandTest.php index 2974c817c..97438fe90 100644 --- a/tests/Db/Command/CommandTest.php +++ b/tests/Db/Command/CommandTest.php @@ -198,7 +198,7 @@ public function testBatchInsert(): void $command = $db->createCommand(); $batchCommands = $command->insertBatch('table', [['value1', 'value2'], ['value3', 'value4']], ['column1', 'column2']); - $this->assertSame(1, $batchCommands); + $this->assertSame(1, $batchCommands->count()); $firstCommand = $batchCommands->current(); $this->assertSame('INSERT INTO [table] ([column1], [column2]) VALUES (:qp0, :qp1), (:qp2, :qp3)', $firstCommand->getSql()); From 1bb5b2e035f35c24e5843b0bdd568ce065d04b5b Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 20:33:21 +0500 Subject: [PATCH 082/137] Fix CI styling --- src/Command/AbstractCommand.php | 2 +- src/Connection/AbstractConnection.php | 10 ++-------- src/Connection/ConnectionInterface.php | 2 +- src/Debug/ConnectionInterfaceProxy.php | 4 ++-- tests/Db/Connection/ConnectionTest.php | 5 +++++ 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/Command/AbstractCommand.php b/src/Command/AbstractCommand.php index bee781ff2..3b1eb29c8 100644 --- a/src/Command/AbstractCommand.php +++ b/src/Command/AbstractCommand.php @@ -224,7 +224,7 @@ public function insertBatch(string $table, iterable $rows, array $columns = [], $columns = $this->getQueryBuilder()->extractColumnNames($data, $columns); $columnsCount = count($columns); - $maxParamsLimit = $this->getConnection()->getParamsLimit(); + $maxParamsLimit = $this->getConnection()->getParametersLimit(); if (!empty($maxParamsLimit) && !empty($rowsAtOnceLimit) && $rowsAtOnceLimit > $maxParamsLimit) { $maxParamsLimit = $rowsAtOnceLimit; } diff --git a/src/Connection/AbstractConnection.php b/src/Connection/AbstractConnection.php index 2eeb9f0d3..5145e9908 100644 --- a/src/Connection/AbstractConnection.php +++ b/src/Connection/AbstractConnection.php @@ -6,7 +6,6 @@ use Closure; use Throwable; -use Yiisoft\Db\Command\BatchCommand; use Yiisoft\Db\Query\BatchQueryResult; use Yiisoft\Db\Query\BatchQueryResultInterface; use Yiisoft\Db\Query\QueryInterface; @@ -119,17 +118,12 @@ protected function rollbackTransactionOnLevel(TransactionInterface $transaction, } } - public function getParamsLimit(): int + public function getParametersLimit(): int { - //must be overriden in a DBMS package which has a limit + // Must be overridden in a DBMS package which has a limit if ($this->getDriverName() === 'pgsql') { return 65535; } return 0; } - - public function createCommandsCollection(): BatchCommand - { - return new BatchCommand($this); - } } diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index 4f082584e..f7e6ab17e 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -233,5 +233,5 @@ public function transaction(Closure $closure, ?string $isolationLevel = null): m * Returns maximum number of bound parameters for a DBMS. Default is 0 which means unlimited. * @return int */ - public function getParamsLimit(): int; + public function getParametersLimit(): int; } diff --git a/src/Debug/ConnectionInterfaceProxy.php b/src/Debug/ConnectionInterfaceProxy.php index 7835a2c65..28a13e600 100644 --- a/src/Debug/ConnectionInterfaceProxy.php +++ b/src/Debug/ConnectionInterfaceProxy.php @@ -164,8 +164,8 @@ public function getDriverName(): string return $this->connection->getDriverName(); } - public function getParamsLimit(): int + public function getParametersLimit(): int { - return $this->connection->getParamsLimit(); + return $this->connection->getParametersLimit(); } } diff --git a/tests/Db/Connection/ConnectionTest.php b/tests/Db/Connection/ConnectionTest.php index d07ac8841..5f9d07e93 100644 --- a/tests/Db/Connection/ConnectionTest.php +++ b/tests/Db/Connection/ConnectionTest.php @@ -34,4 +34,9 @@ public function testSerialized(): void parent::testSerialized(); } + + public function testGetParametersLimit(): void + { + $this->assertSame(0, $this->getConnection()->getParametersLimit()); + } } From 7189f0c7d06d8699b55dbdca01e5a5250c5d9104 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 20:57:44 +0500 Subject: [PATCH 083/137] Fix CI styling --- src/Command/AbstractCommand.php | 8 ++++---- src/Command/CommandInterface.php | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Command/AbstractCommand.php b/src/Command/AbstractCommand.php index 3b1eb29c8..9cc0bb213 100644 --- a/src/Command/AbstractCommand.php +++ b/src/Command/AbstractCommand.php @@ -225,13 +225,13 @@ public function insertBatch(string $table, iterable $rows, array $columns = [], $columnsCount = count($columns); $maxParamsLimit = $this->getConnection()->getParametersLimit(); - if (!empty($maxParamsLimit) && !empty($rowsAtOnceLimit) && $rowsAtOnceLimit > $maxParamsLimit) { - $maxParamsLimit = $rowsAtOnceLimit; - } $totalInsertedParams = $columnsCount * count($data); - if (!empty($maxParamsLimit) && $totalInsertedParams > $maxParamsLimit) { + if ((!empty($maxParamsLimit) && $totalInsertedParams > $maxParamsLimit) || !empty($rowsAtOnceLimit)) { $chunkSize = (int)floor($maxParamsLimit / $columnsCount); + if (!empty($rowsAtOnceLimit) && $chunkSize > $rowsAtOnceLimit) { + $chunkSize = $rowsAtOnceLimit; + } $rowChunks = array_chunk($data, $chunkSize); foreach ($rowChunks as $rowChunk) { $batchCommand->addInsertBatchCommand($table, $rowChunk, $columns); diff --git a/src/Command/CommandInterface.php b/src/Command/CommandInterface.php index c558c2c55..91bf482f3 100644 --- a/src/Command/CommandInterface.php +++ b/src/Command/CommandInterface.php @@ -193,7 +193,8 @@ public function alterColumn(string $table, string $column, ColumnInterface|strin * @param string $table The name of the table to insert new rows into. * @param iterable $rows The rows to be batch inserted into the table. * @param string[] $columns The column names. - * @param int $rowsAtOnceLimit Limit number of rows inserted at once. Default 0 - means maximum allowed by DBMS. + * @param int $rowsAtOnceLimit Limit number of rows inserted at once. Default 0 - means maximum allowed by DBMS. If + * provided value is greater, than supported by DBMS, then DBMS maximum value will be used. * * @throws Exception * @throws InvalidArgumentException From fdc5f2e89535cb7ee15254b612c5c30613436dac Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 21:13:04 +0500 Subject: [PATCH 084/137] Fix CI styling --- tests/AbstractCommandTest.php | 67 +++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/tests/AbstractCommandTest.php b/tests/AbstractCommandTest.php index acf1fc3f9..c0fe22a65 100644 --- a/tests/AbstractCommandTest.php +++ b/tests/AbstractCommandTest.php @@ -290,6 +290,18 @@ public function end(string $token, ContextInterface|array $context = []): void $db->close(); } + public function testBatchInsertEmptyRows(): void + { + $db = $this->getConnection(); + + $command = $db->createCommand(); + $batchCommands = $command->insertBatch('table', [], ['column1', 'column2']); + + $this->assertSame(0, $batchCommands->count()); + + $db->close(); + } + /** * @throws InvalidArgumentException * @throws NotSupportedException @@ -341,4 +353,59 @@ public function testBindParamsOverflowIssue(): void $db->createCommand()->dropTable($tempTableName)->execute(); $db->close(); } + + /** + * @throws InvalidArgumentException + * @throws NotSupportedException + * @throws Exception + * @throws Throwable + * @throws InvalidConfigException + */ + public function testBindParamsCustomRowsAtOnce(): void + { + $db = $this->getConnection(); + + if ($db->getDriverName() !== 'pgsql') { + $this->markTestSkipped('Test is intended for use with pgsql database.'); + } + + $tempTableName = 'testTempTable'; + $db->createCommand()->createTable($tempTableName, [ + 'id' => ColumnBuilder::primaryKey(), + 'first_name' => ColumnBuilder::string()->notNull(), + 'last_name' => ColumnBuilder::string()->notNull(), + 'birth_date' => ColumnBuilder::date(), + 'country' => ColumnBuilder::string(), + 'city' => ColumnBuilder::string(), + 'address' => ColumnBuilder::string(), + ])->execute(); + + $personData = [ + 'first_name' => 'IVAN', + 'last_name' => 'PUPKIN', + 'birth_date' => '1983-08-08', + 'country' => 'Kazakhstan', + 'city' => 'Almaty', + 'address' => '7, Gagarin street, apartment 10', + ]; + + //generate 66 000 params (6 fields x 11000 lines) + $generateRowsCount = 11000; + $insertData = []; + for ($i = 0; $i < $generateRowsCount; $i++) { + $insertData[] = $personData; + } + + $rowsAtOnceLimit = 1000; + $batchCommand = $db->createCommand()->insertBatch($tempTableName, $insertData, [], $rowsAtOnceLimit); + $this->assertEquals($generateRowsCount / $rowsAtOnceLimit, $batchCommand->count()); + + $insertedRowsCount = $batchCommand->execute(); + + $countSql = 'SELECT COUNT(*) FROM ' . $db->getQuoter()->quoteTableName($tempTableName); + $this->assertEquals($insertedRowsCount, $insertedRowsCount); + $this->assertEquals($generateRowsCount, $db->createCommand($countSql)->queryScalar()); + $db->createCommand()->dropTable($tempTableName)->execute(); + $db->close(); + } } From bb6a9bafbd3bfe3edffaff372b87636d041b090a Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 21:44:02 +0500 Subject: [PATCH 085/137] Test for new class added --- tests/Common/CommonBatchCommandTest.php | 39 +++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 tests/Common/CommonBatchCommandTest.php diff --git a/tests/Common/CommonBatchCommandTest.php b/tests/Common/CommonBatchCommandTest.php new file mode 100644 index 000000000..c274427a3 --- /dev/null +++ b/tests/Common/CommonBatchCommandTest.php @@ -0,0 +1,39 @@ +getConnection(true); + $command = $db->createCommand(); + + $batchCommand = $command->insertBatch('customer', [['value1', 'value2'], ['value3', 'value4']], + ['column1', 'column2'], 1); + + $this->assertInstanceOf(BatchCommand::class, $batchCommand); + $this->assertSame(2, $batchCommand->count()); + + $this->assertSame(0, $batchCommand->key()); + $batchCommand->next(); + $this->assertSame(1, $batchCommand->key()); + $batchCommand->rewind(); + $this->assertSame(0, $batchCommand->key()); + + $db->close(); + } + +} From 041c42b4ac3078a3199f7b20379db87eaef91851 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 21:45:14 +0500 Subject: [PATCH 086/137] Test for new class added --- tests/Common/CommonBatchCommandTest.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/Common/CommonBatchCommandTest.php b/tests/Common/CommonBatchCommandTest.php index c274427a3..5f3cde101 100644 --- a/tests/Common/CommonBatchCommandTest.php +++ b/tests/Common/CommonBatchCommandTest.php @@ -21,8 +21,12 @@ public function testBatchQueryResult(): void $db = $this->getConnection(true); $command = $db->createCommand(); - $batchCommand = $command->insertBatch('customer', [['value1', 'value2'], ['value3', 'value4']], - ['column1', 'column2'], 1); + $batchCommand = $command->insertBatch( + 'customer', + [['value1', 'value2'], ['value3', 'value4']], + ['column1', 'column2'], + 1 + ); $this->assertInstanceOf(BatchCommand::class, $batchCommand); $this->assertSame(2, $batchCommand->count()); From 1e0cd080fbbc00454c300b142e3de6c3a73325b4 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 21:46:18 +0500 Subject: [PATCH 087/137] Test for new class added --- tests/Common/CommonBatchCommandTest.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/Common/CommonBatchCommandTest.php b/tests/Common/CommonBatchCommandTest.php index 5f3cde101..fcf64be58 100644 --- a/tests/Common/CommonBatchCommandTest.php +++ b/tests/Common/CommonBatchCommandTest.php @@ -6,9 +6,6 @@ use PHPUnit\Framework\TestCase; use Yiisoft\Db\Command\BatchCommand; -use Yiisoft\Db\Query\BatchQueryResult; -use Yiisoft\Db\Query\BatchQueryResultInterface; -use Yiisoft\Db\Query\Query; use Yiisoft\Db\Tests\Support\TestTrait; abstract class CommonBatchCommandTest extends TestCase @@ -39,5 +36,4 @@ public function testBatchQueryResult(): void $db->close(); } - } From a1237d4092d1675277506c1e7ce8e57050a58dbf Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 22:08:40 +0500 Subject: [PATCH 088/137] Test for new class added --- tests/Common/CommonBatchCommandTest.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/Common/CommonBatchCommandTest.php b/tests/Common/CommonBatchCommandTest.php index fcf64be58..408fce301 100644 --- a/tests/Common/CommonBatchCommandTest.php +++ b/tests/Common/CommonBatchCommandTest.php @@ -12,10 +12,9 @@ abstract class CommonBatchCommandTest extends TestCase { use TestTrait; - public function testBatchQueryResult(): void + public function testBatchQuery(): void { - // initialize property test - $db = $this->getConnection(true); + $db = $this->getConnection(); $command = $db->createCommand(); $batchCommand = $command->insertBatch( From 4fb566e8d7879162ebf7c60f9da0cd6abf4edba1 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 22:19:48 +0500 Subject: [PATCH 089/137] Test for new class added --- tests/Common/CommonBatchCommandTest.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/Common/CommonBatchCommandTest.php b/tests/Common/CommonBatchCommandTest.php index 408fce301..994ddd0af 100644 --- a/tests/Common/CommonBatchCommandTest.php +++ b/tests/Common/CommonBatchCommandTest.php @@ -15,18 +15,20 @@ abstract class CommonBatchCommandTest extends TestCase public function testBatchQuery(): void { $db = $this->getConnection(); - $command = $db->createCommand(); - $batchCommand = $command->insertBatch( + $batchCommand = new BatchCommand($db); + $batchCommand->addInsertBatchCommand( 'customer', - [['value1', 'value2'], ['value3', 'value4']], + [['value1', 'value2']], + ['column1', 'column2'], + ); + $batchCommand->addInsertBatchCommand( + 'customer', + [['value3', 'value4']], ['column1', 'column2'], - 1 ); - $this->assertInstanceOf(BatchCommand::class, $batchCommand); $this->assertSame(2, $batchCommand->count()); - $this->assertSame(0, $batchCommand->key()); $batchCommand->next(); $this->assertSame(1, $batchCommand->key()); From ec45d611c7a6703a1c374d38bde96fde11c2c61c Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 22:32:38 +0500 Subject: [PATCH 090/137] Test for new class added --- tests/Common/CommonBatchCommandTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/Common/CommonBatchCommandTest.php b/tests/Common/CommonBatchCommandTest.php index 994ddd0af..0b0a7711c 100644 --- a/tests/Common/CommonBatchCommandTest.php +++ b/tests/Common/CommonBatchCommandTest.php @@ -30,8 +30,12 @@ public function testBatchQuery(): void $this->assertSame(2, $batchCommand->count()); $this->assertSame(0, $batchCommand->key()); + $this->assertTrue($batchCommand->valid()); $batchCommand->next(); $this->assertSame(1, $batchCommand->key()); + $batchCommand->next(); + $this->assertSame(2, $batchCommand->key()); + $this->assertFalse($batchCommand->valid()); $batchCommand->rewind(); $this->assertSame(0, $batchCommand->key()); From 6f37004a991925d6d7e38d759a15e544b429160c Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 22:58:06 +0500 Subject: [PATCH 091/137] Test for new class added --- tests/Db/Command/CommandTest.php | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/tests/Db/Command/CommandTest.php b/tests/Db/Command/CommandTest.php index 97438fe90..5ba25862c 100644 --- a/tests/Db/Command/CommandTest.php +++ b/tests/Db/Command/CommandTest.php @@ -196,11 +196,13 @@ public function testBatchInsert(): void $db = $this->getConnection(); $command = $db->createCommand(); - $batchCommands = $command->insertBatch('table', [['value1', 'value2'], ['value3', 'value4']], ['column1', 'column2']); + $batchCommand = $command->insertBatch('table', [['value1', 'value2'], ['value3', 'value4']], ['column1', 'column2']); - $this->assertSame(1, $batchCommands->count()); + $this->assertSame(1, $batchCommand->count()); + $this->assertSame(0, $batchCommand->key()); + $this->assertTrue($batchCommand->valid()); - $firstCommand = $batchCommands->current(); + $firstCommand = $batchCommand->current(); $this->assertSame('INSERT INTO [table] ([column1], [column2]) VALUES (:qp0, :qp1), (:qp2, :qp3)', $firstCommand->getSql()); $this->assertSame( [ @@ -211,6 +213,14 @@ public function testBatchInsert(): void ], $firstCommand->getParams() ); + + $batchCommand->next(); + $this->assertSame(1, $batchCommand->key()); + $this->assertFalse($batchCommand->valid()); + + $batchCommand->rewind(); + $this->assertSame(0, $batchCommand->key()); + $db->close(); } From f95ba39cf3677fd0b0a95e540430667f2607fa89 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Tue, 1 Apr 2025 23:01:37 +0500 Subject: [PATCH 092/137] Test for new class added --- tests/Db/Command/CommandTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Db/Command/CommandTest.php b/tests/Db/Command/CommandTest.php index 5ba25862c..5a63e5332 100644 --- a/tests/Db/Command/CommandTest.php +++ b/tests/Db/Command/CommandTest.php @@ -199,7 +199,7 @@ public function testBatchInsert(): void $batchCommand = $command->insertBatch('table', [['value1', 'value2'], ['value3', 'value4']], ['column1', 'column2']); $this->assertSame(1, $batchCommand->count()); - $this->assertSame(0, $batchCommand->key()); + $this->assertSame(0, $batchCommand->key()); $this->assertTrue($batchCommand->valid()); $firstCommand = $batchCommand->current(); @@ -215,11 +215,11 @@ public function testBatchInsert(): void ); $batchCommand->next(); - $this->assertSame(1, $batchCommand->key()); + $this->assertSame(1, $batchCommand->key()); $this->assertFalse($batchCommand->valid()); $batchCommand->rewind(); - $this->assertSame(0, $batchCommand->key()); + $this->assertSame(0, $batchCommand->key()); $db->close(); } From 3d63c518cfc5377257b455f45b845556c1054539 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 3 Apr 2025 20:19:31 +0500 Subject: [PATCH 093/137] Refactor batchInsert method --- src/Command/AbstractCommand.php | 36 ++------- src/Command/BatchCommand.php | 76 +------------------ src/Command/QueryStatement.php | 21 +++++ src/Command/QueryStatementParameters.php | 15 ++++ src/QueryBuilder/AbstractDMLQueryBuilder.php | 44 ++++++++--- src/QueryBuilder/AbstractQueryBuilder.php | 9 ++- src/QueryBuilder/DMLQueryBuilderInterface.php | 5 +- 7 files changed, 89 insertions(+), 117 deletions(-) create mode 100644 src/Command/QueryStatement.php create mode 100644 src/Command/QueryStatementParameters.php diff --git a/src/Command/AbstractCommand.php b/src/Command/AbstractCommand.php index 9cc0bb213..f1175fc84 100644 --- a/src/Command/AbstractCommand.php +++ b/src/Command/AbstractCommand.php @@ -210,37 +210,17 @@ public function batchInsert(string $table, array $columns, iterable $rows): Batc public function insertBatch(string $table, iterable $rows, array $columns = [], int $rowsAtOnceLimit = 0): BatchCommand { $table = $this->getQueryBuilder()->getQuoter()->getRawTableName($table); - $batchCommand = new BatchCommand($this->getConnection()); - if (is_array($rows)) { - $data = $rows; - } else { - $data = iterator_to_array($rows); - } + $statements = $this->getQueryBuilder()->insertBatch($table, $rows, $columns); + $commands = []; + foreach ($statements as $statement) { + $command = $this->db->createCommand(); + $command->setRawSql($statement->sql); + $command->bindValues($statement->params); - if (empty($data)) { - return $batchCommand; + $commands[] = $command; } - $columns = $this->getQueryBuilder()->extractColumnNames($data, $columns); - $columnsCount = count($columns); - - $maxParamsLimit = $this->getConnection()->getParametersLimit(); - $totalInsertedParams = $columnsCount * count($data); - - if ((!empty($maxParamsLimit) && $totalInsertedParams > $maxParamsLimit) || !empty($rowsAtOnceLimit)) { - $chunkSize = (int)floor($maxParamsLimit / $columnsCount); - if (!empty($rowsAtOnceLimit) && $chunkSize > $rowsAtOnceLimit) { - $chunkSize = $rowsAtOnceLimit; - } - $rowChunks = array_chunk($data, $chunkSize); - foreach ($rowChunks as $rowChunk) { - $batchCommand->addInsertBatchCommand($table, $rowChunk, $columns); - } - } else { - $batchCommand->addInsertBatchCommand($table, $data, $columns); - } - - return $batchCommand; + return new BatchCommand($commands); } abstract public function bindValue(int|string $name, mixed $value, ?int $dataType = null): static; diff --git a/src/Command/BatchCommand.php b/src/Command/BatchCommand.php index bacb0f863..cade49884 100644 --- a/src/Command/BatchCommand.php +++ b/src/Command/BatchCommand.php @@ -4,62 +4,19 @@ namespace Yiisoft\Db\Command; -use Iterator; -use Countable; -use Yiisoft\Db\Connection\ConnectionInterface; use Yiisoft\Db\Exception\Exception; -use Yiisoft\Db\Exception\InvalidArgumentException; -use Yiisoft\Db\Exception\InvalidConfigException; -use Yiisoft\Db\QueryBuilder\DMLQueryBuilderInterface; /** * Object used as batch commands container - * - * @implements Iterator - * - * @psalm-import-type BatchValues from DMLQueryBuilderInterface */ -final class BatchCommand implements Iterator, Countable +final class BatchCommand { /** - * @var int Current iterator position. + * @param CommandInterface[] $commands Query statements for execution */ - private int $position = 0; - /** - * @var CommandInterface[] Commands of the collection. - */ - private array $commands = []; - - /** - * @param ConnectionInterface $db Connection to a database. - */ - public function __construct(private readonly ConnectionInterface $db) - { - } - - public function rewind(): void - { - $this->position = 0; - } - - public function current(): CommandInterface - { - return $this->commands[$this->position]; - } - - public function key(): int + public function __construct(private readonly array $commands) { - return $this->position; - } - public function next(): void - { - ++$this->position; - } - - public function valid(): bool - { - return isset($this->commands[$this->position]); } public function count(): int @@ -67,33 +24,6 @@ public function count(): int return count($this->commands); } - /** - * Adds batch insert commands into execution queue - * - * @param string $table The name of the table to insert new rows into. - * @param iterable $rows The rows to be batch inserted into the table. - * @param string[] $columns The column names. - * - * @throws Exception - * @throws InvalidArgumentException - * - * @psalm-param BatchValues $rows - * - * @throws InvalidConfigException - * @throws Exception - */ - public function addInsertBatchCommand(string $table, iterable $rows, array $columns = []): void - { - $command = $this->db->createCommand(); - $params = []; - $sql = $this->db->getQueryBuilder()->insertBatch($table, $rows, $columns, $params); - - $command->setRawSql($sql); - $command->bindValues($params); - - $this->commands[] = $command; - } - /** * @throws \Throwable * @throws Exception diff --git a/src/Command/QueryStatement.php b/src/Command/QueryStatement.php new file mode 100644 index 000000000..8cfd6e8fa --- /dev/null +++ b/src/Command/QueryStatement.php @@ -0,0 +1,21 @@ +sql = $sql; + $this->params = $params; + } +} diff --git a/src/Command/QueryStatementParameters.php b/src/Command/QueryStatementParameters.php new file mode 100644 index 000000000..5f17bb0fb --- /dev/null +++ b/src/Command/QueryStatementParameters.php @@ -0,0 +1,15 @@ +insertBatch($table, $rows, $columns, $params); } - public function insertBatch(string $table, iterable $rows, array $columns = [], array &$params = []): string + public function insertBatch(string $table, iterable $rows, array $columns = [], array $params = []): array { if (!is_array($rows)) { $rows = $this->prepareTraversable($rows); } if (empty($rows)) { - return ''; + return []; } + $statements = []; + $columns = $this->extractColumnNames($rows, $columns); - $values = $this->prepareBatchInsertValues($table, $rows, $columns, $params); + + $parameters = $this->prepareBatchInsertValues($table, $rows, $columns); $query = 'INSERT INTO ' . $this->quoter->quoteTableName($table); @@ -96,7 +101,14 @@ public function insertBatch(string $table, iterable $rows, array $columns = [], $query .= ' (' . implode(', ', $quotedColumnNames) . ')'; } - return $query . ' VALUES (' . implode('), (', $values) . ')'; + foreach ($parameters as $parameter) { + $statements[] = new QueryStatement( + $query . ' VALUES (' . implode('), (', $parameter->values) . ')', + $parameter->params + ); + } + + return $statements; } public function delete(string $table, array|string $condition, array &$params): string @@ -176,21 +188,26 @@ final protected function prepareTraversable(Traversable $rows): Iterator|array * @param string[] $columnNames The column names. * @param array $params The binding parameters that will be generated by this method. * - * @return string[] The values. + * @return QueryStatementParameters[] The values. * * @psalm-param ParamsType $params */ - protected function prepareBatchInsertValues(string $table, iterable $rows, array $columnNames, array &$params): array + protected function prepareBatchInsertValues(string $table, iterable $rows, array $columnNames, int $maxRowsAtOnce = 0): array { - $values = []; + $parameters = []; /** @var string[] $names */ $names = array_values($columnNames); $keys = array_fill_keys($names, false); $columns = $this->schema->getTableSchema($table)?->getColumns() ?? []; + $statementParameters = new QueryStatementParameters(); + $maxParametersLimit = $this->queryBuilder->getParametersLimit(); + + $insertedParametersCount = 0; foreach ($rows as $row) { $i = 0; $placeholders = $keys; + $currentRowParams = []; /** @var int|string $key */ foreach ($row as $key => $value) { @@ -201,18 +218,21 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array } if ($value instanceof ExpressionInterface) { - $placeholders[$columnName] = $this->queryBuilder->buildExpression($value, $params); + $placeholders[$columnName] = $this->queryBuilder->buildExpression($value, $currentRowParams); } else { - $placeholders[$columnName] = $this->queryBuilder->bindParam($value, $params); + $placeholders[$columnName] = $this->queryBuilder->bindParam($value, $currentRowParams); } ++$i; + ++$insertedParametersCount; } - $values[] = implode(', ', $placeholders); + $statementParameters->params = array_merge($statementParameters->params, $currentRowParams); + $statementParameters->values[] = implode(', ', $placeholders); + $parameters[] = $statementParameters; } - return $values; + return $parameters; } public function extractColumnNames(array|Iterator $rows, array $columns): array diff --git a/src/QueryBuilder/AbstractQueryBuilder.php b/src/QueryBuilder/AbstractQueryBuilder.php index 444f5a187..7f8056def 100644 --- a/src/QueryBuilder/AbstractQueryBuilder.php +++ b/src/QueryBuilder/AbstractQueryBuilder.php @@ -139,12 +139,12 @@ public function alterColumn(string $table, string $column, ColumnInterface|strin * * @deprecated Use {@see insertBatch()} instead. It will be removed in version 3.0.0. */ - public function batchInsert(string $table, array $columns, iterable $rows, array &$params = []): string + public function batchInsert(string $table, array $columns, iterable $rows, array $params = []): array { return $this->dmlBuilder->insertBatch($table, $rows, $columns, $params); } - public function insertBatch(string $table, iterable $rows, array $columns = [], array &$params = []): string + public function insertBatch(string $table, iterable $rows, array $columns = [], array $params = []): array { return $this->dmlBuilder->insertBatch($table, $rows, $columns, $params); } @@ -500,4 +500,9 @@ public function extractColumnNames(iterable $rows, array $columns): array { return $this->dmlBuilder->extractColumnNames($rows, $columns); } + + public function getParametersLimit(): int + { + return $this->db->getParametersLimit(); + } } diff --git a/src/QueryBuilder/DMLQueryBuilderInterface.php b/src/QueryBuilder/DMLQueryBuilderInterface.php index 3643ccdd3..1a53044ae 100644 --- a/src/QueryBuilder/DMLQueryBuilderInterface.php +++ b/src/QueryBuilder/DMLQueryBuilderInterface.php @@ -6,6 +6,7 @@ use Iterator; use JsonException; +use Yiisoft\Db\Command\QueryStatement; use Yiisoft\Db\Connection\ConnectionInterface; use Yiisoft\Db\Exception\Exception; use Yiisoft\Db\Exception\InvalidArgumentException; @@ -54,7 +55,7 @@ interface DMLQueryBuilderInterface * @throws Exception * @throws InvalidArgumentException * - * @return string The batch INSERT SQL statement. + * @return QueryStatement[] Array of batch INSERT SQL statements. * * @psalm-param BatchValues $rows * @psalm-param ParamsType $params @@ -63,7 +64,7 @@ interface DMLQueryBuilderInterface * - That the values in each row must match the corresponding column names. * - The method will escape the column names, and quote the values to insert. */ - public function insertBatch(string $table, iterable $rows, array $columns = [], array &$params = []): string; + public function insertBatch(string $table, iterable $rows, array $columns = [], array $params = []): array; /** * Creates a `DELETE` SQL statement. From 38120ed680271e5ef7b7c522ed646bc7570fc8f7 Mon Sep 17 00:00:00 2001 From: evil1 <5018681+evil1@users.noreply.github.com> Date: Thu, 3 Apr 2025 15:20:12 +0000 Subject: [PATCH 094/137] Apply Rector changes (CI) --- src/Command/QueryStatement.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Command/QueryStatement.php b/src/Command/QueryStatement.php index 8cfd6e8fa..ad4c4e458 100644 --- a/src/Command/QueryStatement.php +++ b/src/Command/QueryStatement.php @@ -9,13 +9,7 @@ */ class QueryStatement { - public string $sql; - - public array $params = []; - - public function __construct($sql, array $params = []) + public function __construct(public string $sql, public array $params = []) { - $this->sql = $sql; - $this->params = $params; } } From ac2034d7aa3307395326e001162da70982b682e4 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 3 Apr 2025 20:25:49 +0500 Subject: [PATCH 095/137] Refactor batchInsert method --- src/Command/AbstractCommand.php | 2 +- src/Command/BatchCommand.php | 1 - src/QueryBuilder/AbstractDMLQueryBuilder.php | 15 +++++++++++---- src/QueryBuilder/DMLQueryBuilderInterface.php | 4 ++-- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Command/AbstractCommand.php b/src/Command/AbstractCommand.php index f1175fc84..574f98cb3 100644 --- a/src/Command/AbstractCommand.php +++ b/src/Command/AbstractCommand.php @@ -211,7 +211,7 @@ public function insertBatch(string $table, iterable $rows, array $columns = [], { $table = $this->getQueryBuilder()->getQuoter()->getRawTableName($table); - $statements = $this->getQueryBuilder()->insertBatch($table, $rows, $columns); + $statements = $this->getQueryBuilder()->insertBatch($table, $rows, $columns, $rowsAtOnceLimit); $commands = []; foreach ($statements as $statement) { $command = $this->db->createCommand(); diff --git a/src/Command/BatchCommand.php b/src/Command/BatchCommand.php index cade49884..6ad02dfb8 100644 --- a/src/Command/BatchCommand.php +++ b/src/Command/BatchCommand.php @@ -16,7 +16,6 @@ final class BatchCommand */ public function __construct(private readonly array $commands) { - } public function count(): int diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 4162a7a12..3f0e628c3 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -77,7 +77,7 @@ public function batchInsert(string $table, array $columns, iterable $rows, array return $this->insertBatch($table, $rows, $columns, $params); } - public function insertBatch(string $table, iterable $rows, array $columns = [], array $params = []): array + public function insertBatch(string $table, iterable $rows, array $columns = [], int $rowsAtOnceLimit = 0): array { if (!is_array($rows)) { $rows = $this->prepareTraversable($rows); @@ -91,7 +91,7 @@ public function insertBatch(string $table, iterable $rows, array $columns = [], $columns = $this->extractColumnNames($rows, $columns); - $parameters = $this->prepareBatchInsertValues($table, $rows, $columns); + $parameters = $this->prepareBatchInsertValues($table, $rows, $columns, $rowsAtOnceLimit); $query = 'INSERT INTO ' . $this->quoter->quoteTableName($table); @@ -186,13 +186,13 @@ final protected function prepareTraversable(Traversable $rows): Iterator|array * @param string $table The table name. * @param iterable $rows The rows to be batch inserted into the table. * @param string[] $columnNames The column names. - * @param array $params The binding parameters that will be generated by this method. + * @param int $rowsAtOnceLimit The limit of rows inserted at once. * * @return QueryStatementParameters[] The values. * * @psalm-param ParamsType $params */ - protected function prepareBatchInsertValues(string $table, iterable $rows, array $columnNames, int $maxRowsAtOnce = 0): array + protected function prepareBatchInsertValues(string $table, iterable $rows, array $columnNames, int $rowsAtOnceLimit = 0): array { $parameters = []; /** @var string[] $names */ @@ -204,6 +204,7 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array $maxParametersLimit = $this->queryBuilder->getParametersLimit(); $insertedParametersCount = 0; + $insertedRowsCount = 0; foreach ($rows as $row) { $i = 0; $placeholders = $keys; @@ -227,6 +228,12 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array ++$insertedParametersCount; } + $insertedRowsCount++; + if (!empty($maxParametersLimit) && $insertedRowsCount > $maxParametersLimit) { + $parameters[] = $statementParameters; + $statementParameters = new QueryStatementParameters(); + } + $statementParameters->params = array_merge($statementParameters->params, $currentRowParams); $statementParameters->values[] = implode(', ', $placeholders); $parameters[] = $statementParameters; diff --git a/src/QueryBuilder/DMLQueryBuilderInterface.php b/src/QueryBuilder/DMLQueryBuilderInterface.php index 1a53044ae..e1c65cff6 100644 --- a/src/QueryBuilder/DMLQueryBuilderInterface.php +++ b/src/QueryBuilder/DMLQueryBuilderInterface.php @@ -50,7 +50,7 @@ interface DMLQueryBuilderInterface * @param string $table The table to insert new rows into. * @param iterable $rows The rows to batch-insert into the table. * @param string[] $columns The column names of the table. - * @param array $params The binding parameters. This parameter exists. + * @param int $rowsAtOnceLimit The limit of rows inserted at once. * * @throws Exception * @throws InvalidArgumentException @@ -64,7 +64,7 @@ interface DMLQueryBuilderInterface * - That the values in each row must match the corresponding column names. * - The method will escape the column names, and quote the values to insert. */ - public function insertBatch(string $table, iterable $rows, array $columns = [], array $params = []): array; + public function insertBatch(string $table, iterable $rows, array $columns = [], int $rowsAtOnceLimit = 0): array; /** * Creates a `DELETE` SQL statement. From a12d48ddc25ed769aae45019851a8c4220fc9e26 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 3 Apr 2025 20:29:34 +0500 Subject: [PATCH 096/137] Refactor batchInsert method --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 4 ++-- src/QueryBuilder/AbstractQueryBuilder.php | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 3f0e628c3..7eb731d04 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -72,9 +72,9 @@ public function __construct( * * @deprecated Use {@see insertBatch()} instead. It will be removed in version 3.0.0. */ - public function batchInsert(string $table, array $columns, iterable $rows, array &$params = []): array + public function batchInsert(string $table, array $columns, iterable $rows): array { - return $this->insertBatch($table, $rows, $columns, $params); + return $this->insertBatch($table, $rows, $columns); } public function insertBatch(string $table, iterable $rows, array $columns = [], int $rowsAtOnceLimit = 0): array diff --git a/src/QueryBuilder/AbstractQueryBuilder.php b/src/QueryBuilder/AbstractQueryBuilder.php index 7f8056def..dc46016d2 100644 --- a/src/QueryBuilder/AbstractQueryBuilder.php +++ b/src/QueryBuilder/AbstractQueryBuilder.php @@ -139,14 +139,14 @@ public function alterColumn(string $table, string $column, ColumnInterface|strin * * @deprecated Use {@see insertBatch()} instead. It will be removed in version 3.0.0. */ - public function batchInsert(string $table, array $columns, iterable $rows, array $params = []): array + public function batchInsert(string $table, array $columns, iterable $rows): array { - return $this->dmlBuilder->insertBatch($table, $rows, $columns, $params); + return $this->dmlBuilder->insertBatch($table, $rows, $columns); } - public function insertBatch(string $table, iterable $rows, array $columns = [], array $params = []): array + public function insertBatch(string $table, iterable $rows, array $columns = [], int $rowsAtOnceLimit = 0): array { - return $this->dmlBuilder->insertBatch($table, $rows, $columns, $params); + return $this->dmlBuilder->insertBatch($table, $rows, $columns, $rowsAtOnceLimit); } public function bindParam(mixed $value, array &$params = []): string From 42d4b5eb3a9723390efa963c965798544178e5fd Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 3 Apr 2025 20:32:05 +0500 Subject: [PATCH 097/137] Refactor batchInsert method --- tests/AbstractQueryBuilderTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/AbstractQueryBuilderTest.php b/tests/AbstractQueryBuilderTest.php index 82f120c87..e298adcaa 100644 --- a/tests/AbstractQueryBuilderTest.php +++ b/tests/AbstractQueryBuilderTest.php @@ -224,11 +224,11 @@ public function testBatchInsert( $db = $this->getConnection(true); $qb = $db->getQueryBuilder(); - $params = []; - $sql = $qb->insertBatch($table, $rows, $columns, $params); + $statements = $qb->insertBatch($table, $rows, $columns); - $this->assertSame($expected, $sql); - $this->assertSame($expectedParams, $params); + $this->assertSame(1, count($statements)); + $this->assertSame($expected, $statements[0]->sql); + $this->assertSame($expectedParams, $statements[0]->params); $db->close(); } From 9e2d1f42945071a83f607f12f4108d0cf2bf7f00 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 3 Apr 2025 21:16:48 +0500 Subject: [PATCH 098/137] Refactor batchInsert method --- src/Command/BatchCommand.php | 5 +++ tests/AbstractQueryBuilderTest.php | 2 +- tests/Common/CommonBatchCommandTest.php | 44 ------------------------- tests/Db/Command/CommandTest.php | 12 ++----- 4 files changed, 8 insertions(+), 55 deletions(-) delete mode 100644 tests/Common/CommonBatchCommandTest.php diff --git a/src/Command/BatchCommand.php b/src/Command/BatchCommand.php index 6ad02dfb8..409da0dfb 100644 --- a/src/Command/BatchCommand.php +++ b/src/Command/BatchCommand.php @@ -23,6 +23,11 @@ public function count(): int return count($this->commands); } + public function getCommands(): array + { + return $this->commands; + } + /** * @throws \Throwable * @throws Exception diff --git a/tests/AbstractQueryBuilderTest.php b/tests/AbstractQueryBuilderTest.php index e298adcaa..5615cc60f 100644 --- a/tests/AbstractQueryBuilderTest.php +++ b/tests/AbstractQueryBuilderTest.php @@ -226,7 +226,7 @@ public function testBatchInsert( $statements = $qb->insertBatch($table, $rows, $columns); - $this->assertSame(1, count($statements)); + $this->assertCount(1, $statements); $this->assertSame($expected, $statements[0]->sql); $this->assertSame($expectedParams, $statements[0]->params); $db->close(); diff --git a/tests/Common/CommonBatchCommandTest.php b/tests/Common/CommonBatchCommandTest.php deleted file mode 100644 index 0b0a7711c..000000000 --- a/tests/Common/CommonBatchCommandTest.php +++ /dev/null @@ -1,44 +0,0 @@ -getConnection(); - - $batchCommand = new BatchCommand($db); - $batchCommand->addInsertBatchCommand( - 'customer', - [['value1', 'value2']], - ['column1', 'column2'], - ); - $batchCommand->addInsertBatchCommand( - 'customer', - [['value3', 'value4']], - ['column1', 'column2'], - ); - - $this->assertSame(2, $batchCommand->count()); - $this->assertSame(0, $batchCommand->key()); - $this->assertTrue($batchCommand->valid()); - $batchCommand->next(); - $this->assertSame(1, $batchCommand->key()); - $batchCommand->next(); - $this->assertSame(2, $batchCommand->key()); - $this->assertFalse($batchCommand->valid()); - $batchCommand->rewind(); - $this->assertSame(0, $batchCommand->key()); - - $db->close(); - } -} diff --git a/tests/Db/Command/CommandTest.php b/tests/Db/Command/CommandTest.php index 5a63e5332..bcd0c44eb 100644 --- a/tests/Db/Command/CommandTest.php +++ b/tests/Db/Command/CommandTest.php @@ -199,10 +199,9 @@ public function testBatchInsert(): void $batchCommand = $command->insertBatch('table', [['value1', 'value2'], ['value3', 'value4']], ['column1', 'column2']); $this->assertSame(1, $batchCommand->count()); - $this->assertSame(0, $batchCommand->key()); - $this->assertTrue($batchCommand->valid()); + $commands = $batchCommand->getCommands(); - $firstCommand = $batchCommand->current(); + $firstCommand = $commands[0]; $this->assertSame('INSERT INTO [table] ([column1], [column2]) VALUES (:qp0, :qp1), (:qp2, :qp3)', $firstCommand->getSql()); $this->assertSame( [ @@ -214,13 +213,6 @@ public function testBatchInsert(): void $firstCommand->getParams() ); - $batchCommand->next(); - $this->assertSame(1, $batchCommand->key()); - $this->assertFalse($batchCommand->valid()); - - $batchCommand->rewind(); - $this->assertSame(0, $batchCommand->key()); - $db->close(); } From f2a904470ac6e41c4a7da57d5a34f7b9e5e1ed84 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 3 Apr 2025 21:22:26 +0500 Subject: [PATCH 099/137] Refactor batchInsert method --- tests/Db/QueryBuilder/QueryBuilderTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/Db/QueryBuilder/QueryBuilderTest.php b/tests/Db/QueryBuilder/QueryBuilderTest.php index d72d8ca2b..b22850b3f 100644 --- a/tests/Db/QueryBuilder/QueryBuilderTest.php +++ b/tests/Db/QueryBuilder/QueryBuilderTest.php @@ -65,8 +65,10 @@ public function testBatchInsert( $params = []; try { - $this->assertSame($expected, $qb->insertBatch($table, $rows, $columns, $params)); - $this->assertSame($expectedParams, $params); + $statements = $qb->insertBatch($table, $rows, $columns); + $this->assertCount(1, $statements); + $this->assertSame($expected, $statements[0]->sql); + $this->assertSame($expectedParams, $statements[0]->params); } catch (InvalidArgumentException|Exception) { } finally { $db->close(); From 6d328eac55c1dd7f94cbce7d43d009b34a7c4b02 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 3 Apr 2025 21:28:48 +0500 Subject: [PATCH 100/137] Refactor batchInsert method --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 18 +++++++++++++++--- src/QueryBuilder/AbstractQueryBuilder.php | 5 ----- src/QueryBuilder/DMLQueryBuilderInterface.php | 11 ----------- tests/Db/QueryBuilder/QueryBuilderTest.php | 1 - 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 7eb731d04..7bfee3d30 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -229,20 +229,32 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array } $insertedRowsCount++; - if (!empty($maxParametersLimit) && $insertedRowsCount > $maxParametersLimit) { + if (!empty($rowsAtOnceLimit) && $insertedRowsCount > $rowsAtOnceLimit) { $parameters[] = $statementParameters; $statementParameters = new QueryStatementParameters(); + $insertedRowsCount = 1; } $statementParameters->params = array_merge($statementParameters->params, $currentRowParams); $statementParameters->values[] = implode(', ', $placeholders); - $parameters[] = $statementParameters; } + $parameters[] = $statementParameters; + return $parameters; } - public function extractColumnNames(array|Iterator $rows, array $columns): array + /** + * Extract column names from columns and rows. + * + * @param array[]|Iterator $rows The rows to be batch inserted into the table. + * @param string[] $columns The column names. + * + * @return string[] The column names. + * + * @psalm-param Iterator|non-empty-array> $rows + */ + final protected function extractColumnNames(array|Iterator $rows, array $columns): array { $columns = $this->getNormalizeColumnNames($columns); diff --git a/src/QueryBuilder/AbstractQueryBuilder.php b/src/QueryBuilder/AbstractQueryBuilder.php index dc46016d2..26900cddf 100644 --- a/src/QueryBuilder/AbstractQueryBuilder.php +++ b/src/QueryBuilder/AbstractQueryBuilder.php @@ -496,11 +496,6 @@ protected function prepareBinary(string $binary): string return '0x' . bin2hex($binary); } - public function extractColumnNames(iterable $rows, array $columns): array - { - return $this->dmlBuilder->extractColumnNames($rows, $columns); - } - public function getParametersLimit(): int { return $this->db->getParametersLimit(); diff --git a/src/QueryBuilder/DMLQueryBuilderInterface.php b/src/QueryBuilder/DMLQueryBuilderInterface.php index e1c65cff6..2c0356be9 100644 --- a/src/QueryBuilder/DMLQueryBuilderInterface.php +++ b/src/QueryBuilder/DMLQueryBuilderInterface.php @@ -230,15 +230,4 @@ public function upsert( array &$params ): string; - /** - * Extract column names from columns and rows. - * - * @param array[]|Iterator $rows The rows to be batch inserted into the table. - * @param string[] $columns The column names. - * - * @return string[] The column names. - * - * @psalm-param Iterator|non-empty-array> $rows - */ - public function extractColumnNames(array|Iterator $rows, array $columns): array; } diff --git a/tests/Db/QueryBuilder/QueryBuilderTest.php b/tests/Db/QueryBuilder/QueryBuilderTest.php index b22850b3f..797f11af9 100644 --- a/tests/Db/QueryBuilder/QueryBuilderTest.php +++ b/tests/Db/QueryBuilder/QueryBuilderTest.php @@ -62,7 +62,6 @@ public function testBatchInsert( ): void { $db = $this->getConnection(); $qb = new QueryBuilder($db); - $params = []; try { $statements = $qb->insertBatch($table, $rows, $columns); From fe97ad025750afddd67113483578a81a959f3fa3 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 3 Apr 2025 21:32:16 +0500 Subject: [PATCH 101/137] Refactor batchInsert method --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 9 +++++---- src/QueryBuilder/DMLQueryBuilderInterface.php | 2 -- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 7bfee3d30..58a3ba1aa 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -203,12 +203,12 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array $statementParameters = new QueryStatementParameters(); $maxParametersLimit = $this->queryBuilder->getParametersLimit(); + $currentStatementParams = []; $insertedParametersCount = 0; $insertedRowsCount = 0; foreach ($rows as $row) { $i = 0; $placeholders = $keys; - $currentRowParams = []; /** @var int|string $key */ foreach ($row as $key => $value) { @@ -219,9 +219,9 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array } if ($value instanceof ExpressionInterface) { - $placeholders[$columnName] = $this->queryBuilder->buildExpression($value, $currentRowParams); + $placeholders[$columnName] = $this->queryBuilder->buildExpression($value, $currentStatementParams); } else { - $placeholders[$columnName] = $this->queryBuilder->bindParam($value, $currentRowParams); + $placeholders[$columnName] = $this->queryBuilder->bindParam($value, $currentStatementParams); } ++$i; @@ -230,15 +230,16 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array $insertedRowsCount++; if (!empty($rowsAtOnceLimit) && $insertedRowsCount > $rowsAtOnceLimit) { + $statementParameters->params = $currentStatementParams; $parameters[] = $statementParameters; $statementParameters = new QueryStatementParameters(); $insertedRowsCount = 1; } - $statementParameters->params = array_merge($statementParameters->params, $currentRowParams); $statementParameters->values[] = implode(', ', $placeholders); } + $statementParameters->params = $currentStatementParams; $parameters[] = $statementParameters; return $parameters; diff --git a/src/QueryBuilder/DMLQueryBuilderInterface.php b/src/QueryBuilder/DMLQueryBuilderInterface.php index 2c0356be9..dafb26fce 100644 --- a/src/QueryBuilder/DMLQueryBuilderInterface.php +++ b/src/QueryBuilder/DMLQueryBuilderInterface.php @@ -4,7 +4,6 @@ namespace Yiisoft\Db\QueryBuilder; -use Iterator; use JsonException; use Yiisoft\Db\Command\QueryStatement; use Yiisoft\Db\Connection\ConnectionInterface; @@ -229,5 +228,4 @@ public function upsert( bool|array $updateColumns, array &$params ): string; - } From 8685919f5fed3b051cb305dade887f8f3e00c9b0 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 3 Apr 2025 21:35:27 +0500 Subject: [PATCH 102/137] Refactor batchInsert method --- tests/Common/CommonCommandTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/Common/CommonCommandTest.php b/tests/Common/CommonCommandTest.php index f179505d9..73d41fb7f 100644 --- a/tests/Common/CommonCommandTest.php +++ b/tests/Common/CommonCommandTest.php @@ -324,7 +324,9 @@ public function testBatchInsert( $command = $db->createCommand(); $batchCommand = $command->insertBatch($table, $values, $columns); - $firstCommand = $batchCommand->current(); + $this->assertSame(1, $batchCommand->count()); + $commands = $batchCommand->getCommands(); + $firstCommand = $commands[0]; $this->assertSame($expected, $firstCommand->getSql()); $this->assertSame($expectedParams, $firstCommand->getParams()); From e49b146f6e318b747762ebf638ac5208394d2223 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 3 Apr 2025 21:39:17 +0500 Subject: [PATCH 103/137] Refactor batchInsert method --- tests/Db/QueryBuilder/QueryBuilderTest.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/Db/QueryBuilder/QueryBuilderTest.php b/tests/Db/QueryBuilder/QueryBuilderTest.php index 797f11af9..fa6c08c10 100644 --- a/tests/Db/QueryBuilder/QueryBuilderTest.php +++ b/tests/Db/QueryBuilder/QueryBuilderTest.php @@ -65,9 +65,14 @@ public function testBatchInsert( try { $statements = $qb->insertBatch($table, $rows, $columns); - $this->assertCount(1, $statements); - $this->assertSame($expected, $statements[0]->sql); - $this->assertSame($expectedParams, $statements[0]->params); + + if (empty($expected) && empty($expectedParams)) { + $this->assertCount(0, $statements); + } else { + $this->assertCount(1, $statements); + $this->assertSame($expected, $statements[0]->sql); + $this->assertSame($expectedParams, $statements[0]->params); + } } catch (InvalidArgumentException|Exception) { } finally { $db->close(); From ae82c6c4de9041c5f548ebc1ebbb8295f821fdf1 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 3 Apr 2025 21:45:00 +0500 Subject: [PATCH 104/137] Refactor batchInsert method --- tests/Db/QueryBuilder/QueryBuilderTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/Db/QueryBuilder/QueryBuilderTest.php b/tests/Db/QueryBuilder/QueryBuilderTest.php index fa6c08c10..7e5a7607b 100644 --- a/tests/Db/QueryBuilder/QueryBuilderTest.php +++ b/tests/Db/QueryBuilder/QueryBuilderTest.php @@ -66,11 +66,12 @@ public function testBatchInsert( try { $statements = $qb->insertBatch($table, $rows, $columns); - if (empty($expected) && empty($expectedParams)) { + if (empty($expected)) { $this->assertCount(0, $statements); } else { - $this->assertCount(1, $statements); $this->assertSame($expected, $statements[0]->sql); + } + if (!empty($statements)) { $this->assertSame($expectedParams, $statements[0]->params); } } catch (InvalidArgumentException|Exception) { From efb1b87b1357fb5fbd25a20f4055b8fcab11fc43 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 3 Apr 2025 21:50:00 +0500 Subject: [PATCH 105/137] Refactor batchInsert method --- src/Command/AbstractCommand.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Command/AbstractCommand.php b/src/Command/AbstractCommand.php index 574f98cb3..3d30edebc 100644 --- a/src/Command/AbstractCommand.php +++ b/src/Command/AbstractCommand.php @@ -210,11 +210,12 @@ public function batchInsert(string $table, array $columns, iterable $rows): Batc public function insertBatch(string $table, iterable $rows, array $columns = [], int $rowsAtOnceLimit = 0): BatchCommand { $table = $this->getQueryBuilder()->getQuoter()->getRawTableName($table); + $db = $this->getConnection(); $statements = $this->getQueryBuilder()->insertBatch($table, $rows, $columns, $rowsAtOnceLimit); $commands = []; foreach ($statements as $statement) { - $command = $this->db->createCommand(); + $command = $db->createCommand(); $command->setRawSql($statement->sql); $command->bindValues($statement->params); From f83377326223991b172f5a57613ceaffb3561c74 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 3 Apr 2025 21:59:29 +0500 Subject: [PATCH 106/137] Refactor batchInsert method --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 8 +++++++- src/QueryBuilder/QueryBuilderInterface.php | 6 ++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 58a3ba1aa..c456c0a5d 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -225,7 +225,6 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array } ++$i; - ++$insertedParametersCount; } $insertedRowsCount++; @@ -234,8 +233,15 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array $parameters[] = $statementParameters; $statementParameters = new QueryStatementParameters(); $insertedRowsCount = 1; + } elseif (!empty($maxParametersLimit) && $insertedParametersCount + count($currentStatementParams) > $maxParametersLimit) { + $statementParameters->params = $currentStatementParams; + $parameters[] = $statementParameters; + $statementParameters = new QueryStatementParameters(); + $insertedRowsCount = 1; + $insertedParametersCount = count($currentStatementParams); } + $insertedParametersCount += count($currentStatementParams); $statementParameters->values[] = implode(', ', $placeholders); } diff --git a/src/QueryBuilder/QueryBuilderInterface.php b/src/QueryBuilder/QueryBuilderInterface.php index 661b52c0e..cfae40e79 100644 --- a/src/QueryBuilder/QueryBuilderInterface.php +++ b/src/QueryBuilder/QueryBuilderInterface.php @@ -91,4 +91,10 @@ public function prepareParam(ParamInterface $param): string; * Used when the bind parameter cannot be used in the SQL query. */ public function prepareValue(mixed $value): string; + + /** + * Returns maximum number of parameters for a DBMS. + * @return int + */ + public function getParametersLimit(): int; } From 2494cb83bc3973b3b1970a1436f985fdbd3eed1a Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 3 Apr 2025 22:02:08 +0500 Subject: [PATCH 107/137] Refactor batchInsert method --- tests/AbstractQueryBuilderTest.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/AbstractQueryBuilderTest.php b/tests/AbstractQueryBuilderTest.php index 5615cc60f..2fa121e31 100644 --- a/tests/AbstractQueryBuilderTest.php +++ b/tests/AbstractQueryBuilderTest.php @@ -226,9 +226,14 @@ public function testBatchInsert( $statements = $qb->insertBatch($table, $rows, $columns); - $this->assertCount(1, $statements); - $this->assertSame($expected, $statements[0]->sql); - $this->assertSame($expectedParams, $statements[0]->params); + if (empty($expected)) { + $this->assertCount(0, $statements); + } else { + $this->assertSame($expected, $statements[0]->sql); + } + if ($this->count($statements)) { + $this->assertSame($expectedParams, $statements[0]->params); + } $db->close(); } From 547ce2dc1cea8dee1535b492b7f24d3a2c8151d8 Mon Sep 17 00:00:00 2001 From: evil1 <5018681+evil1@users.noreply.github.com> Date: Thu, 3 Apr 2025 17:02:53 +0000 Subject: [PATCH 108/137] Apply Rector changes (CI) --- tests/AbstractQueryBuilderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/AbstractQueryBuilderTest.php b/tests/AbstractQueryBuilderTest.php index 2fa121e31..6b9d2262e 100644 --- a/tests/AbstractQueryBuilderTest.php +++ b/tests/AbstractQueryBuilderTest.php @@ -231,7 +231,7 @@ public function testBatchInsert( } else { $this->assertSame($expected, $statements[0]->sql); } - if ($this->count($statements)) { + if ($this->count()) { $this->assertSame($expectedParams, $statements[0]->params); } $db->close(); From 309cf28543d3bdd17790bb1c48b31a65f6195166 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 3 Apr 2025 22:03:43 +0500 Subject: [PATCH 109/137] Refactor batchInsert method --- tests/AbstractQueryBuilderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/AbstractQueryBuilderTest.php b/tests/AbstractQueryBuilderTest.php index 2fa121e31..ca66797c0 100644 --- a/tests/AbstractQueryBuilderTest.php +++ b/tests/AbstractQueryBuilderTest.php @@ -231,7 +231,7 @@ public function testBatchInsert( } else { $this->assertSame($expected, $statements[0]->sql); } - if ($this->count($statements)) { + if (count($statements)) { $this->assertSame($expectedParams, $statements[0]->params); } $db->close(); From 390bd69ca70f36108c804685dcd249d5cadda8cc Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 3 Apr 2025 22:10:04 +0500 Subject: [PATCH 110/137] Refactor batchInsert method --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 1 + tests/AbstractQueryBuilderTest.php | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index c456c0a5d..4a5237f28 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -233,6 +233,7 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array $parameters[] = $statementParameters; $statementParameters = new QueryStatementParameters(); $insertedRowsCount = 1; + $insertedParametersCount = count($currentStatementParams); } elseif (!empty($maxParametersLimit) && $insertedParametersCount + count($currentStatementParams) > $maxParametersLimit) { $statementParameters->params = $currentStatementParams; $parameters[] = $statementParameters; diff --git a/tests/AbstractQueryBuilderTest.php b/tests/AbstractQueryBuilderTest.php index ca66797c0..8b94e1552 100644 --- a/tests/AbstractQueryBuilderTest.php +++ b/tests/AbstractQueryBuilderTest.php @@ -230,10 +230,9 @@ public function testBatchInsert( $this->assertCount(0, $statements); } else { $this->assertSame($expected, $statements[0]->sql); - } - if (count($statements)) { $this->assertSame($expectedParams, $statements[0]->params); } + $db->close(); } From 18287541026e0579cb8dd91e458de40ee57f3d1d Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 4 Apr 2025 08:12:53 +0500 Subject: [PATCH 111/137] Refactor batchInsert method --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 25 ++++++++------------ 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 4a5237f28..24e892209 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -194,7 +194,7 @@ final protected function prepareTraversable(Traversable $rows): Iterator|array */ protected function prepareBatchInsertValues(string $table, iterable $rows, array $columnNames, int $rowsAtOnceLimit = 0): array { - $parameters = []; + $queryStatementParameters = []; /** @var string[] $names */ $names = array_values($columnNames); $keys = array_fill_keys($names, false); @@ -204,11 +204,11 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array $maxParametersLimit = $this->queryBuilder->getParametersLimit(); $currentStatementParams = []; - $insertedParametersCount = 0; $insertedRowsCount = 0; foreach ($rows as $row) { $i = 0; $placeholders = $keys; + $statementParameters->params = $currentStatementParams; /** @var int|string $key */ foreach ($row as $key => $value) { @@ -228,28 +228,23 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array } $insertedRowsCount++; - if (!empty($rowsAtOnceLimit) && $insertedRowsCount > $rowsAtOnceLimit) { - $statementParameters->params = $currentStatementParams; - $parameters[] = $statementParameters; - $statementParameters = new QueryStatementParameters(); - $insertedRowsCount = 1; - $insertedParametersCount = count($currentStatementParams); - } elseif (!empty($maxParametersLimit) && $insertedParametersCount + count($currentStatementParams) > $maxParametersLimit) { - $statementParameters->params = $currentStatementParams; - $parameters[] = $statementParameters; + if ((!empty($rowsAtOnceLimit) && $insertedRowsCount > $rowsAtOnceLimit) || + (!empty($maxParametersLimit) && count($currentStatementParams) > $maxParametersLimit)) { + + $queryStatementParameters[] = $statementParameters; $statementParameters = new QueryStatementParameters(); $insertedRowsCount = 1; - $insertedParametersCount = count($currentStatementParams); + $currentStatementParams = []; + } - $insertedParametersCount += count($currentStatementParams); $statementParameters->values[] = implode(', ', $placeholders); } $statementParameters->params = $currentStatementParams; - $parameters[] = $statementParameters; + $queryStatementParameters[] = $statementParameters; - return $parameters; + return $queryStatementParameters; } /** From 59e92f3caac0ed5f33cc61ca2ea9278bc7657c09 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 4 Apr 2025 08:42:39 +0500 Subject: [PATCH 112/137] Refactor batchInsert method --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 24e892209..34bceee8e 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -103,8 +103,8 @@ public function insertBatch(string $table, iterable $rows, array $columns = [], foreach ($parameters as $parameter) { $statements[] = new QueryStatement( - $query . ' VALUES (' . implode('), (', $parameter->values) . ')', - $parameter->params + $query . ' VALUES (' . implode('), (', $parameter['values']) . ')', + $parameter['params'] ); } @@ -188,7 +188,7 @@ final protected function prepareTraversable(Traversable $rows): Iterator|array * @param string[] $columnNames The column names. * @param int $rowsAtOnceLimit The limit of rows inserted at once. * - * @return QueryStatementParameters[] The values. + * @return array[] The values. * * @psalm-param ParamsType $params */ @@ -200,7 +200,7 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array $keys = array_fill_keys($names, false); $columns = $this->schema->getTableSchema($table)?->getColumns() ?? []; - $statementParameters = new QueryStatementParameters(); + $statementParameters = ['values' => [], 'params' => []]; $maxParametersLimit = $this->queryBuilder->getParametersLimit(); $currentStatementParams = []; @@ -208,7 +208,7 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array foreach ($rows as $row) { $i = 0; $placeholders = $keys; - $statementParameters->params = $currentStatementParams; + $statementParameters['params'] = $currentStatementParams; /** @var int|string $key */ foreach ($row as $key => $value) { @@ -230,18 +230,16 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array $insertedRowsCount++; if ((!empty($rowsAtOnceLimit) && $insertedRowsCount > $rowsAtOnceLimit) || (!empty($maxParametersLimit) && count($currentStatementParams) > $maxParametersLimit)) { - $queryStatementParameters[] = $statementParameters; - $statementParameters = new QueryStatementParameters(); + $statementParameters = ['values' => [], 'params' => []]; $insertedRowsCount = 1; $currentStatementParams = []; - } - $statementParameters->values[] = implode(', ', $placeholders); + $statementParameters['values'][] = implode(', ', $placeholders); } - $statementParameters->params = $currentStatementParams; + $statementParameters['params'] = $currentStatementParams; $queryStatementParameters[] = $statementParameters; return $queryStatementParameters; From 5bc377e537819ec76d5d8a3afde743a206c35597 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 4 Apr 2025 09:07:49 +0500 Subject: [PATCH 113/137] Refactor batchInsert method --- src/Command/QueryStatement.php | 4 ++ src/Command/QueryStatementParameters.php | 15 ------- src/QueryBuilder/AbstractDMLQueryBuilder.php | 47 ++++++++++++-------- 3 files changed, 32 insertions(+), 34 deletions(-) delete mode 100644 src/Command/QueryStatementParameters.php diff --git a/src/Command/QueryStatement.php b/src/Command/QueryStatement.php index ad4c4e458..eccb5cc98 100644 --- a/src/Command/QueryStatement.php +++ b/src/Command/QueryStatement.php @@ -9,6 +9,10 @@ */ class QueryStatement { + /** + * @param string $sql SQL query. + * @param array $params Parameters for query execution. + */ public function __construct(public string $sql, public array $params = []) { } diff --git a/src/Command/QueryStatementParameters.php b/src/Command/QueryStatementParameters.php deleted file mode 100644 index 5f17bb0fb..000000000 --- a/src/Command/QueryStatementParameters.php +++ /dev/null @@ -1,15 +0,0 @@ - $value) { - $columnName = $columnNames[$key] ?? (isset($keys[$key]) ? $key : $names[$i] ?? $i); - - if (isset($columns[$columnName])) { - $value = $columns[$columnName]->dbTypecast($value); - } - - if ($value instanceof ExpressionInterface) { - $placeholders[$columnName] = $this->queryBuilder->buildExpression($value, $currentStatementParams); - } else { - $placeholders[$columnName] = $this->queryBuilder->bindParam($value, $currentStatementParams); - } - - ++$i; - } + $placeholders = $this->prepareRowBatchInsertValues($row, $keys, $names, $columns, $currentStatementParams); $insertedRowsCount++; if ((!empty($rowsAtOnceLimit) && $insertedRowsCount > $rowsAtOnceLimit) || @@ -234,6 +216,7 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array $statementParameters = ['values' => [], 'params' => []]; $insertedRowsCount = 1; $currentStatementParams = []; + $placeholders = $this->prepareRowBatchInsertValues($row, $keys, $names, $columns, $currentStatementParams); } $statementParameters['values'][] = implode(', ', $placeholders); @@ -245,6 +228,32 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array return $queryStatementParameters; } + protected function prepareRowBatchInsertValues(iterable $row, array $keys, array $names, array $columns, + array &$currentStatementParams): array + { + $i = 0; + $placeholders = $keys; + + /** @var int|string $key */ + foreach ($row as $key => $value) { + $columnName = $columnNames[$key] ?? (isset($keys[$key]) ? $key : $names[$i] ?? $i); + + if (isset($columns[$columnName])) { + $value = $columns[$columnName]->dbTypecast($value); + } + + if ($value instanceof ExpressionInterface) { + $placeholders[$columnName] = $this->queryBuilder->buildExpression($value, $currentStatementParams); + } else { + $placeholders[$columnName] = $this->queryBuilder->bindParam($value, $currentStatementParams); + } + + ++$i; + } + + return $placeholders; + } + /** * Extract column names from columns and rows. * From 937a491ab9074acdeedda80c09e94d53373e53a5 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 4 Apr 2025 09:13:43 +0500 Subject: [PATCH 114/137] Refactor batchInsert method --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index f9d64bed8..d0886f83e 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -187,7 +187,7 @@ final protected function prepareTraversable(Traversable $rows): Iterator|array * @param string[] $columnNames The column names. * @param int $rowsAtOnceLimit The limit of rows inserted at once. * - * @return array[] The values. + * @return array The values. * * @psalm-param ParamsType $params */ @@ -228,8 +228,13 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array return $queryStatementParameters; } - protected function prepareRowBatchInsertValues(iterable $row, array $keys, array $names, array $columns, - array &$currentStatementParams): array + protected function prepareRowBatchInsertValues( + mixed $row, + array $keys, + array $names, + array $columns, + array &$currentStatementParams + ): array { $i = 0; $placeholders = $keys; From 8d233d734c80e0935b6af85a453e28ba272eb6ff Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 4 Apr 2025 09:25:04 +0500 Subject: [PATCH 115/137] Refactor batchInsert method --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index d0886f83e..2d4af8137 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -234,8 +234,7 @@ protected function prepareRowBatchInsertValues( array $names, array $columns, array &$currentStatementParams - ): array - { + ): array { $i = 0; $placeholders = $keys; From 5bacb06279db7581bf0983279a180763f2369fdd Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 4 Apr 2025 09:35:01 +0500 Subject: [PATCH 116/137] Refactor batchInsert method --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 2d4af8137..e66a49141 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -240,6 +240,7 @@ protected function prepareRowBatchInsertValues( /** @var int|string $key */ foreach ($row as $key => $value) { + /** @var string $columnName */ $columnName = $columnNames[$key] ?? (isset($keys[$key]) ? $key : $names[$i] ?? $i); if (isset($columns[$columnName])) { From 597661f9a44f923c2f80ed022ff8dbd585e8d1d4 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 4 Apr 2025 11:05:17 +0500 Subject: [PATCH 117/137] Refactor batchInsert method --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 21 +++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index e66a49141..8d86d1c22 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -194,10 +194,6 @@ final protected function prepareTraversable(Traversable $rows): Iterator|array protected function prepareBatchInsertValues(string $table, iterable $rows, array $columnNames, int $rowsAtOnceLimit = 0): array { $queryStatementParameters = []; - /** @var string[] $names */ - $names = array_values($columnNames); - $keys = array_fill_keys($names, false); - $columns = $this->schema->getTableSchema($table)?->getColumns() ?? []; $statementParameters = ['values' => [], 'params' => []]; $maxParametersLimit = $this->queryBuilder->getParametersLimit(); @@ -207,7 +203,7 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array foreach ($rows as $row) { $statementParameters['params'] = $currentStatementParams; - $placeholders = $this->prepareRowBatchInsertValues($row, $keys, $names, $columns, $currentStatementParams); + $placeholders = $this->prepareRowBatchInsertValues($table, $row, $columnNames, $currentStatementParams); $insertedRowsCount++; if ((!empty($rowsAtOnceLimit) && $insertedRowsCount > $rowsAtOnceLimit) || @@ -216,7 +212,7 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array $statementParameters = ['values' => [], 'params' => []]; $insertedRowsCount = 1; $currentStatementParams = []; - $placeholders = $this->prepareRowBatchInsertValues($row, $keys, $names, $columns, $currentStatementParams); + $placeholders = $this->prepareRowBatchInsertValues($table, $row, $columnNames, $currentStatementParams); } $statementParameters['values'][] = implode(', ', $placeholders); @@ -229,15 +225,22 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array } protected function prepareRowBatchInsertValues( + string $table, mixed $row, - array $keys, - array $names, - array $columns, + array $columnNames, array &$currentStatementParams ): array { $i = 0; + + /** @var string[] $names */ + $names = array_values($columnNames); + $keys = array_fill_keys($names, false); + $columns = $this->schema->getTableSchema($table)?->getColumns() ?? []; + $placeholders = $keys; + + /** @var int|string $key */ foreach ($row as $key => $value) { /** @var string $columnName */ From ab396bf2aadf1d2d1115f63383204f7f7fa839cf Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 4 Apr 2025 11:08:28 +0500 Subject: [PATCH 118/137] Refactor batchInsert method --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 8d86d1c22..6b71e3830 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -243,7 +243,6 @@ protected function prepareRowBatchInsertValues( /** @var int|string $key */ foreach ($row as $key => $value) { - /** @var string $columnName */ $columnName = $columnNames[$key] ?? (isset($keys[$key]) ? $key : $names[$i] ?? $i); if (isset($columns[$columnName])) { From fdaffb70b4ebdff14474b77bed5a2b3f4565108d Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 4 Apr 2025 11:11:45 +0500 Subject: [PATCH 119/137] Refactor batchInsert method --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 6b71e3830..47874ffac 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -224,6 +224,18 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array return $queryStatementParameters; } + /** + * Prepare values for batch insert for a single row. + * + * @param string $table The table name. + * @param mixed $row The rows to be batch inserted into the table. + * @param string[] $columnNames The column names. + * @param array $currentStatementParams The binding parameters that will be generated by this method. + * + * @return array The placeholders for values. + * + * @psalm-param ParamsType $params + */ protected function prepareRowBatchInsertValues( string $table, mixed $row, From 088adda15e967245e1eb25f94d2d6f38d3e787dc Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 4 Apr 2025 11:19:46 +0500 Subject: [PATCH 120/137] Refactor batchInsert method --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 27 ++++++++++---------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 47874ffac..1920a7b77 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -194,6 +194,10 @@ final protected function prepareTraversable(Traversable $rows): Iterator|array protected function prepareBatchInsertValues(string $table, iterable $rows, array $columnNames, int $rowsAtOnceLimit = 0): array { $queryStatementParameters = []; + /** @var string[] $names */ + $names = array_values($columnNames); + $keys = array_fill_keys($names, false); + $columns = $this->schema->getTableSchema($table)?->getColumns() ?? []; $statementParameters = ['values' => [], 'params' => []]; $maxParametersLimit = $this->queryBuilder->getParametersLimit(); @@ -203,7 +207,7 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array foreach ($rows as $row) { $statementParameters['params'] = $currentStatementParams; - $placeholders = $this->prepareRowBatchInsertValues($table, $row, $columnNames, $currentStatementParams); + $placeholders = $this->prepareRowBatchInsertValues($row, $columnNames, $keys, $names, $columns, $currentStatementParams); $insertedRowsCount++; if ((!empty($rowsAtOnceLimit) && $insertedRowsCount > $rowsAtOnceLimit) || @@ -212,7 +216,7 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array $statementParameters = ['values' => [], 'params' => []]; $insertedRowsCount = 1; $currentStatementParams = []; - $placeholders = $this->prepareRowBatchInsertValues($table, $row, $columnNames, $currentStatementParams); + $placeholders = $this->prepareRowBatchInsertValues($row, $columnNames, $keys, $names, $columns, $currentStatementParams); } $statementParameters['values'][] = implode(', ', $placeholders); @@ -227,34 +231,31 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array /** * Prepare values for batch insert for a single row. * - * @param string $table The table name. * @param mixed $row The rows to be batch inserted into the table. * @param string[] $columnNames The column names. + * @param array $keys The column names. + * @param string[] $names The column names. + * @param array $columns The column names. * @param array $currentStatementParams The binding parameters that will be generated by this method. * - * @return array The placeholders for values. + * @return array The placeholder for a row. * * @psalm-param ParamsType $params */ protected function prepareRowBatchInsertValues( - string $table, mixed $row, array $columnNames, + array $keys, + array $names, + array $columns, array &$currentStatementParams ): array { $i = 0; - - /** @var string[] $names */ - $names = array_values($columnNames); - $keys = array_fill_keys($names, false); - $columns = $this->schema->getTableSchema($table)?->getColumns() ?? []; - $placeholders = $keys; - - /** @var int|string $key */ foreach ($row as $key => $value) { + /** @var string $columnName */ $columnName = $columnNames[$key] ?? (isset($keys[$key]) ? $key : $names[$i] ?? $i); if (isset($columns[$columnName])) { From 44165b8a2b24a6565b62a7c50d7d706118058721 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 4 Apr 2025 11:33:23 +0500 Subject: [PATCH 121/137] Refactor batchInsert method --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 39 +++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 1920a7b77..bc6159d28 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -205,9 +205,27 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array $currentStatementParams = []; $insertedRowsCount = 0; foreach ($rows as $row) { + $i = 0; + $placeholders = $keys; + $statementParameters['params'] = $currentStatementParams; - $placeholders = $this->prepareRowBatchInsertValues($row, $columnNames, $keys, $names, $columns, $currentStatementParams); + /** @var int|string $key */ + foreach ($row as $key => $value) { + $columnName = $columnNames[$key] ?? (isset($keys[$key]) ? $key : $names[$i] ?? $i); + + if (isset($columns[$columnName])) { + $value = $columns[$columnName]->dbTypecast($value); + } + + if ($value instanceof ExpressionInterface) { + $placeholders[$columnName] = $this->queryBuilder->buildExpression($value, $currentStatementParams); + } else { + $placeholders[$columnName] = $this->queryBuilder->bindParam($value, $currentStatementParams); + } + + ++$i; + } $insertedRowsCount++; if ((!empty($rowsAtOnceLimit) && $insertedRowsCount > $rowsAtOnceLimit) || @@ -215,8 +233,25 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array $queryStatementParameters[] = $statementParameters; $statementParameters = ['values' => [], 'params' => []]; $insertedRowsCount = 1; + $currentStatementParams = []; - $placeholders = $this->prepareRowBatchInsertValues($row, $columnNames, $keys, $names, $columns, $currentStatementParams); + $placeholders = $keys; + /** @var int|string $key */ + foreach ($row as $key => $value) { + $columnName = $columnNames[$key] ?? (isset($keys[$key]) ? $key : $names[$i] ?? $i); + + if (isset($columns[$columnName])) { + $value = $columns[$columnName]->dbTypecast($value); + } + + if ($value instanceof ExpressionInterface) { + $placeholders[$columnName] = $this->queryBuilder->buildExpression($value, $currentStatementParams); + } else { + $placeholders[$columnName] = $this->queryBuilder->bindParam($value, $currentStatementParams); + } + + ++$i; + } } $statementParameters['values'][] = implode(', ', $placeholders); From 6cc0a89721feb8c79da1e3f43f5e25ffe66af80e Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 4 Apr 2025 11:37:00 +0500 Subject: [PATCH 122/137] Refactor batchInsert method --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 35 +++++--------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index bc6159d28..77021afd2 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -227,32 +227,15 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array ++$i; } - $insertedRowsCount++; - if ((!empty($rowsAtOnceLimit) && $insertedRowsCount > $rowsAtOnceLimit) || - (!empty($maxParametersLimit) && count($currentStatementParams) > $maxParametersLimit)) { - $queryStatementParameters[] = $statementParameters; - $statementParameters = ['values' => [], 'params' => []]; - $insertedRowsCount = 1; - - $currentStatementParams = []; - $placeholders = $keys; - /** @var int|string $key */ - foreach ($row as $key => $value) { - $columnName = $columnNames[$key] ?? (isset($keys[$key]) ? $key : $names[$i] ?? $i); - - if (isset($columns[$columnName])) { - $value = $columns[$columnName]->dbTypecast($value); - } - - if ($value instanceof ExpressionInterface) { - $placeholders[$columnName] = $this->queryBuilder->buildExpression($value, $currentStatementParams); - } else { - $placeholders[$columnName] = $this->queryBuilder->bindParam($value, $currentStatementParams); - } - - ++$i; - } - } +// $insertedRowsCount++; +// if ((!empty($rowsAtOnceLimit) && $insertedRowsCount > $rowsAtOnceLimit) || +// (!empty($maxParametersLimit) && count($currentStatementParams) > $maxParametersLimit)) { +// $queryStatementParameters[] = $statementParameters; +// $statementParameters = ['values' => [], 'params' => []]; +// $insertedRowsCount = 1; +// $currentStatementParams = []; +// +// } $statementParameters['values'][] = implode(', ', $placeholders); } From fc4c5d663b0a5d6c530698051d52399fcf3b9d31 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 4 Apr 2025 14:12:07 +0500 Subject: [PATCH 123/137] Refactor batchInsert method --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 26 ++++++-------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 77021afd2..2cc0d7125 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -205,27 +205,17 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array $currentStatementParams = []; $insertedRowsCount = 0; foreach ($rows as $row) { - $i = 0; - $placeholders = $keys; $statementParameters['params'] = $currentStatementParams; - /** @var int|string $key */ - foreach ($row as $key => $value) { - $columnName = $columnNames[$key] ?? (isset($keys[$key]) ? $key : $names[$i] ?? $i); - - if (isset($columns[$columnName])) { - $value = $columns[$columnName]->dbTypecast($value); - } - - if ($value instanceof ExpressionInterface) { - $placeholders[$columnName] = $this->queryBuilder->buildExpression($value, $currentStatementParams); - } else { - $placeholders[$columnName] = $this->queryBuilder->bindParam($value, $currentStatementParams); - } - - ++$i; - } + $placeholders = $this->prepareRowBatchInsertValues( + $row, + $columnNames, + $keys, + $names, + $columns, + $currentStatementParams + ); // $insertedRowsCount++; // if ((!empty($rowsAtOnceLimit) && $insertedRowsCount > $rowsAtOnceLimit) || From fc0e2696468bdb8826bcff4ce38e622544fe2b53 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 4 Apr 2025 14:19:12 +0500 Subject: [PATCH 124/137] Refactor batchInsert method --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 29 ++++++++++++-------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 2cc0d7125..1a915d216 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -199,13 +199,12 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array $keys = array_fill_keys($names, false); $columns = $this->schema->getTableSchema($table)?->getColumns() ?? []; - $statementParameters = ['values' => [], 'params' => []]; + $statementParameters = ['values' => []]; $maxParametersLimit = $this->queryBuilder->getParametersLimit(); $currentStatementParams = []; $insertedRowsCount = 0; foreach ($rows as $row) { - $statementParameters['params'] = $currentStatementParams; $placeholders = $this->prepareRowBatchInsertValues( @@ -217,15 +216,23 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array $currentStatementParams ); -// $insertedRowsCount++; -// if ((!empty($rowsAtOnceLimit) && $insertedRowsCount > $rowsAtOnceLimit) || -// (!empty($maxParametersLimit) && count($currentStatementParams) > $maxParametersLimit)) { -// $queryStatementParameters[] = $statementParameters; -// $statementParameters = ['values' => [], 'params' => []]; -// $insertedRowsCount = 1; -// $currentStatementParams = []; -// -// } + $insertedRowsCount++; + if ((!empty($rowsAtOnceLimit) && $insertedRowsCount > $rowsAtOnceLimit) || + (!empty($maxParametersLimit) && count($currentStatementParams) > $maxParametersLimit)) { + $queryStatementParameters[] = $statementParameters; + $statementParameters = ['values' => []]; + $insertedRowsCount = 1; + $currentStatementParams = []; + + $placeholders = $this->prepareRowBatchInsertValues( + $row, + $columnNames, + $keys, + $names, + $columns, + $currentStatementParams + ); + } $statementParameters['values'][] = implode(', ', $placeholders); } From 2a87ca6732bf02b247142381019edb8cf07b33e0 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 4 Apr 2025 14:32:20 +0500 Subject: [PATCH 125/137] Refactor batchInsert method --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 1a915d216..1efbf22b3 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -17,6 +17,7 @@ use Yiisoft\Db\Exception\NotSupportedException; use Yiisoft\Db\Expression\ExpressionInterface; use Yiisoft\Db\Query\QueryInterface; +use Yiisoft\Db\Schema\Column\ColumnInterface; use Yiisoft\Db\Schema\QuoterInterface; use Yiisoft\Db\Schema\SchemaInterface; @@ -250,7 +251,7 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array * @param string[] $columnNames The column names. * @param array $keys The column names. * @param string[] $names The column names. - * @param array $columns The column names. + * @param array|ColumnInterface[] $columns The table columns. * @param array $currentStatementParams The binding parameters that will be generated by this method. * * @return array The placeholder for a row. From 611ed455ab7d0d04307a41965383358e44e57888 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 4 Apr 2025 14:35:03 +0500 Subject: [PATCH 126/137] Refactor batchInsert method --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 1efbf22b3..afe6b8678 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -101,6 +101,7 @@ public function insertBatch(string $table, iterable $rows, array $columns = [], $query .= ' (' . implode(', ', $quotedColumnNames) . ')'; } + /** @var array $parameter */ foreach ($parameters as $parameter) { $statements[] = new QueryStatement( $query . ' VALUES (' . implode('), (', $parameter['values']) . ')', From 1a09db6bf4867fb37cdde5275f41de0867cfeba3 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Sat, 5 Apr 2025 15:23:53 +0500 Subject: [PATCH 127/137] Fix psalm typehinting --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index afe6b8678..9255fef70 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -192,6 +192,7 @@ final protected function prepareTraversable(Traversable $rows): Iterator|array * @return array The values. * * @psalm-param ParamsType $params + * @psalm-return array */ protected function prepareBatchInsertValues(string $table, iterable $rows, array $columnNames, int $rowsAtOnceLimit = 0): array { From 91ffdf62833abb2e9ef57c70b6de4c9f55cccbe7 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Sat, 5 Apr 2025 15:26:06 +0500 Subject: [PATCH 128/137] Fix psalm typehinting --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 9255fef70..cbf87de9d 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -192,7 +192,7 @@ final protected function prepareTraversable(Traversable $rows): Iterator|array * @return array The values. * * @psalm-param ParamsType $params - * @psalm-return array + * @psalm-return array> */ protected function prepareBatchInsertValues(string $table, iterable $rows, array $columnNames, int $rowsAtOnceLimit = 0): array { From c518a0d69537d9c9a0481cb769f2a6261a31c574 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Sat, 5 Apr 2025 15:28:38 +0500 Subject: [PATCH 129/137] Fix psalm typehinting --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index cbf87de9d..6374b8fe1 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -104,7 +104,7 @@ public function insertBatch(string $table, iterable $rows, array $columns = [], /** @var array $parameter */ foreach ($parameters as $parameter) { $statements[] = new QueryStatement( - $query . ' VALUES (' . implode('), (', $parameter['values']) . ')', + $query . ' VALUES (' . implode('), (', (array)$parameter['values']) . ')', $parameter['params'] ); } @@ -192,7 +192,6 @@ final protected function prepareTraversable(Traversable $rows): Iterator|array * @return array The values. * * @psalm-param ParamsType $params - * @psalm-return array> */ protected function prepareBatchInsertValues(string $table, iterable $rows, array $columnNames, int $rowsAtOnceLimit = 0): array { From f11ee5c9c75db786a1fb36595e132433bcaeee39 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 11 Apr 2025 08:17:21 +0500 Subject: [PATCH 130/137] Fix psalm typehinting --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 6374b8fe1..279e31c8d 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -104,7 +104,7 @@ public function insertBatch(string $table, iterable $rows, array $columns = [], /** @var array $parameter */ foreach ($parameters as $parameter) { $statements[] = new QueryStatement( - $query . ' VALUES (' . implode('), (', (array)$parameter['values']) . ')', + $query . ' VALUES (' . implode('), (', $parameter['values']) . ')', $parameter['params'] ); } @@ -192,6 +192,7 @@ final protected function prepareTraversable(Traversable $rows): Iterator|array * @return array The values. * * @psalm-param ParamsType $params + * @psalm-return array */ protected function prepareBatchInsertValues(string $table, iterable $rows, array $columnNames, int $rowsAtOnceLimit = 0): array { From ec50b75933b68ad51decda89ab46eab2ab578fd3 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Fri, 11 Apr 2025 08:26:02 +0500 Subject: [PATCH 131/137] Fix psalm typehinting --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 279e31c8d..6e7254206 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -101,11 +101,14 @@ public function insertBatch(string $table, iterable $rows, array $columns = [], $query .= ' (' . implode(', ', $quotedColumnNames) . ')'; } - /** @var array $parameter */ foreach ($parameters as $parameter) { + /** @var array $values */ + /** @var array $params */ + $values = $parameter['values']; + $params = $parameter['params']; $statements[] = new QueryStatement( - $query . ' VALUES (' . implode('), (', $parameter['values']) . ')', - $parameter['params'] + $query . ' VALUES (' . implode('), (', $values) . ')', + $params ); } From 4e855e9725d950e2f2eef9c3fc820ce57134792c Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Wed, 16 Apr 2025 22:31:18 +0300 Subject: [PATCH 132/137] improve --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 31 ++++++++++++-------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 6e7254206..12a13ffb7 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -102,8 +102,6 @@ public function insertBatch(string $table, iterable $rows, array $columns = [], } foreach ($parameters as $parameter) { - /** @var array $values */ - /** @var array $params */ $values = $parameter['values']; $params = $parameter['params']; $statements[] = new QueryStatement( @@ -168,7 +166,8 @@ public function upsert( * * @return array|Iterator The prepared rows. * - * @psalm-return Iterator|array> + * @psalm-param Traversable> $rows + * @psalm-return Iterator>|array{} */ final protected function prepareTraversable(Traversable $rows): Iterator|array { @@ -194,13 +193,20 @@ final protected function prepareTraversable(Traversable $rows): Iterator|array * * @return array The values. * + * @psalm-param BatchValues $rows * @psalm-param ParamsType $params - * @psalm-return array + * @psalm-return array, + * }> */ - protected function prepareBatchInsertValues(string $table, iterable $rows, array $columnNames, int $rowsAtOnceLimit = 0): array - { + protected function prepareBatchInsertValues( + string $table, + iterable $rows, + array $columnNames, + int $rowsAtOnceLimit = 0 + ): array { $queryStatementParameters = []; - /** @var string[] $names */ $names = array_values($columnNames); $keys = array_fill_keys($names, false); $columns = $this->schema->getTableSchema($table)?->getColumns() ?? []; @@ -252,19 +258,22 @@ protected function prepareBatchInsertValues(string $table, iterable $rows, array /** * Prepare values for batch insert for a single row. * - * @param mixed $row The rows to be batch inserted into the table. + * @param iterable $row The rows to be batch inserted into the table. * @param string[] $columnNames The column names. * @param array $keys The column names. * @param string[] $names The column names. - * @param array|ColumnInterface[] $columns The table columns. + * @param ColumnInterface[] $columns The table columns. * @param array $currentStatementParams The binding parameters that will be generated by this method. * * @return array The placeholder for a row. * + * @psalm-param iterable $row + * @psalm-param array $keys * @psalm-param ParamsType $params + * @psalm-return array */ protected function prepareRowBatchInsertValues( - mixed $row, + iterable $row, array $columnNames, array $keys, array $names, @@ -274,9 +283,7 @@ protected function prepareRowBatchInsertValues( $i = 0; $placeholders = $keys; - /** @var int|string $key */ foreach ($row as $key => $value) { - /** @var string $columnName */ $columnName = $columnNames[$key] ?? (isset($keys[$key]) ? $key : $names[$i] ?? $i); if (isset($columns[$columnName])) { From adaa1fefca16173323e228a9fce186ed96114e71 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Wed, 16 Apr 2025 22:35:46 +0300 Subject: [PATCH 133/137] improve --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 12a13ffb7..3fb4a07ab 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -166,7 +166,6 @@ public function upsert( * * @return array|Iterator The prepared rows. * - * @psalm-param Traversable> $rows * @psalm-return Iterator>|array{} */ final protected function prepareTraversable(Traversable $rows): Iterator|array @@ -175,7 +174,7 @@ final protected function prepareTraversable(Traversable $rows): Iterator|array $rows = $rows->getIterator(); } - /** @var Iterator $rows */ + /** @var Iterator> $rows */ if (!$rows->valid()) { return []; } From 0a3157c9be3fb656d0a752789a095fb23e4606f2 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 17 Apr 2025 06:47:11 +0500 Subject: [PATCH 134/137] Fix psalm typehinting --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 3fb4a07ab..0566c6c1e 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -257,7 +257,7 @@ protected function prepareBatchInsertValues( /** * Prepare values for batch insert for a single row. * - * @param iterable $row The rows to be batch inserted into the table. + * @param iterable|object $row The rows to be batch inserted into the table. * @param string[] $columnNames The column names. * @param array $keys The column names. * @param string[] $names The column names. @@ -266,7 +266,7 @@ protected function prepareBatchInsertValues( * * @return array The placeholder for a row. * - * @psalm-param iterable $row + * @psalm-param iterable|object $row * @psalm-param array $keys * @psalm-param ParamsType $params * @psalm-return array From 2b6b25f36025ea54552a62cdc928d6d756bf7eca Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 17 Apr 2025 06:47:37 +0500 Subject: [PATCH 135/137] Fix psalm typehinting --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 0566c6c1e..2703428ca 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -272,7 +272,7 @@ protected function prepareBatchInsertValues( * @psalm-return array */ protected function prepareRowBatchInsertValues( - iterable $row, + mixed $row, array $columnNames, array $keys, array $names, From 7905ed767dbcfc7712900bf799398435f7bcb7b0 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 17 Apr 2025 07:01:18 +0500 Subject: [PATCH 136/137] Fix psalm typehinting --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 2703428ca..5d0ad551c 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -267,7 +267,7 @@ protected function prepareBatchInsertValues( * @return array The placeholder for a row. * * @psalm-param iterable|object $row - * @psalm-param array $keys + * @psalm-param array $keys * @psalm-param ParamsType $params * @psalm-return array */ From b41aa4cd44fd63f32463d031442a46d51ba3dca1 Mon Sep 17 00:00:00 2001 From: Dmitriy Gritsenko Date: Thu, 17 Apr 2025 07:03:25 +0500 Subject: [PATCH 137/137] Fix psalm typehinting --- src/QueryBuilder/AbstractDMLQueryBuilder.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/QueryBuilder/AbstractDMLQueryBuilder.php b/src/QueryBuilder/AbstractDMLQueryBuilder.php index 5d0ad551c..f8a96d69a 100644 --- a/src/QueryBuilder/AbstractDMLQueryBuilder.php +++ b/src/QueryBuilder/AbstractDMLQueryBuilder.php @@ -267,7 +267,7 @@ protected function prepareBatchInsertValues( * @return array The placeholder for a row. * * @psalm-param iterable|object $row - * @psalm-param array $keys + * @psalm-param array $keys * @psalm-param ParamsType $params * @psalm-return array */ @@ -282,6 +282,9 @@ protected function prepareRowBatchInsertValues( $i = 0; $placeholders = $keys; + /** + * @var string $key + */ foreach ($row as $key => $value) { $columnName = $columnNames[$key] ?? (isset($keys[$key]) ? $key : $names[$i] ?? $i);