Skip to content

Commit 40d9dbe

Browse files
committed
update
1 parent 94b2056 commit 40d9dbe

File tree

1 file changed

+155
-22
lines changed

1 file changed

+155
-22
lines changed

api.php

Lines changed: 155 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4838,9 +4838,14 @@ public function getOffsetLimit(int $offset, int $limit): string
48384838
return '';
48394839
}
48404840
switch ($this->driver) {
4841-
case 'mysql':return " LIMIT $offset, $limit";
4842-
case 'pgsql':return " LIMIT $limit OFFSET $offset";
4843-
case 'sqlsrv':return " OFFSET $offset ROWS FETCH NEXT $limit ROWS ONLY";
4841+
case 'mysql':
4842+
return " LIMIT $offset, $limit";
4843+
case 'pgsql':
4844+
return " LIMIT $limit OFFSET $offset";
4845+
case 'sqlsrv':
4846+
return " OFFSET $offset ROWS FETCH NEXT $limit ROWS ONLY";
4847+
case 'sqlite':
4848+
return " LIMIT $limit OFFSET $offset";
48444849
}
48454850
}
48464851

@@ -4890,9 +4895,14 @@ public function getInsert(ReflectedTable $table, array $columnValues): string
48904895
$valuesSql = '(' . implode(',', $values) . ')';
48914896
$outputColumn = $this->quoteColumnName($table->getPk());
48924897
switch ($this->driver) {
4893-
case 'mysql':return "$columnsSql VALUES $valuesSql";
4894-
case 'pgsql':return "$columnsSql VALUES $valuesSql RETURNING $outputColumn";
4895-
case 'sqlsrv':return "$columnsSql OUTPUT INSERTED.$outputColumn VALUES $valuesSql";
4898+
case 'mysql':
4899+
return "$columnsSql VALUES $valuesSql";
4900+
case 'pgsql':
4901+
return "$columnsSql VALUES $valuesSql RETURNING $outputColumn";
4902+
case 'sqlsrv':
4903+
return "$columnsSql OUTPUT INSERTED.$outputColumn VALUES $valuesSql";
4904+
case 'sqlite':
4905+
return "$columnsSql VALUES $valuesSql";
48964906
}
48974907
}
48984908

@@ -5072,17 +5082,28 @@ private function getColumnConditionSql(ColumnCondition $condition, array &$argum
50725082
private function getSpatialFunctionName(string $operator): string
50735083
{
50745084
switch ($operator) {
5075-
case 'co':return 'ST_Contains';
5076-
case 'cr':return 'ST_Crosses';
5077-
case 'di':return 'ST_Disjoint';
5078-
case 'eq':return 'ST_Equals';
5079-
case 'in':return 'ST_Intersects';
5080-
case 'ov':return 'ST_Overlaps';
5081-
case 'to':return 'ST_Touches';
5082-
case 'wi':return 'ST_Within';
5083-
case 'ic':return 'ST_IsClosed';
5084-
case 'is':return 'ST_IsSimple';
5085-
case 'iv':return 'ST_IsValid';
5085+
case 'co':
5086+
return 'ST_Contains';
5087+
case 'cr':
5088+
return 'ST_Crosses';
5089+
case 'di':
5090+
return 'ST_Disjoint';
5091+
case 'eq':
5092+
return 'ST_Equals';
5093+
case 'in':
5094+
return 'ST_Intersects';
5095+
case 'ov':
5096+
return 'ST_Overlaps';
5097+
case 'to':
5098+
return 'ST_Touches';
5099+
case 'wi':
5100+
return 'ST_Within';
5101+
case 'ic':
5102+
return 'ST_IsClosed';
5103+
case 'is':
5104+
return 'ST_IsSimple';
5105+
case 'iv':
5106+
return 'ST_IsValid';
50865107
}
50875108
}
50885109

@@ -5102,6 +5123,9 @@ private function getSpatialFunctionCall(string $functionName, string $column, bo
51025123
$functionName = str_replace('ST_', 'ST', $functionName);
51035124
$argument = $hasArgument ? 'geometry::STGeomFromText(?,0)' : '';
51045125
return "$column.$functionName($argument)=1";
5126+
case 'sqlite':
5127+
$argument = $hasArgument ? '?' : '0';
5128+
return "$functionName($column, $argument)=1";
51055129
}
51065130
}
51075131

