commit da107cf6e3d77c124cdf19d5568f548c7b695991 Author: Timothy Warren Date: Thu Mar 15 09:25:18 2012 -0400 Initial Commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..048d5fa --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Query + +A query builder/abstraction layer. \ No newline at end of file diff --git a/db_pdo.php b/db_pdo.php new file mode 100644 index 0000000..04cc87a --- /dev/null +++ b/db_pdo.php @@ -0,0 +1,293 @@ +prepare($sql); + + if( ! (is_object($query) || is_resource($query))) + { + $this->get_last_error(); + return FALSE; + } + + // Set the statement in the class variable for easy later access + $this->statement =& $query; + + + if( ! (is_array($data) || is_object($data))) + { + trigger_error("Invalid data argument"); + return FALSE; + } + + // Bind the parameters + foreach($data as $k => $value) + { + if(is_numeric($k)) + { + $k++; + } + + $res = $query->bindValue($k, $value); + + if( ! $res) + { + trigger_error("Parameter not successfully bound"); + return FALSE; + } + } + + return $query; + + } + + // ------------------------------------------------------------------------- + + /** + * Create and execute a prepared statement with the provided parameters + * + * @param string $sql + * @param array $params + * @return PDOStatement + */ + public function prepare_execute($sql, $params) + { + $this->statement = $this->prepare_query($sql, $params); + $this->statement->execute(); + + return $this->statement; + } + + // ------------------------------------------------------------------------- + + /** + * Retreives the data from a select query + * + * @param PDOStatement $statement + * @return array + */ + public function get_query_data($statement) + { + $this->statement =& $statement; + + // Execute the query + $this->statement->execute(); + + // Return the data array fetched + return $this->statement->fetchAll(PDO::FETCH_ASSOC); + } + + // ------------------------------------------------------------------------- + + /** + * Returns number of rows affected by an INSERT, UPDATE, DELETE type query + * + * @param PDOStatement $statement + * @return int + */ + public function affected_rows($statement='') + { + if ( ! empty($statement)) + { + $this->statement = $statement; + } + + if (empty($this->statement)) + { + return FALSE; + } + + // Execute the query + $this->statement->execute(); + + // Return number of rows affected + return $this->statement->rowCount(); + } + + // -------------------------------------------------------------------------- + + /** + * Return the last error for the current database connection + * + * @return string + */ + public function get_last_error() + { + $info = $this->errorInfo(); + + echo "Error:
{$info[0]}:{$info[1]}\n{$info[2]}
"; + } + + // -------------------------------------------------------------------------- + + /** + * Surrounds the string with the databases identifier escape characters + * + * @param mixed $ident + * @return string + */ + public function quote_ident($ident) + { + if (is_array($ident)) + { + return array_map(array($this, 'quote_ident'), $ident); + } + + // Split each identifier by the period + $hiers = explode('.', $ident); + + return '"'.implode('"."', $hiers).'"'; + } + + // ------------------------------------------------------------------------- + + /** + * Deletes all the rows from a table. Does the same as the truncate + * method if the database does not support 'TRUNCATE'; + * + * @param string $table + * @return mixed + */ + public function empty_table($table) + { + $sql = 'DELETE FROM '.$this->quote_ident($table); + + return $this->query($sql); + } + + // ------------------------------------------------------------------------- + + /** + * Abstract public functions to override in child classes + */ + + /** + * Return list of tables for the current database + * + * @return array + */ + abstract public function get_tables(); + + /** + * Empty the passed table + * + * @param string $table + * + * @return void + */ + abstract public function truncate($table); + + /** + * Return the number of rows for the last SELECT query + * + * @return int + */ + abstract public function num_rows(); + + /** + * Retreives an array of non-user-created tables for + * the connection/database + * + * @return array + */ + abstract public function get_system_tables(); + + /** + * Return an SQL file with the database table structure + * + * @return string + */ + abstract public function backup_structure(); + + /** + * Return an SQL file with the database data as insert statements + * + * @return string + */ + abstract public function backup_data(); +} + +// ------------------------------------------------------------------------- + +/** + * Abstract parent for database manipulation subclasses + */ +abstract class DB_SQL { + + /** + * Get database-specific sql to create a new table + * + * @param string $name + * @param array $columns + * @param array $constraints + * @param array $indexes + * @return string + */ + abstract public function create_table($name, $columns, array $constraints=array(), array $indexes=array()); + + /** + * Get database-specific sql to drop a table + * + * @param string $name + * @return string + */ + abstract public function delete_table($name); + + /** + * Get database specific sql for limit clause + * + * @param string $sql + * @param int $limiit + * @param int $offset + * @return string + */ + abstract public function limit($sql, $limit, $offset=FALSE); + + /** + * Get the sql for random ordering + * + * @return string + */ + abstract public function random(); +} +// End of db_pdo.php \ No newline at end of file diff --git a/drivers/firebird-ibase.php b/drivers/firebird-ibase.php new file mode 100644 index 0000000..c0f93bb --- /dev/null +++ b/drivers/firebird-ibase.php @@ -0,0 +1,468 @@ +conn = @ibase_connect($dbpath, $user, $pass, 'utf-8'); + + // Throw an exception to make this match other pdo classes + if ( ! is_resource($this->conn)) + { + throw new PDOException(ibase_errmsg()); + die(); + } + + $class = __CLASS__."_sql"; + $this->sql = new $class; + } + + // -------------------------------------------------------------------------- + + /** + * Close the link to the database + */ + public function __destruct() + { + @ibase_close(); + @ibase_free_result($this->statement); + } + + // -------------------------------------------------------------------------- + + /** + * Empty a database table + * + * @param string $table + */ + public function truncate($table) + { + // Firebird lacka a truncate command + $sql = 'DELETE FROM "'.$table.'"'; + $this->statement = $this->query($sql); + } + + // -------------------------------------------------------------------------- + + /** + * Wrapper public function to better match PDO + * + * @param string $sql + * @param array $params + * @return $this + */ + public function query($sql) + { + $this->count = 0; + + if (isset($this->trans)) + { + $this->statement = @ibase_query($this->trans, $sql); + } + else + { + $this->statement = @ibase_query($this->conn, $sql); + } + + // Throw the error as a exception + if ($this->statement === FALSE) + { + throw new PDOException(ibase_errmsg()); + } + + return $this->statement; + } + + // -------------------------------------------------------------------------- + + /** + * Emulate PDO fetch public function + * + * @param int $fetch_style + * @return mixed + */ + public function fetch($fetch_style=PDO::FETCH_ASSOC) + { + switch($fetch_style) + { + case PDO::FETCH_OBJ: + return ibase_fetch_object($this->statement, IBASE_FETCH_BLOBS); + break; + + case PDO::FETCH_NUM: + return ibase_fetch_row($this->statement, IBASE_FETCH_BLOBS); + break; + + default: + return ibase_fetch_assoc($this->statement, IBASE_FETCH_BLOBS); + break; + } + } + + // -------------------------------------------------------------------------- + + /** + * Emulate PDO fetchAll public function + * + * @param int $fetch_style + * @return mixed + */ + public function fetchAll($fetch_style=PDO::FETCH_ASSOC) + { + $all = array(); + + while($row = $this->fetch($fetch_style)) + { + $all[] = $row; + } + + $this->result = $all; + + return $all; + } + + // -------------------------------------------------------------------------- + + /** + * Emulate PDO prepare + * + * @param string $query + * @return $this + */ + public function prepare($query, $options=NULL) + { + $this->statement = @ibase_prepare($this->conn, $query); + + // Throw the error as an exception + if ($this->statement === FALSE) + { + throw new PDOException(ibase_errmsg()); + } + + return $this->statement; + } + + // -------------------------------------------------------------------------- + + /** + * List tables for the current database + * + * @return array + */ + public function get_tables() + { + $sql = <<statement = $this->query($sql); + + $tables = array(); + + while($row = $this->fetch(PDO::FETCH_ASSOC)) + { + $tables[] = $row['RDB$RELATION_NAME']; + } + + return $tables; + } + + // -------------------------------------------------------------------------- + + /** + * List system tables for the current database + * + * @return array + */ + public function get_system_tables() + { + $sql = <<statement = $this->query($sql); + + $tables = array(); + + while($row = $this->fetch(PDO::FETCH_ASSOC)) + { + $tables[] = $row['RDB$RELATION_NAME']; + } + + return $tables; + } + + // -------------------------------------------------------------------------- + + /** + * Return the number of rows affected by the previous query + * + * @return int + */ + public function affected_rows($statement="") + { + return ibase_affected_rows(); + } + + // -------------------------------------------------------------------------- + + /** + * Return the number of rows returned for a SELECT query + * + * @return int + */ + public function num_rows() + { + // @todo: Redo this similar to the codeigniter driver + if(isset($this->result)) + { + return count($this->result); + } + + //Fetch all the rows for the result + $this->result = $this->fetchAll(); + + return count($this->result); + } + + // -------------------------------------------------------------------------- + + /** + * Start a database transaction + * + * @return bool + */ + public function beginTransaction() + { + if(($this->trans = ibase_trans($this->conn)) !== NULL) + { + return TRUE; + } + + return FALSE; + } + + // -------------------------------------------------------------------------- + + /** + * Commit a database transaction + * + * @return bool + */ + public function commit() + { + return ibase_commit($this->trans); + } + + // -------------------------------------------------------------------------- + + /** + * Rollback a transaction + * + * @return bool + */ + public function rollBack() + { + return ibase_rollback($this->trans); + } + + // -------------------------------------------------------------------------- + + /** + * Run a prepared statement query + * + * @param array $args + * @return bool + */ + public function execute($args) + { + //Add the prepared statement as the first parameter + array_unshift($args, $this->statement); + + // Let php do all the hard stuff in converting + // the array of arguments into a list of arguments + return call_user_func_array('ibase_execute', $args); + } + + // -------------------------------------------------------------------------- + + /** + * Prepare and execute a query + * + * @param string $sql + * @param array $args + * @return resource + */ + public function prepare_execute($sql, $args) + { + $query = $this->prepare($sql); + + // Set the statement in the class variable for easy later access + $this->statement =& $query; + + return $this->execute($args); + } + + // -------------------------------------------------------------------------- + + /** + * Method to emulate PDO->quote + * + * @param string $str + * @return string + */ + public function quote($str, $param_type=NULL) + { + if(is_numeric($str)) + { + return $str; + } + + return "'".str_replace("'", "''", $str)."'"; + } + + // -------------------------------------------------------------------------- + + /** + * Method to emulate PDO->errorInfo / PDOStatement->errorInfo + * + * @return array + */ + public function errorInfo() + { + $code = ibase_errcode(); + $msg = ibase_errmsg(); + + return array(0, $code, $msg); + } + + // -------------------------------------------------------------------------- + + /** + * Bind a prepared query with arguments for executing + * + * @param string $sql + * @param mixed $args + * @return FALSE + */ + public function prepare_query($sql, $args) + { + // You can't bind query statements before execution with + // the firebird database + return FALSE; + } + + // -------------------------------------------------------------------------- + + /** + * Create an SQL backup file for the current database's structure + * + * @return string + */ + public function backup_structure() + { + // @todo Implement Backup function + return ''; + } + + // -------------------------------------------------------------------------- + + /** + * Create an SQL backup file for the current database's data + * + * @param array $exclude + * @param bool $system_tables + * @return string + */ + public function backup_data($exclude=array(), $system_tables=FALSE) + { + // Determine which tables to use + if($system_tables == TRUE) + { + $tables = array_merge($this->get_system_tables(), $this->get_tables()); + } + else + { + $tables = $this->get_tables(); + } + + // Filter out the tables you don't want + if( ! empty($exclude)) + { + $tables = array_diff($tables, $exclude); + } + + $output_sql = ''; + + // Get the data for each object + foreach($tables as $t) + { + $sql = 'SELECT * FROM "'.trim($t).'"'; + $res = $this->query($sql); + $obj_res = $this->fetchAll(PDO::FETCH_ASSOC); + + unset($res); + + // Nab the column names by getting the keys of the first row + $columns = @array_keys($obj_res[0]); + + $insert_rows = array(); + + // Create the insert statements + foreach($obj_res as $row) + { + $row = array_values($row); + + // Quote values as needed by type + if(stripos($t, 'RDB$') === FALSE) + { + $row = array_map(array(&$this, 'quote'), $row); + $row = array_map('trim', $row); + } + + $row_string = 'INSERT INTO "'.trim($t).'" ("'.implode('","', $columns).'") VALUES ('.implode(',', $row).');'; + + unset($row); + + $insert_rows[] = $row_string; + } + + unset($obj_res); + + $output_sql .= "\n\nSET TRANSACTION;\n".implode("\n", $insert_rows)."\nCOMMIT;"; + } + + return $output_sql; + } +} +// End of firebird-ibase.php \ No newline at end of file diff --git a/drivers/firebird_sql.php b/drivers/firebird_sql.php new file mode 100644 index 0000000..1a13fda --- /dev/null +++ b/drivers/firebird_sql.php @@ -0,0 +1,130 @@ + ..., + // 'constraint' => ..., + // 'index' => ..., + // ) + foreach($fields as $colname => $type) + { + if(is_numeric($colname)) + { + $colname = $type; + } + + $column_array[$colname] = array(); + $column_array[$colname]['type'] = ($type !== $colname) ? $type : ''; + } + + if( ! empty($constraints)) + { + foreach($constraints as $col => $const) + { + $column_array[$col]['constraint'] = $const; + } + } + + // Join column definitons together + $columns = array(); + foreach($column_array as $n => $props) + { + $str = '"'.$n.'" '; + $str .= (isset($props['type'])) ? "{$props['type']} " : ""; + $str .= (isset($props['constraint'])) ? "{$props['constraint']} " : ""; + + $columns[] = $str; + } + + // Generate the sql for the creation of the table + $sql = 'CREATE TABLE "'.$name.'" ('; + $sql .= implode(',', $columns); + $sql .= ')'; + + return $sql; + } + + // -------------------------------------------------------------------------- + + /** + * Drop the selected table + * + * @param string $name + * @return string + */ + public function delete_table($name) + { + return 'DROP TABLE "'.$name.'"'; + } + + // -------------------------------------------------------------------------- + + /** + * Limit clause + * + * @param string $sql + * @param int $limit + * @param int $offset + * @return string + */ + public function limit($sql, $limit, $offset=FALSE) + { + // Keep the current sql string safe for a moment + $orig_sql = $sql; + + $sql = 'FIRST '. (int) $limit; + + if ($offset > 0) + { + $sql .= ' SKIP '. (int) $offset; + } + + $sql = preg_replace("`SELECT`i", "SELECT {$sql}", $orig_sql); + + return $sql; + } + + // -------------------------------------------------------------------------- + + /** + * Random ordering keyword + * + * @return string + */ + public function random() + { + return FALSE; + } +} +//End of firebird_sql.php \ No newline at end of file diff --git a/drivers/mysql.php b/drivers/mysql.php new file mode 100644 index 0000000..b35c5ef --- /dev/null +++ b/drivers/mysql.php @@ -0,0 +1,148 @@ +sql = new $class; + } + + // -------------------------------------------------------------------------- + + /** + * Empty a table + * + * @param string $table + */ + public function truncate($table) + { + $this->query("TRUNCATE `{$table}`"); + } + + // -------------------------------------------------------------------------- + + /** + * Get databases for the current connection + * + * @return array + */ + public function get_dbs() + { + $res = $this->query("SHOW DATABASES"); + return $this->fetchAll(PDO::FETCH_ASSOC); + } + + // -------------------------------------------------------------------------- + + /** + * Returns the tables available in the current database + * + * @return array + */ + public function get_tables() + { + $res = $this->query("SHOW TABLES"); + return $res->fetchAll(PDO::FETCH_ASSOC); + } + + // -------------------------------------------------------------------------- + + /** + * Returns system tables for the current database + * + * @return array + */ + public function get_system_tables() + { + //MySQL doesn't have system tables + return array(); + } + + // -------------------------------------------------------------------------- + + /** + * Return the number of rows returned for a SELECT query + * + * @return int + */ + public function num_rows() + { + return isset($this->statement) ? $this->statement->rowCount() : FALSE; + } + + // -------------------------------------------------------------------------- + + /** + * Create an SQL backup file for the current database's structure + * + * @return string + */ + public function backup_structure() + { + // @todo Implement Backup function + return ''; + } + + // -------------------------------------------------------------------------- + + /** + * Create an SQL backup file for the current database's data + * + * @return string + */ + public function backup_data() + { + // @todo Implement Backup function + return ''; + } + + // -------------------------------------------------------------------------- + + /** + * Surrounds the string with the databases identifier escape characters + * + * @param string $ident + * @return string + */ + public function quote_ident($ident) + { + if (is_array($ident)) + { + return array_map(array($this, 'quote_ident'), $ident); + } + + // Split each identifier by the period + $hiers = explode('.', $ident); + + return '`'.implode('`.`', $hiers).'`'; + } +} +//End of mysql.php \ No newline at end of file diff --git a/drivers/mysql_sql.php b/drivers/mysql_sql.php new file mode 100644 index 0000000..1eeec9c --- /dev/null +++ b/drivers/mysql_sql.php @@ -0,0 +1,80 @@ +sql = new $class; + } + + // -------------------------------------------------------------------------- + + /** + * List tables for the current database + * + * @return mixed + */ + public function get_tables() + { + //Not possible reliably with this driver + return FALSE; + } + + // -------------------------------------------------------------------------- + + /** + * List system tables for the current database/connection + * + * @return array + */ + public function get_system_tables() + { + //No way of determining for ODBC + return array(); + } + + // -------------------------------------------------------------------------- + + /** + * Empty the current database + * + * @return void + */ + public function truncate($table) + { + $sql = "DELETE FROM {$table}"; + $this->query($sql); + } + + // -------------------------------------------------------------------------- + + /** + * Return the number of rows returned for a SELECT query + * + * @return int + */ + public function num_rows() + { + // TODO: Implement + } + + // -------------------------------------------------------------------------- + + /** + * Create an SQL backup file for the current database's structure + * + * @return string + */ + public function backup_structure() + { + // Not applicable to ODBC + return ''; + } + + // -------------------------------------------------------------------------- + + /** + * Create an SQL backup file for the current database's data + * + * @return string + */ + public function backup_data() + { + // Not applicable to ODBC + return ''; + } +} +// End of odbc.php \ No newline at end of file diff --git a/drivers/odbc_sql.php b/drivers/odbc_sql.php new file mode 100644 index 0000000..88be0dd --- /dev/null +++ b/drivers/odbc_sql.php @@ -0,0 +1,66 @@ +sql = new $class; + } + + // -------------------------------------------------------------------------- + + /** + * Empty a table + * + * @param string $table + */ + public function truncate($table) + { + $sql = 'TRUNCATE "' . $table . '"'; + $this->query($sql); + } + + // -------------------------------------------------------------------------- + + /** + * Get list of databases for the current connection + * + * @return array + */ + public function get_dbs() + { + $sql = <<query($sql); + + $dbs = $res->fetchAll(PDO::FETCH_ASSOC); + + return $dbs; + } + + // -------------------------------------------------------------------------- + + /** + * Get the list of tables for the current db + * + * @return array + */ + public function get_tables() + { + $sql = <<query($sql); + + $tables = $res->fetchAll(PDO::FETCH_ASSOC); + + return $tables; + } + + // -------------------------------------------------------------------------- + + /** + * Get the list of system tables + * + * @return array + */ + public function get_system_tables() + { + $sql = <<query($sql); + + $tables = $res->fetchAll(PDO::FETCH_ASSOC); + + return $tables; + + } + + // -------------------------------------------------------------------------- + + /** + * Get a list of schemas, either for the current connection, or + * for the current datbase, if specified. + * + * @param string $database="" + * @return array + */ + public function get_schemas($database="") + { + if($database === "") + { + $sql = <<query($sql); + $schemas = $res->fetchAll(PDO::FETCH_ASSOC); + + return $schemas; + } + + // -------------------------------------------------------------------------- + + /** + * Get a list of views for the current db + * + * @return array + */ + public function get_views() + { + $sql = <<query($sql); + + $views = $res->fetchAll(PDO::FETCH_ASSOC); + + return $views; + } + + // -------------------------------------------------------------------------- + + /** + * Return the number of rows returned for a SELECT query + * + * @return int + */ + public function num_rows() + { + return (isset($this->statement)) ? $this->statement->rowCount : FALSE; + } + + // -------------------------------------------------------------------------- + + /** + * Create an SQL backup file for the current database's structure + * + * @return string + */ + public function backup_structure() + { + // @todo Implement Backup function + return ''; + } + + // -------------------------------------------------------------------------- + + /** + * Create an SQL backup file for the current database's data + * + * @return string + */ + public function backup_data() + { + // @todo Implement Backup function + return ''; + } +} +//End of pgsql.php \ No newline at end of file diff --git a/drivers/pgsql_sql.php b/drivers/pgsql_sql.php new file mode 100644 index 0000000..83859d4 --- /dev/null +++ b/drivers/pgsql_sql.php @@ -0,0 +1,67 @@ +sql = new $class; + } + + // -------------------------------------------------------------------------- + + /** + * Empty a table + * + * @param string $table + */ + public function truncate($table) + { + // SQLite has a TRUNCATE optimization, + // but no support for the actual command. + $sql = 'DELETE FROM "'.$table.'"'; + + $this->statement = $this->query($sql); + + return $this->statement; + } + + // -------------------------------------------------------------------------- + + /** + * List tables for the current database + * + * @return mixed + */ + public function get_tables() + { + $tables = array(); + $sql = <<query($sql); + $result = $res->fetchAll(PDO::FETCH_ASSOC); + + foreach($result as $r) + { + $tables[$r['name']] = $r['sql']; + } + + return $tables; + } + + // -------------------------------------------------------------------------- + + /** + * List system tables for the current database + * + * @return array + */ + public function get_system_tables() + { + //SQLite only has the sqlite_master table + // that is of any importance. + return array('sqlite_master'); + } + + // -------------------------------------------------------------------------- + + /** + * Load a database for the current connection + * + * @param string $db + * @param string $name + */ + public function load_database($db, $name) + { + $sql = 'ATTACH DATABASE "'.$db.'" AS "'.$name.'"'; + $this->query($sql); + } + + // -------------------------------------------------------------------------- + + /** + * Unload a database from the current connection + * + * @param string $name + */ + public function unload_database($name) + { + $sql = 'DETACH DATABASE ":name"'; + + $this->prepare_query($sql, array( + ':name' => $name, + )); + + $this->statement->execute(); + } + + // -------------------------------------------------------------------------- + + /** + * Return the number of rows returned for a SELECT query + * + * @return int + */ + public function num_rows() + { + return (isset($this->statement)) ? $this->statement->rowCount : FALSE; + } + + // -------------------------------------------------------------------------- + + /** + * Create an SQL backup file for the current database's structure + * + * @return string + */ + public function backup_structure() + { + // Fairly easy for SQLite...just query the master table + $sql = 'SELECT "sql" FROM "sqlite_master"'; + $res = $this->query($sql); + $result = $res->fetchAll(PDO::FETCH_ASSOC); + + $sql_array = array(); + + foreach($result as $r) + { + $sql_array[] = $r['sql']; + } + + $sql_structure = implode("\n\n", $sql_array); + + return $sql_structure; + } + + // -------------------------------------------------------------------------- + + /** + * Create an SQL backup file for the current database's data + * + * @param array $excluded + * @return string + */ + public function backup_data($excluded=array()) + { + // Get a list of all the objects + $sql = 'SELECT "name" FROM "sqlite_master"'; + + if( ! empty($excluded)) + { + $sql .= ' WHERE NOT IN("'.implode('","', $excluded).'")'; + } + + $res = $this->query($sql); + $result = $res->fetchAll(PDO::FETCH_ASSOC); + + unset($res); + + $output_sql = ''; + + // Get the data for each object + foreach($result as $r) + { + $sql = 'SELECT * FROM "'.$r['name'].'"'; + $res = $this->query($sql); + $obj_res = $res->fetchAll(PDO::FETCH_ASSOC); + + unset($res); + + // Nab the column names by getting the keys of the first row + $columns = array_keys($obj_res[0]); + + $insert_rows = array(); + + // Create the insert statements + foreach($obj_res as $row) + { + $row = array_values($row); + + // Quote values as needed by type + for($i=0, $icount=count($row); $i<$icount; $i++) + { + $row[$i] = (is_numeric($row[$i])) ? $row[$i] : $this->quote($row[$i]); + } + + $row_string = 'INSERT INTO "'.$r['name'].'" ("'.implode('","', $columns).'") VALUES ('.implode(',', $row).');'; + + unset($row); + + $insert_rows[] = $row_string; + } + + unset($obj_res); + + $output_sql .= "\n\n".implode("\n", $insert_rows); + } + + return $output_sql; + } +} +//End of sqlite.php \ No newline at end of file diff --git a/drivers/sqlite_sql.php b/drivers/sqlite_sql.php new file mode 100644 index 0000000..3bfe978 --- /dev/null +++ b/drivers/sqlite_sql.php @@ -0,0 +1,122 @@ + type pairs + * @param array $constraints // column => constraint pairs + * @param array $indexes // column => index pairs + * @return string + */ + public function create_table($name, $columns, array $constraints=array(), array $indexes=array()) + { + $column_array = array(); + + // Reorganize into an array indexed with column information + // Eg $column_array[$colname] = array( + // 'type' => ..., + // 'constraint' => ..., + // 'index' => ..., + // ) + foreach($columns as $colname => $type) + { + if(is_numeric($colname)) + { + $colname = $type; + } + + $column_array[$colname] = array(); + $column_array[$colname]['type'] = ($type !== $colname) ? $type : ''; + } + + if( ! empty($constraints)) + { + foreach($constraints as $col => $const) + { + $column_array[$col]['constraint'] = $const; + } + } + + // Join column definitons together + $columns = array(); + foreach($column_array as $n => $props) + { + $str = "{$n} "; + $str .= (isset($props['type'])) ? "{$props['type']} " : ""; + $str .= (isset($props['constraint'])) ? $props['constraint'] : ""; + + $columns[] = $str; + } + + // Generate the sql for the creation of the table + $sql = "CREATE TABLE IF NOT EXISTS \"{$name}\" ("; + $sql .= implode(", ", $columns); + $sql .= ")"; + + return $sql; + } + + // -------------------------------------------------------------------------- + + /** + * SQL to drop the specified table + * + * @param string $name + * @return string + */ + public function delete_table($name) + { + return 'DROP TABLE IF EXISTS "'.$name.'"'; + } + + // -------------------------------------------------------------------------- + + /** + * Limit clause + * + * @param string $sql + * @param int $limit + * @param int $offset + * @return string + */ + public function limit($sql, $limit, $offset=FALSE) + { + if ( ! is_numeric($offset)) + { + return $sql." LIMIT {$limit}"; + } + + return $sql." LIMIT {$offset}, {$limit}"; + } + + // -------------------------------------------------------------------------- + + /** + * Random ordering keyword + * + * @return string + */ + public function random() + { + return ' RANDOM()'; + } +} +//End of sqlite_sql.php \ No newline at end of file diff --git a/query_builder.php b/query_builder.php new file mode 100644 index 0000000..803b9fd --- /dev/null +++ b/query_builder.php @@ -0,0 +1,1049 @@ +db->sql + private $sql; + + // Query component order mapping + // for complex select queries + // + // Format: + // + // array( + // 'type' => 'where', + // 'conjunction' => ' AND ', + // 'string' => 'k=?' + // ) + private $query_map; + + /** + * Constructor + * + * @param object $conn_name - the name of the connection/parameters + */ + public function __construct($params) + { + $params->type = strtolower($params->type); + $dbtype = ($params->type !== 'postgresql') ? $params->type : 'pgsql'; + + // Initiate the constructor for the selected database + switch($dbtype) + { + default: + $this->db = new $dbtype("host={$params->host};port={$params->port};", $params->user, $params->pass); + break; + + case "sqlite": + if ( ! empty($params->user) && ! empty($params->pass)) + { + $this->db = new $dbtype($params->file, $params->user, $params->pass); + } + else + { + $this->db = new $dbtype($params->file); + } + break; + + case "firebird": + $this->db = new $dbtype("{$params->host}:{$params->file}", $params->user, $params->pass); + break; + } + + // Make things just slightly shorter + $this->sql =& $this->db->sql; + } + + // -------------------------------------------------------------------------- + // ! Select Queries + // -------------------------------------------------------------------------- + + /** + * Specifies rows to select in a query + * + * @param string $fields + * @return $this + */ + public function select($fields) + { + // Split fields by comma + $fields_array = explode(",", $fields); + $fields_array = array_map('trim', $fields_array); + + // Split on 'As' + foreach ($fields_array as $key => $field) + { + if (stripos($field, 'as') !== FALSE) + { + $fields_array[$key] = preg_split('`as`i', $field); + $fields_array[$key] = array_map('trim', $fields_array[$key]); + } + } + + // Quote the identifiers + $safe_array = array_map(array($this->db, 'quote_ident'), $fields_array); + + unset($fields_array); + + // Join the strings back together + for($i = 0, $c = count($safe_array); $i < $c; $i++) + { + if (is_array($safe_array[$i])) + { + $safe_array[$i] = implode(' AS ', $safe_array[$i]); + } + } + + $this->select_string = implode(', ', $safe_array); + + unset($safe_array); + + return $this; + } + + // -------------------------------------------------------------------------- + + /** + * Specify the database table to select from + * + * @param string $dbname + * @return $this + */ + public function from($dbname) + { + // Split identifiers on spaces + $ident_array = explode(' ', trim($dbname)); + $ident_array = array_map('trim', $ident_array); + + // Quote the identifiers + $ident_array = array_map(array($this->db, 'quote_ident'), $ident_array); + + // Paste it back together + $this->from_string = implode(' ', $ident_array); + + return $this; + } + + // -------------------------------------------------------------------------- + // ! 'Like' methods + // -------------------------------------------------------------------------- + + /** + * Creates a Like clause in the sql statement + * + * @param string $field + * @param mixed $val + * @param string $pos + * @return $this + */ + public function like($field, $val, $pos='both') + { + $field = $this->db->quote_ident($field); + + // Add the like string into the order map + $l = $field. ' LIKE ?'; + + if ($pos == 'before') + { + $val = "%{$val}"; + } + elseif ($pos == 'after') + { + $val = "{$val}%"; + } + else + { + $val = "%{$val}%"; + } + + $this->query_map[] = array( + 'type' => 'like', + 'conjunction' => (empty($this->query_map)) ? 'WHERE ' : ' AND ', + 'string' => $l + ); + + // Add to the values array + $this->values[] = $val; + + return $this; + } + + // -------------------------------------------------------------------------- + + /** + * Generates an OR Like clause + * + * @param string $field + * @param mixed $val + * @param string $pos + * @return $this + */ + public function or_like($field, $val, $pos='both') + { + $field = $this->db->quote_ident($field); + + // Add the like string into the order map + $l = $field. ' LIKE ?'; + + if ($pos == 'before') + { + $val = "%{$val}"; + } + elseif ($pos == 'after') + { + $val = "{$val}%"; + } + else + { + $val = "%{$val}%"; + } + + $this->query_map[] = array( + 'type' => 'like', + 'conjunction' => (empty($this->query_map)) ? 'WHERE ' : ' OR ', + 'string' => $l + ); + + // Add to the values array + $this->values[] = $val; + + return $this; + } + + // -------------------------------------------------------------------------- + + /** + * Generates a NOT LIKE clause + * + * @param string $field + * @param mixed $val + * @param string $pos + * @return $this + */ + public function not_like($field, $val, $pos='both') + { + $field = $this->db->quote_ident($field); + + // Add the like string into the order map + $l = $field. ' NOT LIKE ?'; + + if ($pos == 'before') + { + $val = "%{$val}"; + } + elseif ($pos == 'after') + { + $val = "{$val}%"; + } + else + { + $val = "%{$val}%"; + } + + $this->query_map[] = array( + 'type' => 'like', + 'conjunction' => (empty($this->query_map)) ? ' WHERE ' : ' AND ', + 'string' => $l + ); + + // Add to the values array + $this->values[] = $val; + + return $this; + } + + // -------------------------------------------------------------------------- + + /** + * Generates a OR NOT LIKE clause + * + * @param string $field + * @param mixed $val + * @param string $pos + * @return $this; + */ + public function or_not_like($field, $val, $pos='both') + { + $field = $this->db->quote_ident($field); + + // Add the like string into the order map + $l = $field. ' NOT LIKE ?'; + + if ($pos == 'before') + { + $val = "%{$val}"; + } + elseif ($pos == 'after') + { + $val = "{$val}%"; + } + else + { + $val = "%{$val}%"; + } + + $this->query_map[] = array( + 'type' => 'like', + 'conjunction' => (empty($this->query_map)) ? ' WHERE ' : ' OR ', + 'string' => $l + ); + + // Add to the values array + $this->values[] = $val; + + return $this; + } + + // -------------------------------------------------------------------------- + // ! 'Where' methods + // -------------------------------------------------------------------------- + + /** + * Do all the repeditive stuff for where type methods + * + * @param mixed $key + * @param mixed $val + * @return array + */ + private function _where($key, $val=array()) + { + $where = array(); + + // Key and value passed? Add them to the where array + if (is_scalar($key) && is_scalar($val)) + { + $where[$key] = $val; + $this->values[] = $val; + } + // Array or object, loop through and add to the where array + elseif ( ! is_scalar($key)) + { + foreach($key as $k => $v) + { + $where[$k] = $v; + $this->values[] = $v; + } + } + + return $where; + } + + // -------------------------------------------------------------------------- + + /** + * Specify condition(s) in the where clause of a query + * Note: this function works with key / value, or a + * passed array with key / value pairs + * + * @param mixed $key + * @param mixed $val + * @return $this + */ + public function where($key, $val=array()) + { + $where = $this->_where($key, $val); + + // Create key/value placeholders + foreach($where as $f => $val) + { + // Split each key by spaces, in case there + // is an operator such as >, <, !=, etc. + $f_array = explode(' ', trim($f)); + + $item = $this->db->quote_ident($f_array[0]); + + // Simple key value, or an operator + $item .= (count($f_array === 1)) ? '= ?' : " {$f_array[1]} ?"; + + // Put in the query map for select statements + $this->query_map[] = array( + 'type' => 'where', + 'conjunction' => ( ! empty($this->query_map)) ? ' AND ' : ' WHERE ', + 'string' => $item + ); + } + + return $this; + } + + // -------------------------------------------------------------------------- + + /** + * Where clause prefixed with "OR" + * + * @param string $field + * @param mixed $val + * @return $this + */ + public function or_where($field, $val=array()) + { + $where = $this->_where($field, $val); + + // Create key/value placeholders + foreach($where as $f => $val) + { + // Split each key by spaces, incase there + // is an operator such as >, <, !=, etc. + $f_array = explode(' ', trim($f)); + + // Simple key = val + if (count($f_array) === 1) + { + $item = $this->db->quote_ident($f_array[0]) . '= ?'; + } + else // Other operators + { + $item = $this->db->quote_ident($f_array[0]) . " {$f_array[1]} ?"; + } + + // Put in the query map for select statements + $this->query_map[] = array( + 'type' => 'where', + 'conjunction' => ( ! empty($this->query_map)) ? ' OR ' : ' WHERE ', + 'string' => $item + ); + } + + return $this; + } + + // -------------------------------------------------------------------------- + + /** + * Where clause with 'IN' statement + * + * @param mixed $field + * @param mixed $val + * @return $this + */ + public function where_in($field, $val=array()) + { + $field = $this->db->quote_ident($field); + $params = array_fill(0, count($val), '?'); + + foreach($val as $v) + { + $this->values[] = $v; + } + + $string = $field . ' IN ('.implode(',', $params).') '; + + $this->query_map[] = array( + 'type' => 'where_in', + 'conjunction' => ( ! empty($this->query_map)) ? ' AND ' : ' WHERE ', + 'string' => $string + ); + + return $this; + } + + // -------------------------------------------------------------------------- + + /** + * Where in statement prefixed with "or" + * + * @param string $field + * @param mixed $val + * @return $this + */ + public function or_where_in($field, $val=array()) + { + $field = $this->db->quote_ident($field); + $params = array_fill(0, count($val), '?'); + + foreach($val as $v) + { + $this->values[] = $v; + } + + $string = $field . ' IN ('.implode(',', $params).') '; + + $this->query_map[] = array( + 'type' => 'where_in', + 'conjunction' => ( ! empty($this->query_map)) ? ' OR ' : ' WHERE ', + 'string' => $string + ); + + return $this; + } + + // -------------------------------------------------------------------------- + + /** + * WHERE NOT IN (FOO) clause + * + * @param string $field + * @param mixed $val + * @return $this + */ + public function where_not_in($field, $val=array()) + { + $field = $this->db->quote_ident($field); + $params = array_fill(0, count($val), '?'); + + foreach($val as $v) + { + $this->values[] = $v; + } + + $string = $field.' NOT IN ('.implode(',', $params).') '; + + $this->query_map[] = array( + 'type' => 'where_in', + 'conjunction' => ( ! empty($this->query_map)) ? ' AND ' : ' WHERE ', + 'string' => $string + ); + + return $this; + } + + // -------------------------------------------------------------------------- + + /** + * OR WHERE NOT IN (FOO) clause + * + * @param string $field + * @param mixed $val + * @return $this + */ + public function or_where_not_in($field, $val=array()) + { + $field = $this->db->quote_ident($field); + $params = array_fill(0, count($val), '?'); + + foreach($val as $v) + { + $this->values[] = $v; + } + + $string = $field.' NOT IN ('.implode(',', $params).') '; + + $this->query_map[] = array( + 'type' => 'where_in', + 'conjunction' => ( ! empty($this->query_map)) ? ' OR ' : ' WHERE ', + 'string' => $string + ); + + return $this; + } + + // -------------------------------------------------------------------------- + // ! Other Query Modifier methods + // -------------------------------------------------------------------------- + + /** + * Creates a join phrase in a compiled query + * + * @param string $table + * @param string $condition + * @param string $type + * @return $this + */ + public function join($table, $condition, $type='') + { + // Paste it back together + $table = implode(" ", array_map(array($this->db, 'quote_ident'), explode(' ', trim($table)))); + //$condition = preg_replace('`(\W)`', " $1 ", $condition); + $cond_array = explode(' ', trim($condition)); + $cond_array = array_map('trim', $cond_array); + + $condition = $table . ' ON ' . $this->db->quote_ident($cond_array[0]) . $cond_array[1] . + ' ' . $this->db->quote_ident($cond_array[2]); + + $this->query_map[] = array( + 'type' => 'join', + 'conjunction' => strtoupper($type).' JOIN ', + 'string' => $condition, + ); + + return $this; + } + + // -------------------------------------------------------------------------- + + /** + * Group the results by the selected field(s) + * + * @param mixed $field + * @return $this + */ + public function group_by($field) + { + if ( ! is_scalar($field)) + { + $this->group_array = array_map(array($this->db, 'quote_ident'), $field); + } + else + { + $this->group_array[] = $this->db->quote_ident($field); + } + + $this->group_string = ' GROUP BY ' . implode(', ', $this->group_array); + + return $this; + } + + // -------------------------------------------------------------------------- + + /** + * Order the results by the selected field(s) + * + * @param string $field + * @param string $type + * @return $this + */ + public function order_by($field, $type="") + { + // Random case + if (stripos($type, 'rand') !== FALSE) + { + $type = (($rand = $this->sql->random()) !== FALSE ) ? $rand : 'ASC'; + } + + // Set fields for later manipulation + $field = $this->db->quote_ident($field); + $this->order_array[$field] = $type; + + $order_clauses = array(); + + // Flatten key/val pairs into an array of space-separated pairs + foreach($this->order_array as $k => $v) + { + $order_clauses[] = $k . ' ' . strtoupper($v); + } + + // Set the final string + $this->order_string = (empty($rand)) + ? ' ORDER BY '.implode(',', $order_clauses) + : ' ORDER BY'.$rand; + + return $this; + } + + // -------------------------------------------------------------------------- + + /** + * Set a limit on the current sql statement + * + * @param int $limit + * @param int $offset + * @return string + */ + public function limit($limit, $offset=FALSE) + { + $this->limit = $limit; + $this->offset = $offset; + + return $this; + } + + // -------------------------------------------------------------------------- + // ! Query execution methods + // -------------------------------------------------------------------------- + + /** + * Select and retrieve all records from the current table, and/or + * execute current compiled query + * + * @param $table + * @param int $limit + * @param int $offset + * @return object + */ + public function get($table='', $limit=FALSE, $offset=FALSE) + { + // Set the table + if ( ! empty($table)) + { + $this->from($table); + } + + // Set the limit, if it exists + if ($limit !== FALSE) + { + $this->limit($limit, $offset); + } + + $sql = $this->_compile(); + + // Do prepared statements for anything involving a "where" clause + if ( ! empty($this->query_map)) + { + $result = $this->db->prepare_execute($sql, $this->values); + } + else + { + // Otherwise, a simple query will do. + $result = $this->db->query($sql); + } + + // Reset for next query + $this->_reset(); + + return $result; + } + + // -------------------------------------------------------------------------- + + /** + * Creates an insert clause, and executes it + * + * @param string $table + * @param mixed $data + * @return mixed + */ + public function insert($table, $data=array()) + { + // No use duplicating logic! + if ( ! empty($data)) + { + $this->set($data); + } + + $sql = $this->_compile("insert", $table); + + $res = $this->db->prepare_execute($sql, $this->values); + + $this->_reset(); + + return $res; + } + + // -------------------------------------------------------------------------- + + /** + * Creates an update clause, and executes it + * + * @param string $table + * @param mixed $data + * @return mixed + */ + public function update($table, $data=array()) + { + // No use duplicating logic! + if ( ! empty($data)) + { + $this->set($data); + } + + $sql = $this->_compile('update', $table); + + $res = $this->db->prepare_execute($sql, $this->values); + + $this->_reset(); + + // Run the query + return $res; + } + + // -------------------------------------------------------------------------- + + /** + * Deletes data from a table + * + * @param string $table + * @param mixed $where + * @return mixed + */ + public function delete($table, $where='') + { + // Set the where clause + if ( ! empty($where)) + { + $this->where($where); + } + + // Create the SQL and parameters + $sql = $this->_compile("delete", $table); + + $res = $this->db->prepare_execute($sql, $this->values); + + $this->_reset(); + + // Delete the table rows, and return the result + return $res; + } + + // -------------------------------------------------------------------------- + // ! Query Grouping Methods + // -------------------------------------------------------------------------- + + /** + * Adds a paren to the current query for query grouping + * + * @return $this + */ + public function group_start() + { + $this->query_map[] = array( + 'type' => 'group_start', + 'conjunction' => '', + 'string' => ' (' + ); + + return $this; + } + + // -------------------------------------------------------------------------- + + /** + * Adds a paren to the current query for query grouping, + * prefixed with 'OR' + * + * @return $this + */ + public function or_group_start() + { + $this->query_map[] = array( + 'type' => 'group_start', + 'conjunction' => '', + 'string' => ' OR (' + ); + + return $this; + } + + // -------------------------------------------------------------------------- + + /** + * Adds a paren to the current query for query grouping, + * prefixed with 'OR NOT' + * + * @return $this + */ + public function or_not_group_start() + { + $this->query_map[] = array( + 'type' => 'group_start', + 'conjunction' => '', + 'string' => ' OR NOT (' + ); + + return $this; + } + + // -------------------------------------------------------------------------- + + /** + * Ends a query group + * + * @return $this + */ + public function group_end() + { + $this->query_map[] = array( + 'type' => 'group_end', + 'conjunction' => '', + 'string' => ' ) ' + ); + + return $this; + } + + // -------------------------------------------------------------------------- + // ! Miscellaneous Methods + // -------------------------------------------------------------------------- + + /** + * Sets values for inserts / updates / deletes + * + * @param mixed $key + * @param mixed $val + * @return $this + */ + public function set($key, $val) + { + // Plain key, value pair + if (is_scalar($key) && is_scalar($val)) + { + $this->set_array[$key] = $val; + $this->values[] = $val; + } + // Object or array + elseif ( ! is_scalar($key)) + { + foreach($key as $k => $v) + { + $this->set_array[$k] = $v; + $this->values[] = $val; + } + } + + // Use the keys of the array to make the insert/update string + // Escape the field names + $this->set_array_keys = array_map(array($this->db, 'quote_ident'), array_keys($this->set_array)); + + // Generate the "set" string + $this->set_string = implode('=?, ', $this->set_array_keys); + $this->set_string .= '=?'; + + return $this; + } + + // -------------------------------------------------------------------------- + + /** + * Clear out the class variables, so the next query can be run + */ + private function _reset() + { + // Only unset class variables that + // are not callable. Otherwise, we'll + // delete class methods! + foreach($this as $name => $var) + { + // Skip properties that are needed for every query + $save_properties = array( + 'db', + 'sql' + ); + + if (in_array($name, $save_properties)) + { + continue; + } + + // Nothing query-generation related is safe! + if ( ! is_callable($this->$name)) + { + unset($this->$name); + } + + // Set values as an empty array + $this->values = array(); + } + } + + // -------------------------------------------------------------------------- + + /** + * String together the sql statements for sending to the db + * + * @param string $type + * @param string $table + * @return $string + */ + private function _compile($type='', $table="") + { + $sql = ''; + + switch($type) + { + default: + $sql = 'SELECT * FROM '.$this->from_string; + + // Set the select string + if ( ! empty($this->select_string)) + { + // Replace the star with the selected fields + $sql = str_replace('*', $this->select_string, $sql); + } + + // Set the where string + if ( ! empty($this->query_map)) + { + foreach($this->query_map as $q) + { + $sql .= $q['conjunction'] . $q['string']; + } + } + + // Set the group_by string + if ( ! empty($this->group_string)) + { + $sql .= $this->group_string; + } + + // Set the order_by string + if ( ! empty($this->order_string)) + { + $sql .= $this->order_string; + } + + // Set the limit via the class variables + if (isset($this->limit) && is_numeric($this->limit)) + { + $sql = $this->sql->limit($sql, $this->limit, $this->offset); + } + break; + + case "insert": + $param_count = count($this->set_array); + $params = array_fill(0, $param_count, '?'); + $sql = 'INSERT INTO '. $this->db->quote_ident($table) . + ' (' . implode(', ', $this->set_array_keys) . + ') VALUES ('.implode(', ', $params).')'; + break; + + case "update": + $sql = 'UPDATE '.$this->db->quote_ident($table). ' SET '. $this->set_string; + + // Set the where string + if ( ! empty($this->query_map)) + { + foreach($this->query_map as $q) + { + $sql .= $q['conjunction'] . $q['string']; + } + } + break; + + case "delete": + $sql = 'DELETE FROM '.$this->db->quote_ident($table); + + // Set the where string + if ( ! empty($this->query_map)) + { + foreach($this->query_map as $q) + { + $sql .= $q['conjunction'] . $q['string']; + } + } + + break; + } + + echo $sql.'
'; + + return $sql; + } +} +// End of query_builder.php \ No newline at end of file diff --git a/tests/databases/firebird-qb.php b/tests/databases/firebird-qb.php new file mode 100644 index 0000000..6e212b6 --- /dev/null +++ b/tests/databases/firebird-qb.php @@ -0,0 +1,219 @@ +type = 'firebird'; + $params->file = $dbpath; + $params->host = 'localhost'; + $params->user = 'sysdba'; + $params->pass = 'masterkey'; + $this->db = new Query_Builder($params); + + echo '
Firebird Queries
'; + } + + function TestGet() + { + $query = $this->db->get('create_test ct'); + + $this->assertTrue(is_resource($query)); + } + + function TestGetLimit() + { + $query = $this->db->get('create_test', 2); + + $this->assertTrue(is_resource($query)); + } + + function TestGetLimitSkip() + { + $query = $this->db->get('create_test', 2, 1); + + $this->assertTrue(is_resource($query)); + } + + function TestSelectWhereGet() + { + $query = $this->db->select('id, key as k, val') + ->where('id >', 1) + ->where('id <', 800) + ->get('create_test', 2, 1); + + $this->assertTrue(is_resource($query)); + } + + function TestSelectWhereGet2() + { + $query = $this->db->select('id, key as k, val') + ->where(' id ', 1) + + ->get('create_test', 2, 1); + + $this->assertTrue(is_resource($query)); + } + + function TestSelectGet() + { + $query = $this->db->select('id, key as k, val') + ->get('create_test', 2, 1); + + $this->assertTrue(is_resource($query)); + } + + function TestSelectFromGet() + { + $query = $this->db->select('id, key as k, val') + ->from('create_test ct') + ->where('id >', 1) + ->get(); + + $this->assertTrue(is_resource($query)); + } + + function TestSelectFromLimitGet() + { + $query = $this->db->select('id, key as k, val') + ->from('create_test ct') + ->where('id >', 1) + ->limit(3) + ->get(); + + $this->assertTrue(is_resource($query)); + } + + function TestOrderBy() + { + $query = $this->db->select('id, key as k, val') + ->from('create_test') + ->where('id >', 0) + ->where('id <', 9000) + ->order_by('id', 'DESC') + ->order_by('k', 'ASC') + ->limit(5,2) + ->get(); + + $this->assertTrue(is_resource($query)); + } + + function TestOrderByRand() + { + $query = $this->db->select('id, key as k, val') + ->from('create_test') + ->where('id >', 0) + ->where('id <', 9000) + ->order_by('id', 'rand') + ->limit(5,2) + ->get(); + + $this->assertTrue(is_resource($query)); + } + + function TestOrWhere() + { + $query = $this->db->select('id, key as k, val') + ->from('create_test') + ->where(' id ', 1) + ->or_where('key >', 0) + ->limit(2, 1) + ->get(); + + $this->assertTrue(is_resource($query)); + } + + /*function TestGroupBy() + { + $query = $this->db->select('id, key as k, val') + ->from('create_test') + ->where('id >', 0) + ->where('id <', 9000) + ->group_by('k') + ->group_by('val') + ->order_by('id', 'DESC') + ->order_by('k', 'ASC') + ->limit(5,2) + ->get(); + + $this->assertTrue(is_resource($query)); + }*/ + + function TestLike() + { + $query = $this->db->from('create_test') + ->like('key', 'og') + ->get(); + + $this->assertTrue(is_resource($query)); + } + + function TestWhereIn() + { + $query = $this->db->from('create_test') + ->where_in('key', array(12, 96, "works")) + ->get(); + + $this->assertTrue(is_resource($query)); + } + + function TestJoin() + { + $query = $this->db->from('create_test') + ->join('create_join cj', 'cj.id = create_test.id') + ->get(); + + $this->assertTrue(is_resource($query)); + } + + function TestInsert() + { + $query = $this->db->set('id', 4) + ->set('key', 4) + ->set('val', 5) + ->insert('create_test'); + + $this->assertTrue($query); + } + + function TestUpdate() + { + $query = $this->db->set('id', 4) + ->set('key', 'gogle') + ->set('val', 'non-word') + ->where('id', 4) + ->update('create_test'); + + $this->assertTrue($query); + } + + function TestDelete() + { + $query = $this->db->where('id', 4)->delete('create_test'); + + $this->assertTrue($query); + } + + +} \ No newline at end of file diff --git a/tests/databases/firebird.php b/tests/databases/firebird.php new file mode 100644 index 0000000..b1aa4af --- /dev/null +++ b/tests/databases/firebird.php @@ -0,0 +1,181 @@ +db = new Firebird('localhost:'.$dbpath); + $this->tables = $this->db->get_tables(); + } + + function tearDown() + { + unset($this->db); + unset($this->tables); + } + + function TestConnection() + { + $this->assertIsA($this->db, 'Firebird'); + } + + function TestGetTables() + { + $tables = $this->tables; + $this->assertTrue(is_array($tables)); + } + + function TestGetSystemTables() + { + $only_system = TRUE; + + $tables = $this->db->get_system_tables(); + + foreach($tables as $t) + { + if(stripos($t, 'rdb$') !== 0 && stripos($t, 'mon$') !== 0) + { + $only_system = FALSE; + break; + } + } + + $this->assertTrue($only_system); + } + + function TestCreateTransaction() + { + $res = $this->db->beginTransaction(); + $this->assertTrue($res); + } + + /*function TestCreateTable() + { + //Attempt to create the table + $sql = $this->db->sql->create_table('create_join', array( + 'id' => 'SMALLINT', + 'key' => 'VARCHAR(64)', + 'val' => 'BLOB SUB_TYPE TEXT' + )); + $this->db->query($sql); + + //This test fails for an unknown reason, when clearly the table exists + //Reset + $this->tearDown(); + $this->setUp(); + + //Check + $table_exists = (bool)in_array('create_test', $this->tables); + + echo "create_test exists :".(int)$table_exists.'
'; + + $this->assertTrue($table_exists); + }*/ + + + + function TestTruncate() + { + $this->db->truncate('create_test'); + + $this->assertTrue($this->db->affected_rows() > 0); + } + + function TestCommitTransaction() + { + $res = $this->db->beginTransaction(); + + $sql = 'INSERT INTO "create_test" ("id", "key", "val") VALUES (10, 12, 14)'; + $this->db->query($sql); + + $res = $this->db->commit(); + $this->assertTrue($res); + } + + function TestRollbackTransaction() + { + $res = $this->db->beginTransaction(); + + $sql = 'INSERT INTO "create_test" ("id", "key", "val") VALUES (182, 96, 43)'; + $this->db->query($sql); + + $res = $this->db->rollback(); + $this->assertTrue($res); + } + + + + function TestPreparedStatements() + { + $sql = <<db->prepare($sql); + $this->db->execute(array(1,"booger's", "Gross")); + + } + + function TestPrepareExecute() + { + $sql = <<db->prepare_execute($sql, array( + 2, "works", 'also?' + )); + + } + + function TestPrepareQuery() + { + $this->assertFalse($this->db->prepare_query('', array())); + } + + /*function TestDeleteTable() + { + //Attempt to delete the table + $sql = $this->db->sql->delete_table('create_test'); + $this->db->query($sql); + + //Reset + $this->tearDown(); + $this->setUp(); + + //Check + $table_exists = in_array('create_test', $this->tables); + $this->assertFalse($table_exists); + }*/ +} \ No newline at end of file diff --git a/tests/databases/mysql-qb.php b/tests/databases/mysql-qb.php new file mode 100644 index 0000000..2b6d235 --- /dev/null +++ b/tests/databases/mysql-qb.php @@ -0,0 +1,26 @@ +assertTrue(in_array('mysql', pdo_drivers())); + } +} \ No newline at end of file diff --git a/tests/databases/mysql.php b/tests/databases/mysql.php new file mode 100644 index 0000000..1c4a01a --- /dev/null +++ b/tests/databases/mysql.php @@ -0,0 +1,32 @@ +assertTrue(in_array('mysql', pdo_drivers())); + } +} + diff --git a/tests/databases/odbc-qb.php b/tests/databases/odbc-qb.php new file mode 100644 index 0000000..a794797 --- /dev/null +++ b/tests/databases/odbc-qb.php @@ -0,0 +1,26 @@ +assertTrue(in_array('odbc', pdo_drivers())); + } +} \ No newline at end of file diff --git a/tests/databases/odbc.php b/tests/databases/odbc.php new file mode 100644 index 0000000..aaf849e --- /dev/null +++ b/tests/databases/odbc.php @@ -0,0 +1,31 @@ +assertTrue(in_array('odbc', pdo_drivers())); + } +} \ No newline at end of file diff --git a/tests/databases/pgsql-qb.php b/tests/databases/pgsql-qb.php new file mode 100644 index 0000000..16039d5 --- /dev/null +++ b/tests/databases/pgsql-qb.php @@ -0,0 +1,26 @@ +assertTrue(in_array('pgsql', pdo_drivers())); + } +} \ No newline at end of file diff --git a/tests/databases/pgsql.php b/tests/databases/pgsql.php new file mode 100644 index 0000000..b8e5d2b --- /dev/null +++ b/tests/databases/pgsql.php @@ -0,0 +1,37 @@ +assertTrue(in_array('pgsql', pdo_drivers())); + } +} \ No newline at end of file diff --git a/tests/databases/sqlite-qb.php b/tests/databases/sqlite-qb.php new file mode 100644 index 0000000..ad06d7a --- /dev/null +++ b/tests/databases/sqlite-qb.php @@ -0,0 +1,203 @@ +type = 'sqlite'; + $params->file = $path; + $params->host = 'localhost'; + $this->db = new Query_Builder($params); + + echo '
SQLite Queries
'; + } + + function TestGet() + { + $query = $this->db->get('create_test ct'); + + $this->assertIsA($query, 'PDOStatement'); + } + + function TestGetLimit() + { + $query = $this->db->get('create_test', 2); + + $this->assertIsA($query, 'PDOStatement'); + } + + function TestGetLimitSkip() + { + $query = $this->db->get('create_test', 2, 1); + + $this->assertIsA($query, 'PDOStatement'); + } + + function TestSelectWhereGet() + { + $query = $this->db->select('id, key as k, val') + ->where('id >', 1) + ->where('id <', 900) + ->get('create_test', 2, 1); + + $this->assertIsA($query, 'PDOStatement'); + } + + function TestSelectWhereGet2() + { + $query = $this->db->select('id, key as k, val') + ->where('id !=', 1) + ->get('create_test', 2, 1); + + $this->assertIsA($query, 'PDOStatement'); + } + + function TestSelectGet() + { + $query = $this->db->select('id, key as k, val') + ->get('create_test', 2, 1); + + $this->assertIsA($query, 'PDOStatement'); + } + + function TestSelectFromGet() + { + $query = $this->db->select('id, key as k, val') + ->from('create_test ct') + ->where('id >', 1) + ->get(); + + $this->assertIsA($query, 'PDOStatement'); + } + + function TestSelectFromLimitGet() + { + $query = $this->db->select('id, key as k, val') + ->from('create_test ct') + ->where('id >', 1) + ->limit(3) + ->get(); + + $this->assertIsA($query, 'PDOStatement'); + } + + function TestOrderBy() + { + $query = $this->db->select('id, key as k, val') + ->from('create_test') + ->where('id >', 0) + ->where('id <', 9000) + ->order_by('id', 'DESC') + ->order_by('k', 'ASC') + ->limit(5,2) + ->get(); + + $this->assertIsA($query, 'PDOStatement'); + } + + function TestOrderByRandom() + { + $query = $this->db->select('id, key as k, val') + ->from('create_test') + ->where('id >', 0) + ->where('id <', 9000) + ->order_by('id', 'rand') + ->limit(5,2) + ->get(); + + $this->assertIsA($query, 'PDOStatement'); + } + + function TestGroupBy() + { + $query = $this->db->select('id, key as k, val') + ->from('create_test') + ->where('id >', 0) + ->where('id <', 9000) + ->group_by('k') + ->group_by('val') + ->order_by('id', 'DESC') + ->order_by('k', 'ASC') + ->limit(5,2) + ->get(); + + $this->assertIsA($query, 'PDOStatement'); + } + + function TestOrWhere() + { + $query = $this->db->select('id, key as k, val') + ->from('create_test') + ->where(' id ', 1) + ->or_where('key >', 0) + ->limit(2, 1) + ->get(); + + $this->assertIsA($query, 'PDOStatement'); + } + + function TestLike() + { + $query = $this->db->from('create_test') + ->like('key', 'og') + ->get(); + + $this->assertIsA($query, 'PDOStatement'); + } + + function TestJoin() + { + $query = $this->db->from('create_test') + ->join('create_join cj', 'cj.id = create_test.id') + ->get(); + + $this->assertIsA($query, 'PDOStatement'); + } + + function TestInsert() + { + $query = $this->db->set('id', 4) + ->set('key', 4) + ->set('val', 5) + ->insert('create_test'); + + $this->assertIsA($query, 'PDOStatement'); + } + + function TestUpdate() + { + $query = $this->db->set('id', 4) + ->set('key', 'gogle') + ->set('val', 'non-word') + ->where('id', 4) + ->update('create_test'); + + $this->assertIsA($query, 'PDOStatement'); + } + + function TestDelete() + { + $query = $this->db->where('id', 4)->delete('create_test'); + + $this->assertIsA($query, 'PDOStatement'); + } +} \ No newline at end of file diff --git a/tests/databases/sqlite.php b/tests/databases/sqlite.php new file mode 100644 index 0000000..3bd5eb4 --- /dev/null +++ b/tests/databases/sqlite.php @@ -0,0 +1,163 @@ +db = new SQLite($path); + } + + function tearDown() + { + unset($this->db); + } + + function TestConnection() + { + $this->assertIsA($this->db, 'SQLite'); + } + + function TestGetTables() + { + $tables = $this->db->get_tables(); + $this->assertTrue(is_array($tables)); + } + + function TestGetSystemTables() + { + $tables = $this->db->get_system_tables(); + + $this->assertTrue(is_array($tables)); + } + + function TestCreateTransaction() + { + $res = $this->db->beginTransaction(); + $this->assertTrue($res); + } + + function TestCreateTable() + { + //Attempt to create the table + $sql = $this->db->sql->create_table('create_test', + array( + 'id' => 'INTEGER', + 'key' => 'TEXT', + 'val' => 'TEXT', + ), + array( + 'id' => 'PRIMARY KEY' + ) + ); + $this->db->query($sql); + + //Attempt to create the table + $sql = $this->db->sql->create_table('create_join', + array( + 'id' => 'INTEGER', + 'key' => 'TEXT', + 'val' => 'TEXT', + ), + array( + 'id' => 'PRIMARY KEY' + ) + ); + $this->db->query($sql); + + //Check + $dbs = $this->db->get_tables(); + $this->assertEqual($dbs['create_test'], 'CREATE TABLE "create_test" (id INTEGER PRIMARY KEY, key TEXT , val TEXT )'); + } + + function TestTruncate() + { + $this->db->truncate('create_test'); + $this->assertIsA($this->db->affected_rows(), 'int'); + } + + function TestPreparedStatements() + { + $sql = <<db->prepare_query($sql, array(1,"boogers", "Gross")); + + $statement->execute(); + + } + + function TestPrepareExecute() + { + $sql = <<db->prepare_execute($sql, array( + 2, "works", 'also?' + )); + + } + + function TestCommitTransaction() + { + $res = $this->db->beginTransaction(); + + $sql = 'INSERT INTO "create_test" ("id", "key", "val") VALUES (10, 12, 14)'; + $this->db->query($sql); + + $res = $this->db->commit(); + $this->assertTrue($res); + } + + function TestRollbackTransaction() + { + $res = $this->db->beginTransaction(); + + $sql = 'INSERT INTO "create_test" ("id", "key", "val") VALUES (182, 96, 43)'; + $this->db->query($sql); + + $res = $this->db->rollback(); + $this->assertTrue($res); + } + + // This is really time intensive ! Run only when needed + /*function TestDeleteTable() + { + //Make sure the table exists to delete + $dbs = $this->db->get_tables(); + $this->assertTrue(isset($dbs['create_test'])); + + //Attempt to delete the table + $sql = $this->db->sql->delete_table('create_test'); + $this->db->query($sql); + + //Check + $dbs = $this->db->get_tables(); + $this->assertFalse(in_array('create_test', $dbs)); + }*/ + +} \ No newline at end of file diff --git a/tests/index.php b/tests/index.php new file mode 100644 index 0000000..0b463cc --- /dev/null +++ b/tests/index.php @@ -0,0 +1,70 @@ +