Merge pull request #8034 from nineinchnick/7374-inserting-ar-without-values

Saving AR without values / calling Command::insert without columns
This commit is contained in:
Alexander Makarov
2015-05-25 01:42:46 +03:00
9 changed files with 98 additions and 10 deletions

View File

@@ -5,6 +5,7 @@ Yii Framework 2 Change Log
----------------------- -----------------------
- Bug #7305: Logging of Exception objects resulted in failure of the logger i.e. no logs being written (cebe) - Bug #7305: Logging of Exception objects resulted in failure of the logger i.e. no logs being written (cebe)
- Bug #7374: Use proper INSERT syntax with default values when no values are specified (nineinchnick)
- Bug #7707: client-side `trim` validator now passes the trimmed value to subsequent validators (nkovacs) - Bug #7707: client-side `trim` validator now passes the trimmed value to subsequent validators (nkovacs)
- Bug #8322: `yii\behaviors\TimestampBehavior::touch()` now throws an exception if owner is new record (klimov-paul) - Bug #8322: `yii\behaviors\TimestampBehavior::touch()` now throws an exception if owner is new record (klimov-paul)
- Bug #8451: `yii\i18n\Formatter` did not allow negative unix timestamps as input for date formatting (cebe) - Bug #8451: `yii\i18n\Formatter` did not allow negative unix timestamps as input for date formatting (cebe)

View File

@@ -449,11 +449,6 @@ class ActiveRecord extends BaseActiveRecord
return false; return false;
} }
$values = $this->getDirtyAttributes($attributes); $values = $this->getDirtyAttributes($attributes);
if (empty($values)) {
foreach ($this->getPrimaryKey(true) as $key => $value) {
$values[$key] = $value;
}
}
if (($primaryKeys = static::getDb()->schema->insert($this->tableName(), $values)) === false) { if (($primaryKeys = static::getDb()->schema->insert($this->tableName(), $values)) === false) {
return false; return false;
} }

View File

@@ -153,8 +153,8 @@ class QueryBuilder extends \yii\base\Object
} }
return 'INSERT INTO ' . $schema->quoteTableName($table) return 'INSERT INTO ' . $schema->quoteTableName($table)
. ' (' . implode(', ', $names) . ') VALUES (' . (!empty($names) ? ' (' . implode(', ', $names) . ')' : '')
. implode(', ', $placeholders) . ')'; . (!empty($placeholders) ? ' VALUES (' . implode(', ', $placeholders) . ')' : ' DEFAULT VALUES');
} }
/** /**

View File

@@ -164,4 +164,43 @@ class QueryBuilder extends \yii\db\QueryBuilder
return $sql; return $sql;
} }
/**
* @inheritdoc
*/
public function insert($table, $columns, &$params)
{
$schema = $this->db->getSchema();
if (($tableSchema = $schema->getTableSchema($table)) !== null) {
$columnSchemas = $tableSchema->columns;
} else {
$columnSchemas = [];
}
$names = [];
$placeholders = [];
foreach ($columns as $name => $value) {
$names[] = $schema->quoteColumnName($name);
if ($value instanceof Expression) {
$placeholders[] = $value->expression;
foreach ($value->params as $n => $v) {
$params[$n] = $v;
}
} else {
$phName = self::PARAM_PREFIX . count($params);
$placeholders[] = $phName;
$params[$phName] = !is_array($value) && isset($columnSchemas[$name]) ? $columnSchemas[$name]->dbTypecast($value) : $value;
}
}
if (empty($names) && $tableSchema !== null) {
$columns = !empty($tableSchema->primaryKey) ? $tableSchema->primaryKey : reset($tableSchema->columns)->name;
foreach ($columns as $name) {
$names[] = $schema->quoteColumnName($name);
$placeholders[] = 'DEFAULT';
}
}
return 'INSERT INTO ' . $schema->quoteTableName($table)
. (!empty($names) ? ' (' . implode(', ', $names) . ')' : '')
. (!empty($placeholders) ? ' VALUES (' . implode(', ', $placeholders) . ')' : ' DEFAULT VALUES');
}
} }

View File