@@ -5157,10 +5181,10 @@ private function convertRecordValue($conversion, $value)
51575181

51585182
private function getRecordValueConversion(ReflectedColumn $column): string
51595183
{
5160-
if (in_array($this->driver, ['mysql', 'sqlsrv']) && $column->isBoolean()) {
5184+
if (in_array($this->driver, ['mysql', 'sqlsrv', 'sqlite']) && $column->isBoolean()) {
51615185
return 'boolean';
51625186
}
5163-
if ($this->driver == 'sqlsrv' && $column->getType() == 'bigint') {
5187+
if (in_array($this->driver, ['sqlsrv', 'sqlite']) && in_array($column->getType(), ['integer', 'bigint'])) {
51645188
return 'integer';
51655189
}
51665190
return 'none';
@@ -5255,6 +5279,8 @@ private function getDsn(): string
52555279
return "$this->driver:host=$this->address port=$this->port dbname=$this->database options='--client_encoding=UTF8'";
52565280
case 'sqlsrv':
52575281
return "$this->driver:Server=$this->address,$this->port;Database=$this->database";
5282+
case 'sqlite':
5283+
return "$this->driver:$this->address";
52585284
}
52595285
}
52605286

@@ -5273,6 +5299,10 @@ private function getCommands(): array
52735299
];
52745300
case 'sqlsrv':
52755301
return [];
5302+
case 'sqlite':
5303+
return [
5304+
'PRAGMA foreign_keys = on;',
5305+
];
52765306
}
52775307
}
52785308

@@ -5299,6 +5329,8 @@ private function getOptions(): array
52995329
\PDO::SQLSRV_ATTR_DIRECT_QUERY => false,
53005330
\PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE => true,
53015331
];
5332+
case 'sqlite':
5333+
return $options + [];
53025334
}
53035335
}
53045336

