disconnect(); } /** * Alter database's character set. * * @param string $dbName The database name that will be altered * * @return boolean|resource * * @since 2.0.0 * @throws \RuntimeException */ public function alterDbCharacterSet($dbName) { return false; } /** * Connects to the database if needed. * * @return void Returns void if the database connected successfully. * * @since 2.0.0 * @throws RuntimeException */ public function connect() { if ($this->connection) { return; } parent::connect(); $this->connection->sqliteCreateFunction( 'ROW_NUMBER', function ($init = null) { static $rownum, $partition; if ($init !== null) { $rownum = $init; $partition = null; return $rownum; } $args = \func_get_args(); array_shift($args); $partitionBy = $args ? implode(',', $args) : null; if ($partitionBy === null || $partitionBy === $partition) { $rownum++; } else { $rownum = 1; $partition = $partitionBy; } return $rownum; } ); } /** * Create a new database using information from $options object. * * @param \stdClass $options Object used to pass user and database name to database driver. This object must have "db_name" and "db_user" set. * @param boolean $utf True if the database supports the UTF-8 character set. * * @return boolean|resource * * @since 2.0.0 * @throws \RuntimeException */ public function createDatabase($options, $utf = true) { // SQLite doesn't have a query for this return true; } /** * Method to escape a string for usage in an SQLite statement. * * Note: Using query objects with bound variables is preferable to the below. * * @param string $text The string to be escaped. * @param boolean $extra Unused optional parameter to provide extra escaping. * * @return string The escaped string. * * @since 1.0 */ public function escape($text, $extra = false) { if (\is_int($text)) { return $text; } if (\is_float($text)) { // Force the dot as a decimal point. return str_replace(',', '.', $text); } return \SQLite3::escapeString($text); } /** * Method to get the database collation in use by sampling a text field of a table in the database. * * @return string|boolean The collation in use by the database or boolean false if not supported. * * @since 1.0 */ public function getCollation() { return false; } /** * Method to get the database connection collation in use by sampling a text field of a table in the database. * * @return string|boolean The collation in use by the database connection (string) or boolean false if not supported. * * @since 1.6.0 * @throws \RuntimeException */ public function getConnectionCollation() { return false; } /** * Method to get the database encryption details (cipher and protocol) in use. * * @return string The database encryption details. * * @since 2.0.0 * @throws \RuntimeException */ public function getConnectionEncryption(): string { // TODO: Not fake this return ''; } /** * Method to test if the database TLS connections encryption are supported. * * @return boolean Whether the database supports TLS connections encryption. * * @since 2.0.0 */ public function isConnectionEncryptionSupported(): bool { // TODO: Not fake this return false; } /** * Shows the table CREATE statement that creates the given tables. * * Note: Doesn't appear to have support in SQLite * * @param mixed $tables A table name or a list of table names. * * @return array A list of the create SQL for the tables. * * @since 1.0 * @throws \RuntimeException */ public function getTableCreate($tables) { $this->connect(); // Sanitize input to an array and iterate over the list. $tables = (array) $tables; return $tables; } /** * Retrieves field information about a given table. * * @param string $table The name of the database table. * @param boolean $typeOnly True to only return field types. * * @return array An array of fields for the database table. * * @since 1.0 * @throws \RuntimeException */ public function getTableColumns($table, $typeOnly = true) { $this->connect(); $columns = []; $fieldCasing = $this->getOption(\PDO::ATTR_CASE); $this->setOption(\PDO::ATTR_CASE, \PDO::CASE_UPPER); $table = strtoupper($table); $fields = $this->setQuery('pragma table_info(' . $table . ')')->loadObjectList(); if ($typeOnly) { foreach ($fields as $field) { $columns[$field->NAME] = $field->TYPE; } } else { foreach ($fields as $field) { // Do some dirty translation to MySQL output. // TODO: Come up with and implement a standard across databases. $columns[$field->NAME] = (object) [ 'Field' => $field->NAME, 'Type' => $field->TYPE, 'Null' => $field->NOTNULL == '1' ? 'NO' : 'YES', 'Default' => $field->DFLT_VALUE, 'Key' => $field->PK != '0' ? 'PRI' : '', ]; } } $this->setOption(\PDO::ATTR_CASE, $fieldCasing); return $columns; } /** * Get the details list of keys for a table. * * @param string $table The name of the table. * * @return array An array of the column specification for the table. * * @since 1.0 * @throws \RuntimeException */ public function getTableKeys($table) { $this->connect(); $keys = []; $fieldCasing = $this->getOption(\PDO::ATTR_CASE); $this->setOption(\PDO::ATTR_CASE, \PDO::CASE_UPPER); $table = strtoupper($table); $rows = $this->setQuery('pragma table_info( ' . $table . ')')->loadObjectList(); foreach ($rows as $column) { if ($column->PK == 1) { $keys[$column->NAME] = $column; } } $this->setOption(\PDO::ATTR_CASE, $fieldCasing); return $keys; } /** * Method to get an array of all tables in the database (schema). * * @return array An array of all the tables in the database. * * @since 1.0 * @throws \RuntimeException */ public function getTableList() { $this->connect(); $type = 'table'; $query = $this->getQuery(true) ->select('name') ->from('sqlite_master') ->where('type = :type') ->bind(':type', $type) ->order('name'); return $this->setQuery($query)->loadColumn(); } /** * Get the version of the database connector. * * @return string The database connector version. * * @since 1.0 */ public function getVersion() { $this->connect(); return $this->setQuery('SELECT sqlite_version()')->loadResult(); } /** * Select a database for use. * * @param string $database The name of the database to select for use. * * @return boolean True if the database was successfully selected. * * @since 1.0 * @throws \RuntimeException */ public function select($database) { $this->connect(); return true; } /** * Set the connection to use UTF-8 character encoding. * * Returns false automatically for the Oracle driver since * you can only set the character set when the connection * is created. * * @return boolean True on success. * * @since 1.0 */ public function setUtf() { $this->connect(); return false; } /** * Locks a table in the database. * * @param string $table The name of the table to unlock. * * @return $this * * @since 1.0 * @throws \RuntimeException */ public function lockTable($table) { return $this; } /** * Renames a table in the database. * * @param string $oldTable The name of the table to be renamed * @param string $newTable The new name for the table. * @param string $backup Not used by Sqlite. * @param string $prefix Not used by Sqlite. * * @return $this * * @since 1.0 * @throws \RuntimeException */ public function renameTable($oldTable, $newTable, $backup = null, $prefix = null) { $this->setQuery('ALTER TABLE ' . $oldTable . ' RENAME TO ' . $newTable)->execute(); return $this; } /** * Method to truncate a table. * * @param string $table The table to truncate * * @return void * * @since 1.2.1 * @throws \RuntimeException */ public function truncateTable($table) { $this->setQuery('DELETE FROM ' . $this->quoteName($table)) ->execute(); } /** * Unlocks tables in the database. * * @return $this * * @since 1.0 * @throws \RuntimeException */ public function unlockTables() { return $this; } /** * Test to see if the PDO ODBC connector is available. * * @return boolean True on success, false otherwise. * * @since 1.0 */ public static function isSupported() { return class_exists('\\PDO') && class_exists('\\SQLite3') && \in_array('sqlite', \PDO::getAvailableDrivers(), true); } /** * Method to commit a transaction. * * @param boolean $toSavepoint If true, commit to the last savepoint. * * @return void * * @since 1.0 * @throws \RuntimeException */ public function transactionCommit($toSavepoint = false) { $this->connect(); if (!$toSavepoint || $this->transactionDepth <= 1) { parent::transactionCommit($toSavepoint); } else { $this->transactionDepth--; } } /** * Method to roll back a transaction. * * @param boolean $toSavepoint If true, rollback to the last savepoint. * * @return void * * @since 1.0 * @throws \RuntimeException */ public function transactionRollback($toSavepoint = false) { $this->connect(); if (!$toSavepoint || $this->transactionDepth <= 1) { parent::transactionRollback($toSavepoint); } else { $savepoint = 'SP_' . ($this->transactionDepth - 1); $this->setQuery('ROLLBACK TO ' . $this->quoteName($savepoint))->execute(); $this->transactionDepth--; } } /** * Method to initialize a transaction. * * @param boolean $asSavepoint If true and a transaction is already active, a savepoint will be created. * * @return void * * @since 1.0 * @throws \RuntimeException */ public function transactionStart($asSavepoint = false) { $this->connect(); if (!$asSavepoint || !$this->transactionDepth) { parent::transactionStart($asSavepoint); } else { $savepoint = 'SP_' . $this->transactionDepth; $this->setQuery('SAVEPOINT ' . $this->quoteName($savepoint))->execute(); $this->transactionDepth++; } } }