Version 3 #1
2
.gitignore
vendored
2
.gitignore
vendored
@ -130,7 +130,7 @@ $RECYCLE.BIN/
|
||||
|
||||
test_config.json
|
||||
index.html
|
||||
tests/db_files/*
|
||||
tests/db_files/*.db
|
||||
build/api/*
|
||||
build/coverage/*
|
||||
build/logs/*
|
||||
|
@ -15,7 +15,6 @@
|
||||
namespace Query;
|
||||
|
||||
use DomainException;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Connection manager class to manage connections for the
|
||||
@ -97,7 +96,7 @@ final class ConnectionManager {
|
||||
*
|
||||
* @param string|array|object $name
|
||||
* @return QueryBuilderInterface
|
||||
* @throws InvalidArgumentException
|
||||
* @throws Exception\NonExistentConnectionException
|
||||
*/
|
||||
public function getConnection($name = ''): QueryBuilderInterface
|
||||
{
|
||||
@ -112,14 +111,14 @@ final class ConnectionManager {
|
||||
}
|
||||
|
||||
// You should actually connect before trying to get a connection...
|
||||
throw new InvalidArgumentException('The specified connection does not exist');
|
||||
throw new Exception\NonExistentConnectionException('The specified connection does not exist');
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the passed parameters and return a connection
|
||||
*
|
||||
* @param object|array $params
|
||||
* @throws BadDBDriverException
|
||||
* @throws Exception\BadDBDriverException
|
||||
* @return QueryBuilderInterface
|
||||
*/
|
||||
public function connect($params): QueryBuilderInterface
|
||||
@ -162,7 +161,7 @@ final class ConnectionManager {
|
||||
*
|
||||
* @param \stdClass $params
|
||||
* @return object|array
|
||||
* @throws BadDBDriverException
|
||||
* @throws Exception\BadDBDriverException
|
||||
*/
|
||||
public function parseParams($params): array
|
||||
{
|
||||
@ -174,7 +173,7 @@ final class ConnectionManager {
|
||||
// Make sure the class exists
|
||||
if ( ! class_exists("\\Query\\Drivers\\{$dbtype}\\Driver"))
|
||||
{
|
||||
throw new BadDBDriverException('Database driver does not exist, or is not supported');
|
||||
throw new Exception\BadDBDriverException('Database driver does not exist, or is not supported');
|
||||
}
|
||||
|
||||
// Set additional PDO options
|
||||
|
@ -199,7 +199,7 @@ abstract class AbstractDriver
|
||||
* @return PDOStatement | FALSE
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function prepareQuery(string $sql, array $data): ?PDOStatement
|
||||
public function prepareQuery(string $sql, array $data): PDOStatement
|
||||
{
|
||||
// Prepare the sql, save the statement for easy access later
|
||||
$this->statement = $this->prepare($sql);
|
||||
@ -227,7 +227,7 @@ abstract class AbstractDriver
|
||||
* @throws InvalidArgumentException
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function prepareExecute(string $sql, array $params): ?PDOStatement
|
||||
public function prepareExecute(string $sql, array $params): PDOStatement
|
||||
{
|
||||
$this->statement = $this->prepareQuery($sql, $params);
|
||||
$this->statement->execute();
|
||||
@ -636,7 +636,7 @@ abstract class AbstractDriver
|
||||
* @param string $table
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function truncate(string $table): ?PDOStatement
|
||||
public function truncate(string $table): PDOStatement
|
||||
{
|
||||
$sql = $this->hasTruncate
|
||||
? 'TRUNCATE TABLE '
|
||||
|
@ -14,7 +14,6 @@
|
||||
*/
|
||||
namespace Query\Drivers;
|
||||
|
||||
use PDO;
|
||||
use PDOStatement;
|
||||
|
||||
/**
|
||||
@ -40,7 +39,7 @@ interface DriverInterface {
|
||||
* @return \PDOStatement|null
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function prepareQuery(string $sql, array $data): ?PDOStatement;
|
||||
public function prepareQuery(string $sql, array $data): PDOStatement;
|
||||
|
||||
/**
|
||||
* Retrieve column information for the current database table
|
||||
@ -162,7 +161,7 @@ interface DriverInterface {
|
||||
* @param array $params
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function prepareExecute(string $sql, array $params): ?PDOStatement;
|
||||
public function prepareExecute(string $sql, array $params): PDOStatement;
|
||||
|
||||
/**
|
||||
* Method to simplify retrieving db results for meta-data queries
|
||||
|
@ -67,7 +67,10 @@ class SQL extends AbstractSQL {
|
||||
*/
|
||||
public function dbList(): string
|
||||
{
|
||||
return "SHOW DATABASES WHERE `Database` NOT IN ('information_schema','mysql')";
|
||||
return <<<SQL
|
||||
SHOW DATABASES WHERE `Database` NOT IN ('information_schema','mysql')
|
||||
SQL;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -95,8 +98,10 @@ class SQL extends AbstractSQL {
|
||||
*/
|
||||
public function systemTableList(): string
|
||||
{
|
||||
return 'SELECT `TABLE_NAME` FROM `information_schema`.`TABLES`
|
||||
WHERE `TABLE_SCHEMA`=\'information_schema\'';
|
||||
return <<<SQL
|
||||
SELECT `TABLE_NAME` FROM `information_schema`.`TABLES`
|
||||
WHERE `TABLE_SCHEMA`='information_schema'
|
||||
SQL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -156,7 +161,7 @@ class SQL extends AbstractSQL {
|
||||
*/
|
||||
public function typeList(): string
|
||||
{
|
||||
return "SELECT DISTINCT `DATA_TYPE` FROM `information_schema`.`COLUMNS`";
|
||||
return 'SELECT DISTINCT `DATA_TYPE` FROM `information_schema`.`COLUMNS`';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -180,7 +185,8 @@ class SQL extends AbstractSQL {
|
||||
public function fkList(string $table): string
|
||||
{
|
||||
return <<<SQL
|
||||
SELECT DISTINCT `kcu`.`COLUMN_NAME` as `child_column`,
|
||||
SELECT DISTINCT
|
||||
`kcu`.`COLUMN_NAME` as `child_column`,
|
||||
`kcu`.`REFERENCED_TABLE_NAME` as `parent_table`,
|
||||
`kcu`.`REFERENCED_COLUMN_NAME` as `parent_column`,
|
||||
`rc`.`UPDATE_RULE` AS `update`,
|
||||
|
@ -15,6 +15,7 @@
|
||||
namespace Query\Drivers\Sqlite;
|
||||
|
||||
use Query\Drivers\AbstractSQL;
|
||||
use Query\Exception\NotImplementedException;
|
||||
|
||||
/**
|
||||
* SQLite Specific SQL
|
||||
@ -60,11 +61,13 @@ class SQL extends AbstractSQL {
|
||||
public function tableList(): string
|
||||
{
|
||||
return <<<SQL
|
||||
SELECT DISTINCT "name"
|
||||
FROM "sqlite_master"
|
||||
SELECT "name" FROM (
|
||||
SELECT * FROM "sqlite_master" UNION ALL
|
||||
SELECT * FROM "sqlite_temp_master"
|
||||
)
|
||||
WHERE "type"='table'
|
||||
AND "name" NOT LIKE 'sqlite_%'
|
||||
ORDER BY "name" DESC
|
||||
AND "name" NOT LIKE "sqlite_%"
|
||||
ORDER BY "name"
|
||||
SQL;
|
||||
}
|
||||
|
||||
@ -75,7 +78,11 @@ SQL;
|
||||
*/
|
||||
public function systemTableList(): array
|
||||
{
|
||||
return ['sqlite_master', 'sqlite_temp_master', 'sqlite_sequence'];
|
||||
return [
|
||||
'sqlite_master',
|
||||
'sqlite_temp_master',
|
||||
'sqlite_sequence'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -97,27 +104,31 @@ SQL;
|
||||
*/
|
||||
public function triggerList(): string
|
||||
{
|
||||
return 'SELECT "name" FROM "sqlite_master" WHERE "type"=\'trigger\'';
|
||||
return <<<SQL
|
||||
SELECT "name" FROM "sqlite_master" WHERE "type"='trigger'
|
||||
SQL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return sql to list functions
|
||||
*
|
||||
* @throws NotImplementedException
|
||||
* @return string
|
||||
*/
|
||||
public function functionList(): ?string
|
||||
public function functionList(): string
|
||||
{
|
||||
return NULL;
|
||||
throw new NotImplementedException('Functionality does not exist in SQLite');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return sql to list stored procedures
|
||||
*
|
||||
* @throws NotImplementedException
|
||||
* @return string
|
||||
*/
|
||||
public function procedureList(): ?string
|
||||
public function procedureList(): string
|
||||
{
|
||||
return NULL;
|
||||
throw new NotImplementedException('Functionality does not exist in SQLite');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -125,9 +136,9 @@ SQL;
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function sequenceList(): ?string
|
||||
public function sequenceList(): string
|
||||
{
|
||||
return NULL;
|
||||
return 'SELECT "name" FROM "sqlite_sequence"';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -137,7 +148,7 @@ SQL;
|
||||
*/
|
||||
public function typeList(): array
|
||||
{
|
||||
return ['INTEGER', 'REAL', 'TEXT', 'BLOB'];
|
||||
return ['INTEGER', 'REAL', 'TEXT', 'BLOB', 'NULL'];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -148,7 +159,9 @@ SQL;
|
||||
*/
|
||||
public function columnList(string $table): string
|
||||
{
|
||||
return 'PRAGMA table_info("' . $table . '")';
|
||||
return <<<SQL
|
||||
PRAGMA table_info("$table")
|
||||
SQL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -160,7 +173,9 @@ SQL;
|
||||
*/
|
||||
public function fkList(string $table): string
|
||||
{
|
||||
return 'PRAGMA foreign_key_list("' . $table . '")';
|
||||
return <<<SQL
|
||||
PRAGMA foreign_key_list("$table")
|
||||
SQL;
|
||||
}
|
||||
|
||||
|
||||
@ -172,6 +187,8 @@ SQL;
|
||||
*/
|
||||
public function indexList(string $table): string
|
||||
{
|
||||
return 'PRAGMA index_list("' . $table . '")';
|
||||
return <<<SQL
|
||||
PRAGMA index_list("$table")
|
||||
SQL;
|
||||
}
|
||||
}
|
@ -19,9 +19,6 @@ use Query\Drivers\AbstractUtil;
|
||||
|
||||
/**
|
||||
* SQLite-specific backup, import and creation methods
|
||||
*
|
||||
* @method mixed query(string $sql)
|
||||
* @method string quote(string $str)
|
||||
*/
|
||||
class Util extends AbstractUtil {
|
||||
|
||||
@ -78,7 +75,7 @@ class Util extends AbstractUtil {
|
||||
// Quote values as needed by type
|
||||
for($i=0, $icount=count($row); $i<$icount; $i++)
|
||||
{
|
||||
$row[$i] = (is_numeric($row[$i])) ? $row[$i] : $this->getDriver()->quote($row[$i]);
|
||||
$row[$i] = is_numeric($row[$i]) ? $row[$i] : $this->getDriver()->quote($row[$i]);
|
||||
}
|
||||
|
||||
$rowString = 'INSERT INTO "'.$r['name'].'" ("'.implode('","', $columns).'") VALUES ('.implode(',', $row).');';
|
||||
|
@ -12,7 +12,7 @@
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link https://git.timshomepage.net/aviat4ion/Query
|
||||
*/
|
||||
namespace Query;
|
||||
namespace Query\Exception;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
23
src/Exception/NonExistentConnectionException.php
Normal file
23
src/Exception/NonExistentConnectionException.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* Query
|
||||
*
|
||||
* SQL Query Builder / Database Abstraction Layer
|
||||
*
|
||||
* PHP version 7.1
|
||||
*
|
||||
* @package Query
|
||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||
* @copyright 2012 - 2018 Timothy J. Warren
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link https://git.timshomepage.net/aviat4ion/Query
|
||||
*/
|
||||
namespace Query\Exception;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Exception for missing database connection
|
||||
*/
|
||||
class NonExistentConnectionException extends InvalidArgumentException {
|
||||
}
|
23
src/Exception/NotImplementedException.php
Normal file
23
src/Exception/NotImplementedException.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* Query
|
||||
*
|
||||
* SQL Query Builder / Database Abstraction Layer
|
||||
*
|
||||
* PHP version 7.1
|
||||
*
|
||||
* @package Query
|
||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||
* @copyright 2012 - 2018 Timothy J. Warren
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link https://git.timshomepage.net/aviat4ion/Query
|
||||
*/
|
||||
namespace Query\Exception;
|
||||
|
||||
use BadMethodCallException;
|
||||
|
||||
/**
|
||||
* Exception for non-implemented method
|
||||
*/
|
||||
class NotImplementedException extends BadMethodCallException{
|
||||
}
|
@ -648,7 +648,7 @@ class QueryBuilder implements QueryBuilderInterface {
|
||||
* @param int|bool $offset
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function get(string $table='', $limit=FALSE, $offset=FALSE): ?PDOStatement
|
||||
public function get(string $table='', $limit=FALSE, $offset=FALSE): PDOStatement
|
||||
{
|
||||
// Set the table
|
||||
if ( ! empty($table))
|
||||
@ -674,7 +674,7 @@ class QueryBuilder implements QueryBuilderInterface {
|
||||
* @param int|bool $offset
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function getWhere(string $table, $where=[], $limit=FALSE, $offset=FALSE): ?PDOStatement
|
||||
public function getWhere(string $table, $where=[], $limit=FALSE, $offset=FALSE): PDOStatement
|
||||
{
|
||||
// Create the where clause
|
||||
$this->where($where);
|
||||
@ -725,7 +725,7 @@ class QueryBuilder implements QueryBuilderInterface {
|
||||
* @param mixed $data
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function insert(string $table, $data=[]): ?PDOStatement
|
||||
public function insert(string $table, $data=[]): PDOStatement
|
||||
{
|
||||
if ( ! empty($data))
|
||||
{
|
||||
@ -742,7 +742,7 @@ class QueryBuilder implements QueryBuilderInterface {
|
||||
* @param array $data
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function insertBatch(string $table, $data=[]): ?PDOStatement
|
||||
public function insertBatch(string $table, $data=[]): PDOStatement
|
||||
{
|
||||
// Get the generated values and sql string
|
||||
[$sql, $data] = $this->driver->insertBatch($table, $data);
|
||||
@ -799,7 +799,7 @@ class QueryBuilder implements QueryBuilderInterface {
|
||||
* @param array $data
|
||||
* @return \PDOStatement|null
|
||||
*/
|
||||
public function replace(string $table, $data=[]): ?PDOStatement
|
||||
public function replace(string $table, $data=[]): PDOStatement
|
||||
{
|
||||
if ( ! empty($data))
|
||||
{
|
||||
@ -816,7 +816,7 @@ class QueryBuilder implements QueryBuilderInterface {
|
||||
* @param mixed $where
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function delete(string $table, $where=''): ?PDOStatement
|
||||
public function delete(string $table, $where=''): PDOStatement
|
||||
{
|
||||
// Set the where clause
|
||||
if ( ! empty($where))
|
||||
@ -1167,7 +1167,7 @@ class QueryBuilder implements QueryBuilderInterface {
|
||||
* @param int $totalTime
|
||||
* @return void
|
||||
*/
|
||||
protected function _appendQuery(array $values = NULL, string $sql, int $totalTime)
|
||||
protected function _appendQuery(array $values = NULL, string $sql, int $totalTime): void
|
||||
{
|
||||
$evals = \is_array($values) ? $values : [];
|
||||
$esql = str_replace('?', "%s", $sql);
|
||||
|
@ -322,7 +322,7 @@ interface QueryBuilderInterface {
|
||||
* @param int|bool $offset
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function get(string $table='', $limit=FALSE, $offset=FALSE): ?PDOStatement;
|
||||
public function get(string $table='', $limit=FALSE, $offset=FALSE): PDOStatement;
|
||||
|
||||
/**
|
||||
* Convenience method for get() with a where clause
|
||||
@ -333,7 +333,7 @@ interface QueryBuilderInterface {
|
||||
* @param int|bool $offset
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function getWhere(string $table, $where=[], $limit=FALSE, $offset=FALSE): ?PDOStatement;
|
||||
public function getWhere(string $table, $where=[], $limit=FALSE, $offset=FALSE): PDOStatement;
|
||||
|
||||
/**
|
||||
* Retrieve the number of rows in the selected table
|
||||
@ -360,7 +360,7 @@ interface QueryBuilderInterface {
|
||||
* @param mixed $data
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function insert(string $table, $data=[]): ?PDOStatement;
|
||||
public function insert(string $table, $data=[]): PDOStatement;
|
||||
|
||||
/**
|
||||
* Creates and executes a batch insertion query
|
||||
@ -369,7 +369,7 @@ interface QueryBuilderInterface {
|
||||
* @param array $data
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function insertBatch(string $table, $data=[]): ?PDOStatement;
|
||||
public function insertBatch(string $table, $data=[]): PDOStatement;
|
||||
|
||||
/**
|
||||
* Insertion with automatic overwrite, rather than attempted duplication
|
||||
@ -378,7 +378,7 @@ interface QueryBuilderInterface {
|
||||
* @param array $data
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function replace(string $table, $data=[]): ?PDOStatement;
|
||||
public function replace(string $table, $data=[]): PDOStatement;
|
||||
|
||||
/**
|
||||
* Creates an update clause, and executes it
|
||||
@ -387,7 +387,7 @@ interface QueryBuilderInterface {
|
||||
* @param mixed $data
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function update(string $table, $data=[]): ?PDOStatement;
|
||||
public function update(string $table, $data=[]): PDOStatement;
|
||||
|
||||
/**
|
||||
* Creates a batch update, and executes it.
|
||||
@ -407,7 +407,7 @@ interface QueryBuilderInterface {
|
||||
* @param mixed $where
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function delete(string $table, $where=''): ?PDOStatement;
|
||||
public function delete(string $table, $where=''): PDOStatement;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// ! SQL Returning Methods
|
||||
|
@ -16,7 +16,7 @@ namespace Query\Tests;
|
||||
|
||||
use BadMethodCallException;
|
||||
use PDO;
|
||||
use Query\BadDBDriverException;
|
||||
use Query\Exception\BadDBDriverException;
|
||||
|
||||
/**
|
||||
* Query builder parent test class
|
||||
|
@ -16,6 +16,7 @@ namespace Query\Tests\Drivers\SQLite;
|
||||
|
||||
use PDO;
|
||||
use Query\Drivers\Sqlite\Driver;
|
||||
use Query\Exception\NotImplementedException;
|
||||
use Query\Tests\BaseDriverTest;
|
||||
|
||||
/**
|
||||
@ -83,7 +84,8 @@ SQL;
|
||||
{
|
||||
$sql = mb_trim(self::$db->getUtil()->backupStructure());
|
||||
$expected = <<<SQL
|
||||
CREATE TABLE "create_test" ("id" INTEGER PRIMARY KEY, "key" TEXT, "val" TEXT);
|
||||
CREATE TABLE "create_test" ("id" INTEGER PRIMARY KEY AUTOINCREMENT, "key" TEXT, "val" TEXT);
|
||||
CREATE TABLE sqlite_sequence(name,seq);
|
||||
CREATE TABLE "create_join" ("id" INTEGER PRIMARY KEY, "key" TEXT, "val" TEXT);
|
||||
CREATE TABLE "create_delete" ("id" INTEGER PRIMARY KEY, "key" TEXT, "val" TEXT);
|
||||
CREATE TABLE TEST1 (
|
||||
@ -250,7 +252,7 @@ SQL;
|
||||
|
||||
public function testGetDBs()
|
||||
{
|
||||
$this->assertTrue(is_array(self::$db->getDbs()));
|
||||
$this->assertTrue(\is_array(self::$db->getDbs()));
|
||||
}
|
||||
|
||||
public function testGetSchemas()
|
||||
@ -262,18 +264,6 @@ SQL;
|
||||
// ! SQL tests
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
public function testNullMethods()
|
||||
{
|
||||
$sql = self::$db->getSQL()->functionList();
|
||||
$this->assertEqual(NULL, $sql);
|
||||
|
||||
$sql = self::$db->getSQL()->procedureList();
|
||||
$this->assertEqual(NULL, $sql);
|
||||
|
||||
$sql = self::$db->getSQL()->sequenceList();
|
||||
$this->assertEqual(NULL, $sql);
|
||||
}
|
||||
|
||||
public function testGetSystemTables()
|
||||
{
|
||||
$sql = self::$db->getSystemTables();
|
||||
@ -282,16 +272,19 @@ SQL;
|
||||
|
||||
public function testGetSequences()
|
||||
{
|
||||
$this->assertNull(self::$db->getSequences());
|
||||
$sql = self::$db->getSequences();
|
||||
$this->assertEquals(['create_test'], $sql);
|
||||
}
|
||||
|
||||
public function testGetFunctions()
|
||||
{
|
||||
$this->assertNull(self::$db->getFunctions());
|
||||
$this->expectException(NotImplementedException::class);
|
||||
self::$db->getFunctions();
|
||||
}
|
||||
|
||||
public function testGetProcedures()
|
||||
{
|
||||
$this->assertNull(self::$db->getProcedures());
|
||||
$this->expectException(NotImplementedException::class);
|
||||
self::$db->getProcedures();
|
||||
}
|
||||
}
|
||||
|
0
tests/db_files/oci.sql
Normal file
0
tests/db_files/oci.sql
Normal file
@ -1,5 +1,5 @@
|
||||
-- sample data to test SQLite
|
||||
CREATE TABLE IF NOT EXISTS "create_test" ("id" INTEGER PRIMARY KEY, "key" TEXT, "val" TEXT);
|
||||
CREATE TABLE IF NOT EXISTS "create_test" ("id" INTEGER PRIMARY KEY AUTOINCREMENT, "key" TEXT, "val" TEXT);
|
||||
CREATE TABLE IF NOT EXISTS "create_join" ("id" INTEGER PRIMARY KEY, "key" TEXT, "val" TEXT);
|
||||
CREATE TABLE IF NOT EXISTS "create_delete" ("id" INTEGER PRIMARY KEY, "key" TEXT, "val" TEXT);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user