@@ -5406,11 +5438,17 @@ public function createSingle(ReflectedTable $table, array $columnValues) /*: ?St
54065438
case 'mysql':
54075439
$stmt = $this->query('SELECT LAST_INSERT_ID()', []);
54085440
break;
5441+
case 'sqlite':
5442+
$stmt = $this->query('SELECT LAST_INSERT_ROWID()', []);
5443+
break;
54095444
}
54105445
$pkValue = $stmt->fetchColumn(0);
54115446
if ($this->driver == 'sqlsrv' && $table->getPk()->getType() == 'bigint') {
54125447
return (int) $pkValue;
54135448
}
5449+
if ($this->driver == 'sqlite' && in_array($table->getPk()->getType(), ['integer', 'bigint'])) {
5450+
return (int) $pkValue;
5451+
}
54145452
return $pkValue;
54155453
}
54165454

@@ -5996,6 +6034,51 @@ public function __construct(LazyPdo $pdo, string $driver, string $database, arra
59966034
$this->typeConverter = new TypeConverter($driver);
59976035
}
59986036

6037+
private function createSqlLiteReflectionTables() /*: void */
6038+
{
6039+
$reflection = $this->query('SELECT "name" FROM "sqlite_master" WHERE "type" = \'table\' and name like \'sys/%\';', []);
6040+
if (count($reflection) == 0) {
6041+
//create reflection tables
6042+
$this->query('CREATE table "sys/version" ("version" integer);', []);
6043+
$this->query('CREATE table "sys/tables" ("name" text, "type" text);', []);
6044+
$this->query('CREATE table "sys/columns" ("self" text,"cid" integer,"name" text,"type" integer,"notnull" integer,"dflt_value" integer,"pk" integer);', []);
6045+
$this->query('CREATE table "sys/foreign_keys" ("self" text,"id" integer,"seq" integer,"table" text,"from" text,"to" text,"on_update" text,"on_delete" text,"match" text);', []);
6046+
}
6047+
$version = $this->query('pragma schema_version;', [])[0]["schema_version"];
6048+
$current = $this->query('SELECT "version" from "sys/version";', []);
6049+
if (!$current || count($current) == 0 || !isset($current[0]["schema_version"]) || $version != $current[0]["schema_version"]) {
6050+
// reflection may take a while
6051+
set_time_limit(3600);
6052+
// update version data
6053+
$this->query('DELETE FROM "sys/version";', []);
6054+
$this->query('INSERT into "sys/version" ("version") VALUES (?);', [$version]);
6055+
6056+
// update tables data
6057+
$this->query('DELETE FROM "sys/tables";', []);
6058+
$result = $this->query('SELECT "name", "type" FROM sqlite_master WHERE ("type" = \'table\' or "type" = \'view\') and name not like "sys/%" and name<>"sqlite_sequence";', []);
6059+
$tables = array();
6060+
foreach ($result as $row) {
6061+
$tables[] = $row['name'];
6062+
$this->query('INSERT into "sys/tables" ("name", "type") VALUES (?, ?);', [$row['name'], $row['type']]);
6063+
}
6064+
// update columns and foreign_keys data
6065+
$this->query('DELETE FROM "sys/columns";', []);
6066+
$this->query('DELETE FROM "sys/foreign_keys";', []);
6067+
foreach ($tables as $table) {
6068+
$result = $this->query("pragma table_info(`$table`);", []);
6069+
foreach ($result as $row) {
6070+
array_unshift($row, $table);
6071+
$this->query('INSERT into "sys/columns" ("self","cid","name","type","notnull","dflt_value","pk") VALUES (?,?,?,?,?,?,?);', array_values($row));
6072+
}
6073+
$result = $this->query("pragma foreign_key_list(`$table`);", []);
6074+
foreach ($result as $row) {
6075+
array_unshift($row, $table);
6076+
$this->query('INSERT into "sys/foreign_keys" ("self","id","seq","table","from","to","on_update","on_delete","match") VALUES (?,?,?,?,?,?,?,?,?);', array_values($row));
6077+
}
6078+
}
6079+
}
6080+
}
6081+
59996082
public function getIgnoredTables(): array
60006083
{
60016084
switch ($this->driver) {
@@ -6005,6 +6088,8 @@ public function getIgnoredTables(): array
60056088
return ['spatial_ref_sys', 'raster_columns', 'raster_overviews', 'geography_columns', 'geometry_columns'];
60066089
case 'sqlsrv':
60076090
return [];
6091+
case 'sqlite':
6092+
return ['sys/version', 'sys/tables', 'sys/columns', 'sys/foreign_keys'];
60086093
}
60096094
}
60106095

@@ -6017,6 +6102,9 @@ private function getTablesSQL(): string
60176102
return 'SELECT c.relname as "TABLE_NAME", c.relkind as "TABLE_TYPE" FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind IN (\'r\', \'v\') AND n.nspname <> \'pg_catalog\' AND n.nspname <> \'information_schema\' AND n.nspname !~ \'^pg_toast\' AND pg_catalog.pg_table_is_visible(c.oid) AND \'\' <> ? ORDER BY "TABLE_NAME";';
60186103
case 'sqlsrv':
60196104
return 'SELECT o.name as "TABLE_NAME", o.xtype as "TABLE_TYPE" FROM sysobjects o WHERE o.xtype IN (\'U\', \'V\') ORDER BY "TABLE_NAME"';
6105+
case 'sqlite':
6106+
$this->createSqlLiteReflectionTables();
6107+
return 'SELECT t.name as "TABLE_NAME", t.type as "TABLE_TYPE" FROM "sys/tables" t WHERE t.type IN (\'table\', \'view\') AND \'\' <> ? ORDER BY "TABLE_NAME"';
60206108
}
60216109
}
60226110