@@ -161,6 +161,45 @@ EOD;
return $sql; return $sql;
} }
/**
* @inheritdoc
*/
public function insert($table, $columns, &$params)
{
$schema = $this->db->getSchema();
if (($tableSchema = $schema->getTableSchema($table)) !== null) {
$columnSchemas = $tableSchema->columns;
} else {
$columnSchemas = [];
}
$names = [];
$placeholders = [];
foreach ($columns as $name => $value) {
$names[] = $schema->quoteColumnName($name);
if ($value instanceof Expression) {
$placeholders[] = $value->expression;
foreach ($value->params as $n => $v) {
$params[$n] = $v;
}
} else {
$phName = self::PARAM_PREFIX . count($params);
$placeholders[] = $phName;
$params[$phName] = !is_array($value) && isset($columnSchemas[$name]) ? $columnSchemas[$name]->dbTypecast($value) : $value;
}
}
if (empty($names) && $tableSchema !== null) {
$columns = !empty($tableSchema->primaryKey) ? $tableSchema->primaryKey : reset($tableSchema->columns)->name;
foreach ($columns as $name) {
$names[] = $schema->quoteColumnName($name);
$placeholders[] = 'DEFAULT';
}
}
return 'INSERT INTO ' . $schema->quoteTableName($table)
. (!empty($names) ? ' (' . implode(', ', $names) . ')' : '')
. (!empty($placeholders) ? ' VALUES (' . implode(', ', $placeholders) . ')' : ' DEFAULT VALUES');
}
/** /**
* Generates a batch INSERT SQL statement. * Generates a batch INSERT SQL statement.
* For example, * For example,

View File

@@ -29,6 +29,7 @@ BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "category_SEQ"'; EXCEPTION WHEN OTHERS TH
BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "item_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;-- BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "item_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;--
BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "order_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;-- BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "order_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;--
BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "order_with_null_fk_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;-- BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "order_with_null_fk_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;--
BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "null_values_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;--
BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "bool_values_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;-- BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "bool_values_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;--
BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "animal_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;-- BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "animal_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;--
@@ -127,6 +128,7 @@ CREATE TABLE "null_values" (
"stringcol" varchar2(32) DEFAULT NULL, "stringcol" varchar2(32) DEFAULT NULL,
CONSTRAINT "null_values_PK" PRIMARY KEY ("id") ENABLE CONSTRAINT "null_values_PK" PRIMARY KEY ("id") ENABLE
); );
CREATE SEQUENCE "null_values_SEQ";
CREATE TABLE "type" ( CREATE TABLE "type" (
"int_col" integer NOT NULL, "int_col" integer NOT NULL,
@@ -220,6 +222,11 @@ CREATE TRIGGER "order_with_null_fk_TRG" BEFORE INSERT ON "order_with_null_fk" FO
END COLUMN_SEQUENCES; END COLUMN_SEQUENCES;
END; END;
/ /
CREATE TRIGGER "null_values_TRG" BEFORE INSERT ON "null_values" FOR EACH ROW BEGIN <<COLUMN_SEQUENCES>> BEGIN
IF INSERTING AND :NEW."id" IS NULL THEN SELECT "null_values_SEQ".NEXTVAL INTO :NEW."id" FROM SYS.DUAL; END IF;
END COLUMN_SEQUENCES;
END;
/
CREATE TRIGGER "bool_values_TRG" BEFORE INSERT ON "bool_values" FOR EACH ROW BEGIN <<COLUMN_SEQUENCES>> BEGIN CREATE TRIGGER "bool_values_TRG" BEFORE INSERT ON "bool_values" FOR EACH ROW BEGIN <<COLUMN_SEQUENCES>> BEGIN
IF INSERTING AND :NEW."id" IS NULL THEN SELECT "bool_values_SEQ".NEXTVAL INTO :NEW."id" FROM SYS.DUAL; END IF; IF INSERTING AND :NEW."id" IS NULL THEN SELECT "bool_values_SEQ".NEXTVAL INTO :NEW."id" FROM SYS.DUAL; END IF;
END COLUMN_SEQUENCES; END COLUMN_SEQUENCES;

View File

@@ -103,7 +103,7 @@ CREATE TABLE "composite_fk" (
); );
CREATE TABLE "null_values" ( CREATE TABLE "null_values" (
id INT NOT NULL, id serial NOT NULL,
var1 INT NULL, var1 INT NULL,
var2 INT NULL, var2 INT NULL,
var3 INT DEFAULT NULL, var3 INT DEFAULT NULL,

View File

@@ -87,7 +87,7 @@ CREATE TABLE "composite_fk" (
); );
CREATE TABLE "null_values" ( CREATE TABLE "null_values" (
id INTEGER UNSIGNED PRIMARY KEY NOT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
var1 INTEGER UNSIGNED, var1 INTEGER UNSIGNED,
var2 INTEGER, var2 INTEGER,
var3 INTEGER DEFAULT NULL, var3 INTEGER DEFAULT NULL,

View File

@@ -699,4 +699,11 @@ class ActiveRecordTest extends DatabaseTestCase
$animal = Animal::find()->where(['type' => Cat::className()])->one(); $animal = Animal::find()->where(['type' => Cat::className()])->one();
$this->assertEquals('meow', $animal->getDoes()); $this->assertEquals('meow', $animal->getDoes());
} }
public function testSaveEmpty()
{
$record = new NullValues;
$this->assertTrue($record->save(false));
$this->assertEquals(1, $record->id);
}
} }