Browse Source

Fixes #14289: Added `yii\db\Command::executeResetSequence()` to work with Oracle

tags/2.0.16
CedricYii 6 years ago committed by Alexander Makarov
parent
commit
3555633223
  1. 1
      framework/CHANGELOG.md
  2. 20
      framework/db/Command.php
  3. 20
      framework/db/QueryBuilder.php
  4. 17
      framework/db/oci/QueryBuilder.php
  5. 2
      framework/test/ActiveFixture.php
  6. 18
      tests/framework/db/oci/QueryBuilderTest.php

1
framework/CHANGELOG.md

@ -4,6 +4,7 @@ Yii Framework 2 Change Log
2.0.16 under development
------------------------
- Enh #14289: Added `yii\db\Command::executeResetSequence()` to work with Oracle (CedricYii)
- Enh #9133: Added `yii\behaviors\OptimisticLockBehavior` (tunecino)
- Bug #16104: Fixed `yii\db\pgsql\QueryBuilder::dropIndex()` to prepend index name with schema name (wapmorgan)
- Bug #16193: Fixed `yii\filters\Cors` to not reflect origin header value when configured to wildcard origins (Jianjun Chen)

20
framework/db/Command.php

@ -931,10 +931,10 @@ class Command extends Component
/**
* Creates a SQL command for resetting the sequence value of a table's primary key.
* The sequence will be reset such that the primary key of the next new row inserted
* will have the specified value or 1.
* will have the specified value or the maximum existing value +1.
* @param string $table the name of the table whose primary key sequence will be reset
* @param mixed $value the value for the primary key of the next new row inserted. If this is not set,
* the next new row's primary key will have a value 1.
* the next new row's primary key will have the maximum existing value +1.
* @return $this the command object itself
* @throws NotSupportedException if this is not supported by the underlying DBMS
*/
@ -946,6 +946,22 @@ class Command extends Component
}
/**
* Executes a db command resetting the sequence value of a table's primary key.
* Reason for execute is that some databases (Oracle) need several queries to do so.
* The sequence is reset such that the primary key of the next new row inserted
* will have the specified value or the maximum existing value +1.
* @param string $table the name of the table whose primary key sequence is reset
* @param mixed $value the value for the primary key of the next new row inserted. If this is not set,
* the next new row's primary key will have the maximum existing value +1.
* @throws NotSupportedException if this is not supported by the underlying DBMS
* @since 2.0.16
*/
public function executeResetSequence($table, $value = null)
{
return $this->db->getQueryBuilder()->executeResetSequence($table, $value);
}
/**
* Builds a SQL command for enabling or disabling integrity check.
* @param bool $check whether to turn on or off the integrity check.
* @param string $schema the schema name of the tables. Defaults to empty string, meaning the current

20
framework/db/QueryBuilder.php

@ -1028,10 +1028,10 @@ class QueryBuilder extends \yii\base\BaseObject
/**
* Creates a SQL statement for resetting the sequence value of a table's primary key.
* The sequence will be reset such that the primary key of the next new row inserted
* will have the specified value or 1.
* will have the specified value or the maximum existing value +1.
* @param string $table the name of the table whose primary key sequence will be reset
* @param array|string $value the value for the primary key of the next new row inserted. If this is not set,
* the next new row's primary key will have a value 1.
* the next new row's primary key will have the maximum existing value +1.
* @return string the SQL statement for resetting sequence
* @throws NotSupportedException if this is not supported by the underlying DBMS
*/
@ -1041,6 +1041,22 @@ class QueryBuilder extends \yii\base\BaseObject
}
/**
* Execute a SQL statement for resetting the sequence value of a table's primary key.
* Reason for execute is that some databases (Oracle) need several queries to do so.
* The sequence is reset such that the primary key of the next new row inserted
* will have the specified value or the maximum existing value +1.
* @param string $table the name of the table whose primary key sequence is reset
* @param array|string $value the value for the primary key of the next new row inserted. If this is not set,
* the next new row's primary key will have the maximum existing value +1.
* @throws NotSupportedException if this is not supported by the underlying DBMS
* @since 2.0.16
*/
public function executeResetSequence($table, $value = null)
{
$this->db->createCommand()->resetSequence($table, $value)->execute();
}
/**
* Builds a SQL statement for enabling or disabling integrity check.
* @param bool $check whether to turn on or off the integrity check.
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema.

17
framework/db/oci/QueryBuilder.php

@ -138,27 +138,34 @@ EOD;
/**
* {@inheritdoc}
*/
public function resetSequence($table, $value = null)
public function executeResetSequence($table, $value = null)
{
$tableSchema = $this->db->getTableSchema($table);
if ($tableSchema === null) {
throw new InvalidArgumentException("Unknown table: $table");
}
if ($tableSchema->sequenceName === null) {
return '';
throw new InvalidArgumentException("There is no sequence associated with table: $table");
}
if ($value !== null) {
$value = (int) $value;
} else {
if (count($tableSchema->primaryKey)>1) {
throw new InvalidArgumentException("Can't reset sequence for composite primary key in table: $table");
}
// use master connection to get the biggest PK value
$value = $this->db->useMaster(function (Connection $db) use ($tableSchema) {
return $db->createCommand("SELECT MAX(\"{$tableSchema->primaryKey}\") FROM \"{$tableSchema->name}\"")->queryScalar();
return $db->createCommand(
'SELECT MAX("' . $tableSchema->primaryKey[0] . '") FROM "'. $tableSchema->name . '"'
)->queryScalar();
}) + 1;
}
return "DROP SEQUENCE \"{$tableSchema->name}_SEQ\";"
. "CREATE SEQUENCE \"{$tableSchema->name}_SEQ\" START WITH {$value} INCREMENT BY 1 NOMAXVALUE NOCACHE";
//Oracle needs at least two queries to reset sequence (see adding transactions and/or use alter method to avoid grants' issue?)
$this->db->createCommand('DROP SEQUENCE "' . $tableSchema->sequenceName . '"')->execute();
$this->db->createCommand('CREATE SEQUENCE "' . $tableSchema->sequenceName . '" START WITH ' . $value
. ' INCREMENT BY 1 NOMAXVALUE NOCACHE')->execute();
}
/**

2
framework/test/ActiveFixture.php

@ -125,7 +125,7 @@ class ActiveFixture extends BaseActiveFixture
$table = $this->getTableSchema();
$this->db->createCommand()->delete($table->fullName)->execute();
if ($table->sequenceName !== null) {
$this->db->createCommand()->resetSequence($table->fullName, 1)->execute();
$this->db->createCommand()->executeResetSequence($table->fullName, 1);
}
}

18
tests/framework/db/oci/QueryBuilderTest.php

@ -106,19 +106,19 @@ class QueryBuilderTest extends \yiiunit\framework\db\QueryBuilderTest
$this->assertEquals($this->replaceQuotes($expected), $sql);
}
public function testResetSequence()
public function testExecuteResetSequence()
{
$db = $this->getConnection();
$qb = $this->getQueryBuilder();
$sqlResult = "SELECT last_number FROM user_sequences WHERE sequence_name = 'item_SEQ'";
$expected = 'DROP SEQUENCE "item_SEQ";'
. 'CREATE SEQUENCE "item_SEQ" START WITH 6 INCREMENT BY 1 NOMAXVALUE NOCACHE';
$sql = $qb->resetSequence('item');
$this->assertEquals($expected, $sql);
$qb->executeResetSequence('item');
$result = $db->createCommand($sqlResult)->queryScalar();
$this->assertEquals(6, $result);
$expected = 'DROP SEQUENCE "item_SEQ";'
. 'CREATE SEQUENCE "item_SEQ" START WITH 4 INCREMENT BY 1 NOMAXVALUE NOCACHE';
$sql = $qb->resetSequence('item', 4);
$this->assertEquals($expected, $sql);
$qb->executeResetSequence('item', 4);
$result = $db->createCommand($sqlResult)->queryScalar();
$this->assertEquals(4, $result);
}
public function likeConditionProvider()

Loading…
Cancel
Save