@@ -6029,6 +6117,8 @@ private function getTableColumnsSQL(): string
60296117
return 'SELECT a.attname AS "COLUMN_NAME", case when a.attnotnull then \'NO\' else \'YES\' end as "IS_NULLABLE", pg_catalog.format_type(a.atttypid, -1) as "DATA_TYPE", case when a.atttypmod < 0 then NULL else a.atttypmod-4 end as "CHARACTER_MAXIMUM_LENGTH", case when a.atttypid != 1700 then NULL else ((a.atttypmod - 4) >> 16) & 65535 end as "NUMERIC_PRECISION", case when a.atttypid != 1700 then NULL else (a.atttypmod - 4) & 65535 end as "NUMERIC_SCALE", \'\' AS "COLUMN_TYPE" FROM pg_attribute a JOIN pg_class pgc ON pgc.oid = a.attrelid WHERE pgc.relname = ? AND \'\' <> ? AND a.attnum > 0 AND NOT a.attisdropped;';
60306118
case 'sqlsrv':
60316119
return 'SELECT c.name AS "COLUMN_NAME", c.is_nullable AS "IS_NULLABLE", t.Name AS "DATA_TYPE", (c.max_length/2) AS "CHARACTER_MAXIMUM_LENGTH", c.precision AS "NUMERIC_PRECISION", c.scale AS "NUMERIC_SCALE", \'\' AS "COLUMN_TYPE" FROM sys.columns c INNER JOIN sys.types t ON c.user_type_id = t.user_type_id WHERE c.object_id = OBJECT_ID(?) AND \'\' <> ?';
6120+
case 'sqlite':
6121+
return 'SELECT "name" AS "COLUMN_NAME", case when "notnull"==1 then \'no\' else \'yes\' end as "IS_NULLABLE", "type" AS "DATA_TYPE", 2147483647 AS "CHARACTER_MAXIMUM_LENGTH", 0 AS "NUMERIC_PRECISION", 0 AS "NUMERIC_SCALE", \'\' AS "COLUMN_TYPE" FROM "sys/columns" WHERE "self" = ? AND \'\' <> ?';
60326122
}
60336123
}
60346124

@@ -6041,6 +6131,8 @@ private function getTablePrimaryKeysSQL(): string
60416131
return 'SELECT a.attname AS "COLUMN_NAME" FROM pg_attribute a JOIN pg_constraint c ON (c.conrelid, c.conkey[1]) = (a.attrelid, a.attnum) JOIN pg_class pgc ON pgc.oid = a.attrelid WHERE pgc.relname = ? AND \'\' <> ? AND c.contype = \'p\'';
60426132
case 'sqlsrv':
60436133
return 'SELECT c.NAME as "COLUMN_NAME" FROM sys.key_constraints kc inner join sys.objects t on t.object_id = kc.parent_object_id INNER JOIN sys.index_columns ic ON kc.parent_object_id = ic.object_id and kc.unique_index_id = ic.index_id INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id WHERE kc.type = \'PK\' and t.object_id = OBJECT_ID(?) and \'\' <> ?';
6134+
case 'sqlite':
6135+
return 'SELECT "name" as "COLUMN_NAME" FROM "sys/columns" WHERE "pk"=1 AND "self"=? AND \'\' <> ?';
60446136
}
60456137
}
60466138

@@ -6053,6 +6145,8 @@ private function getTableForeignKeysSQL(): string
60536145
return 'SELECT a.attname AS "COLUMN_NAME", c.confrelid::regclass::text AS "REFERENCED_TABLE_NAME" FROM pg_attribute a JOIN pg_constraint c ON (c.conrelid, c.conkey[1]) = (a.attrelid, a.attnum) JOIN pg_class pgc ON pgc.oid = a.attrelid WHERE pgc.relname = ? AND \'\' <> ? AND c.contype = \'f\'';
60546146
case 'sqlsrv':
60556147
return 'SELECT COL_NAME(fc.parent_object_id, fc.parent_column_id) AS "COLUMN_NAME", OBJECT_NAME (f.referenced_object_id) AS "REFERENCED_TABLE_NAME" FROM sys.foreign_keys AS f INNER JOIN sys.foreign_key_columns AS fc ON f.OBJECT_ID = fc.constraint_object_id WHERE f.parent_object_id = OBJECT_ID(?) and \'\' <> ?';
6148+
case 'sqlite':
6149+
return 'SELECT "from" AS "COLUMN_NAME", "table" AS "REFERENCED_TABLE_NAME" FROM "sys/foreign_keys" WHERE "self" = ? AND \'\' <> ?';
60566150
}
60576151
}
60586152

