Skip to content

Commit

Permalink
Merge pull request #1281 from markstory/3.0-sqlite-create
Browse files Browse the repository at this point in the history
3.0 sqlite create table
  • Loading branch information
markstory committed May 17, 2013
2 parents ad25d26 + 3f6e294 commit 4b2ecb9
Show file tree
Hide file tree
Showing 7 changed files with 505 additions and 155 deletions.
28 changes: 28 additions & 0 deletions lib/Cake/Database/Driver.php
Expand Up @@ -135,6 +135,34 @@ public function supportsQuoting() {
return true;
}

/**
* Escapes values for use in schema definitions.
*
* @param mixed $value The value to escape.
* @return string String for use in schema definitions.
*/
public function schemaValue($value) {
if (is_null($value)) {
return 'NULL';
}
if ($value === false) {
return 'FALSE';
}
if ($value === true) {
return 'TRUE';
}
if (is_float($value)) {
return str_replace(',', '.', strval($value));
}
if ((is_int($value) || $value === '0') || (
is_numeric($value) && strpos($value, ',') === false &&
$value[0] != '0' && strpos($value, 'e') === false)
) {
return $value;
}
return $this->_connection->quote($value, \PDO::PARAM_STR);
}

/**
* Returns last id generated for a table or sequence in database
*
Expand Down
32 changes: 2 additions & 30 deletions lib/Cake/Database/Schema/MysqlSchema.php
Expand Up @@ -240,7 +240,7 @@ public function columnSql(Table $table, $name) {
unset($data['default']);
}
if (isset($data['default']) && $data['type'] !== 'timestamp') {
$out .= ' DEFAULT ' . $this->_value($data['default']);
$out .= ' DEFAULT ' . $this->_driver->schemaValue($data['default']);
}
if (
isset($data['default']) &&
Expand All @@ -250,39 +250,11 @@ public function columnSql(Table $table, $name) {
$out .= ' DEFAULT CURRENT_TIMESTAMP';
}
if (isset($data['comment'])) {
$out .= ' COMMENT ' . $this->_value($data['comment']);
$out .= ' COMMENT ' . $this->_driver->schemaValue($data['comment']);
}
return $out;
}

/**
* Escapes values for use in schema definitions.
*
* @param mixed $value The value to escape.
* @return string String for use in schema definitions.
*/
protected function _value($value) {
if (is_null($value)) {
return 'NULL';
}
if ($value === false) {
return 'FALSE';
}
if ($value === true) {
return 'TRUE';
}
if (is_float($value)) {
return str_replace(',', '.', strval($value));
}
if ((is_int($value) || $value === '0') || (
is_numeric($value) && strpos($value, ',') === false &&
$value[0] != '0' && strpos($value, 'e') === false)
) {
return $value;
}
return $this->_driver->quote($value, \PDO::PARAM_STR);
}

/**
* Generate the SQL fragment for a single index in MySQL
*
Expand Down
103 changes: 103 additions & 0 deletions lib/Cake/Database/Schema/SqliteSchema.php
Expand Up @@ -139,4 +139,107 @@ public function convertFieldDescription(Table $table, $row, $fieldParams = []) {
}
}

/**
* Generate the SQL fragment for a single column in Sqlite
*
* @param Cake\Database\Schema\Table $table The table object the column is in.
* @param string $name The name of the column.
* @return string SQL fragment.
*/
public function columnSql(Table $table, $name) {
$data = $table->column($name);
$typeMap = [
'string' => ' VARCHAR',
'integer' => ' INTEGER',
'biginteger' => ' BIGINT',
'boolean' => ' BOOLEAN',
'binary' => ' BLOB',
'float' => ' FLOAT',
'decimal' => ' DECIMAL',
'text' => ' TEXT',
'date' => ' DATE',
'time' => ' TIME',
'datetime' => ' DATETIME',
'timestamp' => ' TIMESTAMP',
];
if (!isset($typeMap[$data['type']])) {
throw new Error\Exception(__d('cake_dev', 'Unknown column type "%s"', $data['type']));
}

$out = $this->_driver->quoteIdentifier($name);
$out .= $typeMap[$data['type']];

$hasLength = ['integer', 'string'];
if (in_array($data['type'], $hasLength, true) && isset($data['length'])) {
$out .= '(' . (int)$data['length'] . ')';
}
$hasPrecision = ['float', 'decimal'];
if (
in_array($data['type'], $hasPrecision, true) &&
(isset($data['length']) || isset($data['precision']))
) {
$out .= '(' . (int)$data['length'] . ',' . (int)$data['precision'] . ')';
}
if (isset($data['null']) && $data['null'] === false) {
$out .= ' NOT NULL';
}
if ($data['type'] === 'integer' && $name == $table->primaryKey()[0]) {
$out .= ' PRIMARY KEY AUTOINCREMENT';
}
if (isset($data['null']) && $data['null'] === true) {
$out .= ' DEFAULT NULL';
unset($data['default']);
}
if (isset($data['default'])) {
$out .= ' DEFAULT ' . $this->_driver->schemaValue($data['default']);
}
return $out;
}

/**
* Generate the SQL fragment for a single index in MySQL
*
* Note integer primary keys will return ''. This is intentional as Sqlite requires
* that integer primary keys be defined in the column definition.
*
* @param Cake\Database\Schema\Table $table The table object the column is in.
* @param string $name The name of the column.
* @return string SQL fragment.
*/
public function indexSql(Table $table, $name) {
$data = $table->index($name);

if (
count($data['columns']) === 1 &&
$table->column($data['columns'][0])['type'] === 'integer'
) {
return '';
}

$out = 'CONSTRAINT ';
$out .= $this->_driver->quoteIdentifier($name);
if ($data['type'] === Table::INDEX_PRIMARY) {
$out .= ' PRIMARY KEY';
}
if ($data['type'] === Table::INDEX_UNIQUE) {
$out .= ' UNIQUE';
}
$columns = array_map(
[$this->_driver, 'quoteIdentifier'],
$data['columns']
);
return $out . ' (' . implode(', ', $columns) . ')';
}

/**
* Generate the SQL to create a table.
*
* @param string $table The name of the table.
* @param array $lines The lines (columns + indexes) to go inside the table.
* @return string A complete CREATE TABLE statement
*/
public function createTableSql($table, $lines) {
$content = implode(",\n", array_filter($lines));
return sprintf("CREATE TABLE \"%s\" (\n%s\n);", $table, $content);
}
}
37 changes: 37 additions & 0 deletions lib/Cake/Test/TestCase/Database/Driver/SqliteTest.php
Expand Up @@ -95,4 +95,41 @@ public function testConnectionConfigCustom() {
$driver->connect($config);
}

/**
* Data provider for schemaValue()
*
* @return array
*/
public static function schemaValueProvider() {
return [
[null, 'NULL'],
[false, 'FALSE'],
[true, 'TRUE'],
[3.14159, '3.14159'],
['33', '33'],
[66, 66],
[0, 0],
[10e5, '1000000'],
['farts', '"farts"'],
];
}

/**
* Test the schemaValue method on Driver.
*
* @dataProvider schemaValueProvider
* @return void
*/
public function testSchemaValue($input, $expected) {
$driver = new Sqlite();
$mock = $this->getMock('FakePdo', ['quote', 'quoteIdentifier']);
$mock->expects($this->any())
->method('quote')
->will($this->returnCallback(function ($value) {
return '"' . $value . '"';
}));
$driver->connection($mock);
$this->assertEquals($expected, $driver->schemaValue($input));
}

}

0 comments on commit 4b2ecb9

Please sign in to comment.