@@ -6070,20 +6164,22 @@ public function getTables(): array
60706164
return !$tables || in_array($v['TABLE_NAME'], $tables);
60716165
});
60726166
foreach ($results as &$result) {
6167+
$map = [];
60736168
switch ($this->driver) {
60746169
case 'mysql':
60756170
$map = ['BASE TABLE' => 'table', 'VIEW' => 'view'];
6076-
$result['TABLE_TYPE'] = $map[$result['TABLE_TYPE']];
60776171
break;
60786172
case 'pgsql':
60796173
$map = ['r' => 'table', 'v' => 'view'];
6080-
$result['TABLE_TYPE'] = $map[$result['TABLE_TYPE']];
60816174
break;
60826175
case 'sqlsrv':
60836176
$map = ['U' => 'table', 'V' => 'view'];
6084-
$result['TABLE_TYPE'] = $map[trim($result['TABLE_TYPE'])];
6177+
break;
6178+
case 'sqlite':
6179+
$map = ['table' => 'table', 'view' => 'view'];
60856180
break;
60866181
}
6182+
$result['TABLE_TYPE'] = $map[trim($result['TABLE_TYPE'])];
60876183
}
60886184
return $results;
60896185
}
@@ -6112,6 +6208,23 @@ public function getTableColumns(string $tableName, string $type): array
61126208
}
61136209
}
61146210
}
6211+
if ($this->driver == 'sqlite') {
6212+
foreach ($results as &$result) {
6213+
// mysql does not properly reflect display width of types
6214+
preg_match('|([a-z]+)(\(([0-9]+)(,([0-9]+))?\))?|', $result['DATA_TYPE'], $matches);
6215+
if (isset($matches[1])) {
6216+
$result['DATA_TYPE'] = $matches[1];
6217+
} else {
6218+
$result['DATA_TYPE'] = 'integer';
6219+
}
6220+
if (isset($matches[5])) {
6221+
$result['NUMERIC_PRECISION'] = $matches[3];
6222+
$result['NUMERIC_SCALE'] = $matches[5];
6223+
} else if (isset($matches[3])) {
6224+
$result['CHARACTER_MAXIMUM_LENGTH'] = $matches[3];
6225+
}
6226+
}
6227+
}
61156228
return $results;
61166229
}
61176230

@@ -6399,6 +6512,20 @@ public function __construct(string $driver)
63996512
'uniqueidentifier' => 'char',
64006513
'xml' => 'clob',
64016514
],
6515+
'sqlite' => [
6516+
'tinytext' => 'clob',
6517+
'text' => 'clob',
6518+
'mediumtext' => 'clob',
6519+
'longtext' => 'clob',
6520+
'mediumint' => 'integer',
6521+
'int' => 'integer',
6522+
'bigint' => 'bigint',
6523+
'int2' => 'smallint',
6524+
'int4' => 'integer',
6525+
'int8' => 'bigint',
6526+
'double precision' => 'double',
6527+
'datetime' => 'timestamp'
6528+
],
64026529
];
64036530

64046531
// source: https://docs.oracle.com/javase/9/docs/api/java/sql/Types.html
@@ -6964,6 +7091,8 @@ public function handle(ServerRequestInterface $request): ResponseInterface
69647091
} catch (\PDOException $e) {
69657092
if (strpos(strtolower($e->getMessage()), 'duplicate') !== false) {
69667093
$response = $this->responder->error(ErrorCode::DUPLICATE_KEY_EXCEPTION, '');
7094+
} elseif (strpos(strtolower($e->getMessage()), 'unique constraint') !== false) {
7095+
$response = $this->responder->error(ErrorCode::DUPLICATE_KEY_EXCEPTION, '');
69677096
} elseif (strpos(strtolower($e->getMessage()), 'default value') !== false) {
69687097
$response = $this->responder->error(ErrorCode::DATA_INTEGRITY_VIOLATION, '');
69697098
} elseif (strpos(strtolower($e->getMessage()), 'allow nulls') !== false) {
@@ -10269,6 +10398,8 @@ private function getDefaultPort(string $driver): int
1026910398
return 5432;
1027010399
case 'sqlsrv':
1027110400
return 1433;
10401+
case 'sqlite':
10402+
return 0;
1027210403
}
1027310404
}
1027410405

@@ -10281,6 +10412,8 @@ private function getDefaultAddress(string $driver): string
1028110412
return 'localhost';
1028210413
case 'sqlsrv':
1028310414
return 'localhost';
10415+
case 'sqlite':
10416+
return 'data.db';
1028410417
}
1028510418
}
1028610419

0 commit comments

Comments
 (0)