* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
abstract class Horde_Db_Adapter_Base_Schema
{
/**
* A Horde_Db_Adapter instance.
*
* @var Horde_Db_Adapter_Base
*/
protected $_adapter = null;
/**
* List of public methods supported by the attached adapter.
*
* Method names are in the keys.
*
* @var array
*/
protected $_adapterMethods = array();
/*##########################################################################
# Construct/Destruct
##########################################################################*/
/**
* Constructor.
*
* @param Horde_Db_Adapter_Base $adapter A Horde_Db_Adapter instance.
*/
public function __construct(Horde_Db_Adapter $adapter)
{
$this->setAdapter($adapter);
}
/**
* Setter for a Horde_Db_Adapter instance.
*
* @param Horde_Db_Adapter $adapter A Horde_Db_Adapter instance.
*/
public function setAdapter(Horde_Db_Adapter $adapter)
{
$this->_adapter = $adapter;
$this->_adapterMethods = array_flip(get_class_methods($adapter));
}
/*##########################################################################
# Object factories
##########################################################################*/
/**
* Factory for Column objects.
*
* @param string $name The column's name, such as "supplier_id" in
* "supplier_id int(11)".
* @param string $default The type-casted default value, such as "new" in
* "sales_stage varchar(20) default 'new'".
* @param string $sqlType Used to extract the column's type, length and
* signed status, if necessary. For example
* "varchar" and "60" in "company_name varchar(60)"
* or "unsigned => true" in "int(10) UNSIGNED".
* @param boolean $null Whether this column allows NULL values.
*
* @return Horde_Db_Adapter_Base_Column A column object.
*/
public function makeColumn($name, $default, $sqlType = null, $null = true)
{
return new Horde_Db_Adapter_Base_Column($name, $default, $sqlType, $null);
}
/**
* Factory for ColumnDefinition objects.
*
* @return Horde_Db_Adapter_Base_ColumnDefinition A column definition
* object.
*/
public function makeColumnDefinition(
$base, $name, $type, $limit = null, $precision = null, $scale = null,
$unsigned = null, $default = null, $null = null, $autoincrement = null)
{
return new Horde_Db_Adapter_Base_ColumnDefinition(
$base, $name, $type, $limit, $precision, $scale, $unsigned,
$default, $null, $autoincrement);
}
/**
* Factory for Index objects.
*
* @param string $table The table the index is on.
* @param string $name The index's name.
* @param boolean $primary Is this a primary key?
* @param boolean $unique Is this a unique index?
* @param array $columns The columns this index covers.
*
* @return Horde_Db_Adapter_Base_Index An index object.
*/
public function makeIndex($table, $name, $primary, $unique, $columns)
{
return new Horde_Db_Adapter_Base_Index($table, $name, $primary, $unique, $columns);
}
/**
* Factory for Table objects.
*
* @return Horde_Db_Adapter_Base_Table A table object.
*/
public function makeTable($name, $primaryKey, $columns, $indexes)
{
return new Horde_Db_Adapter_Base_Table($name, $primaryKey, $columns, $indexes);
}
/**
* Factory for TableDefinition objects.
*
* @return Horde_Db_Adapter_Base_TableDefinition A table definition object.
*/
public function makeTableDefinition($name, $base, $options = array())
{
return new Horde_Db_Adapter_Base_TableDefinition($name, $base, $options);
}
/*##########################################################################
# Object composition
##########################################################################*/
/**
* Delegates calls to the adapter object.
*
* @param string $method A method name.
* @param array $args Method parameters.
*
* @return mixed The method call result.
* @throws BadMethodCallException if method doesn't exist in the adapter.
*/
public function __call($method, $args)
{
if (isset($this->_adapterMethods[$method])) {
return call_user_func_array(array($this->_adapter, $method), $args);
}
throw new BadMethodCallException('Call to undeclared method "' . $method . '"');
}
/**
* Delegates access to $_cache and $_logger to the adapter object.
*
* @param string $key Property name. Only '_cache' and '_logger' are
* supported.
*
* @return object The request property object.
*/
public function __get($key)
{
if ($key == '_cache' || $key == '_logger') {
$getter = 'get' . ucfirst(substr($key, 1));
return $this->_adapter->$getter();
}
}
/*##########################################################################
# Quoting
##########################################################################*/
/**
* Quotes the column value to help prevent SQL injection attacks.
*
* This method makes educated guesses on the scalar type based on the
* passed value. Make sure to correctly cast the value and/or pass the
* $column parameter to get the best results.
*
* @param mixed $value The scalar value to quote, a Horde_Db_Value,
* Horde_Date, or DateTime instance, or an object
* implementing quotedId().
* @param object $column An object implementing getType().
*
* @return string The correctly quoted value.
*/
public function quote($value, $column = null)
{
if (is_object($value) && is_callable(array($value, 'quotedId'))) {
return $value->quotedId();
}
if ($value instanceof Horde_Db_Value) {
return $value->quote($this->_adapter);
}
$type = isset($column) ? $column->getType() : null;
if (is_null($value)) {
return 'NULL';
} elseif ($value === true) {
return $type == 'integer' ? '1' : $this->quoteTrue();
} elseif ($value === false) {
return $type == 'integer' ? '0' : $this->quoteFalse();
} elseif (is_float($value)) {
return sprintf('%F', $value);
} elseif (is_int($value)) {
return $value;
} elseif ($value instanceof DateTime || $value instanceof Horde_Date) {
return $this->_adapter->quoteString($type == 'integer'
? $value->format('U')
: $value->format('Y-m-d H:i:s'));
} elseif ($type == 'integer') {
return (int)$value;
} elseif ($type == 'float') {
return sprintf('%F', $value);
} else {
return $this->_adapter->quoteString($value);
}
}
/**
* Quotes a string, escaping any ' (single quote) and \ (backslash)
* characters.
*
* @param string $string A string to escape.
*
* @return string The escaped and quoted string.
*/
public function quoteString($string)
{
return "'" . str_replace(array('\\', '\''), array('\\\\', '\\\''), $string) . "'";
}
/**
* Returns a quoted form of the column name.
*
* @param string $name A column name.
*
* @return string The quoted column name.
*/
abstract public function quoteColumnName($name);
/**
* Returns a quoted form of the table name.
*
* Defaults to column name quoting.
*
* @param string $name A table name.
*
* @return string The quoted table name.
*/
public function quoteTableName($name)
{
return $this->quoteColumnName($name);
}
/**
* Returns a quoted boolean true.
*
* @return string The quoted boolean true.
*/
public function quoteTrue()
{
return "'t'";
}
/**
* Returns a quoted boolean false.
*
* @return string The quoted boolean false.
*/
public function quoteFalse()
{
return "'f'";
}
/**
* Returns a quoted date value.
*
* @param mixed A date value that can be casted to string.
*
* @return string The quoted date value.
*/
public function quoteDate($value)
{
return $this->quoteString((string)$value);
}
/**
* Returns a quoted binary value.
*
* @param mixed A binary value.
*
* @return string The quoted binary value.
*/
public function quoteBinary($value)
{
return $this->quoteString($value);
}
/*##########################################################################
# Schema Statements
##########################################################################*/
/**
* Returns a hash of mappings from the abstract data types to the native
* database types.
*
* See TableDefinition::column() for details on the recognized abstract
* data types.
*
* @see TableDefinition::column()
*
* @return array A database type map.
*/
public function nativeDatabaseTypes()
{
return array();
}
/**
* Returns the maximum length a table alias can have.
*
* @return integer The maximum table alias length.
*/
public function tableAliasLength()
{
return 255;
}
/**
* Converts a table name into a suitable table alias.
*
* @param string $tableName A table name.
*
* @return string A possible alias name for the table.
*/
public function tableAliasFor($tableName)
{
$alias = substr($tableName, 0, $this->tableAliasLength());
return str_replace('.', '_', $alias);
}
/**
* Returns a list of all tables of the current database.
*
* @return array A table list.
*/
abstract public function tables();
/**
* Returns a Horde_Db_Adapter_Base_Table object for a table.
*
* @param string $tableName A table name.
* @param string $name (can be removed?)
*
* @return Horde_Db_Adapter_Base_Table A table object.
*/
public function table($tableName, $name = null)
{
return $this->makeTable(
$tableName,
$this->primaryKey($tableName),
$this->columns($tableName, $name),
$this->indexes($tableName, $name)
);
}
/**
* Returns a table's primary key.
*
* @param string $tableName A table name.
* @param string $name (can be removed?)
*
* @return Horde_Db_Adapter_Base_Index The primary key index object.
*/
abstract public function primaryKey($tableName, $name = null);
/**
* Returns a list of tables indexes.
*
* @param string $tableName A table name.
* @param string $name (can be removed?)
*
* @return array A list of Horde_Db_Adapter_Base_Index objects.
*/
abstract public function indexes($tableName, $name = null);
/**
* Returns a list of table columns.
*
* @param string $tableName A table name.
* @param string $name (can be removed?)
*
* @return array A list of Horde_Db_Adapter_Base_Column objects.
*/
abstract public function columns($tableName, $name = null);
/**
* Creates a new table.
*
* The $options hash can include the following keys:
* - autoincrementKey (string|array):
* The name of the autoincrementing primary key, if one is to be added
* automatically. Defaults to "id".
* - options (array):
* Any extra options you want appended to the table definition.
* - temporary (boolean):
* Make a temporary table.
* - force (boolean):
* Set to true or false to drop the table before creating it.
* Defaults to false.
*
* Examples:
*
* // Add a backend specific option to the generated SQL (MySQL)
* $schema->createTable('suppliers', array('options' => 'ENGINE=InnoDB DEFAULT CHARSET=utf8')));
*
* generates:
*
* CREATE TABLE suppliers (
* id int(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
* ) ENGINE=InnoDB DEFAULT CHARSET=utf8
*
*
*
* // Rename the primary key column
* $table = $schema->createTable('objects', array('autoincrementKey' => 'guid'));
* $table->column('name', 'string', array('limit' => 80));
* $table->end();
*
* generates:
*
* CREATE TABLE objects (
* guid int(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
* name varchar(80)
* )
*
*
*
* // Do not add a primary key column, use fluent interface, use type
* // method.
* $schema->createTable('categories_suppliers', array('autoincrementKey' => false))
* ->column('category_id', 'integer')
* ->integer('supplier_id')
* ->end();
*
* generates:
*
* CREATE TABLE categories_suppliers (
* category_id int(11),
* supplier_id int(11)
* )
*
*
* See also Horde_Db_Adapter_Base_TableDefinition::column() for details on
* how to create columns.
*
* @param string $name A table name.
* @param array $options A list of table options, see the method
* description.
*
* @return Horde_Db_Adapter_Base_TableDefinition The definition of the
* created table.
*/
public function createTable($name, $options = array())
{
$tableDefinition = $this->makeTableDefinition($name, $this, $options);
if (isset($options['autoincrementKey'])) {
if ($options['autoincrementKey'] === true ||
$options['autoincrementKey'] === 'true' ||
$options['autoincrementKey'] === 't' ||
$options['autoincrementKey'] === 1 ||
$options['autoincrementKey'] === '1') {
$pk = 'id';
} elseif ($options['autoincrementKey'] === false ||
$options['autoincrementKey'] === 'false' ||
$options['autoincrementKey'] === 'f' ||
$options['autoincrementKey'] === 0 ||
$options['autoincrementKey'] === '0') {
$pk = false;
} else {
$pk = $options['autoincrementKey'];
}
} else {
$pk = 'id';
}
if ($pk != false) {
$tableDefinition->primaryKey($pk);
}
return $tableDefinition;
}
/**
* Finishes and executes table creation.
*
* @param string|Horde_Db_Adapter_Base_TableDefinition $name
* A table name or object.
* @param array $options
* A list of options. See createTable().
*/
public function endTable($name, $options = array())
{
if ($name instanceof Horde_Db_Adapter_Base_TableDefinition) {
$tableDefinition = $name;
$options = array_merge($tableDefinition->getOptions(), $options);
} else {
$tableDefinition = $this->createTable($name, $options);
}
// Drop previous table.
if (isset($options['force'])) {
$this->dropTable($tableDefinition->getName(), $options);
}
$temp = !empty($options['temporary']) ? 'TEMPORARY' : null;
$opts = !empty($options['options']) ? $options['options'] : null;
$sql = sprintf("CREATE %s TABLE %s (\n%s\n) %s",
$temp,
$this->quoteTableName($tableDefinition->getName()),
$tableDefinition->toSql(),
$opts);
return $this->execute($sql);
}
/**
* Renames a table.
*
* @param string $name A table name.
* @param string $newName The new table name.
*/
abstract public function renameTable($name, $newName);
/**
* Drops a table from the database.
*
* @param string $name A table name.
*/
public function dropTable($name)
{
$this->_clearTableCache($name);
return $this->execute('DROP TABLE ' . $this->quoteTableName($name));
}
/**
* Adds a new column to a table.
*
* @param string $tableName A table name.
* @param string $columnName A column name.
* @param string $type A data type.
* @param array $options Column options. See
* Horde_Db_Adapter_Base_TableDefinition#column()
* for details.
*/
public function addColumn($tableName, $columnName, $type,
$options = array())
{
$this->_clearTableCache($tableName);
$options = array_merge(
array('limit' => null,
'precision' => null,
'scale' => null,
'unsigned' => null),
$options);
$sql = sprintf('ALTER TABLE %s ADD %s %s',
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName),
$this->typeToSql($type,
$options['limit'],
$options['precision'],
$options['scale'],
$options['unsigned']));
$sql = $this->addColumnOptions($sql, $options);
return $this->execute($sql);
}
/**
* Removes a column from a table.
*
* @param string $tableName A table name.
* @param string $columnName A column name.
*/
public function removeColumn($tableName, $columnName)
{
$this->_clearTableCache($tableName);
$sql = sprintf('ALTER TABLE %s DROP %s',
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName));
return $this->execute($sql);
}
/**
* Changes an existing column's definition.
*
* @param string $tableName A table name.
* @param string $columnName A column name.
* @param string $type A data type.
* @param array $options Column options. See
* Horde_Db_Adapter_Base_TableDefinition#column()
* for details.
*/
abstract public function changeColumn($tableName, $columnName, $type, $options = array());
/**
* Sets a new default value for a column.
*
* If you want to set the default value to NULL, you are out of luck. You
* need to execute the apppropriate SQL statement yourself.
*
* @param string $tableName A table name.
* @param string $columnName A column name.
* @param mixed $default The new default value.
*/
abstract public function changeColumnDefault($tableName, $columnName, $default);
/**
* Renames a column.
*
* @param string $tableName A table name.
* @param string $columnName A column name.
* @param string $newColumnName The new column name.
*/
abstract public function renameColumn($tableName, $columnName, $newColumnName);
/**
* Adds a primary key to a table.
*
* @param string $tableName A table name.
* @param string|array $columnName One or more column names.
*
* @throws Horde_Db_Exception
*/
public function addPrimaryKey($tableName, $columns)
{
$this->_clearTableCache($tableName);
$columns = (array)$columns;
$sql = sprintf('ALTER TABLE %s ADD PRIMARY KEY (%s)',
$this->quoteTableName($tableName),
implode(', ', $columns));
return $this->execute($sql);
}
/**
* Removes a primary key from a table.
*
* @param string $tableName A table name.
*
* @throws Horde_Db_Exception
*/
abstract public function removePrimaryKey($tableName);
/**
* Adds a new index to a table.
*
* The index will be named after the table and the first column names,
* unless you pass 'name' as an option.
*
* When creating an index on multiple columns, the first column is used as
* a name for the index. For example, when you specify an index on two
* columns 'first' and 'last', the DBMS creates an index for both columns
* as well as an index for the first colum 'first'. Using just the first
* name for this index makes sense, because you will never have to create a
* singular index with this name.
*
* Examples:
*
* Creating a simple index
*
* $schema->addIndex('suppliers', 'name');
*
* generates
*
* CREATE INDEX suppliers_name_index ON suppliers(name)
*
*
* Creating a unique index
*
* $schema->addIndex('accounts',
* array('branch_id', 'party_id'),
* array('unique' => true));
*
* generates
*
* CREATE UNIQUE INDEX accounts_branch_id_index ON accounts(branch_id, party_id)
*
*
* Creating a named index
*
* $schema->addIndex('accounts',
* array('branch_id', 'party_id'),
* array('unique' => true, 'name' => 'by_branch_party'));
*
* generates
*
* CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id)
*
*
* @param string $tableName A table name.
* @param string|array $columnName One or more column names.
* @param array $options Index options:
* - name: (string) the index name.
* - unique: (boolean) create a unique
* index?
*/
public function addIndex($tableName, $columnName, $options = array())
{
$this->_clearTableCache($tableName);
$columnNames = (array)$columnName;
$indexName = empty($options['name'])
? $this->indexName($tableName, array('column' => $columnNames))
: $options['name'];
foreach ($columnNames as &$colName) {
$colName = $this->quoteColumnName($colName);
}
$sql = sprintf('CREATE %s INDEX %s ON %s (%s)',
empty($options['unique']) ? null : 'UNIQUE',
$this->quoteColumnName($indexName),
$this->quoteTableName($tableName),
implode(', ', $columnNames));
return $this->execute($sql);
}
/**
* Removes an index from a table.
*
* Examples:
*
* Remove the suppliers_name_index in the suppliers table:
*
* $schema->removeIndex('suppliers', 'name');
*
*
* Remove the index named accounts_branch_id in the accounts table:
*
* $schema->removeIndex('accounts', array('column' => 'branch_id'));
*
*
* Remove the index named by_branch_party in the accounts table:
*
* $schema->removeIndex('accounts', array('name' => 'by_branch_party'));
*
*
* You can remove an index on multiple columns by specifying the first
* column:
*
* $schema->addIndex('accounts', array('username', 'password'))
* $schema->removeIndex('accounts', 'username');
*
*
* @param string $tableName A table name.
* @param string|array $options Either a column name or index options:
* - name: (string) the index name.
* - column: (string|array) column name(s).
*/
public function removeIndex($tableName, $options = array())
{
$this->_clearTableCache($tableName);
$index = $this->indexName($tableName, $options);
$sql = sprintf('DROP INDEX %s ON %s',
$this->quoteColumnName($index),
$this->quoteTableName($tableName));
return $this->execute($sql);
}
/**
* Builds the name for an index.
*
* @param string $tableName A table name.
* @param string|array $options Either a column name or index options:
* - column: (string|array) column name(s).
* - name: (string) the index name to fall
* back to if no column names specified.
*/
public function indexName($tableName, $options = array())
{
if (!is_array($options)) {
$options = array('column' => $options);
}
if (isset($options['column'])) {
$columns = (array)$options['column'];
return "index_{$tableName}_on_" . implode('_and_', $columns);
}
if (isset($options['name'])) {
return $options['name'];
}
throw new Horde_Db_Exception('You must specify the index name');
}
/**
* Recreates, i.e. drops then creates a database.
*
* @param string $name A database name.
*/
public function recreateDatabase($name)
{
$this->dropDatabase($name);
return $this->createDatabase($name);
}
/**
* Creates a database.
*
* @param string $name A database name.
* @param array $options Database options.
*/
abstract public function createDatabase($name, $options = array());
/**
* Drops a database.
*
* @param string $name A database name.
*/
abstract public function dropDatabase($name);
/**
* Returns the name of the currently selected database.
*
* @return string The database name.
*/
abstract public function currentDatabase();
/**
* Generates the SQL definition for a column type.
*
* @param string $type A column type.
* @param integer $limit Maximum column length (non decimal type only)
* @param integer $precision The number precision (decimal type only).
* @param integer $scale The number scaling (decimal columns only).
* @param boolean $unsigned Whether the column is an unsigned number
* (non decimal columns only).
*
* @return string The SQL definition. If $type is not one of the
* internally supported types, $type is returned unchanged.
*/
public function typeToSql($type, $limit = null, $precision = null,
$scale = null, $unsigned = null)
{
$natives = $this->nativeDatabaseTypes();
$native = isset($natives[$type]) ? $natives[$type] : null;
if (empty($native)) {
return $type;
}
$sql = is_array($native) ? $native['name'] : $native;
if ($type == 'decimal') {
$nativePrec = isset($native['precision']) ? $native['precision'] : null;
$nativeScale = isset($native['scale']) ? $native['scale'] : null;
$precision = !empty($precision) ? $precision : $nativePrec;
$scale = !empty($scale) ? $scale : $nativeScale;
if ($precision) {
$sql .= $scale ? "($precision, $scale)" : "($precision)";
}
} else {
$nativeLimit = is_array($native) ? $native['limit'] : null;
// If there is no explicit limit, adjust $nativeLimit for unsigned
// integers.
if (!empty($unsigned) && empty($limit) && is_integer($nativeLimit)) {
$nativeLimit--;
}
if ($limit = !empty($limit) ? $limit : $nativeLimit) {
$sql .= "($limit)";
}
}
return $sql;
}
/**
* Adds default/null options to column SQL definitions.
*
* @param string $sql Existing SQL definition for a column.
* @param array $options Column options:
* - null: (boolean) Whether to allow NULL values.
* - default: (mixed) Default column value.
* - autoincrement: (boolean) Whether the column is
* an autoincrement column. Driver depedendent.
*
* @return string The manipulated SQL definition.
*/
public function addColumnOptions($sql, $options)
{
/* 'autoincrement' is not handled here - it varies too much between
* DBs. Do autoincrement-specific handling in the driver. */
if (isset($options['null']) && $options['null'] === false) {
$sql .= ' NOT NULL';
}
if (isset($options['default'])) {
$default = $options['default'];
$column = isset($options['column']) ? $options['column'] : null;
$sql .= ' DEFAULT ' . $this->quote($default, $column);
}
return $sql;
}
/**
* Generates a DISTINCT clause for SELECT queries.
*
*
* $connection->distinct('posts.id', 'posts.created_at DESC')
*
*
* @param string $columns A column list.
* @param string $orderBy An ORDER clause.
*
* @return string The generated DISTINCT clause.
*/
public function distinct($columns, $orderBy = null)
{
return 'DISTINCT ' . $columns;
}
/**
* Adds an ORDER BY clause to an existing query.
*
* @param string $sql An SQL query to manipulate.
* @param array $options Options:
* - order: Order column an direction.
*
* @return string The manipulated SQL query.
*/
public function addOrderByForAssocLimiting($sql, $options)
{
return $sql . 'ORDER BY ' . $options['order'];
}
/**
* Generates an INTERVAL clause for SELECT queries.
*
* @deprecated since version 1.2.0. This function does not work with SQLite
* as a backend so you should avoid using it. Use "modifyDate()" instead.
*
* @param string $interval The interval.
* @param string $precision The precision.
*
* @return string The generated INTERVAL clause.
*/
public function interval($interval, $precision)
{
return 'INTERVAL ' . $precision . ' ' . $interval;
}
/**
* Generates a modified date for SELECT queries.
*
* @param string $reference The reference date - this is a column
* referenced in the SELECT.
* @param string $operator Add or subtract time? (+/-)
* @param integer $amount The shift amount (number of days if $interval
* is DAY, etc).
* @param string $interval The interval (SECOND, MINUTE, HOUR, DAY,
* MONTH, YEAR).
*
* @return string The generated INTERVAL clause.
*/
public function modifyDate($reference, $operator, $amount, $interval)
{
if (!is_int($amount)) {
throw new InvalidArgumentException('$amount parameter must be an integer');
}
return sprintf('%s %s INTERVAL \'%s\' %s',
$reference,
$operator,
$amount,
$interval);
}
/**
* Returns an expression using the specified operator.
*
* @param string $lhs The column or expression to test.
* @param string $op The operator.
* @param string $rhs The comparison value.
* @param boolean $bind If true, the method returns the query and a list
* of values suitable for binding as an array.
* @param array $params Any additional parameters for the operator.
*
* @return string|array The SQL test fragment, or an array containing the
* query and a list of values if $bind is true.
*/
public function buildClause($lhs, $op, $rhs, $bind = false,
$params = array())
{
$lhs = $this->_escapePrepare($lhs);
switch ($op) {
case '|':
case '&':
if ($bind) {
return array($lhs . ' ' . $op . ' ?',
array((int)$rhs));
}
return $lhs . ' ' . $op . ' ' . (int)$rhs;
case '~':
if ($bind) {
return array($lhs . ' ' . $op . ' ?', array($rhs));
}
return $lhs . ' ' . $op . ' ' . $rhs;
case 'IN':
if ($bind) {
if (is_array($rhs)) {
return array($lhs . ' IN (?' . str_repeat(', ?', count($rhs) - 1) . ')', $rhs);
}
/* We need to bind each member of the IN clause separately to
* ensure proper quoting. */
if (substr($rhs, 0, 1) == '(') {
$rhs = substr($rhs, 1);
}
if (substr($rhs, -1) == ')') {
$rhs = substr($rhs, 0, -1);
}
$ids = preg_split('/\s*,\s*/', $rhs);
return array($lhs . ' IN (?' . str_repeat(', ?', count($ids) - 1) . ')', $ids);
}
if (is_array($rhs)) {
return $lhs . ' IN ' . implode(', ', $rhs);
}
return $lhs . ' IN ' . $rhs;
case 'LIKE':
$query = 'LOWER(%s) LIKE LOWER(%s)';
if ($bind) {
if (empty($params['begin'])) {
return array(sprintf($query, $lhs, '?'),
array('%' . $rhs . '%'));
}
return array(sprintf('(' . $query . ' OR ' . $query . ')',
$lhs, '?', $lhs, '?'),
array($rhs . '%', '% ' . $rhs . '%'));
}
if (empty($params['begin'])) {
return sprintf($query,
$lhs,
$this->_escapePrepare($this->quote('%' . $rhs . '%')));
}
return sprintf('(' . $query . ' OR ' . $query . ')',
$lhs,
$this->_escapePrepare($this->quote($rhs . '%')),
$lhs,
$this->_escapePrepare($this->quote('% ' . $rhs . '%')));
default:
if ($bind) {
return array($lhs . ' ' . $this->_escapePrepare($op) . ' ?', array($rhs));
}
return $lhs . ' ' . $this->_escapePrepare($op . ' ' . $this->quote($rhs));
}
}
/**
* Escapes all characters in a string that are placeholders for
* prepare/execute methods.
*
* @param string $query A string to escape.
*
* @return string The correctly escaped string.
*/
protected function _escapePrepare($query)
{
return preg_replace('/[?!&]/', '\\\\$0', $query);
}
/*##########################################################################
# Protected
##########################################################################*/
/**
* Clears the cache for tables when altering them.
*
* @param string $tableName A table name.
*/
protected function _clearTableCache($tableName)
{
$this->_cache->set('tables/columns/' . $tableName, '');
$this->_cache->set('tables/indexes/' . $tableName, '');
}
}
Horde_Db-2.0.4/lib/Horde/Db/Adapter/Base/Table.php 0000664 0001750 0001750 00000010777 12205351473 017433 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
class Horde_Db_Adapter_Base_Table implements ArrayAccess, IteratorAggregate
{
/**
* The table's name.
*
* @var string
*/
protected $_name;
protected $_primaryKey;
protected $_columns;
protected $_indexes;
/*##########################################################################
# Construct/Destruct
##########################################################################*/
/**
* Constructor.
*
* @param string $name The table's name.
*/
public function __construct($name, $primaryKey, $columns, $indexes)
{
$this->_name = $name;
$this->_primaryKey = $primaryKey;
$this->_columns = $columns;
$this->_indexes = $indexes;
}
/*##########################################################################
# Accessor
##########################################################################*/
/**
* @return string
*/
public function getName()
{
return $this->_name;
}
/**
* @return mixed
*/
public function getPrimaryKey()
{
return $this->_primaryKey;
}
/**
* @return array
*/
public function getColumns()
{
return $this->_columns;
}
/**
* @return Horde_Db_Adapter_Base_Column
*/
public function getColumn($column)
{
return isset($this->_columns[$column]) ? $this->_columns[$column] : null;
}
/**
* @return array
*/
public function getColumnNames()
{
$names = array();
foreach ($this->_columns as $column) {
$names[] = $column->getName();
}
return $names;
}
/**
* @return array
*/
public function getIndexes()
{
return $this->_indexes;
}
/**
* @return array
*/
public function getIndexNames()
{
$names = array();
foreach ($this->_indexes as $index) {
$names[] = $index->getName();
}
return $names;
}
/*##########################################################################
# Object composition
##########################################################################*/
public function __get($key)
{
return $this->getColumn($key);
}
public function __isset($key)
{
return isset($this->_columns[$key]);
}
/*##########################################################################
# ArrayAccess
##########################################################################*/
/**
* ArrayAccess: Check if the given offset exists
*
* @param int $offset
* @return boolean
*/
public function offsetExists($offset)
{
return isset($this->_columns[$offset]);
}
/**
* ArrayAccess: Return the value for the given offset.
*
* @param int $offset
* @return object {@link {@Horde_Db_Adapter_Base_ColumnDefinition}
*/
public function offsetGet($offset)
{
return $this->getColumn($offset);
}
/**
* ArrayAccess: Set value for given offset
*
* @param int $offset
* @param mixed $value
*/
public function offsetSet($offset, $value)
{
}
/**
* ArrayAccess: remove element
*
* @param int $offset
*/
public function offsetUnset($offset)
{
}
/*##########################################################################
# IteratorAggregate
##########################################################################*/
public function getIterator()
{
return new ArrayIterator($this->_columns);
}
/*##########################################################################
# Protected
##########################################################################*/
}
Horde_Db-2.0.4/lib/Horde/Db/Adapter/Base/TableDefinition.php 0000664 0001750 0001750 00000022676 12205351473 021445 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
class Horde_Db_Adapter_Base_TableDefinition implements ArrayAccess, IteratorAggregate
{
protected $_name = null;
protected $_base = null;
protected $_options = null;
protected $_columns = null;
protected $_primaryKey = null;
protected $_columntypes = array('string', 'text', 'integer', 'float',
'datetime', 'timestamp', 'time', 'date', 'binary', 'boolean');
/**
* Constructor.
*
* @param string $name
* @param Horde_Db_Adapter_Base_Schema $base
* @param array $options
*/
public function __construct($name, $base, $options = array())
{
$this->_name = $name;
$this->_base = $base;
$this->_options = $options;
$this->_columns = array();
}
/**
* @return string
*/
public function getName()
{
return $this->_name;
}
/**
* @return array
*/
public function getOptions()
{
return $this->_options;
}
/**
* @param string $name
*/
public function primaryKey($name)
{
if (is_scalar($name) && $name !== false) {
$natives = $this->_native();
$this->column($name, $natives['autoincrementKey']);
}
$this->_primaryKey = $name;
}
/**
* Adds a new column to the table definition.
*
* Examples:
*
* // Assuming $def is an instance of Horde_Db_Adapter_Base_TableDefinition
*
* $def->column('granted', 'boolean');
* // => granted BOOLEAN
*
* $def->column('picture', 'binary', 'limit' => 4096);
* // => picture BLOB(4096)
*
* $def->column('sales_stage', 'string', array('limit' => 20, 'default' => 'new', 'null' => false));
* // => sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL
*
*
* @param string $type Column type, one of:
* autoincrementKey, string, text, integer, float,
* datetime, timestamp, time, date, binary, boolean.
* @param array $options Column options:
* - limit: (integer) Maximum column length (string,
* text, binary or integer columns only)
* - default: (mixed) The column's default value.
* You cannot explicitly set the default value to
* NULL. Simply leave off this option if you want
* a NULL default value.
* - null: (boolean) Whether NULL values are allowed
* in the column.
* - precision: (integer) The number precision
* (float columns only).
* - scale: (integer) The number scaling (float
* columns only).
* - unsigned: (boolean) Whether the column is an
* unsigned number (integer columns only).
* - autoincrement: (boolean) Whether the column is
* an autoincrement column. Restrictions are
* RDMS specific.
*
* @return Horde_Db_Adapter_Base_TableDefinition This object.
*/
public function column($name, $type, $options = array())
{
$options = array_merge(
array('limit' => null,
'precision' => null,
'scale' => null,
'unsigned' => null,
'default' => null,
'null' => null,
'autoincrement' => null),
$options);
$column = $this->_base->makeColumnDefinition($this->_base, $name, $type);
$column->setLimit($options['limit']);
$column->setPrecision($options['precision']);
$column->setScale($options['scale']);
$column->setUnsigned($options['unsigned']);
$column->setDefault($options['default']);
$column->setNull($options['null']);
$column->setAutoIncrement($options['autoincrement']);
$this[$name] ? $this[$name] = $column : $this->_columns[] = $column;
return $this;
}
/**
* Adds created_at and updated_at columns to the table.
*/
public function timestamps()
{
return $this->column('created_at', 'datetime')
->column('updated_at', 'datetime');
}
/**
* Add one or several references to foreign keys
*
* This method returns self.
*/
public function belongsTo($columns)
{
if (!is_array($columns)) { $columns = array($columns); }
foreach ($columns as $col) {
$this->column($col . '_id', 'integer');
}
return $this;
}
/**
* Alias for the belongsTo() method
*
* This method returns self.
*/
public function references($columns)
{
return $this->belongsTo($columns);
}
/**
* Use __call to provide shorthand column creation ($this->integer(), etc.)
*/
public function __call($method, $arguments)
{
if (!in_array($method, $this->_columntypes)) {
throw new BadMethodCallException('Call to undeclared method "' . $method . '"');
}
if (count($arguments) > 0 && count($arguments) < 3) {
return $this->column($arguments[0], $method,
isset($arguments[1]) ? $arguments[1] : array());
}
throw new BadMethodCallException('Method "'.$method.'" takes two arguments');
}
/**
* Wrap up table creation block & create the table
*/
public function end()
{
return $this->_base->endTable($this);
}
/**
* Returns a String whose contents are the column definitions
* concatenated together. This string can then be pre and appended to
* to generate the final SQL to create the table.
*
* @return string
*/
public function toSql()
{
$cols = array();
foreach ($this->_columns as $col) {
$cols[] = $col->toSql();
}
$sql = ' ' . implode(", \n ", $cols);
// Specify composite primary keys as well
if (is_array($this->_primaryKey)) {
$pk = array();
foreach ($this->_primaryKey as $pkColumn) {
$pk[] = $this->_base->quoteColumnName($pkColumn);
}
$sql .= ", \n PRIMARY KEY(" . implode(', ', $pk) . ')';
}
return $sql;
}
public function __toString()
{
return $this->toSql();
}
/*##########################################################################
# ArrayAccess
##########################################################################*/
/**
* ArrayAccess: Check if the given offset exists
*
* @param int $offset
* @return boolean
*/
public function offsetExists($offset)
{
foreach ($this->_columns as $column) {
if ($column->getName() == $offset) return true;
}
return false;
}
/**
* ArrayAccess: Return the value for the given offset.
*
* @param int $offset
* @return object {@link {@Horde_Db_Adapter_Base_ColumnDefinition}
*/
public function offsetGet($offset)
{
if (!$this->offsetExists($offset)) {
return null;
}
foreach ($this->_columns as $column) {
if ($column->getName() == $offset) {
return $column;
}
}
}
/**
* ArrayAccess: Set value for given offset
*
* @param int $offset
* @param mixed $value
*/
public function offsetSet($offset, $value)
{
foreach ($this->_columns as $key=>$column) {
if ($column->getName() == $offset) {
$this->_columns[$key] = $value;
}
}
}
/**
* ArrayAccess: remove element
*
* @param int $offset
*/
public function offsetUnset($offset)
{
foreach ($this->_columns as $key=>$column) {
if ($column->getName() == $offset) {
unset($this->_columns[$key]);
}
}
}
/*##########################################################################
# IteratorAggregate
##########################################################################*/
public function getIterator()
{
return new ArrayIterator($this->_columns);
}
/*##########################################################################
# Protected
##########################################################################*/
/**
* Get the types
*/
protected function _native()
{
return $this->_base->nativeDatabaseTypes();
}
}
Horde_Db-2.0.4/lib/Horde/Db/Adapter/Mysql/Column.php 0000664 0001750 0001750 00000004542 12205351473 020065 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
class Horde_Db_Adapter_Mysql_Column extends Horde_Db_Adapter_Base_Column
{
/**
* @var array
*/
protected static $_hasEmptyStringDefault = array('binary', 'string', 'text');
/**
* @var string
*/
protected $_originalDefault = null;
/**
* Construct
* @param string $name
* @param string $default
* @param string $sqlType
* @param boolean $null
*/
public function __construct($name, $default, $sqlType=null, $null=true)
{
$this->_originalDefault = $default;
parent::__construct($name, $default, $sqlType, $null);
if ($this->_isMissingDefaultForgedAsEmptyString()) {
$this->_default = null;
}
}
/**
* @param string $fieldType
* @return string
*/
protected function _simplifiedType($fieldType)
{
if (strpos(strtolower($fieldType), 'tinyint(1)') !== false) {
return 'boolean';
} elseif (preg_match('/enum/i', $fieldType)) {
return 'string';
}
return parent::_simplifiedType($fieldType);
}
/**
* MySQL misreports NOT NULL column default when none is given.
* We can't detect this for columns which may have a legitimate ''
* default (string, text, binary) but we can for others (integer,
* datetime, boolean, and the rest).
*
* Test whether the column has default '', is not null, and is not
* a type allowing default ''.
*
* @return boolean
*/
protected function _isMissingDefaultForgedAsEmptyString()
{
return !$this->_null && $this->_originalDefault == '' &&
!in_array($this->_type, self::$_hasEmptyStringDefault);
}
}
Horde_Db-2.0.4/lib/Horde/Db/Adapter/Mysql/Result.php 0000664 0001750 0001750 00000012356 12205351473 020110 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
class Horde_Db_Adapter_Mysql_Result implements Iterator
{
/**
* @var Horde_Db_Adapter
*/
protected $_adapter;
/**
* @var string
*/
protected $_sql;
/**
* @var mixed
*/
protected $_arg1;
/**
* @var string
*/
protected $_arg2;
/**
* Result resource
* @var resource
*/
protected $_result;
/**
* Current row
* @var array
*/
protected $_current;
/**
* Current offset
* @var integer
*/
protected $_index;
/**
* Are we at the end of the result?
* @var boolean
*/
protected $_eof;
/**
* Which kind of keys to use for results.
*/
protected $_fetchMode = MYSQL_ASSOC;
/**
* Constructor
*
* @param Horde_Db_Adapter $adapter
* @param string $sql
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
*/
public function __construct($adapter, $sql, $arg1 = null, $arg2 = null)
{
$this->_adapter = $adapter;
$this->_sql = $sql;
$this->_arg1 = $arg1;
$this->_arg2 = $arg2;
}
/**
* Destructor - release any resources.
*/
public function __destruct()
{
if ($this->_result) {
unset($this->_result);
}
}
/**
* Implementation of the rewind() method for iterator.
*/
public function rewind()
{
if ($this->_result) {
unset($this->_result);
}
$this->_current = null;
$this->_index = null;
$this->_eof = true;
$this->_result = $this->_adapter->execute($this->_sql, $this->_arg1, $this->_arg2);
$this->next();
}
/**
* Implementation of the current() method for iterator.
*
* @return mixed The current row, or null if no rows.
*/
public function current()
{
if (is_null($this->_result)) {
$this->rewind();
}
return $this->_current;
}
/**
* Implementation of the key() method for iterator.
*
* @return mixed The current row number (starts at 0), or NULL if no rows
*/
public function key()
{
if (is_null($this->_result)) {
$this->rewind();
}
return $this->_index;
}
/**
* Implementation of the next() method.
*
* @return array|null The next row in the resultset or null if there are no
* more results.
*/
public function next()
{
if (is_null($this->_result)) {
$this->rewind();
}
if ($this->_result) {
$row = mysql_fetch_array($this->_result, $this->_fetchMode);
if (!$row) {
$this->_eof = true;
} else {
$this->_eof = false;
if (is_null($this->_index)) {
$this->_index = 0;
} else {
++$this->_index;
}
$this->_current = $row;
}
}
return $this->_current;
}
/**
* Returns the current row and advances the recordset one row.
*
* @param integer $fetchmode The default fetch mode for this result. One
* of the Horde_Db::FETCH_* constants.
*/
public function fetch($fetchmode = Horde_Db::FETCH_ASSOC)
{
if (!$this->valid()) {
return null;
}
$this->setFetchMode($fetchmode);
$row = $this->current();
$this->next();
return $row;
}
/**
* Implementation of the valid() method for iterator
*
* @return boolean Whether the iteration is valid
*/
public function valid()
{
if (is_null($this->_result)) {
$this->rewind();
}
return !$this->_eof;
}
/**
* Sets the default fetch mode for this result.
*
* @param integer $fetchmode One of the Horde_Db::FETCH_* constants.
*/
public function setFetchMode($fetchmode)
{
$map = array(Horde_Db::FETCH_ASSOC => MYSQL_ASSOC,
Horde_Db::FETCH_NUM => MYSQL_NUM,
Horde_Db::FETCH_BOTH => MYSQL_BOTH);
$this->_fetchMode = $map[$fetchmode];
}
/**
* Returns the number of columns in the result set
*
* @return integer Number of columns.
*/
public function columnCount()
{
if (is_null($this->_result)) {
$this->rewind();
}
return mysql_num_fields($this->_result);
}
}
Horde_Db-2.0.4/lib/Horde/Db/Adapter/Mysql/Schema.php 0000664 0001750 0001750 00000053163 12205351473 020033 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @author Jan Schneider
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @author Jan Schneider
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
class Horde_Db_Adapter_Mysql_Schema extends Horde_Db_Adapter_Base_Schema
{
/*##########################################################################
# Object factories
##########################################################################*/
/**
* Factory for Column objects.
*
* @param string $name The column's name, such as "supplier_id" in
* "supplier_id int(11)".
* @param string $default The type-casted default value, such as "new" in
* "sales_stage varchar(20) default 'new'".
* @param string $sqlType Used to extract the column's type, length and
* signed status, if necessary. For example
* "varchar" and "60" in "company_name varchar(60)"
* or "unsigned => true" in "int(10) UNSIGNED".
* @param boolean $null Whether this column allows NULL values.
*
* @return Horde_Db_Adapter_Mysql_Column A column object.
*/
public function makeColumn($name, $default, $sqlType = null, $null = true)
{
return new Horde_Db_Adapter_Mysql_Column($name, $default, $sqlType, $null);
}
/*##########################################################################
# Quoting
##########################################################################*/
/**
* Returns a quoted form of the column name.
*
* @param string $name A column name.
*
* @return string The quoted column name.
*/
public function quoteColumnName($name)
{
return '`' . str_replace('`', '``', $name) . '`';
}
/**
* Returns a quoted form of the table name.
*
* Defaults to column name quoting.
*
* @param string $name A table name.
*
* @return string The quoted table name.
*/
public function quoteTableName($name)
{
return str_replace('.', '`.`', $this->quoteColumnName($name));
}
/**
* Returns a quoted boolean true.
*
* @return string The quoted boolean true.
*/
public function quoteTrue()
{
return '1';
}
/**
* Returns a quoted boolean false.
*
* @return string The quoted boolean false.
*/
public function quoteFalse()
{
return '0';
}
/*##########################################################################
# Schema Statements
##########################################################################*/
/**
* Returns a hash of mappings from the abstract data types to the native
* database types.
*
* See TableDefinition::column() for details on the recognized abstract
* data types.
*
* @see TableDefinition::column()
*
* @return array A database type map.
*/
public function nativeDatabaseTypes()
{
return array(
'autoincrementKey' => 'int(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY',
'string' => array('name' => 'varchar', 'limit' => 255),
'text' => array('name' => 'text', 'limit' => null),
'mediumtext' => array('name' => 'mediumtext', 'limit' => null),
'longtext' => array('name' => 'longtext', 'limit' => null),
'integer' => array('name' => 'int', 'limit' => 11),
'float' => array('name' => 'float', 'limit' => null),
'decimal' => array('name' => 'decimal', 'limit' => null),
'datetime' => array('name' => 'datetime', 'limit' => null),
'timestamp' => array('name' => 'datetime', 'limit' => null),
'time' => array('name' => 'time', 'limit' => null),
'date' => array('name' => 'date', 'limit' => null),
'binary' => array('name' => 'longblob', 'limit' => null),
'boolean' => array('name' => 'tinyint', 'limit' => 1),
);
}
/**
* Returns a list of all tables of the current database.
*
* @return array A table list.
*/
public function tables()
{
return $this->selectValues('SHOW TABLES');
}
/**
* Returns a table's primary key.
*
* @param string $tableName A table name.
* @param string $name (can be removed?)
*
* @return Horde_Db_Adapter_Base_Index The primary key index object.
*/
public function primaryKey($tableName, $name = null)
{
// Share the column cache with the columns() method
$rows = @unserialize($this->_cache->get("tables/columns/$tableName", 0));
if (!$rows) {
$rows = $this->selectAll(
'SHOW FIELDS FROM ' . $this->quoteTableName($tableName),
$name);
$this->_cache->set("tables/columns/$tableName", serialize($rows));
}
$pk = $this->makeIndex($tableName, 'PRIMARY', true, true, array());
foreach ($rows as $row) {
if ($row['Key'] == 'PRI') {
$pk->columns[] = $row['Field'];
}
}
return $pk;
}
/**
* Returns a list of tables indexes.
*
* @param string $tableName A table name.
* @param string $name (can be removed?)
*
* @return array A list of Horde_Db_Adapter_Base_Index objects.
*/
public function indexes($tableName, $name=null)
{
$indexes = @unserialize($this->_cache->get("tables/indexes/$tableName", 0));
if (!$indexes) {
$indexes = array();
$currentIndex = null;
foreach ($this->select('SHOW KEYS FROM ' . $this->quoteTableName($tableName)) as $row) {
if ($currentIndex != $row['Key_name']) {
if ($row['Key_name'] == 'PRIMARY') {
continue;
}
$currentIndex = $row['Key_name'];
$indexes[] = $this->makeIndex(
$tableName, $row['Key_name'], false, $row['Non_unique'] == '0', array());
}
$indexes[count($indexes) - 1]->columns[] = $row['Column_name'];
}
$this->_cache->set("tables/indexes/$tableName", serialize($indexes));
}
return $indexes;
}
/**
* Returns a list of table columns.
*
* @param string $tableName A table name.
* @param string $name (can be removed?)
*
* @return array A list of Horde_Db_Adapter_Base_Column objects.
*/
public function columns($tableName, $name=null)
{
$rows = @unserialize($this->_cache->get("tables/columns/$tableName", 0));
if (!$rows) {
$rows = $this->selectAll('SHOW FIELDS FROM ' . $this->quoteTableName($tableName), $name);
$this->_cache->set("tables/columns/$tableName", serialize($rows));
}
// Create columns from rows.
$columns = array();
foreach ($rows as $row) {
$columns[$row['Field']] = $this->makeColumn(
$row['Field'], $row['Default'], $row['Type'], $row['Null'] == 'YES');
}
return $columns;
}
/**
* Finishes and executes table creation.
*
* @param string|Horde_Db_Adapter_Base_TableDefinition $name
* A table name or object.
* @param array $options
* A list of options. See createTable().
*/
public function endTable($name, $options = array())
{
if ($name instanceof Horde_Db_Adapter_Base_TableDefinition) {
$options = array_merge($name->getOptions(), $options);
}
if (isset($options['options'])) {
$opts = $options['options'];
} else {
if (empty($options['charset'])) {
$options['charset'] = $this->getCharset();
}
$opts = 'ENGINE=InnoDB DEFAULT CHARSET=' . $options['charset'];
}
return parent::endTable($name, array_merge(array('options' => $opts), $options));
}
/**
* Renames a table.
*
* @param string $name A table name.
* @param string $newName The new table name.
*/
public function renameTable($name, $newName)
{
$this->_clearTableCache($name);
$sql = sprintf('ALTER TABLE %s RENAME %s',
$this->quoteTableName($name),
$this->quoteTableName($newName));
return $this->execute($sql);
}
/**
* Changes an existing column's definition.
*
* @param string $tableName A table name.
* @param string $columnName A column name.
* @param string $type A data type.
* @param array $options Column options. See
* Horde_Db_Adapter_Base_TableDefinition#column()
* for details.
*/
public function changeColumn($tableName, $columnName, $type,
$options = array())
{
$this->_clearTableCache($tableName);
$quotedTableName = $this->quoteTableName($tableName);
$quotedColumnName = $this->quoteColumnName($columnName);
$options = array_merge(
array('limit' => null,
'precision' => null,
'scale' => null,
'unsigned' => null),
$options);
$sql = sprintf('SHOW COLUMNS FROM %s LIKE %s',
$quotedTableName,
$this->quoteString($columnName));
$row = $this->selectOne($sql);
if (!array_key_exists('default', $options)) {
$options['default'] = $row['Default'];
$options['column'] = $this->makeColumn($columnName,
$row['Default'],
$row['Type'],
$row['Null'] == 'YES');
}
$typeSql = $this->typeToSql($type, $options['limit'],
$options['precision'], $options['scale'],
$options['unsigned']);
$dropPk = ($type == 'autoincrementKey' && $row['Key'] == 'PRI')
? 'DROP PRIMARY KEY,'
: '';
$sql = sprintf('ALTER TABLE %s %s CHANGE %s %s %s',
$quotedTableName,
$dropPk,
$quotedColumnName,
$quotedColumnName,
$typeSql);
if ($type != 'autoincrementKey') {
$sql = $this->addColumnOptions($sql, $options);
}
$this->execute($sql);
}
/**
* Sets a new default value for a column.
*
* If you want to set the default value to NULL, you are out of luck. You
* need to execute the apppropriate SQL statement yourself.
*
* @param string $tableName A table name.
* @param string $columnName A column name.
* @param mixed $default The new default value.
*/
public function changeColumnDefault($tableName, $columnName, $default)
{
$this->_clearTableCache($tableName);
$quotedTableName = $this->quoteTableName($tableName);
$quotedColumnName = $this->quoteColumnName($columnName);
$sql = sprintf('SHOW COLUMNS FROM %s LIKE %s',
$quotedTableName,
$this->quoteString($columnName));
$res = $this->selectOne($sql);
$column = $this->makeColumn($columnName, $res['Default'], $res['Type'], $res['Null'] == 'YES');
$default = $this->quote($default, $column);
$sql = sprintf('ALTER TABLE %s CHANGE %s %s %s DEFAULT %s',
$quotedTableName,
$quotedColumnName,
$quotedColumnName,
$res['Type'],
$default);
return $this->execute($sql);
}
/**
* Renames a column.
*
* @param string $tableName A table name.
* @param string $columnName A column name.
* @param string $newColumnName The new column name.
*/
public function renameColumn($tableName, $columnName, $newColumnName)
{
$this->_clearTableCache($tableName);
$quotedTableName = $this->quoteTableName($tableName);
$quotedColumnName = $this->quoteColumnName($columnName);
$sql = sprintf('SHOW COLUMNS FROM %s LIKE %s',
$quotedTableName,
$this->quoteString($columnName));
$res = $this->selectOne($sql);
$currentType = $res['Type'];
$sql = sprintf('ALTER TABLE %s CHANGE %s %s %s',
$quotedTableName,
$quotedColumnName,
$this->quoteColumnName($newColumnName),
$currentType);
return $this->execute($sql);
}
/**
* Removes a primary key from a table.
*
* @param string $tableName A table name.
*
* @throws Horde_Db_Exception
*/
public function removePrimaryKey($tableName)
{
$this->_clearTableCache($tableName);
$sql = sprintf('ALTER TABLE %s DROP PRIMARY KEY',
$this->quoteTableName($tableName));
return $this->execute($sql);
}
/**
* Builds the name for an index.
*
* Cuts the index name to the maximum length of 64 characters limited by
* MySQL.
*
* @param string $tableName A table name.
* @param string|array $options Either a column name or index options:
* - column: (string|array) column name(s).
* - name: (string) the index name to fall
* back to if no column names specified.
*/
public function indexName($tableName, $options=array())
{
$indexName = parent::indexName($tableName, $options);
if (strlen($indexName) > 64) {
$indexName = substr($indexName, 0, 64);
}
return $indexName;
}
/**
* Creates a database.
*
* @param string $name A database name.
* @param array $options Database options.
*/
public function createDatabase($name, $options = array())
{
return $this->execute("CREATE DATABASE `$name`");
}
/**
* Drops a database.
*
* @param string $name A database name.
*/
public function dropDatabase($name)
{
return $this->execute("DROP DATABASE IF EXISTS `$name`");
}
/**
* Returns the name of the currently selected database.
*
* @return string The database name.
*/
public function currentDatabase()
{
return $this->selectValue('SELECT DATABASE() AS db');
}
/**
* Generates the SQL definition for a column type.
*
* @param string $type A column type.
* @param integer $limit Maximum column length (non decimal type only)
* @param integer $precision The number precision (decimal type only).
* @param integer $scale The number scaling (decimal columns only).
* @param boolean $unsigned Whether the column is an unsigned number
* (non decimal columns only).
*
* @return string The SQL definition. If $type is not one of the
* internally supported types, $type is returned unchanged.
*/
public function typeToSql($type, $limit = null, $precision = null,
$scale = null, $unsigned = null)
{
// If there is no explicit limit, adjust $nativeLimit for unsigned
// integers.
if ($type == 'integer' && !empty($unsigned) && empty($limit)) {
$natives = $this->nativeDatabaseTypes();
$native = isset($natives[$type]) ? $natives[$type] : null;
if (empty($native)) {
return $type;
}
$nativeLimit = is_array($native) ? $native['limit'] : null;
if (is_integer($nativeLimit)) {
$limit = $nativeLimit - 1;
}
}
$sql = parent::typeToSql($type, $limit, $precision, $scale, $unsigned);
if (!empty($unsigned)) {
$sql .= ' UNSIGNED';
}
return $sql;
}
/**
* Adds default/null options to column SQL definitions.
*
* @param string $sql Existing SQL definition for a column.
* @param array $options Column options:
* - null: (boolean) Whether to allow NULL values.
* - default: (mixed) Default column value.
* - autoincrement: (boolean) Whether the column is
* an autoincrement column. Driver depedendent.
* - after: (string) Insert column after this one.
* MySQL specific.
*
* @return string The manipulated SQL definition.
*/
public function addColumnOptions($sql, $options)
{
$sql = parent::addColumnOptions($sql, $options);
if (isset($options['after'])) {
$sql .= ' AFTER ' . $this->quoteColumnName($options['after']);
}
if (!empty($options['autoincrement'])) {
$sql .= ' AUTO_INCREMENT';
}
return $sql;
}
/**
* Returns an expression using the specified operator.
*
* @param string $lhs The column or expression to test.
* @param string $op The operator.
* @param string $rhs The comparison value.
* @param boolean $bind If true, the method returns the query and a list
* of values suitable for binding as an array.
* @param array $params Any additional parameters for the operator.
*
* @return string|array The SQL test fragment, or an array containing the
* query and a list of values if $bind is true.
*/
public function buildClause($lhs, $op, $rhs, $bind = false,
$params = array())
{
switch ($op) {
case '~':
if ($bind) {
return array($lhs . ' REGEXP ?', array($rhs));
} else {
return $lhs . ' REGEXP ' . $rhs;
}
}
return parent::buildClause($lhs, $op, $rhs, $bind, $params);
}
/*##########################################################################
# MySQL specific methods
##########################################################################*/
/**
* Returns the character set of query results.
*
* @return string The result's charset.
*/
public function getCharset()
{
return $this->showVariable('character_set_results');
}
/**
* Sets the client and result charset.
*
* @param string $charset The character set to use for client queries and
* results.
*/
public function setCharset($charset)
{
$charset = $this->_mysqlCharsetName($charset);
$this->execute('SET NAMES ' . $this->quoteString($charset));
}
/**
* Returns the MySQL name of a character set.
*
* @param string $charset A charset name.
*
* @return string MySQL-normalized charset.
*/
public function _mysqlCharsetName($charset)
{
$charset = preg_replace(array('/[^a-z0-9]/', '/iso8859(\d)/'),
array('', 'latin$1'),
Horde_String::lower($charset));
$validCharsets = $this->selectValues('SHOW CHARACTER SET');
if (!in_array($charset, $validCharsets)) {
throw new Horde_Db_Exception($charset . ' is not supported by MySQL (' . implode(', ', $validCharsets) . ')');
}
return $charset;
}
/**
* Returns the database collation strategy.
*
* @return string Database collation.
*/
public function getCollation()
{
return $this->showVariable('collation_database');
}
/**
* Returns a database variable.
*
* Convenience wrapper around "SHOW VARIABLES LIKE 'name'".
*
* @param string $name A variable name.
*
* @return string The variable value.
* @throws Horde_Db_Exception
*/
public function showVariable($name)
{
$value = $this->selectOne('SHOW VARIABLES LIKE ' . $this->quoteString($name));
if ($value['Variable_name'] == $name) {
return $value['Value'];
} else {
throw new Horde_Db_Exception($name . ' is not a recognized variable');
}
}
/**
*/
public function caseSensitiveEqualityOperator()
{
return '= BINARY';
}
/**
*/
public function limitedUpdateConditions($whereSql, $quotedTableName,
$quotedPrimaryKey)
{
return $whereSql;
}
}
Horde_Db-2.0.4/lib/Horde/Db/Adapter/Mysqli/Result.php 0000664 0001750 0001750 00000012352 12205351473 020255 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
class Horde_Db_Adapter_Mysqli_Result implements Iterator
{
/**
* @var Horde_Db_Adapter
*/
protected $_adapter;
/**
* @var string
*/
protected $_sql;
/**
* @var mixed
*/
protected $_arg1;
/**
* @var string
*/
protected $_arg2;
/**
* Result resource
* @var mysqli_result
*/
protected $_result;
/**
* Current row
* @var array
*/
protected $_current;
/**
* Current offset
* @var integer
*/
protected $_index;
/**
* Are we at the end of the result?
* @var boolean
*/
protected $_eof;
/**
* Which kind of keys to use for results.
*/
protected $_fetchMode = MYSQLI_ASSOC;
/**
* Constructor
*
* @param Horde_Db_Adapter $adapter
* @param string $sql
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
*/
public function __construct($adapter, $sql, $arg1 = null, $arg2 = null)
{
$this->_adapter = $adapter;
$this->_sql = $sql;
$this->_arg1 = $arg1;
$this->_arg2 = $arg2;
}
/**
* Destructor - release any resources.
*/
public function __destruct()
{
if ($this->_result) {
unset($this->_result);
}
}
/**
* Implementation of the rewind() method for iterator.
*/
public function rewind()
{
if ($this->_result) {
unset($this->_result);
}
$this->_current = null;
$this->_index = null;
$this->_eof = true;
$this->_result = $this->_adapter->execute($this->_sql, $this->_arg1, $this->_arg2);
$this->next();
}
/**
* Implementation of the current() method for iterator.
*
* @return mixed The current row, or null if no rows.
*/
public function current()
{
if (is_null($this->_result)) {
$this->rewind();
}
return $this->_current;
}
/**
* Implementation of the key() method for iterator.
*
* @return mixed The current row number (starts at 0), or NULL if no rows
*/
public function key()
{
if (is_null($this->_result)) {
$this->rewind();
}
return $this->_index;
}
/**
* Implementation of the next() method.
*
* @return array|null The next row in the resultset or null if there are no
* more results.
*/
public function next()
{
if (is_null($this->_result)) {
$this->rewind();
}
if ($this->_result) {
$row = $this->_result->fetch_array($this->_fetchMode);
if (!$row) {
$this->_eof = true;
} else {
$this->_eof = false;
if (is_null($this->_index)) {
$this->_index = 0;
} else {
++$this->_index;
}
$this->_current = $row;
}
}
return $this->_current;
}
/**
* Returns the current row and advances the recordset one row.
*
* @param integer $fetchmode The default fetch mode for this result. One
* of the Horde_Db::FETCH_* constants.
*/
public function fetch($fetchmode = Horde_Db::FETCH_ASSOC)
{
if (!$this->valid()) {
return null;
}
$this->setFetchMode($fetchmode);
$row = $this->current();
$this->next();
return $row;
}
/**
* Implementation of the valid() method for iterator
*
* @return boolean Whether the iteration is valid
*/
public function valid()
{
if (is_null($this->_result)) {
$this->rewind();
}
return !$this->_eof;
}
/**
* Sets the default fetch mode for this result.
*
* @param integer $fetchmode One of the Horde_Db::FETCH_* constants.
*/
public function setFetchMode($fetchmode)
{
$map = array(Horde_Db::FETCH_ASSOC => MYSQL_ASSOC,
Horde_Db::FETCH_NUM => MYSQL_NUM,
Horde_Db::FETCH_BOTH => MYSQL_BOTH);
$this->_fetchMode = $map[$fetchmode];
}
/**
* Returns the number of columns in the result set
*
* @return integer Number of columns.
*/
public function columnCount()
{
if (is_null($this->_result)) {
$this->rewind();
}
return $this->_result->field_count;
}
}
Horde_Db-2.0.4/lib/Horde/Db/Adapter/Pdo/Base.php 0000664 0001750 0001750 00000016215 12205351473 017117 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
abstract class Horde_Db_Adapter_Pdo_Base extends Horde_Db_Adapter_Base
{
/*##########################################################################
# Connection Management
##########################################################################*/
/**
* Connect to the db
*/
public function connect()
{
if ($this->_active) {
return;
}
list($dsn, $user, $pass) = $this->_parseConfig();
try {
$pdo = @new PDO($dsn, $user, $pass);
} catch (PDOException $e) {
$msg = "Could not instantiate PDO with DSN \"$dsn\". PDOException: "
. $e->getMessage();
throw new Horde_Db_Exception($msg);
}
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$this->_connection = $pdo;
$this->_active = true;
}
/**
* Check if the connection is active
*
* @return boolean
*/
public function isActive()
{
$this->_lastQuery = $sql = 'SELECT 1';
return isset($this->_connection) &&
$this->_connection->query($sql);
}
/*##########################################################################
# Database Statements
##########################################################################*/
/**
* Returns an array of record hashes with the column names as keys and
* column values as values.
*
* @param string $sql
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
*/
public function selectAll($sql, $arg1=null, $arg2=null)
{
$result = $this->execute($sql, $arg1, $arg2);
return $result ? $result->fetchAll(PDO::FETCH_ASSOC) : array();
}
/**
* Returns a record hash with the column names as keys and column values as
* values.
*
* @param string $sql A query.
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
*
* @return array|boolean A record hash or false if no record found.
*/
public function selectOne($sql, $arg1 = null, $arg2 = null)
{
$result = $this->execute($sql, $arg1, $arg2);
return $result ? $result->fetch(PDO::FETCH_ASSOC) : array();
}
/**
* Returns a single value from a record
*
* @param string $sql
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
* @return string
*/
public function selectValue($sql, $arg1=null, $arg2=null)
{
$result = $this->execute($sql, $arg1, $arg2);
return $result ? $result->fetchColumn(0) : null;
}
/**
* Returns an array of the values of the first column in a select:
* selectValues("SELECT id FROM companies LIMIT 3") => [1,2,3]
*
* @param string $sql
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
*/
public function selectValues($sql, $arg1=null, $arg2=null)
{
$result = $this->execute($sql, $arg1, $arg2);
return $result ? $result->fetchAll(PDO::FETCH_COLUMN, 0) : array();
}
/**
* Returns an array where the keys are the first column of a select, and the
* values are the second column:
*
* selectAssoc("SELECT id, name FROM companies LIMIT 3") => [1 => 'Ford', 2 => 'GM', 3 => 'Chrysler']
*
* @param string $sql
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
*/
public function selectAssoc($sql, $arg1=null, $arg2=null)
{
$result = $this->execute($sql, $arg1, $arg2);
return $result ? $result->fetchAll(PDO::FETCH_KEY_PAIR) : array();
}
/*##########################################################################
# Quoting
##########################################################################*/
/**
* Quotes a string, escaping any ' (single quote) and \ (backslash)
* characters..
*
* @param string $string
* @return string
*/
public function quoteString($string)
{
return $this->_connection->quote($string);
}
/*##########################################################################
# Protected
##########################################################################*/
protected function _normalizeConfig($params)
{
// Normalize config parameters to what PDO expects.
$normalize = array('database' => 'dbname',
'hostspec' => 'host');
foreach ($normalize as $from => $to) {
if (isset($params[$from])) {
$params[$to] = $params[$from];
unset($params[$from]);
}
}
return $params;
}
protected function _buildDsnString($params)
{
$dsn = $this->_config['adapter'] . ':';
foreach ($params as $k => $v) {
if (strlen($v)) {
$dsn .= "$k=$v;";
}
}
return rtrim($dsn, ';');
}
/**
* Parse configuration array into options for PDO constructor.
*
* @throws Horde_Db_Exception
* @return array [dsn, username, password]
*/
protected function _parseConfig()
{
$this->_checkRequiredConfig(array('adapter', 'username'));
// try an empty password if it's not set.
if (!isset($this->_config['password'])) {
$this->_config['password'] = '';
}
// collect options to build PDO Data Source Name (DSN) string
$dsnOpts = $this->_config;
unset(
$dsnOpts['adapter'],
$dsnOpts['username'],
$dsnOpts['password'],
$dsnOpts['protocol'],
$dsnOpts['persistent'],
$dsnOpts['charset'],
$dsnOpts['phptype'],
$dsnOpts['socket']
);
// return DSN and user/pass for connection
return array(
$this->_buildDsnString($this->_normalizeConfig($dsnOpts)),
$this->_config['username'],
$this->_config['password']);
}
}
Horde_Db-2.0.4/lib/Horde/Db/Adapter/Pdo/Mysql.php 0000664 0001750 0001750 00000007435 12205351473 017356 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
/**
* PDO_MySQL Horde_Db_Adapter
*
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
class Horde_Db_Adapter_Pdo_Mysql extends Horde_Db_Adapter_Pdo_Base
{
/**
* @var string
*/
protected $_schemaClass = 'Horde_Db_Adapter_Mysql_Schema';
/**
* @return string
*/
public function adapterName()
{
return 'PDO_MySQL';
}
/**
* @return boolean
*/
public function supportsMigrations()
{
return true;
}
/*##########################################################################
# Connection Management
##########################################################################*/
/**
* Connect to the db
*/
public function connect()
{
if ($this->_active) {
return;
}
parent::connect();
// ? $this->_connection->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
// Set the default charset. http://dev.mysql.com/doc/refman/5.1/en/charset-connection.html
if (!empty($this->_config['charset'])) {
$this->setCharset($this->_config['charset']);
}
}
/*##########################################################################
# Protected
##########################################################################*/
/**
* Parse configuration array into options for PDO constructor.
*
* http://pecl.php.net/bugs/7234
* Setting a bogus socket does not appear to work.
*
* @throws Horde_Db_Exception
* @return array [dsn, username, password]
*/
protected function _parseConfig()
{
$this->_config['adapter'] = 'mysql';
$this->_checkRequiredConfig(array('adapter', 'username'));
if (!empty($this->_config['socket'])) {
$this->_config['unix_socket'] = $this->_config['socket'];
unset($this->_config['socket']);
}
if (!empty($this->_config['host']) &&
$this->_config['host'] == 'localhost') {
$this->_config['host'] = '127.0.0.1';
}
// Try an empty password if it's not set.
if (!isset($this->_config['password'])) {
$this->_config['password'] = '';
}
// Collect options to build PDO Data Source Name (DSN) string.
$dsnOpts = $this->_config;
unset($dsnOpts['adapter'],
$dsnOpts['username'],
$dsnOpts['password'],
$dsnOpts['charset'],
$dsnOpts['phptype']);
$dsnOpts = $this->_normalizeConfig($dsnOpts);
if (isset($dsnOpts['port'])) {
if (empty($dsnOpts['host'])) {
throw new Horde_Db_Exception('Host is required if port is specified');
}
}
if (isset($dsnOpts['unix_socket'])) {
if (!empty($dsnOpts['host']) ||
!empty($dsnOpts['port'])) {
throw new Horde_Db_Exception('Host and port must not be set if using a UNIX socket');
}
}
// Return DSN and user/pass for connection.
return array(
$this->_buildDsnString($dsnOpts),
$this->_config['username'],
$this->_config['password']);
}
}
Horde_Db-2.0.4/lib/Horde/Db/Adapter/Pdo/Pgsql.php 0000664 0001750 0001750 00000022505 12205351473 017332 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
/**
* PDO_PostgreSQL Horde_Db_Adapter
*
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
class Horde_Db_Adapter_Pdo_Pgsql extends Horde_Db_Adapter_Pdo_Base
{
/**
* @var string
*/
protected $_schemaClass = 'Horde_Db_Adapter_Postgresql_Schema';
/**
* @return string
*/
public function adapterName()
{
return 'PDO_PostgreSQL';
}
/**
* @return boolean
*/
public function supportsMigrations()
{
return true;
}
/**
* Does PostgreSQL support standard conforming strings?
* @return boolean
*/
public function supportsStandardConformingStrings()
{
// Temporarily set the client message level above error to prevent unintentional
// error messages in the logs when working on a PostgreSQL database server that
// does not support standard conforming strings.
$clientMinMessagesOld = $this->getClientMinMessages();
$this->setClientMinMessages('panic');
$hasSupport = $this->selectValue('SHOW standard_conforming_strings');
$this->setClientMinMessages($clientMinMessageOld);
return $hasSupport;
}
public function supportsInsertWithReturning()
{
return $this->postgresqlVersion() >= 80200;
}
/*##########################################################################
# Connection Management
##########################################################################*/
/**
* Connect to the db.
*
* @throws Horde_Db_Exception
*/
public function connect()
{
if ($this->_active) {
return;
}
parent::connect();
$this->_lastQuery = $sql = "SET datestyle TO 'iso'";
$retval = $this->_connection->exec($sql);
if ($retval === false) {
$error = $this->_connection->errorInfo();
throw new Horde_Db_Exception($error[2]);
}
// Money type has a fixed precision of 10 in PostgreSQL 8.2 and below, and as of
// PostgreSQL 8.3 it has a fixed precision of 19. PostgreSQLColumn.extract_precision
// should know about this but can't detect it there, so deal with it here.
Horde_Db_Adapter_Postgresql_Column::$moneyPrecision = ($this->postgresqlVersion() >= 80300) ? 19 : 10;
$this->_configureConnection();
}
/*##########################################################################
# Database Statements
##########################################################################*/
/**
* Inserts a row into a table.
*
* @param string $sql SQL statement.
* @param array|string $arg1 Either an array of bound parameters or a
* query name.
* @param string $arg2 If $arg1 contains bound parameters, the
* query name.
* @param string $pk The primary key column.
* @param integer $idValue The primary key value. This parameter is
* required if the primary key is inserted
* manually.
* @param string $sequenceName The sequence name.
*
* @return integer Last inserted ID.
* @throws Horde_Db_Exception
*/
public function insert($sql, $arg1 = null, $arg2 = null, $pk = null,
$idValue = null, $sequenceName = null)
{
// Extract the table from the insert sql. Yuck.
$temp = explode(' ', trim($sql), 4);
$table = str_replace('"', '', $temp[2]);
// Try an insert with 'returning id' if available (PG >= 8.2)
if ($this->supportsInsertWithReturning()) {
if (!$pk) {
list($pk, $sequenceName) = $this->pkAndSequenceFor($table);
}
if ($pk) {
$id = $this->selectValue($sql . ' RETURNING ' . $this->quoteColumnName($pk), $arg1, $arg2);
$this->resetPkSequence($table, $pk, $sequenceName);
return $id;
}
}
// If neither pk nor sequence name is given, look them up.
if (!($pk || $sequenceName)) {
list($pk, $sequenceName) = $this->pkAndSequenceFor($table);
}
// Otherwise, insert then grab last_insert_id.
if ($insertId = parent::insert($sql, $arg1, $arg2, $pk, $idValue, $sequenceName)) {
$this->resetPkSequence($table, $pk, $sequenceName);
return $insertId;
}
// If a pk is given, fallback to default sequence name.
// Don't fetch last insert id for a table without a pk.
if ($pk &&
($sequenceName ||
$sequenceName = $this->defaultSequenceName($table, $pk))) {
$this->resetPkSequence($table, $pk, $sequenceName);
return $this->_lastInsertId($table, $sequenceName);
}
}
/**
* Appends LIMIT and OFFSET options to a SQL statement.
*
* @param string $sql SQL statement.
* @param array $options Hash with 'limit' and (optional) 'offset' values.
*
* @return string
*/
public function addLimitOffset($sql, $options)
{
if (isset($options['limit']) && $limit = $options['limit']) {
$sql .= " LIMIT $limit";
}
if (isset($options['offset']) && $offset = $options['offset']) {
$sql .= " OFFSET $offset";
}
return $sql;
}
/*##########################################################################
# Protected
##########################################################################*/
/**
* Parse configuration array into options for PDO constructor.
*
* @throws Horde_Db_Exception
* @return array [dsn, username, password]
*/
protected function _parseConfig()
{
$this->_config['adapter'] = 'pgsql';
// PDO for PostgreSQL does not accept a socket argument
// in the connection string; the location can be set via the
// "host" argument instead.
if (!empty($this->_config['socket'])) {
$this->_config['host'] = $this->_config['socket'];
unset($this->_config['socket']);
}
return parent::_parseConfig();
}
/**
* Configures the encoding, verbosity, and schema search path of the connection.
* This is called by connect() and should not be called manually.
*/
protected function _configureConnection()
{
if (!empty($this->_config['charset'])) {
$this->_lastQuery = $sql = 'SET client_encoding TO '.$this->quoteString($this->_config['charset']);
$this->execute($sql);
}
if (!empty($this->_config['client_min_messages'])) $this->setClientMinMessages($this->_config['client_min_messages']);
$this->setSchemaSearchPath(!empty($this->_config['schema_search_path']) || !empty($this->_config['schema_order']));
}
/**
* @TODO
*/
protected function _selectRaw($sql, $arg1=null, $arg2=null)
{
$result = $this->execute($sql, $arg1, $arg2);
if (!$result) return array();
$moneyFields = array();
for ($i = 0, $i_max = $result->columnCount(); $i < $i_max; $i++) {
$f = $result->getColumnMeta($i);
if (!empty($f['pgsql:oid']) && $f['pgsql:oid'] == Horde_Db_Adapter_Postgresql_Column::MONEY_COLUMN_TYPE_OID) {
$moneyFields[] = $i;
$moneyFields[] = $f['name'];
}
}
foreach ($result as $row) {
// If this is a money type column and there are any currency
// symbols, then strip them off. Indeed it would be prettier to do
// this in Horde_Db_Adapter_Postgres_Column::stringToDecimal but
// would break form input fields that call valueBeforeTypeCast.
foreach ($moneyFields as $f) {
// Because money output is formatted according to the locale, there are two
// cases to consider (note the decimal separators):
// (1) $12,345,678.12
// (2) $12.345.678,12
if (preg_match('/^-?\D+[\d,]+\.\d{2}$/', $row[$f])) { // #1
$row[$f] = preg_replace('/[^-\d\.]/', '', $row[$f]) . "\n";
} elseif (preg_match('/^-?\D+[\d\.]+,\d{2}$/', $row[$f])) { // #2
$row[$f] = str_replace(',', '.', preg_replace('/[^-\d,]/', '', $row[$f])) . "\n";
}
}
$rows[] = $row;
}
$result->closeCursor();
return $rows;
}
/**
* Returns the current ID of a table's sequence.
*/
protected function _lastInsertId($table, $sequenceName)
{
return (int)$this->selectValue('SELECT currval('.$this->quoteSequenceName($sequenceName).')');
}
}
Horde_Db-2.0.4/lib/Horde/Db/Adapter/Pdo/Sqlite.php 0000664 0001750 0001750 00000013433 12205351473 017505 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
/**
* PDO_SQLite Horde_Db_Adapter
*
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
class Horde_Db_Adapter_Pdo_Sqlite extends Horde_Db_Adapter_Pdo_Base
{
/**
* @var string
*/
protected $_schemaClass = 'Horde_Db_Adapter_Sqlite_Schema';
/**
* SQLite version number
* @var integer
*/
protected $_sqliteVersion;
/**
* @return string
*/
public function adapterName()
{
return 'PDO_SQLite';
}
/**
* @return boolean
*/
public function supportsMigrations()
{
return true;
}
/**
* Does this adapter support using DISTINCT within COUNT? This is +true+
* for all adapters except sqlite.
*
* @return boolean
*/
public function supportsCountDistinct()
{
return $this->_sqliteVersion >= '3.2.6';
}
public function supportsAutoIncrement()
{
return $this->_sqliteVersion >= '3.1.0';
}
/*##########################################################################
# Connection Management
##########################################################################*/
/**
* Connect to the db.
*
* @throws Horde_Db_Exception
*/
public function connect()
{
if ($this->_active) {
return;
}
parent::connect();
$this->_connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$this->_lastQuery = $sql = 'PRAGMA full_column_names=0';
$retval = $this->_connection->exec($sql);
if ($retval === false) {
$error = $this->_connection->errorInfo();
throw new Horde_Db_Exception($error[2]);
}
$this->_lastQuery = $sql = 'PRAGMA short_column_names=1';
$retval = $this->_connection->exec($sql);
if ($retval === false) {
$error = $this->_connection->errorInfo();
throw new Horde_Db_Exception($error[2]);
}
$this->_lastQuery = $sql = 'SELECT sqlite_version(*)';
$this->_sqliteVersion = $this->selectValue($sql);
}
/*##########################################################################
# Database Statements
##########################################################################*/
/**
* Executes the SQL statement in the context of this connection.
*
* @param string $sql
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
*/
public function execute($sql, $arg1=null, $arg2=null)
{
return $this->_catchSchemaChanges('execute', array($sql, $arg1, $arg2));
}
/**
* Begins the transaction (and turns off auto-committing).
*/
public function beginDbTransaction()
{
return $this->_catchSchemaChanges('beginDbTransaction');
}
/**
* Commits the transaction (and turns on auto-committing).
*/
public function commitDbTransaction()
{
return $this->_catchSchemaChanges('commitDbTransaction');
}
/**
* Rolls back the transaction (and turns on auto-committing). Must be
* done if the transaction block raises an exception or returns false.
*/
public function rollbackDbTransaction()
{
return $this->_catchSchemaChanges('rollbackDbTransaction');
}
/**
* SELECT ... FOR UPDATE is redundant since the table is locked.
*/
public function addLock(&$sql, array $options = array())
{
}
public function emptyInsertStatement($tableName)
{
return 'INSERT INTO '.$this->quoteTableName($tableName).' VALUES(NULL)';
}
/*##########################################################################
# Protected
##########################################################################*/
protected function _catchSchemaChanges($method, $args = array())
{
try {
return call_user_func_array(array($this, "parent::$method"), $args);
} catch (Exception $e) {
if (preg_match('/database schema has changed/i', $e->getMessage())) {
$this->reconnect();
return call_user_func_array(array($this, "parent::$method"), $args);
} else {
throw $e;
}
}
}
protected function _buildDsnString($params)
{
return 'sqlite:' . $params['dbname'];
}
/**
* Parse configuration array into options for PDO constructor
*
* @throws Horde_Db_Exception
* @return array [dsn, username, password]
*/
protected function _parseConfig()
{
// check required config keys are present
if (empty($this->_config['database']) && empty($this->_config['dbname'])) {
$msg = 'Either dbname or database is required';
throw new Horde_Db_Exception($msg);
}
// collect options to build PDO Data Source Name (DSN) string
$dsnOpts = $this->_config;
unset($dsnOpts['adapter'], $dsnOpts['username'], $dsnOpts['password']);
// return DSN and dummy user/pass for connection
return array($this->_buildDsnString($this->_normalizeConfig($dsnOpts)), '', '');
}
}
Horde_Db-2.0.4/lib/Horde/Db/Adapter/Postgresql/Column.php 0000664 0001750 0001750 00000017115 12205351473 021123 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
class Horde_Db_Adapter_Postgresql_Column extends Horde_Db_Adapter_Base_Column
{
/*##########################################################################
# Constants
##########################################################################*/
/**
* The internal PostgreSQL identifier of the money data type.
* @const integer
*/
const MONEY_COLUMN_TYPE_OID = 790;
/**
* @var integer
*/
public static $moneyPrecision = 19;
/**
* @var array
*/
protected static $_hasEmptyStringDefault = array('binary', 'string', 'text');
/**
* Construct
* @param string $name
* @param string $default
* @param string $sqlType
* @param boolean $null
*/
public function __construct($name, $default, $sqlType=null, $null=true)
{
parent::__construct($name, $this->_extractValueFromDefault($default), $sqlType, $null);
}
/**
* @param string $fieldType
* @return string
*/
protected function _simplifiedType($fieldType)
{
switch (true) {
// Numeric and monetary types
case preg_match('/^(?:real|double precision)$/', $fieldType):
return 'float';
// Monetary types
case preg_match('/^money$/', $fieldType):
return 'decimal';
// Character types
case preg_match('/^(?:character varying|bpchar)(?:\(\d+\))?$/', $fieldType):
return 'string';
// Binary data types
case preg_match('/^bytea$/', $fieldType):
return 'binary';
// Date/time types
case preg_match('/^timestamp with(?:out)? time zone$/', $fieldType):
return 'datetime';
case preg_match('/^interval$/', $fieldType):
return 'string';
// Geometric types
case preg_match('/^(?:point|line|lseg|box|"?path"?|polygon|circle)$/', $fieldType):
return 'string';
// Network address types
case preg_match('/^(?:cidr|inet|macaddr)$/', $fieldType):
return 'string';
// Bit strings
case preg_match('/^bit(?: varying)?(?:\(\d+\))?$/', $fieldType):
return 'string';
// XML type
case preg_match('/^xml$/', $fieldType):
return 'string';
// Arrays
case preg_match('/^\D+\[\]$/', $fieldType):
return 'string';
// Object identifier types
case preg_match('/^oid$/', $fieldType):
return 'integer';
}
// Pass through all types that are not specific to PostgreSQL.
return parent::_simplifiedType($fieldType);
}
/**
* Extracts the value from a PostgreSQL column default definition.
*/
protected function _extractValueFromDefault($default)
{
switch (true) {
// Numeric types
case preg_match('/\A-?\d+(\.\d*)?\z/', $default):
return $default;
// Character types
case preg_match('/\A\'(.*)\'::(?:character varying|bpchar|text)\z/m', $default, $matches):
return $matches[1];
// Character types (8.1 formatting)
case preg_match('/\AE\'(.*)\'::(?:character varying|bpchar|text)\z/m', $default, $matches):
/*@TODO fix preg callback*/
return preg_replace('/\\(\d\d\d)/', '$1.oct.chr', $matches[1]);
// Binary data types
case preg_match('/\A\'(.*)\'::bytea\z/m', $default, $matches):
return $matches[1];
// Date/time types
case preg_match('/\A\'(.+)\'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/', $default, $matches):
return $matches[1];
case preg_match('/\A\'(.*)\'::interval\z/', $default, $matches):
return $matches[1];
// Boolean type
case $default == 'true':
return true;
case $default == 'false':
return false;
// Geometric types
case preg_match('/\A\'(.*)\'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/', $default, $matches):
return $matches[1];
// Network address types
case preg_match('/\A\'(.*)\'::(?:cidr|inet|macaddr)\z/', $default, $matches):
return $matches[1];
// Bit string types
case preg_match('/\AB\'(.*)\'::"?bit(?: varying)?"?\z/', $default, $matches):
return $matches[1];
// XML type
case preg_match('/\A\'(.*)\'::xml\z/m', $default, $matches):
return $matches[1];
// Arrays
case preg_match('/\A\'(.*)\'::"?\D+"?\[\]\z/', $default, $matches):
return $matches[1];
// Object identifier types
case preg_match('/\A-?\d+\z/', $default, $matches):
return $matches[1];
default:
// Anything else is blank, some user type, or some function
// and we can't know the value of that, so return nil.
return null;
}
}
/**
* Used to convert from BLOBs (BYTEAs) to Strings.
*
* @return string
*/
public function binaryToString($value)
{
if (is_resource($value)) {
$string = stream_get_contents($value);
fclose($value);
return $string;
}
return preg_replace_callback("/(?:\\\'|\\\\\\\\|\\\\\d{3})/", array($this, 'binaryToStringCallback'), $value);
}
/**
* Callback function for binaryToString().
*/
public function binaryToStringCallback($matches)
{
if ($matches[0] == '\\\'') {
return "'";
} elseif ($matches[0] == '\\\\\\\\') {
return '\\';
}
return chr(octdec(substr($matches[0], -3)));
}
/*##########################################################################
# Protected
##########################################################################*/
/**
* @param string $sqlType
* @return int
*/
protected function _extractLimit($sqlType)
{
if (preg_match('/^bigint/i', $sqlType)) {
return 8;
}
if (preg_match('/^smallint/i', $sqlType)) {
return 2;
}
return parent::_extractLimit($sqlType);
}
/**
* @param string $sqlType
* @return int
*/
protected function _extractPrecision($sqlType)
{
if (preg_match('/^money/', $sqlType)) {
return self::$moneyPrecision;
}
return parent::_extractPrecision($sqlType);
}
/**
* @param string $sqlType
* @return int
*/
protected function _extractScale($sqlType)
{
if (preg_match('/^money/', $sqlType)) {
return 2;
}
return parent::_extractScale($sqlType);
}
}
Horde_Db-2.0.4/lib/Horde/Db/Adapter/Postgresql/Schema.php 0000664 0001750 0001750 00000125610 12205351473 021066 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @author Jan Schneider
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @author Jan Schneider
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
class Horde_Db_Adapter_Postgresql_Schema extends Horde_Db_Adapter_Base_Schema
{
/**
* The active schema search path.
*
* @var string
*/
protected $_schemaSearchPath = '';
/**
* Cached version.
*
* @var integer
*/
protected $_version;
/*##########################################################################
# Object factories
##########################################################################*/
/**
* Factory for Column objects.
*
* @param string $name The column's name, such as "supplier_id" in
* "supplier_id int(11)".
* @param string $default The type-casted default value, such as "new" in
* "sales_stage varchar(20) default 'new'".
* @param string $sqlType Used to extract the column's type, length and
* signed status, if necessary. For example
* "varchar" and "60" in "company_name varchar(60)"
* or "unsigned => true" in "int(10) UNSIGNED".
* @param boolean $null Whether this column allows NULL values.
*
* @return Horde_Db_Adapter_Postgresql_Column A column object.
*/
public function makeColumn($name, $default, $sqlType = null, $null = true)
{
return new Horde_Db_Adapter_Postgresql_Column($name, $default, $sqlType, $null);
}
/*##########################################################################
# Quoting
##########################################################################*/
/**
* Quotes the column value to help prevent SQL injection attacks.
*
* This method makes educated guesses on the scalar type based on the
* passed value. Make sure to correctly cast the value and/or pass the
* $column parameter to get the best results.
*
* @param mixed $value The scalar value to quote, a Horde_Db_Value,
* Horde_Date, or DateTime instance, or an object
* implementing quotedId().
* @param object $column An object implementing getType().
*
* @return string The correctly quoted value.
*/
public function quote($value, $column = null)
{
if (!$column) {
return parent::quote($value, $column);
}
if (is_string($value) &&
$column->getType() == 'binary') {
return $this->quoteBinary($value);
}
if (is_string($value) && $column->getSqlType() == 'xml') {
return "xml '" . $this->quoteString($value) . "'";
}
if (is_numeric($value) && $column->getSqlType() == 'money') {
// Not truly string input, so doesn't require (or allow) escape
// string syntax.
return "'" . $value . "'";
}
if (is_string($value) && substr($column->getSqlType(), 0, 3) == 'bit') {
if (preg_match('/^[01]*$/', $value)) {
// Bit-string notation
return "B'" . $value . "'";
}
if (preg_match('/^[0-9A-F]*$/i')) {
// Hexadecimal notation
return "X'" . $value . "'";
}
}
return parent::quote($value, $column);
}
/**
* Returns a quoted form of the column name.
*
* @param string $name A column name.
*
* @return string The quoted column name.
*/
public function quoteColumnName($name)
{
return '"' . str_replace('"', '""', $name) . '"';
}
/**
* Returns a quoted sequence name.
*
* PostgreSQL specific method.
*
* @param string $name A sequence name.
*
* @return string The quoted sequence name.
*/
public function quoteSequenceName($name)
{
return '\'' . str_replace('"', '""', $name) . '\'';
}
/**
* Returns a quoted binary value.
*
* @param mixed A binary value.
*
* @return string The quoted binary value.
*/
public function quoteBinary($value)
{
if ($this->postgresqlVersion() >= 90000) {
return "E'\\\\x" . bin2hex($value) . "'";
}
/* MUST escape zero octet(0), single quote (39), and backslash (92).
* MAY escape non-printable octets, but they are required in some
* instances so it is best to escape all. */
return "E'" . preg_replace_callback("/[\\x00-\\x1f\\x27\\x5c\\x7f-\\xff]/", array($this, '_quoteBinaryCallback'), $value) . "'";
}
/**
* Callback function for quoteBinary().
*
* @param array $matches Matches from preg_replace().
*
* @return string Escaped/encoded binary value.
*/
protected function _quoteBinaryCallback($matches)
{
return sprintf('\\\\%03.o', ord($matches[0]));
}
/*##########################################################################
# Schema Statements
##########################################################################*/
/**
* Returns a hash of mappings from the abstract data types to the native
* database types.
*
* See TableDefinition::column() for details on the recognized abstract
* data types.
*
* @see TableDefinition::column()
*
* @return array A database type map.
*/
public function nativeDatabaseTypes()
{
return array(
'autoincrementKey' => 'serial primary key',
'string' => array('name' => 'character varying',
'limit' => 255),
'text' => array('name' => 'text',
'limit' => null),
'mediumtext' => array('name' => 'text',
'limit' => null),
'longtext' => array('name' => 'text',
'limit' => null),
'integer' => array('name' => 'integer',
'limit' => null),
'float' => array('name' => 'float',
'limit' => null),
'decimal' => array('name' => 'decimal',
'limit' => null),
'datetime' => array('name' => 'timestamp',
'limit' => null),
'timestamp' => array('name' => 'timestamp',
'limit' => null),
'time' => array('name' => 'time',
'limit' => null),
'date' => array('name' => 'date',
'limit' => null),
'binary' => array('name' => 'bytea',
'limit' => null),
'boolean' => array('name' => 'boolean',
'limit' => null),
);
}
/**
* Returns the maximum length a table alias can have.
*
* Returns the configured supported identifier length supported by
* PostgreSQL, or report the default of 63 on PostgreSQL 7.x.
*
* @return integer The maximum table alias length.
*/
public function tableAliasLength()
{
if ($this->postgresqlVersion() >= 80000) {
return (int)$this->selectValue('SHOW max_identifier_length');
}
return 63;
}
/**
* Returns a list of all tables in the schema search path.
*
* @return array A table list.
*/
public function tables()
{
$schemas = array();
foreach (explode(',', $this->getSchemaSearchPath()) as $p) {
$schemas[] = $this->quote($p);
}
return $this->selectValues('SELECT tablename FROM pg_tables WHERE schemaname IN (' . implode(',', $schemas) . ')');
}
/**
* Returns a table's primary key.
*
* @param string $tableName A table name.
* @param string $name (can be removed?)
*
* @return Horde_Db_Adapter_Base_Index The primary key index object.
*/
public function primaryKey($tableName, $name = null)
{
$sql = '
SELECT column_name
FROM information_schema.constraint_column_usage
WHERE table_name = ?
AND constraint_name = (SELECT constraint_name
FROM information_schema.table_constraints
WHERE table_name = ?
AND constraint_type = ?)';
$pk = $this->selectValues($sql,
array($tableName, $tableName, 'PRIMARY KEY'),
$name);
return $this->makeIndex($tableName, 'PRIMARY', true, true, $pk);
}
/**
* Returns a list of tables indexes.
*
* @param string $tableName A table name.
* @param string $name (can be removed?)
*
* @return array A list of Horde_Db_Adapter_Base_Index objects.
*/
public function indexes($tableName, $name = null)
{
$indexes = @unserialize($this->_cache->get("tables/indexes/$tableName", 0));
if (!$indexes) {
$schemas = array();
foreach (explode(',', $this->getSchemaSearchPath()) as $p) {
$schemas[] = $this->quote($p);
}
$sql = "
SELECT distinct i.relname, d.indisunique, a.attname
FROM pg_class t, pg_class i, pg_index d, pg_attribute a
WHERE i.relkind = 'i'
AND d.indexrelid = i.oid
AND d.indisprimary = 'f'
AND t.oid = d.indrelid
AND t.relname = " . $this->quote($tableName) . "
AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname IN (" . implode(',', $schemas) . ") )
AND a.attrelid = t.oid
AND (d.indkey[0] = a.attnum OR d.indkey[1] = a.attnum
OR d.indkey[2] = a.attnum OR d.indkey[3] = a.attnum
OR d.indkey[4] = a.attnum OR d.indkey[5] = a.attnum
OR d.indkey[6] = a.attnum OR d.indkey[7] = a.attnum
OR d.indkey[8] = a.attnum OR d.indkey[9] = a.attnum)
ORDER BY i.relname";
$result = $this->select($sql, $name);
$currentIndex = null;
$indexes = array();
foreach ($result as $row) {
if ($currentIndex != $row['relname']) {
$currentIndex = $row['relname'];
$indexes[] = $this->makeIndex(
$tableName, $row['relname'], false, $row['indisunique'] == 't', array());
}
$indexes[count($indexes) - 1]->columns[] = $row['attname'];
}
$this->_cache->set("tables/indexes/$tableName", serialize($indexes));
}
return $indexes;
}
/**
* Returns a list of table columns.
*
* @param string $tableName A table name.
* @param string $name (can be removed?)
*
* @return array A list of Horde_Db_Adapter_Base_Column objects.
*/
public function columns($tableName, $name = null)
{
$rows = @unserialize($this->_cache->get("tables/columns/$tableName", 0));
if (!$rows) {
$rows = $this->_columnDefinitions($tableName, $name);
$this->_cache->set("tables/columns/$tableName", serialize($rows));
}
// Create columns from rows.
$columns = array();
foreach ($rows as $row) {
$columns[$row['attname']] = $this->makeColumn(
$row['attname'], $row['adsrc'], $row['format_type'], !(boolean)$row['attnotnull']);
}
return $columns;
}
/**
* Returns the list of a table's column names, data types, and default
* values.
*
* The underlying query is roughly:
* SELECT column.name, column.type, default.value
* FROM column LEFT JOIN default
* ON column.table_id = default.table_id
* AND column.num = default.column_num
* WHERE column.table_id = get_table_id('table_name')
* AND column.num > 0
* AND NOT column.is_dropped
* ORDER BY column.num
*
* If the table name is not prefixed with a schema, the database will take
* the first match from the schema search path.
*
* Query implementation notes:
* - format_type includes the column size constraint, e.g. varchar(50)
* - ::regclass is a function that gives the id for a table name
*/
protected function _columnDefinitions($tableName, $name = null)
{
/* @todo See if we can get this from information_schema instead */
return $this->selectAll('
SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull
FROM pg_attribute a LEFT JOIN pg_attrdef d
ON a.attrelid = d.adrelid AND a.attnum = d.adnum
WHERE a.attrelid = ' . $this->quote($tableName) . '::regclass
AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum', $name);
}
/**
* Renames a table.
*
* @param string $name A table name.
* @param string $newName The new table name.
*/
public function renameTable($name, $newName)
{
$this->_clearTableCache($name);
return $this->execute(sprintf('ALTER TABLE %s RENAME TO %s', $this->quoteTableName($name), $this->quoteTableName($newName)));
}
/**
* Adds a new column to a table.
*
* @param string $tableName A table name.
* @param string $columnName A column name.
* @param string $type A data type.
* @param array $options Column options. See
* Horde_Db_Adapter_Base_TableDefinition#column()
* for details.
*/
public function addColumn($tableName, $columnName, $type,
$options = array())
{
$this->_clearTableCache($tableName);
$options = array_merge(
array('autoincrement' => null,
'limit' => null,
'precision' => null,
'scale' => null),
$options);
$sqltype = $this->typeToSql($type, $options['limit'],
$options['precision'], $options['scale']);
/* Convert to SERIAL type if needed. */
if ($options['autoincrement']) {
switch ($sqltype) {
case 'bigint':
$sqltype = 'BIGSERIAL';
break;
case 'integer':
default:
$sqltype = 'SERIAL';
break;
}
}
// Add the column.
$sql = sprintf('ALTER TABLE %s ADD COLUMN %s %s',
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName),
$sqltype);
$this->execute($sql);
if (array_key_exists('default', $options)) {
$sql = sprintf('UPDATE %s SET %s = %s',
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName),
$this->quote($options['default']));
$this->execute($sql);
$this->changeColumnDefault($tableName, $columnName,
$options['default']);
}
if (isset($options['null']) && $options['null'] === false) {
$this->changeColumnNull(
$tableName, $columnName, false,
isset($options['default']) ? $options['default'] : null);
}
}
/**
* Changes an existing column's definition.
*
* @param string $tableName A table name.
* @param string $columnName A column name.
* @param string $type A data type.
* @param array $options Column options. See
* Horde_Db_Adapter_Base_TableDefinition#column()
* for details.
*/
public function changeColumn($tableName, $columnName, $type,
$options = array())
{
$this->_clearTableCache($tableName);
$options = array_merge(
array('autoincrement' => null,
'limit' => null,
'precision' => null,
'scale' => null),
$options);
$quotedTableName = $this->quoteTableName($tableName);
$primaryKey = $type == 'autoincrementKey';
if ($primaryKey) {
$type = 'integer';
$options['autoincrement'] = true;
$options['limit'] = $options['precision'] = $options['scale'] = null;
try {
$this->removePrimaryKey($tableName);
} catch (Horde_Db_Exception $e) {
}
}
$sql = sprintf('ALTER TABLE %s ALTER COLUMN %s TYPE %s',
$quotedTableName,
$this->quoteColumnName($columnName),
$this->typeToSql($type,
$options['limit'],
$options['precision'],
$options['scale']));
try {
$this->execute($sql);
} catch (Horde_Db_Exception $e) {
// This is PostgreSQL 7.x, or the old type could not be coerced to
// the new type, so we have to use a more arcane way of doing it.
try {
// Booleans can't always be cast to other data types; do extra
// work to handle them.
$oldType = null;
foreach ($this->columns($tableName) as $column) {
if ($column->getName() == $columnName) {
$oldType = $column->getType();
break;
}
}
if ($oldType === null) {
throw new Horde_Db_Exception("$tableName does not have a column '$columnName'");
}
$this->beginDbTransaction();
$tmpColumnName = $columnName.'_change_tmp';
$this->addColumn($tableName, $tmpColumnName, $type, $options);
if ($oldType == 'boolean') {
$sql = sprintf('UPDATE %s SET %s = CAST(CASE WHEN %s IS TRUE THEN 1 ELSE 0 END AS %s)',
$quotedTableName,
$this->quoteColumnName($tmpColumnName),
$this->quoteColumnName($columnName),
$this->typeToSql($type,
$options['limit'],
$options['precision'],
$options['scale']));
} else {
$sql = sprintf('UPDATE %s SET %s = CAST(%s AS %s)',
$quotedTableName,
$this->quoteColumnName($tmpColumnName),
$this->quoteColumnName($columnName),
$this->typeToSql($type,
$options['limit'],
$options['precision'],
$options['scale']));
}
$this->execute($sql);
$this->removeColumn($tableName, $columnName);
$this->renameColumn($tableName, $tmpColumnName, $columnName);
$this->commitDbTransaction();
} catch (Horde_Db_Exception $e) {
$this->rollbackDbTransaction();
throw $e;
}
}
if ($options['autoincrement']) {
$seq_name = $this->defaultSequenceName($tableName, $columnName);
try {
$this->execute('DROP SEQUENCE ' . $seq_name . ' CASCADE');
} catch (Horde_Db_Exception $e) {}
$this->execute('CREATE SEQUENCE ' . $seq_name);
$this->resetPkSequence($tableName, $columnName, $seq_name);
/* Can't use changeColumnDefault() since it quotes the
* default value (NEXTVAL is a postgres keyword, not a text
* value). */
$this->_clearTableCache($tableName);
$sql = sprintf('ALTER TABLE %s ALTER COLUMN %s SET DEFAULT NEXTVAL(%s)',
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName),
$this->quoteSequenceName($seq_name));
$this->execute($sql);
if ($this->postgresqlVersion() >= 80200) {
$sql = sprintf('ALTER SEQUENCE %s OWNED BY %s.%s',
$seq_name,
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName));
$this->execute($sql);
}
} elseif (array_key_exists('default', $options)) {
$this->changeColumnDefault($tableName, $columnName,
$options['default']);
}
if ($primaryKey) {
$this->addPrimaryKey($tableName, $columnName);
}
if (array_key_exists('null', $options)) {
$this->changeColumnNull(
$tableName, $columnName, $options['null'],
isset($options['default']) ? $options['default'] : null);
}
}
/**
* Sets a new default value for a column.
*
* If you want to set the default value to NULL, you are out of luck. You
* need to execute the apppropriate SQL statement yourself.
*
* @param string $tableName A table name.
* @param string $columnName A column name.
* @param mixed $default The new default value.
*/
public function changeColumnDefault($tableName, $columnName, $default)
{
$this->_clearTableCache($tableName);
$sql = sprintf('ALTER TABLE %s ALTER COLUMN %s SET DEFAULT %s',
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName),
$this->quote($default));
return $this->execute($sql);
}
/**
* Sets whether a column allows NULL values.
*
* @param string $tableName A table name.
* @param string $columnName A column name.
* @param boolean $null Whether NULL values are allowed.
* @param mixed $default The new default value.
*/
public function changeColumnNull($tableName, $columnName, $null,
$default = null)
{
$this->_clearTableCache($tableName);
if (!$null && !is_null($default)) {
$sql = sprintf('UPDATE %s SET %s = %s WHERE %s IS NULL',
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName),
$this->quote($default),
$this->quoteColumnName($columnName));
$this->execute($sql);
}
$sql = sprintf('ALTER TABLE %s ALTER %s %s NOT NULL',
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName),
$null ? 'DROP' : 'SET');
return $this->execute($sql);
}
/**
* Renames a column.
*
* @param string $tableName A table name.
* @param string $columnName A column name.
* @param string $newColumnName The new column name.
*/
public function renameColumn($tableName, $columnName, $newColumnName)
{
$this->_clearTableCache($tableName);
$sql = sprintf('ALTER TABLE %s RENAME COLUMN %s TO %s',
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName),
$this->quoteColumnName($newColumnName));
return $this->execute($sql);
}
/**
* Removes a primary key from a table.
*
* @param string $tableName A table name.
*
* @throws Horde_Db_Exception
*/
public function removePrimaryKey($tableName)
{
$this->_clearTableCache($tableName);
$keyName = $this->selectValue(
'SELECT constraint_name
FROM information_schema.table_constraints
WHERE table_name = ?
AND constraint_type = ?',
array($tableName, 'PRIMARY KEY'));
if ($keyName) {
$sql = sprintf('ALTER TABLE %s DROP CONSTRAINT %s CASCADE',
$this->quoteTableName($tableName),
$this->quoteColumnName($keyName));
return $this->execute($sql);
}
}
/**
* Removes an index from a table.
*
* See parent class for examples.
*
* @param string $tableName A table name.
* @param string|array $options Either a column name or index options:
* - name: (string) the index name.
* - column: (string|array) column name(s).
*/
public function removeIndex($tableName, $options = array())
{
$this->_clearTableCache($tableName);
return $this->execute('DROP INDEX ' . $this->indexName($tableName, $options));
}
/**
* Creates a database.
*
* @param string $name A database name.
* @param array $options Database options: owner, template, charset,
* tablespace, and connection_limit.
*/
public function createDatabase($name, $options = array())
{
$options = array_merge(array('charset' => 'utf8'), $options);
$optionString = '';
foreach ($options as $key => $value) {
switch ($key) {
case 'owner':
$optionString .= " OWNER = '$value'";
break;
case 'template':
$optionString .= " TEMPLATE = $value";
break;
case 'charset':
$optionString .= " ENCODING = '$value'";
break;
case 'tablespace':
$optionString .= " TABLESPACE = $value";
break;
case 'connection_limit':
$optionString .= " CONNECTION LIMIT = $value";
}
}
return $this->execute('CREATE DATABASE ' . $this->quoteTableName($name) . $optionString);
}
/**
* Drops a database.
*
* @param string $name A database name.
*/
public function dropDatabase($name)
{
if ($this->postgresqlVersion() >= 80200) {
return $this->execute('DROP DATABASE IF EXISTS ' . $this->quoteTableName($name));
}
try {
return $this->execute('DROP DATABASE ' . $this->quoteTableName($name));
} catch (Horde_Db_Exception $e) {
if ($this->_logger) {
$this->_logger->warn("$name database doesn't exist");
}
}
}
/**
* Returns the name of the currently selected database.
*
* @return string The database name.
*/
public function currentDatabase()
{
return $this->selectValue('SELECT current_database()');
}
/**
* Generates the SQL definition for a column type.
*
* @param string $type A column type.
* @param integer $limit Maximum column length (non decimal type only)
* @param integer $precision The number precision (decimal type only).
* @param integer $scale The number scaling (decimal columns only).
* @param boolean $unsigned Whether the column is an unsigned number
* (non decimal columns only).
*
* @return string The SQL definition. If $type is not one of the
* internally supported types, $type is returned unchanged.
*/
public function typeToSql($type, $limit = null, $precision = null,
$scale = null, $unsigned = null)
{
if ($type != 'integer') {
return parent::typeToSql($type, $limit, $precision, $scale);
}
switch ($limit) {
case 1:
case 2:
return 'smallint';
case 3:
case 4:
case null:
return 'integer';
case 5:
case 6:
case 7:
case 8:
return 'bigint';
}
throw new Horde_Db_Exception("No integer type has byte size $limit. Use a numeric with precision 0 instead.");
}
/**
* Generates a DISTINCT clause for SELECT queries.
*
* PostgreSQL requires the ORDER BY columns in the SELECT list for distinct
* queries, and requires that the ORDER BY include the DISTINCT column.
*
*
* $connection->distinct('posts.id', 'posts.created_at DESC')
*
*
* @param string $columns A column list.
* @param string $orderBy An ORDER clause.
*
* @return string The generated DISTINCT clause.
*/
public function distinct($columns, $orderBy = null)
{
if (empty($orderBy)) {
return 'DISTINCT ' . $columns;
}
// Construct a clean list of column names from the ORDER BY clause,
// removing any ASC/DESC modifiers.
$orderColumns = array();
foreach (preg_split('/\s*,\s*/', $orderBy, -1, PREG_SPLIT_NO_EMPTY) as $orderByClause) {
$orderColumns[] = current(preg_split('/\s+/', $orderByClause, -1, PREG_SPLIT_NO_EMPTY)) . ' AS alias_' . count($orderColumns);
}
// Return a DISTINCT ON() clause that's distinct on the columns we want
// but includes all the required columns for the ORDER BY to work
// properly.
return sprintf('DISTINCT ON (%s) %s, %s',
$columns, $columns, implode(', ', $orderColumns));
}
/**
* Adds an ORDER BY clause to an existing query.
*
* PostgreSQL does not allow arbitrary ordering when using DISTINCT ON, so
* we work around this by wrapping the $sql string as a sub-select and
* ordering in that query.
*
* @param string $sql An SQL query to manipulate.
* @param array $options Options:
* - order: Order column an direction.
*
* @return string The manipulated SQL query.
*/
public function addOrderByForAssociationLimiting($sql, $options)
{
if (empty($options['order'])) {
return $sql;
}
$order = array();
foreach (preg_split('/\s*,\s*/', $options['order'], -1, PREG_SPLIT_NO_EMPTY) as $s) {
if (preg_match('/\bdesc$/i', $s)) {
$s = 'DESC';
}
$order[] = 'id_list.alias_' . count($order) . ' ' . $s;
}
$order = implode(', ', $order);
return sprintf('SELECT * FROM (%s) AS id_list ORDER BY %s',
$sql, $order);
}
/**
* Generates an INTERVAL clause for SELECT queries.
*
* @param string $interval The interval.
* @param string $precision The precision.
*
* @return string The generated INTERVAL clause.
*/
public function interval($interval, $precision)
{
return 'INTERVAL \'' . $interval . ' ' . $precision . '\'';
}
/**
* Generates a modified date for SELECT queries.
*
* @param string $reference The reference date - this is a column
* referenced in the SELECT.
* @param string $operator Add or subtract time? (+/-)
* @param integer $amount The shift amount (number of days if $interval
* is DAY, etc).
* @param string $interval The interval (SECOND, MINUTE, HOUR, DAY,
* MONTH, YEAR).
*
* @return string The generated INTERVAL clause.
*/
public function modifyDate($reference, $operator, $amount, $interval)
{
if (!is_int($amount)) {
throw new InvalidArgumentException('$amount parameter must be an integer');
}
return sprintf('%s %s INTERVAL \'%s %s\'',
$reference,
$operator,
$amount,
$interval);
}
/**
* Returns an expression using the specified operator.
*
* @param string $lhs The column or expression to test.
* @param string $op The operator.
* @param string $rhs The comparison value.
* @param boolean $bind If true, the method returns the query and a list
* of values suitable for binding as an array.
* @param array $params Any additional parameters for the operator.
*
* @return string|array The SQL test fragment, or an array containing the
* query and a list of values if $bind is true.
*/
public function buildClause($lhs, $op, $rhs, $bind = false,
$params = array())
{
$lhs = $this->_escapePrepare($lhs);
switch ($op) {
case '|':
case '&':
/* Only PgSQL 7.3+ understands SQL99 'SIMILAR TO'; use ~ for
* greater backwards compatibility. */
$query = 'CASE WHEN CAST(%s AS VARCHAR) ~ \'^-?[0-9]+$\' THEN (CAST(%s AS INTEGER) %s %s) <> 0 ELSE FALSE END';
if ($bind) {
return array(sprintf($query, $lhs, $lhs, $op, '?'),
array((int)$rhs));
} else {
return sprintf($query, $lhs, $lhs, $op, (int)$rhs);
}
case 'LIKE':
$query = '%s ILIKE %s';
if ($bind) {
if (empty($params['begin'])) {
return array(sprintf($query, $lhs, '?'),
array('%' . $rhs . '%'));
}
return array(sprintf('(' . $query . ' OR ' . $query . ')',
$lhs, '?', $lhs, '?'),
array($rhs . '%', '% ' . $rhs . '%'));
}
if (empty($params['begin'])) {
return sprintf($query,
$lhs,
$this->_escapePrepare($this->quote('%' . $rhs . '%')));
}
return sprintf('(' . $query . ' OR ' . $query . ')',
$lhs,
$this->_escapePrepare($this->quote($rhs . '%')),
$lhs,
$this->_escapePrepare($this->quote('% ' . $rhs . '%')));
}
return parent::buildClause($lhs, $op, $rhs, $bind, $params);
}
/*##########################################################################
# PostgreSQL specific methods
##########################################################################*/
/**
* Returns the current database's encoding format.
*
* @return string The current database's encoding format.
*/
public function encoding()
{
return $this->selectValue(
'SELECT pg_encoding_to_char(pg_database.encoding) FROM pg_database
WHERE pg_database.datname LIKE ' . $this->quote($this->currentDatabase()));
}
/**
* Sets the schema search path to a string of comma-separated schema names.
*
* Names beginning with $ have to be quoted (e.g. $user => '$user'). See:
* http://www.postgresql.org/docs/current/static/ddl-schemas.html
*
* @param string $schemaCsv A comma-separated schema name list.
*/
public function setSchemaSearchPath($schemaCsv)
{
if ($schemaCsv) {
$this->execute('SET search_path TO ' . $schemaCsv);
$this->_schemaSearchPath = $schemaCsv;
}
}
/**
* Returns the active schema search path.
*
* @return string The active schema search path.
*/
public function getSchemaSearchPath()
{
if (!$this->_schemaSearchPath) {
$this->_schemaSearchPath = $this->selectValue('SHOW search_path');
}
return $this->_schemaSearchPath;
}
/**
* Returns the current client log message level.
*
* @return string The current client log message level.
*/
public function getClientMinMessages()
{
return $this->selectValue('SHOW client_min_messages');
}
/**
* Sets the client log message level.
*
* @param string $level The client log message level. One of DEBUG5,
* DEBUG4, DEBUG3, DEBUG2, DEBUG1, LOG, NOTICE,
* WARNING, ERROR, FATAL, or PANIC.
*/
public function setClientMinMessages($level)
{
return $this->execute('SET client_min_messages TO ' . $this->quote($level));
}
/**
* Returns the sequence name for a table's primary key or some other
* specified key.
*
* If a sequence name doesn't exist, it is built from the table and primary
* key name.
*
* @param string $tableName A table name.
* @param string $pk A primary key name. Overrides the existing key
* name when building a new sequence name.
*
* @return string The key's sequence name.
*/
public function defaultSequenceName($tableName, $pk = null)
{
list($defaultPk, $defaultSeq) = $this->pkAndSequenceFor($tableName);
if (!$defaultSeq) {
$defaultSeq = $tableName . '_' . ($pk ? $pk : ($defaultPk ? $defaultPk : 'id')) . '_seq';
}
return $defaultSeq;
}
/**
* Resets the sequence of a table's primary key to the maximum value.
*
* @param string $tableName A table name.
* @param string $pk A primary key name. Defaults to the existing
* primary key.
* @param string $sequence A sequence name. Defaults to the sequence name
* of the existing primary key.
*
* @return integer The (next) sequence value if a primary key and a
* sequence exist.
*/
public function resetPkSequence($table, $pk = null, $sequence = null)
{
if (!$pk || !$sequence) {
list($defaultPk, $defaultSequence) = $this->pkAndSequenceFor($table);
if (!$pk) {
$pk = $defaultPk;
}
if (!$sequence) {
$sequence = $defaultSequence;
}
}
if ($pk) {
if ($sequence) {
$quotedSequence = $this->quoteSequenceName($sequence);
$quotedTable = $this->quoteTableName($table);
$quotedPk = $this->quoteColumnName($pk);
$sql = sprintf('SELECT setval(%s, (SELECT COALESCE(MAX(%s) + (SELECT increment_by FROM %s), (SELECT min_value FROM %s)) FROM %s), false)',
$quotedSequence,
$quotedPk,
$sequence,
$sequence,
$quotedTable);
$this->selectValue($sql, 'Reset sequence');
} else {
if ($this->_logger) {
$this->_logger->warn(sprintf('%s has primary key %s with no default sequence', $table, $pk));
}
}
}
}
/**
* Returns a table's primary key and the key's sequence.
*
* @param string $tableName A table name.
*
* @return array Array with two values: the primary key name and the key's
* sequence name.
*/
public function pkAndSequenceFor($table)
{
// First try looking for a sequence with a dependency on the
// given table's primary key.
$sql = "
SELECT attr.attname, seq.relname
FROM pg_class seq,
pg_attribute attr,
pg_depend dep,
pg_namespace name,
pg_constraint cons
WHERE seq.oid = dep.objid
AND seq.relkind = 'S'
AND attr.attrelid = dep.refobjid
AND attr.attnum = dep.refobjsubid
AND attr.attrelid = cons.conrelid
AND attr.attnum = cons.conkey[1]
AND cons.contype = 'p'
AND dep.refobjid = '$table'::regclass";
$result = $this->selectOne($sql, 'PK and serial sequence');
if (!$result) {
// If that fails, try parsing the primary key's default value.
// Support the 7.x and 8.0 nextval('foo'::text) as well as
// the 8.1+ nextval('foo'::regclass).
$sql = "
SELECT attr.attname,
CASE
WHEN split_part(def.adsrc, '''', 2) ~ '.' THEN
substr(split_part(def.adsrc, '''', 2),
strpos(split_part(def.adsrc, '''', 2), '.')+1)
ELSE split_part(def.adsrc, '''', 2)
END AS relname
FROM pg_class t
JOIN pg_attribute attr ON (t.oid = attrelid)
JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
WHERE t.oid = '$table'::regclass
AND cons.contype = 'p'
AND def.adsrc ~* 'nextval'";
$result = $this->selectOne($sql, 'PK and custom sequence');
}
// [primary_key, sequence]
return array($result['attname'], $result['relname']);
}
/**
* Returns the version of the connected PostgreSQL server.
*
* @return integer Zero padded PostgreSQL version, e.g. 80108 for 8.1.8.
*/
public function postgresqlVersion()
{
if (!$this->_version) {
try {
$version = $this->selectValue('SELECT version()');
if (preg_match('/PostgreSQL (\d+)\.(\d+)\.(\d+)/', $version, $matches))
$this->_version = ($matches[1] * 10000) + ($matches[2] * 100) + $matches[3];
} catch (Exception $e) {
return 0;
}
}
return $this->_version;
}
}
Horde_Db-2.0.4/lib/Horde/Db/Adapter/Sqlite/Column.php 0000664 0001750 0001750 00000004554 12205351473 020224 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
class Horde_Db_Adapter_Sqlite_Column extends Horde_Db_Adapter_Base_Column
{
/**
* @var array
*/
protected static $_hasEmptyStringDefault = array('binary', 'string', 'text');
public function extractDefault($default)
{
$default = parent::extractDefault($default);
if ($this->isText()) {
$default = $this->_unquote($default);
}
return $default;
}
/*##########################################################################
# Type Juggling
##########################################################################*/
public function binaryToString($value)
{
return str_replace(array('%00', '%25'), array("\0", '%'), $value);
}
/**
* @param mixed $value
* @return boolean
*/
public function valueToBoolean($value)
{
if ($value == '"t"' || $value == "'t'") {
return true;
} elseif ($value == '""' || $value == "''") {
return null;
} else {
return parent::valueToBoolean($value);
}
}
/*##########################################################################
# Protected
##########################################################################*/
/**
* Unquote a string value
*
* @return string
*/
protected function _unquote($string)
{
$first = substr($string, 0, 1);
if ($first == "'" || $first == '"') {
$string = substr($string, 1);
if (substr($string, -1) == $first) {
$string = substr($string, 0, -1);
}
$string = str_replace("$first$first", $first, $string);
}
return $string;
}
}
Horde_Db-2.0.4/lib/Horde/Db/Adapter/Sqlite/Schema.php 0000664 0001750 0001750 00000064572 12205351473 020175 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @author Jan Schneider
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @author Jan Schneider
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
class Horde_Db_Adapter_Sqlite_Schema extends Horde_Db_Adapter_Base_Schema
{
/*##########################################################################
# Object factories
##########################################################################*/
/**
* Factory for Column objects.
*
* @param string $name The column's name, such as "supplier_id" in
* "supplier_id int(11)".
* @param string $default The type-casted default value, such as "new" in
* "sales_stage varchar(20) default 'new'".
* @param string $sqlType Used to extract the column's type, length and
* signed status, if necessary. For example
* "varchar" and "60" in "company_name varchar(60)"
* or "unsigned => true" in "int(10) UNSIGNED".
* @param boolean $null Whether this column allows NULL values.
*
* @return Horde_Db_Adapter_Base_Column A column object.
*/
public function makeColumn($name, $default, $sqlType = null, $null = true)
{
return new Horde_Db_Adapter_Sqlite_Column($name, $default, $sqlType, $null);
}
/*##########################################################################
# Quoting
##########################################################################*/
/**
* Returns a quoted form of the column name.
*
* @param string $name A column name.
*
* @return string The quoted column name.
*/
public function quoteColumnName($name)
{
return '"' . str_replace('"', '""', $name) . '"';
}
/**
* Returns a quoted boolean true.
*
* @return string The quoted boolean true.
*/
public function quoteTrue()
{
return '1';
}
/**
* Returns a quoted boolean false.
*
* @return string The quoted boolean false.
*/
public function quoteFalse()
{
return '0';
}
/**
* Returns a quoted binary value.
*
* @param mixed A binary value.
*
* @return string The quoted binary value.
*/
public function quoteBinary($value)
{
return "'" . str_replace(array("'", '%', "\0"), array("''", '%25', '%00'), $value) . "'";
}
/*##########################################################################
# Schema Statements
##########################################################################*/
/**
* Returns a hash of mappings from the abstract data types to the native
* database types.
*
* See TableDefinition::column() for details on the recognized abstract
* data types.
*
* @see TableDefinition::column()
*
* @return array A database type map.
*/
public function nativeDatabaseTypes()
{
return array(
'autoincrementKey' => $this->_defaultPrimaryKeyType(),
'string' => array('name' => 'varchar', 'limit' => 255),
'text' => array('name' => 'text', 'limit' => null),
'mediumtext' => array('name' => 'text', 'limit' => null),
'longtext' => array('name' => 'text', 'limit' => null),
'integer' => array('name' => 'int', 'limit' => null),
'float' => array('name' => 'float', 'limit' => null),
'decimal' => array('name' => 'decimal', 'limit' => null),
'datetime' => array('name' => 'datetime', 'limit' => null),
'timestamp' => array('name' => 'datetime', 'limit' => null),
'time' => array('name' => 'time', 'limit' => null),
'date' => array('name' => 'date', 'limit' => null),
'binary' => array('name' => 'blob', 'limit' => null),
'boolean' => array('name' => 'boolean', 'limit' => null),
);
}
/**
* Returns a list of all tables of the current database.
*
* @return array A table list.
*/
public function tables()
{
return $this->selectValues("SELECT name FROM sqlite_master WHERE type = 'table' UNION ALL SELECT name FROM sqlite_temp_master WHERE type = 'table' AND name != 'sqlite_sequence' ORDER BY name");
}
/**
* Returns a table's primary key.
*
* @param string $tableName A table name.
* @param string $name (can be removed?)
*
* @return Horde_Db_Adapter_Base_Index The primary key index object.
*/
public function primaryKey($tableName, $name = null)
{
// Share the columns cache with the columns() method
$rows = @unserialize($this->_cache->get("tables/columns/$tableName", 0));
if (!$rows) {
$rows = $this->selectAll('PRAGMA table_info(' . $this->quoteTableName($tableName) . ')', $name);
$this->_cache->set("tables/columns/$tableName", serialize($rows));
}
$pk = $this->makeIndex($tableName, 'PRIMARY', true, true, array());
foreach ($rows as $row) {
if ($row['pk'] == 1) {
$pk->columns[] = $row['name'];
}
}
return $pk;
}
/**
* Returns a list of tables indexes.
*
* @param string $tableName A table name.
* @param string $name (can be removed?)
*
* @return array A list of Horde_Db_Adapter_Base_Index objects.
*/
public function indexes($tableName, $name = null)
{
$indexes = @unserialize($this->_cache->get("tables/indexes/$tableName", 0));
if (!$indexes) {
$indexes = array();
foreach ($this->select('PRAGMA index_list(' . $this->quoteTableName($tableName) . ')') as $row) {
if (strpos($row['name'], 'sqlite_') !== false) {
// ignore internal sqlite_* index tables
continue;
}
$index = $this->makeIndex(
$tableName, $row['name'], false, (bool)$row['unique'], array());
foreach ($this->select('PRAGMA index_info(' . $this->quoteColumnName($index->name) . ')') as $field) {
$index->columns[] = $field['name'];
}
$indexes[] = $index;
}
$this->_cache->set("tables/indexes/$tableName", serialize($indexes));
}
return $indexes;
}
/**
* Returns a list of table columns.
*
* @param string $tableName A table name.
* @param string $name (can be removed?)
*
* @return array A list of Horde_Db_Adapter_Base_Column objects.
*/
public function columns($tableName, $name = null)
{
$rows = @unserialize($this->_cache->get("tables/columns/$tableName", 0));
if (!$rows) {
$rows = $this->selectAll('PRAGMA table_info(' . $this->quoteTableName($tableName) . ')', $name);
$this->_cache->set("tables/columns/$tableName", serialize($rows));
}
// create columns from rows
$columns = array();
foreach ($rows as $row) {
$columns[$row['name']] = $this->makeColumn(
$row['name'], $row['dflt_value'], $row['type'], !(bool)$row['notnull']);
}
return $columns;
}
/**
* Renames a table.
*
* @param string $name A table name.
* @param string $newName The new table name.
*/
public function renameTable($name, $newName)
{
$this->_clearTableCache($name);
$sql = sprintf('ALTER TABLE %s RENAME TO %s',
$this->quoteTableName($name),
$this->quoteTableName($newName));
return $this->execute($sql);
}
/**
* Adds a new column to a table.
*
* @param string $tableName A table name.
* @param string $columnName A column name.
* @param string $type A data type.
* @param array $options Column options. See
* Horde_Db_Adapter_Base_TableDefinition#column()
* for details.
*/
public function addColumn($tableName, $columnName, $type, $options=array())
{
/* Ignore ':autoincrement' - it is handled automatically by SQLite
* for any 'INTEGER PRIMARY KEY' column. */
if ($this->transactionStarted()) {
throw new Horde_Db_Exception('Cannot add columns to a SQLite database while inside a transaction');
}
parent::addColumn($tableName, $columnName, $type, $options);
// See last paragraph on http://www.sqlite.org/lang_altertable.html
$this->execute('VACUUM');
}
/**
* Removes a column from a table.
*
* @param string $tableName A table name.
* @param string $columnName A column name.
*/
public function removeColumn($tableName, $columnName)
{
$this->_clearTableCache($tableName);
return $this->_alterTable(
$tableName,
array(),
create_function('$definition',
'unset($definition["' . $columnName . '"]);'));
}
/**
* Changes an existing column's definition.
*
* @param string $tableName A table name.
* @param string $columnName A column name.
* @param string $type A data type.
* @param array $options Column options. See
* Horde_Db_Adapter_Base_TableDefinition#column()
* for details.
*/
public function changeColumn($tableName, $columnName, $type, $options=array())
{
$this->_clearTableCache($tableName);
$defs = array(sprintf('$definition["%s"]->setType("%s"); if ("%s" == "autoincrementKey") $definition->primaryKey(false);', $columnName, $type, $type));
if (isset($options['limit'])) {
$defs[] = sprintf('$definition["%s"]->setLimit("%s");', $columnName, $options['limit']);
}
if (isset($options['null'])) {
$defs[] = sprintf('$definition["%s"]->setNull("%s");', $columnName, $options['null']);
}
if (isset($options['precision'])) {
$defs[] = sprintf('$definition["%s"]->setPrecision("%s");', $columnName, $options['precision']);
}
if (isset($options['scale'])) {
$defs[] = sprintf('$definition["%s"]->setScale("%s");', $columnName, $options['scale']);
}
if (array_key_exists('default', $options)) {
if ($options['default'] === true) {
$default = 'true';
} elseif ($options['default'] === false) {
$default = 'false';
} elseif ($options['default'] === null) {
$default = 'null';
} else {
$default = '"' . $options['default'] . '"';
}
$defs[] = sprintf('$definition["%s"]->setDefault(%s);', $columnName, $default);
}
return $this->_alterTable(
$tableName,
array(),
create_function('$definition', implode("\n", $defs)));
}
/**
* Sets a new default value for a column.
*
* If you want to set the default value to NULL, you are out of luck. You
* need to execute the apppropriate SQL statement yourself.
*
* @param string $tableName A table name.
* @param string $columnName A column name.
* @param mixed $default The new default value.
*/
public function changeColumnDefault($tableName, $columnName, $default)
{
$this->_clearTableCache($tableName);
$default = is_null($default) ? 'null' : '"' . $default . '"';
return $this->_alterTable(
$tableName,
array(),
create_function('$definition',
sprintf('$definition["%s"]->setDefault(%s);',
$columnName, $default)));
}
/**
* Renames a column.
*
* @param string $tableName A table name.
* @param string $columnName A column name.
* @param string $newColumnName The new column name.
*/
public function renameColumn($tableName, $columnName, $newColumnName)
{
$this->_clearTableCache($tableName);
return $this->_alterTable(
$tableName,
array('rename' => array($columnName => $newColumnName)));
}
/**
* Adds a primary key to a table.
*
* @param string $tableName A table name.
* @param string|array $columnName One or more column names.
*
* @throws Horde_Db_Exception
*/
public function addPrimaryKey($tableName, $columns)
{
$this->_clearTableCache($tableName);
$columns = (array)$columns;
foreach ($columns as &$column) {
$column = '"' . $column . '"';
}
$callback = create_function(
'$definition',
sprintf('$definition->primaryKey(array(%s));',
implode(', ', $columns)));
$this->_alterTable($tableName, array(), $callback);
}
/**
* Removes a primary key from a table.
*
* @param string $tableName A table name.
*
* @throws Horde_Db_Exception
*/
public function removePrimaryKey($tableName)
{
$this->_clearTableCache($tableName);
$callback = create_function('$definition',
'$definition->primaryKey(false);');
$this->_alterTable($tableName, array(), $callback);
}
/**
* Removes an index from a table.
*
* See parent class for examples.
*
* @param string $tableName A table name.
* @param string|array $options Either a column name or index options:
* - name: (string) the index name.
* - column: (string|array) column name(s).
*/
public function removeIndex($tableName, $options=array())
{
$this->_clearTableCache($tableName);
$index = $this->indexName($tableName, $options);
$sql = 'DROP INDEX ' . $this->quoteColumnName($index);
return $this->execute($sql);
}
/**
* Creates a database.
*
* @param string $name A database name.
* @param array $options Database options.
*/
public function createDatabase($name, $options = array())
{
return new PDO('sqlite:' . $name);
}
/**
* Drops a database.
*
* @param string $name A database name.
*/
public function dropDatabase($name)
{
if (!@file_exists($name)) {
throw new Horde_Db_Exception('database does not exist');
}
if (!@unlink($name)) {
throw new Horde_Db_Exception('could not remove the database file');
}
}
/**
* Returns the name of the currently selected database.
*
* @return string The database name.
*/
public function currentDatabase()
{
return $this->_config['dbname'];
}
/**
* Generates a modified date for SELECT queries.
*
* @param string $reference The reference date - this is a column
* referenced in the SELECT.
* @param string $operator Add or subtract time? (+/-)
* @param integer $amount The shift amount (number of days if $interval
* is DAY, etc).
* @param string $interval The interval (SECOND, MINUTE, HOUR, DAY,
* MONTH, YEAR).
*
* @return string The generated INTERVAL clause.
*/
public function modifyDate($reference, $operator, $amount, $interval)
{
if (!is_int($amount)) {
throw new InvalidArgumentException('$amount parameter must be an integer');
}
switch ($interval) {
case 'YEAR':
$interval = 'years';
break;
case 'MONTH':
$interval = 'months';
break;
case 'DAY':
$interval = 'days';
break;
case 'HOUR':
$interval = 'hours';
break;
case 'MINUTE':
$interval = 'minutes';
break;
case 'SECOND':
$interval = 'seconds';
break;
default:
break;
}
return 'datetime(' . $reference . ', \'' . $operator . $amount . ' '
. $interval . '\')';
}
/*##########################################################################
# Protected
##########################################################################*/
/**
* Returns a column type definition to be use for primary keys.
*
* @return string Primary key type definition.
*/
protected function _defaultPrimaryKeyType()
{
if ($this->supportsAutoIncrement()) {
return 'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL';
} else {
return 'INTEGER PRIMARY KEY NOT NULL';
}
}
/**
* Alters a table.
*
* This is done by creating a temporary copy, applying changes and callback
* methods, and copying the table back.
*
* @param string $tableName A table name.
* @param array $options Any options to apply when creating the
* temporary table. Supports a 'rename' key for
* the new table name, additionally to the
* options in createTable().
* @param function $callback A callback function that can manipulate the
* Horde_Db_Adapter_Base_TableDefinition object
* available in $definition. See _copyTable().
*/
protected function _alterTable($tableName, $options = array(), $callback = null)
{
$this->beginDbTransaction();
$alteredTableName = 'altered_' . $tableName;
$this->_moveTable($tableName,
$alteredTableName,
array_merge($options, array('temporary' => true)));
$this->_moveTable($alteredTableName,
$tableName,
array(),
$callback);
$this->commitDbTransaction();
}
/**
* Moves a table.
*
* This is done by creating a temporary copy, applying changes and callback
* methods, and dropping the original table.
*
* @param string $from The name of the source table.
* @param string $to The name of the target table.
* @param array $options Any options to apply when creating the
* temporary table. Supports a 'rename' key for
* the new table name, additionally to the
* options in createTable().
* @param function $callback A callback function that can manipulate the
* Horde_Db_Adapter_Base_TableDefinition object
* available in $definition. See _copyTable().
*/
protected function _moveTable($from, $to, $options = array(),
$callback = null)
{
$this->_copyTable($from, $to, $options, $callback);
$this->dropTable($from);
}
/**
* Copies a table.
*
* Also applies changes and callback methods before creating the new table.
*
* @param string $from The name of the source table.
* @param string $to The name of the target table.
* @param array $options Any options to apply when creating the
* temporary table. Supports a 'rename' key for
* the new table name, additionally to the
* options in createTable().
* @param function $callback A callback function that can manipulate the
* Horde_Db_Adapter_Base_TableDefinition object
* available in $definition.
*/
protected function _copyTable($from, $to, $options = array(),
$callback = null)
{
$fromColumns = $this->columns($from);
$pk = $this->primaryKey($from);
if ($pk && count($pk->columns) == 1) {
/* A primary key is not necessarily what matches the pseudo type
* "autoincrementKey". We need to parse the table definition to
* find out if the column is AUTOINCREMENT too. */
$tableDefinition = $this->selectValue('SELECT sql FROM sqlite_master WHERE name = ? UNION ALL SELECT sql FROM sqlite_temp_master WHERE name = ?',
array($from, $from));
if (strpos($tableDefinition, $this->quoteColumnName($pk->columns[0]) . ' INTEGER PRIMARY KEY AUTOINCREMENT')) {
$pkColumn = $pk->columns[0];
} else {
$pkColumn = null;
}
} else {
$pkColumn = null;
}
$options = array_merge($options, array('autoincrementKey' => false));
$copyPk = true;
$definition = $this->createTable($to, $options);
foreach ($fromColumns as $column) {
$columnName = isset($options['rename'][$column->getName()])
? $options['rename'][$column->getName()]
: $column->getName();
$columnType = $column->getName() == $pkColumn
? 'autoincrementKey'
: $column->getType();
if ($columnType == 'autoincrementKey') {
$copyPk = false;
}
$definition->column($columnName, $columnType,
array('limit' => $column->getLimit(),
'default' => $column->getDefault(),
'null' => $column->isNull()));
}
if ($pkColumn && count($pk->columns) && $copyPk) {
$definition->primaryKey($pk->columns);
}
if (is_callable($callback)) {
call_user_func($callback, $definition);
}
$definition->end();
$this->_copyTableIndexes(
$from,
$to,
isset($options['rename']) ? $options['rename'] : array());
$this->_copyTableContents(
$from,
$to,
array_map(create_function('$c', 'return $c->getName();'),
iterator_to_array($definition)),
isset($options['rename']) ? $options['rename'] : array());
}
/**
* Copies indexes from one table to another.
*
* @param string $from The name of the source table.
* @param string $to The name of the target table.
* @param array $rename A hash of columns to rename during the copy, with
* original names as keys and the new names as values.
*/
protected function _copyTableIndexes($from, $to, $rename = array())
{
$toColumnNames = array();
foreach ($this->columns($to) as $c) {
$toColumnNames[$c->getName()] = true;
}
foreach ($this->indexes($from) as $index) {
$name = $index->getName();
if ($to == 'altered_' . $from) {
$name = 'temp_' . $name;
} elseif ($from == 'altered_' . $to) {
$name = substr($name, 5);
}
$columns = array();
foreach ($index->columns as $c) {
if (isset($rename[$c])) {
$c = $rename[$c];
}
if (isset($toColumnNames[$c])) {
$columns[] = $c;
}
}
if (!empty($columns)) {
// Index name can't be the same
$opts = array('name' => str_replace('_' . $from . '_', '_' . $to . '_', $name));
if ($index->unique) {
$opts['unique'] = true;
}
$this->addIndex($to, $columns, $opts);
}
}
}
/**
* Copies the content of one table to another.
*
* @param string $from The name of the source table.
* @param string $to The name of the target table.
* @param array $columns A list of columns to copy.
* @param array $rename A hash of columns to rename during the copy, with
* original names as keys and the new names as
* values.
*/
protected function _copyTableContents($from, $to, $columns,
$rename = array())
{
$columnMappings = array_combine($columns, $columns);
foreach ($rename as $renameFrom => $renameTo) {
$columnMappings[$renameTo] = $renameFrom;
}
$fromColumns = array();
foreach ($this->columns($from) as $col) {
$fromColumns[] = $col->getName();
}
$tmpColumns = array();
foreach ($columns as $col) {
if (in_array($columnMappings[$col], $fromColumns)) {
$tmpColumns[] = $col;
}
}
$columns = $tmpColumns;
$fromColumns = array();
foreach ($columns as $col) {
$fromColumns[] = $columnMappings[$col];
}
$quotedTo = $this->quoteTableName($to);
$quotedToColumns = implode(', ', array_map(array($this, 'quoteColumnName'), $columns));
$quotedFrom = $this->quoteTableName($from);
$quotedFromColumns = implode(', ', array_map(array($this, 'quoteColumnName'), $fromColumns));
$sql = sprintf('INSERT INTO %s (%s) SELECT %s FROM %s',
$quotedTo,
$quotedToColumns,
$quotedFromColumns,
$quotedFrom);
$this->execute($sql);
}
}
Horde_Db-2.0.4/lib/Horde/Db/Adapter/Base.php 0000664 0001750 0001750 00000054330 12205351473 016375 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
abstract class Horde_Db_Adapter_Base implements Horde_Db_Adapter
{
/**
* Config options.
*
* @var array
*/
protected $_config = array();
/**
* DB connection.
*
* @var mixed
*/
protected $_connection = null;
/**
* Has a transaction been started?
*
* @var integer
*/
protected $_transactionStarted = 0;
/**
* The last query sent to the database.
*
* @var string
*/
protected $_lastQuery;
/**
* Row count of last action.
*
* @var integer
*/
protected $_rowCount = null;
/**
* Runtime of last query.
*
* @var integer
*/
protected $_runtime;
/**
* Is connection active?
*
* @var boolean
*/
protected $_active = null;
/**
* Cache object.
*
* @var Horde_Cache
*/
protected $_cache;
/**
* Log object.
*
* @var Horde_Log_Logger
*/
protected $_logger;
/**
* Schema object.
*
* @var Horde_Db_Adapter_Base_Schema
*/
protected $_schema = null;
/**
* Schema class to use.
*
* @var string
*/
protected $_schemaClass = null;
/**
* List of schema methods.
*
* @var array
*/
protected $_schemaMethods = array();
/*##########################################################################
# Construct/Destruct
##########################################################################*/
/**
* Constructor.
*
* @param array $config Configuration options and optional objects:
*
* 'charset' - (string) TODO
*
*/
public function __construct($config)
{
/* Can't set cache/logger in constructor - these objects may use DB
* for storage. Add stubs for now - they have to be manually set
* later with setCache() and setLogger(). */
$this->_cache = new Horde_Support_Stub();
$this->_logger = new Horde_Support_Stub();
// Default to UTF-8
if (!isset($config['charset'])) {
$config['charset'] = 'UTF-8';
}
$this->_config = $config;
$this->_runtime = 0;
if (!$this->_schemaClass) {
$this->_schemaClass = __CLASS__ . '_Schema';
}
$this->connect();
}
/**
* Free any resources that are open.
*/
public function __destruct()
{
$this->disconnect();
}
/**
* Serialize callback.
*/
public function __sleep()
{
return array_diff(array_keys(get_class_vars(__CLASS__)), array('_active', '_connection'));
}
/**
* Unserialize callback.
*/
public function __wakeup()
{
$this->_schema->setAdapter($this);
$this->connect();
}
/**
* Returns an adaptor option set through the constructor.
*
* @param string $option The option to return.
*
* @return mixed The option value or null if option doesn't exist or is
* not set.
*/
public function getOption($option)
{
return isset($this->_config[$option]) ? $this->_config[$option] : null;
}
/*##########################################################################
# Dependency setters/getters
##########################################################################*/
/**
* Set a cache object.
*
* @inject
*
* @var Horde_Cache $logger The cache object.
*/
public function setCache(Horde_Cache $cache)
{
$this->_cache = $cache;
}
/**
* @return Horde_Cache
*/
public function getCache()
{
return $this->_cache;
}
/**
* Set a logger object.
*
* @inject
*
* @var Horde_Log_Logger $logger The logger object.
*/
public function setLogger(Horde_Log_Logger $logger)
{
$this->_logger = $logger;
}
/**
* return Horde_Log_Logger
*/
public function getLogger()
{
return $this->_logger;
}
/*##########################################################################
# Object composition
##########################################################################*/
/**
* Delegate calls to the schema object.
*
* @param string $method
* @param array $args
*
* @return mixed TODO
* @throws BadMethodCallException
*/
public function __call($method, $args)
{
if (!$this->_schema) {
// Create the database-specific (but not adapter specific) schema
// object.
$this->_schema = new $this->_schemaClass($this, array(
'cache' => $this->_cache,
'logger' => $this->_logger
));
$this->_schemaMethods = array_flip(get_class_methods($this->_schema));
}
if (isset($this->_schemaMethods[$method])) {
return call_user_func_array(array($this->_schema, $method), $args);
}
$support = new Horde_Support_Backtrace();
$context = $support->getContext(1);
$caller = $context['function'];
if (isset($context['class'])) {
$caller = $context['class'] . '::' . $caller;
}
throw new BadMethodCallException('Call to undeclared method "' . get_class($this) . '::' . $method . '" from "' . $caller . '"');
}
/*##########################################################################
# Public
##########################################################################*/
/**
* Returns the human-readable name of the adapter. Use mixed case - one
* can always use downcase if needed.
*
* @return string
*/
public function adapterName()
{
return 'Base';
}
/**
* Does this adapter support migrations? Backend specific, as the
* abstract adapter always returns +false+.
*
* @return boolean
*/
public function supportsMigrations()
{
return false;
}
/**
* Does this adapter support using DISTINCT within COUNT? This is +true+
* for all adapters except sqlite.
*
* @return boolean
*/
public function supportsCountDistinct()
{
return true;
}
/**
* Should primary key values be selected from their corresponding
* sequence before the insert statement? If true, next_sequence_value
* is called before each insert to set the record's primary key.
* This is false for all adapters but Firebird.
*
* @return boolean
*/
public function prefetchPrimaryKey($tableName = null)
{
return false;
}
/**
* Get the last query run
*
* @return string
*/
public function getLastQuery()
{
return $this->_lastQuery;
}
/**
* Reset the timer
*
* @return integer
*/
public function resetRuntime()
{
$this->_runtime = 0;
return $this->_runtime;
}
/*##########################################################################
# Connection Management
##########################################################################*/
/**
* Is the connection active?
*
* @return boolean
*/
public function isActive()
{
return $this->_active && $this->_connection;
}
/**
* Reconnect to the db.
*/
public function reconnect()
{
$this->disconnect();
$this->connect();
}
/**
* Disconnect from db.
*/
public function disconnect()
{
$this->_connection = null;
$this->_active = false;
}
/**
* Provides access to the underlying database connection. Useful for when
* you need to call a proprietary method such as postgresql's
* lo_* methods.
*
* @return resource
*/
public function rawConnection()
{
return $this->_connection;
}
/*##########################################################################
# Database Statements
##########################################################################*/
/**
* Returns an array of records with the column names as keys, and
* column values as values.
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return PDOStatement
* @throws Horde_Db_Exception
*/
public function select($sql, $arg1 = null, $arg2 = null)
{
return $this->execute($sql, $arg1, $arg2);
}
/**
* Returns an array of record hashes with the column names as keys and
* column values as values.
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return array
* @throws Horde_Db_Exception
*/
public function selectAll($sql, $arg1 = null, $arg2 = null)
{
$rows = array();
$result = $this->select($sql, $arg1, $arg2);
if ($result) {
foreach ($result as $row) {
$rows[] = $row;
}
}
return $rows;
}
/**
* Returns a record hash with the column names as keys and column values
* as values.
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return array
* @throws Horde_Db_Exception
*/
public function selectOne($sql, $arg1 = null, $arg2 = null)
{
$result = $this->selectAll($sql, $arg1, $arg2);
return $result
? next($result)
: array();
}
/**
* Returns a single value from a record
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return string
* @throws Horde_Db_Exception
*/
public function selectValue($sql, $arg1 = null, $arg2 = null)
{
$result = $this->selectOne($sql, $arg1, $arg2);
return $result
? next($result)
: null;
}
/**
* Returns an array of the values of the first column in a select:
* selectValues("SELECT id FROM companies LIMIT 3") => [1,2,3]
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return array
* @throws Horde_Db_Exception
*/
public function selectValues($sql, $arg1 = null, $arg2 = null)
{
$result = $this->selectAll($sql, $arg1, $arg2);
$values = array();
foreach ($result as $row) {
$values[] = next($row);
}
return $values;
}
/**
* Returns an array where the keys are the first column of a select, and the
* values are the second column:
*
* selectAssoc("SELECT id, name FROM companies LIMIT 3") => [1 => 'Ford', 2 => 'GM', 3 => 'Chrysler']
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return array
* @throws Horde_Db_Exception
*/
public function selectAssoc($sql, $arg1 = null, $arg2 = null)
{
$result = $this->selectAll($sql, $arg1, $arg2);
$values = array();
foreach ($result as $row) {
$values[current($row)] = next($row);
}
return $values;
}
/**
* Executes the SQL statement in the context of this connection.
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return PDOStatement
* @throws Horde_Db_Exception
*/
public function execute($sql, $arg1 = null, $arg2 = null)
{
if (!$this->isActive()) { $this->reconnect(); }
if (is_array($arg1)) {
$sql = $this->_replaceParameters($sql, $arg1);
$name = $arg2;
} else {
$name = $arg1;
}
$t = new Horde_Support_Timer;
$t->push();
try {
$this->_lastQuery = $sql;
$stmt = $this->_connection->query($sql);
} catch (Exception $e) {
$this->_logError($sql, 'QUERY FAILED: ' . $e->getMessage());
$this->_logInfo($sql, $name);
throw new Horde_Db_Exception($e);
}
$this->_logInfo($sql, $name, $t->pop());
$this->_rowCount = $stmt ? $stmt->rowCount() : 0;
return $stmt;
}
/**
* Inserts a row into a table.
*
* @param string $sql SQL statement.
* @param array|string $arg1 Either an array of bound parameters or a
* query name.
* @param string $arg2 If $arg1 contains bound parameters, the
* query name.
* @param string $pk The primary key column.
* @param integer $idValue The primary key value. This parameter is
* required if the primary key is inserted
* manually.
* @param string $sequenceName The sequence name.
*
* @return integer Last inserted ID.
* @throws Horde_Db_Exception
*/
public function insert($sql, $arg1 = null, $arg2 = null, $pk = null,
$idValue = null, $sequenceName = null)
{
$this->execute($sql, $arg1, $arg2);
return $idValue
? $idValue
: $this->_connection->lastInsertId($sequenceName);
}
/**
* Executes the update statement and returns the number of rows affected.
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return integer Number of rows affected.
* @throws Horde_Db_Exception
*/
public function update($sql, $arg1 = null, $arg2 = null)
{
$this->execute($sql, $arg1, $arg2);
return $this->_rowCount;
}
/**
* Executes the delete statement and returns the number of rows affected.
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return integer Number of rows affected.
* @throws Horde_Db_Exception
*/
public function delete($sql, $arg1 = null, $arg2 = null)
{
$this->execute($sql, $arg1, $arg2);
return $this->_rowCount;
}
/**
* Check if a transaction has been started.
*
* @return boolean True if transaction has been started.
*/
public function transactionStarted()
{
return (bool)$this->_transactionStarted;
}
/**
* Begins the transaction (and turns off auto-committing).
*/
public function beginDbTransaction()
{
if (!$this->_transactionStarted) {
$this->_connection->beginTransaction();
}
$this->_transactionStarted++;
}
/**
* Commits the transaction (and turns on auto-committing).
*/
public function commitDbTransaction()
{
$this->_transactionStarted--;
if (!$this->_transactionStarted) {
$this->_connection->commit();
}
}
/**
* Rolls back the transaction (and turns on auto-committing). Must be
* done if the transaction block raises an exception or returns false.
*/
public function rollbackDbTransaction()
{
if (!$this->_transactionStarted) {
return;
}
$this->_connection->rollBack();
$this->_transactionStarted = 0;
}
/**
* Appends LIMIT and OFFSET options to a SQL statement.
*
* @param string $sql SQL statement.
* @param array $options Hash with 'limit' and (optional) 'offset' values.
*
* @return string
*/
public function addLimitOffset($sql, $options)
{
if (isset($options['limit']) && $limit = $options['limit']) {
if (isset($options['offset']) && $offset = $options['offset']) {
$sql .= " LIMIT $offset, $limit";
} else {
$sql .= " LIMIT $limit";
}
}
return $sql;
}
/**
* TODO
*/
public function sanitizeLimit($limit)
{
return (strpos($limit, ',') !== false)
? implode(',', array_map('intval', explode(',', $limit)))
: intval($limit);
}
/**
* Appends a locking clause to an SQL statement.
* This method *modifies* the +sql+ parameter.
*
* # SELECT * FROM suppliers FOR UPDATE
* add_lock! 'SELECT * FROM suppliers', :lock => true
* add_lock! 'SELECT * FROM suppliers', :lock => ' FOR UPDATE'
*
* @param string &$sql SQL statment.
* @param array $options TODO.
*/
public function addLock(&$sql, array $options = array())
{
$sql .= (isset($options['lock']) && is_string($options['lock']))
? ' ' . $options['lock']
: ' FOR UPDATE';
}
/**
* Inserts the given fixture into the table. Overridden in adapters that
* require something beyond a simple insert (eg. Oracle).
*
* @param TODO $fixture TODO
* @param TODO $tableName TODO
*
* @return TODO
*/
public function insertFixture($fixture, $tableName)
{
/*@TODO*/
return $this->execute("INSERT INTO #{quote_table_name(table_name)} (#{fixture.key_list}) VALUES (#{fixture.value_list})", 'Fixture Insert');
}
/**
* TODO
*
* @param string $tableName TODO
*
* @return string TODO
*/
public function emptyInsertStatement($tableName)
{
return 'INSERT INTO ' . $this->quoteTableName($tableName) . ' VALUES(DEFAULT)';
}
/*##########################################################################
# Protected
##########################################################################*/
/**
* Checks if required configuration keys are present.
*
* @param array $required Required configuration keys.
*
* @throws Horde_Db_Exception if a required key is missing.
*/
protected function _checkRequiredConfig(array $required)
{
$diff = array_diff_key(array_flip($required), $this->_config);
if (!empty($diff)) {
$msg = 'Required config missing: ' . implode(', ', array_keys($diff));
throw new Horde_Db_Exception($msg);
}
}
/**
* Replace ? in a SQL statement with quoted values from $args
*
* @param string $sql SQL statement.
* @param array $args TODO
*
* @return string Modified SQL statement.
* @throws Horde_Db_Exception
*/
protected function _replaceParameters($sql, array $args)
{
$paramCount = substr_count($sql, '?');
if (count($args) != $paramCount) {
$this->_logError('Parameter count mismatch: ' . $sql, 'Horde_Db_Adapter_Base::_replaceParameters');
throw new Horde_Db_Exception(sprintf('Parameter count mismatch, expecting %d, got %d', $paramCount, count($args)));
}
$sqlPieces = explode('?', $sql);
$sql = array_shift($sqlPieces);
while (count($sqlPieces)) {
$sql .= $this->quote(array_shift($args)) . array_shift($sqlPieces);
}
return $sql;
}
/**
* Logs the SQL query for debugging.
*
* @param string $sql SQL statement.
* @param string $name TODO
* @param float $runtime Runtime interval.
*/
protected function _logInfo($sql, $name, $runtime = null)
{
if ($this->_logger) {
$name = (empty($name) ? '' : $name)
. (empty($runtime) ? '' : sprintf(" (%.4fs)", $runtime));
$this->_logger->debug($this->_formatLogEntry($name, $sql));
}
}
protected function _logError($error, $name, $runtime = null)
{
if ($this->_logger) {
$name = (empty($name) ? '' : $name)
. (empty($runtime) ? '' : sprintf(" (%.4fs)", $runtime));
$this->_logger->err($this->_formatLogEntry($name, $error));
}
}
/**
* Formats the log entry.
*
* @param string $message Message.
* @param string $sql SQL statment.
*
* @return string Formatted log entry.
*/
protected function _formatLogEntry($message, $sql)
{
return "SQL $message \n\t" . wordwrap(preg_replace("/\s+/", ' ', $sql), 70, "\n\t ", 1);
}
}
Horde_Db-2.0.4/lib/Horde/Db/Adapter/Mysql.php 0000664 0001750 0001750 00000027612 12205351473 016633 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
/**
* MySQL Horde_Db_Adapter
*
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
class Horde_Db_Adapter_Mysql extends Horde_Db_Adapter_Base
{
/**
* Mysql database connection handle.
* @var resource
*/
protected $_connection = null;
/**
* Last auto-generated insert_id
* @var integer
*/
protected $_insertId;
/**
* @var string
*/
protected $_schemaClass = 'Horde_Db_Adapter_Mysql_Schema';
/*##########################################################################
# Public
##########################################################################*/
/**
* Returns the human-readable name of the adapter. Use mixed case - one
* can always use downcase if needed.
*
* @return string
*/
public function adapterName()
{
return 'MySQL';
}
/**
* Does this adapter support migrations? Backend specific, as the
* abstract adapter always returns +false+.
*
* @return boolean
*/
public function supportsMigrations()
{
return true;
}
/*##########################################################################
# Connection Management
##########################################################################*/
/**
* Connect to the db
*/
public function connect()
{
if ($this->_active) {
return;
}
$config = $this->_parseConfig();
$oldTrackErrors = ini_set('track_errors', 1);
$mysql = @mysql_connect($config['host'], $config['username'], $config['password']);
ini_set('track_errors', $oldTrackErrors);
if (!$mysql) {
throw new Horde_Db_Exception('Connect failed: ' . $php_errormsg);
}
if (!mysql_select_db($config['dbname'])) {
throw new Horde_Db_Exception('Could not select database: ' . $config['dbname']);
}
$this->_connection = $mysql;
$this->_active = true;
// Set the default charset. http://dev.mysql.com/doc/refman/5.1/en/charset-connection.html
if (!empty($config['charset'])) {
$this->setCharset($config['charset']);
}
}
/**
* Disconnect from db
*/
public function disconnect()
{
if ($this->_connection) { @mysql_close($this->_connection); }
$this->_connection = null;
$this->_active = false;
}
/**
* Check if the connection is active
*
* @return boolean
*/
public function isActive()
{
return isset($this->_connection) && @mysql_ping($this->_connection);
}
/*##########################################################################
# Quoting
##########################################################################*/
/**
* Quotes a string, escaping any ' (single quote) and \ (backslash)
* characters..
*
* @param string $string
* @return string
*/
public function quoteString($string)
{
return "'" . mysql_real_escape_string($string, $this->_connection) . "'";
}
/*##########################################################################
# Database Statements
##########################################################################*/
/**
* Returns an array of records with the column names as keys, and
* column values as values.
*
* @param string $sql
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
* @return array
*/
public function select($sql, $arg1 = null, $arg2 = null)
{
return new Horde_Db_Adapter_Mysql_Result($this, $sql, $arg1, $arg2);
}
/**
* Returns an array of record hashes with the column names as keys and
* column values as values.
*
* @param string $sql
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
*/
public function selectAll($sql, $arg1 = null, $arg2 = null)
{
$result = $this->execute($sql, $arg1, $arg2);
$rows = array();
if ($result) {
while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
$rows[] = $row;
}
}
return $rows;
}
/**
* Returns a record hash with the column names as keys and column values as
* values.
*
* @param string $sql A query.
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
*
* @return array|boolean A record hash or false if no record found.
*/
public function selectOne($sql, $arg1 = null, $arg2 = null)
{
$result = $this->execute($sql, $arg1, $arg2);
return $result ? mysql_fetch_array($result, MYSQL_ASSOC) : array();
}
/**
* Returns a single value from a record
*
* @param string $sql
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
* @return string
*/
public function selectValue($sql, $arg1=null, $arg2=null)
{
$result = $this->selectOne($sql, $arg1, $arg2);
return $result ? current($result) : null;
}
/**
* Returns an array of the values of the first column in a select:
* select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
*
* @param string $sql
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
*/
public function selectValues($sql, $arg1=null, $arg2=null)
{
$values = array();
$result = $this->execute($sql, $arg1, $arg2);
if ($result) {
while ($row = mysql_fetch_row($result)) {
$values[] = $row[0];
}
}
return $values;
}
/**
* Executes the SQL statement in the context of this connection.
*
* @param string $sql
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
*/
public function execute($sql, $arg1=null, $arg2=null)
{
if (is_array($arg1)) {
$sql = $this->_replaceParameters($sql, $arg1);
$name = $arg2;
} else {
$name = $arg1;
}
$t = new Horde_Support_Timer();
$t->push();
$this->_lastQuery = $sql;
$stmt = mysql_query($sql, $this->_connection);
if (!$stmt) {
$this->_logInfo($sql, 'QUERY FAILED: ' . mysql_error($this->_connection));
$this->_logInfo($sql, $name);
throw new Horde_Db_Exception('QUERY FAILED: ' . mysql_error($this->_connection) . "\n\n" . $sql,
$this->_errorCode(null, mysql_errno($this->_connection)));
}
$this->_logInfo($sql, $name, $t->pop());
$this->_rowCount = mysql_affected_rows($this->_connection);
$this->_insertId = mysql_insert_id($this->_connection);
return $stmt;
}
/**
* Returns the last auto-generated ID from the affected table.
*
* @param string $sql
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
* @param string $pk
* @param int $idValue
* @param string $sequenceName
*/
public function insert($sql, $arg1 = null, $arg2 = null, $pk = null, $idValue = null, $sequenceName = null)
{
$this->execute($sql, $arg1, $arg2);
return isset($idValue) ? $idValue : $this->_insertId;
}
/**
* Begins the transaction (and turns off auto-committing).
*/
public function beginDbTransaction()
{
$this->_transactionStarted++;
$this->_lastQuery = 'SET AUTOCOMMIT=0; BEGIN';
@mysql_query('SET AUTOCOMMIT=0', $this->_connection) && @mysql_query('BEGIN', $this->_connection);
}
/**
* Commits the transaction (and turns on auto-committing).
*/
public function commitDbTransaction()
{
$this->_transactionStarted--;
if (!$this->_transactionStarted) {
$this->_lastQuery = 'COMMIT; SET AUTOCOMMIT=1';
@mysql_query('COMMIT', $this->_connection) && @mysql_query('SET AUTOCOMMIT=1', $this->_connection);
}
}
/**
* Rolls back the transaction (and turns on auto-committing). Must be
* done if the transaction block raises an exception or returns false.
*/
public function rollbackDbTransaction()
{
if (!$this->_transactionStarted) {
return;
}
$this->_lastQuery = 'ROLLBACK; SET AUTOCOMMIT=1';
@mysql_query('ROLLBACK', $this->_connection) && @mysql_query('SET AUTOCOMMIT=1', $this->_connection);
$this->_transactionStarted = 0;
}
/*##########################################################################
# Protected
##########################################################################*/
/**
* Return a standard error code
*
* @param string $sqlstate
* @param integer $errno
* @return integer
*/
protected function _errorCode($sqlstate, $errno)
{
/*@TODO do something with standard sqlstate vs. MySQL error codes vs. whatever else*/
return $errno;
}
/**
* Parse configuration array into options for mysql_connect
*
* @throws Horde_Db_Exception
* @return array [host, username, password, dbname]
*/
protected function _parseConfig()
{
$this->_checkRequiredConfig(array('username'));
$rails2mysqli = array('database' => 'dbname');
foreach ($rails2mysqli as $from => $to) {
if (isset($this->_config[$from])) {
$this->_config[$to] = $this->_config[$from];
unset($this->_config[$from]);
}
}
if (!empty($this->_config['host']) &&
$this->_config['host'] == 'localhost') {
$this->_config['host'] = '127.0.0.1';
}
if (isset($this->_config['port'])) {
if (empty($this->_config['host'])) {
throw new Horde_Db_Exception('Host is required if port is specified');
}
$this->_config['host'] .= ':' . $this->_config['port'];
unset($this->_config['port']);
}
if (!empty($this->_config['socket'])) {
if (!empty($this->_config['host'])) {
throw new Horde_Db_Exception('Can only specify host or socket, not both');
}
$this->_config['host'] = ':' . $this->_config['socket'];
unset($this->_config['socket']);
}
$config = $this->_config;
if (!isset($config['host'])) $config['host'] = null;
if (!isset($config['username'])) $config['username'] = null;
if (!isset($config['password'])) $config['password'] = null;
if (!isset($config['dbname'])) $config['dbname'] = null;
return $config;
}
}
Horde_Db-2.0.4/lib/Horde/Db/Adapter/Mysqli.php 0000664 0001750 0001750 00000033324 12205351473 017001 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
/**
* MySQL Improved Horde_Db_Adapter
*
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
class Horde_Db_Adapter_Mysqli extends Horde_Db_Adapter_Base
{
/**
* Mysqli database connection object.
* @var mysqli
*/
protected $_connection = null;
/**
* Last auto-generated insert_id
* @var integer
*/
protected $_insertId;
/**
* @var string
*/
protected $_schemaClass = 'Horde_Db_Adapter_Mysql_Schema';
/**
* @var boolean
*/
protected $_hasMysqliFetchAll = false;
/*##########################################################################
# Public
##########################################################################*/
/**
* Returns the human-readable name of the adapter. Use mixed case - one
* can always use downcase if needed.
*
* @return string
*/
public function adapterName()
{
return 'MySQLi';
}
/**
* Does this adapter support migrations? Backend specific, as the
* abstract adapter always returns +false+.
*
* @return boolean
*/
public function supportsMigrations()
{
return true;
}
/*##########################################################################
# Connection Management
##########################################################################*/
/**
* Connect to the db
*
* MySQLi can connect using SSL if $config contains an 'ssl' sub-array
* containing the following keys:
* + key The path to the key file.
* + cert The path to the certificate file.
* + ca The path to the certificate authority file.
* + capath The path to a directory that contains trusted SSL
* CA certificates in pem format.
* + cipher The list of allowable ciphers for SSL encryption.
*
* Example of how to connect using SSL:
*
* $config = array(
* 'username' => 'someuser',
* 'password' => 'apasswd',
* 'hostspec' => 'localhost',
* 'database' => 'thedb',
* 'ssl' => array(
* 'key' => 'client-key.pem',
* 'cert' => 'client-cert.pem',
* 'ca' => 'cacert.pem',
* 'capath' => '/path/to/ca/dir',
* 'cipher' => 'AES',
* ),
* );
*
* $db = new Horde_Db_Adapter_Mysqli($config);
*
*/
public function connect()
{
if ($this->_active) {
return;
}
$config = $this->_parseConfig();
if (!empty($config['ssl'])) {
$mysqli = mysqli_init();
$mysqli->ssl_set(
empty($config['ssl']['key']) ? null : $config['ssl']['key'],
empty($config['ssl']['cert']) ? null : $config['ssl']['cert'],
empty($config['ssl']['ca']) ? null : $config['ssl']['ca'],
empty($config['ssl']['capath']) ? null : $config['ssl']['capath'],
empty($config['ssl']['cipher']) ? null : $config['ssl']['cipher']
);
$mysqli->real_connect(
$config['host'], $config['username'], $config['password'],
$config['dbname'], $config['port'], $config['socket']);
} else {
$mysqli = new mysqli(
$config['host'], $config['username'], $config['password'],
$config['dbname'], $config['port'], $config['socket']);
}
if (mysqli_connect_errno()) {
throw new Horde_Db_Exception('Connect failed: (' . mysqli_connect_errno() . ') ' . mysqli_connect_error(), mysqli_connect_errno());
}
// If supported, request real datatypes from MySQL instead of returning
// everything as a string.
if (defined('MYSQLI_OPT_INT_AND_FLOAT_NATIVE')) {
$mysqli->options(MYSQLI_OPT_INT_AND_FLOAT_NATIVE, true);
}
$this->_connection = $mysqli;
$this->_active = true;
// Set the default charset. http://dev.mysql.com/doc/refman/5.1/en/charset-connection.html
if (!empty($config['charset'])) {
$this->setCharset($config['charset']);
}
$this->_hasMysqliFetchAll = function_exists('mysqli_fetch_all');
}
/**
* Disconnect from db
*/
public function disconnect()
{
if ($this->_connection) { $this->_connection->close(); }
$this->_connection = null;
$this->_active = false;
}
/**
* Check if the connection is active
*
* @return boolean
*/
public function isActive()
{
$this->_lastQuery = 'SELECT 1';
return isset($this->_connection) && $this->_connection->query('SELECT 1');
}
/*##########################################################################
# Quoting
##########################################################################*/
/**
* Quotes a string, escaping any ' (single quote) and \ (backslash)
* characters..
*
* @param string $string
* @return string
*/
public function quoteString($string)
{
return "'".$this->_connection->real_escape_string($string)."'";
}
/*##########################################################################
# Database Statements
##########################################################################*/
/**
* Returns an array of records with the column names as keys, and
* column values as values.
*
* @param string $sql
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
* @return array
*/
public function select($sql, $arg1=null, $arg2=null)
{
return new Horde_Db_Adapter_Mysqli_Result($this, $sql, $arg1, $arg2);
}
/**
* Returns an array of record hashes with the column names as keys and
* column values as values.
*
* @param string $sql
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
*/
public function selectAll($sql, $arg1=null, $arg2=null)
{
$result = $this->execute($sql, $arg1, $arg2);
if ($this->_hasMysqliFetchAll) {
return $result->fetch_all(MYSQLI_ASSOC);
} else {
$rows = array();
if ($result) {
while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
$rows[] = $row;
}
}
}
return $rows;
}
/**
* Returns a record hash with the column names as keys and column values as
* values.
*
* @param string $sql A query.
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
*
* @return array|boolean A record hash or false if no record found.
*/
public function selectOne($sql, $arg1 = null, $arg2 = null)
{
$result = $this->execute($sql, $arg1, $arg2);
$result = $result ? $result->fetch_array(MYSQLI_ASSOC) : array();
return is_null($result) ? false : $result;
}
/**
* Returns a single value from a record
*
* @param string $sql
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
* @return string
*/
public function selectValue($sql, $arg1=null, $arg2=null)
{
$result = $this->selectOne($sql, $arg1, $arg2);
return $result ? current($result) : null;
}
/**
* Returns an array of the values of the first column in a select:
* select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
*
* @param string $sql
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
*/
public function selectValues($sql, $arg1=null, $arg2=null)
{
$values = array();
$result = $this->execute($sql, $arg1, $arg2);
if ($result) {
while ($row = $result->fetch_row()) {
$values[] = $row[0];
}
}
return $values;
}
/**
* Executes the SQL statement in the context of this connection.
*
* @param string $sql
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
*/
public function execute($sql, $arg1=null, $arg2=null)
{
if (is_array($arg1)) {
$sql = $this->_replaceParameters($sql, $arg1);
$name = $arg2;
} else {
$name = $arg1;
}
$t = new Horde_Support_Timer();
$t->push();
$this->_lastQuery = $sql;
$stmt = $this->_connection->query($sql);
if (!$stmt) {
$this->_logInfo($sql, 'QUERY FAILED: ' . $this->_connection->error);
$this->_logInfo($sql, $name);
throw new Horde_Db_Exception('QUERY FAILED: ' . $this->_connection->error . "\n\n" . $sql,
$this->_errorCode($this->_connection->sqlstate, $this->_connection->errno));
}
$this->_logInfo($sql, $name, $t->pop());
//@TODO if ($this->_connection->info) $this->_loginfo($sql, $this->_connection->info);
//@TODO also log warnings? http://php.net/mysqli.warning-count and http://php.net/mysqli.get-warnings
$this->_rowCount = $this->_connection->affected_rows;
$this->_insertId = $this->_connection->insert_id;
return $stmt;
}
/**
* Returns the last auto-generated ID from the affected table.
*
* @param string $sql
* @param mixed $arg1 Either an array of bound parameters or a query name.
* @param string $arg2 If $arg1 contains bound parameters, the query name.
* @param string $pk
* @param int $idValue
* @param string $sequenceName
*/
public function insert($sql, $arg1=null, $arg2=null, $pk=null, $idValue=null, $sequenceName=null)
{
$this->execute($sql, $arg1, $arg2);
return isset($idValue) ? $idValue : $this->_insertId;
}
/**
* Begins the transaction (and turns off auto-committing).
*/
public function beginDbTransaction()
{
$this->_connection->autocommit(false);
$this->_transactionStarted++;
}
/**
* Commits the transaction (and turns on auto-committing).
*/
public function commitDbTransaction()
{
parent::commitDbTransaction();
if (!$this->_transactionStarted) {
$this->_connection->autocommit(true);
}
}
/**
* Rolls back the transaction (and turns on auto-committing). Must be
* done if the transaction block raises an exception or returns false.
*/
public function rollbackDbTransaction()
{
parent::rollbackDbTransaction();
if (!$this->_transactionStarted) {
$this->_connection->autocommit(true);
}
}
/*##########################################################################
# Protected
##########################################################################*/
/**
* Return a standard error code
*
* @param string $sqlstate
* @param integer $errno
* @return integer
*/
protected function _errorCode($sqlstate, $errno)
{
/*@TODO do something with standard sqlstate vs. MySQL error codes vs. whatever else*/
return $errno;
}
/**
* Parse configuration array into options for MySQLi constructor.
*
* @throws Horde_Db_Exception
* @return array [host, username, password, dbname, port, socket]
*/
protected function _parseConfig()
{
$this->_checkRequiredConfig(array('username'));
$rails2mysqli = array('database' => 'dbname');
foreach ($rails2mysqli as $from => $to) {
if (isset($this->_config[$from])) {
$this->_config[$to] = $this->_config[$from];
unset($this->_config[$from]);
}
}
if (!empty($this->_config['host']) &&
$this->_config['host'] == 'localhost') {
$this->_config['host'] = '127.0.0.1';
}
if (isset($this->_config['port'])) {
if (empty($this->_config['host'])) {
throw new Horde_Db_Exception('Host is required if port is specified');
}
}
$config = $this->_config;
if (!isset($config['host'])) $config['host'] = null;
if (!isset($config['username'])) $config['username'] = null;
if (!isset($config['password'])) $config['password'] = null;
if (!isset($config['dbname'])) $config['dbname'] = null;
if (!isset($config['port'])) $config['port'] = null;
if (!isset($config['socket'])) $config['socket'] = null;
return $config;
}
}
Horde_Db-2.0.4/lib/Horde/Db/Adapter/SplitRead.php 0000664 0001750 0001750 00000034734 12205351473 017420 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @author Michael J. Rubinsky
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
/**
* The Horde_Db_Adapter_SplitRead:: class wraps two individual adapters to
* provide support for split read/write database setups.
*
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @author Michael J. Rubinsky
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
class Horde_Db_Adapter_SplitRead implements Horde_Db_Adapter
{
/**
* The read adapter
*
* @var Horde_Db_Adapter
*/
private $_read;
/**
* The write adapter
*
* @var Horde_Db_Adapter
*/
private $_write;
/**
* Const'r
*
* @param Horde_Db_Adapter $read
* @param Horde_Db_Adapter $write
*/
public function __construct(Horde_Db_Adapter $read, Horde_Db_Adapter $write)
{
$this->_read = $read;
$this->_write = $write;
}
/**
* Delegate unknown methods to the _write adapter.
*
* @param string $method
* @param array $args
*/
public function __call($method, $args)
{
$result = call_user_func_array(array($this->_write, $method), $args);
$this->_lastQuery = $this->_write->getLastQuery();
return $result;
}
/**
* Returns the human-readable name of the adapter. Use mixed case - one
* can always use downcase if needed.
*
* @return string
*/
public function adapterName()
{
return 'SplitRead';
}
/**
* Does this adapter support migrations?
*
* @return boolean
*/
public function supportsMigrations()
{
return $this->_write->supportsMigrations();
}
/**
* Does this adapter support using DISTINCT within COUNT? This is +true+
* for all adapters except sqlite.
*
* @return boolean
*/
public function supportsCountDistinct()
{
return $this->_read->supportsCountDistinct();
}
/**
* Should primary key values be selected from their corresponding
* sequence before the insert statement? If true, next_sequence_value
* is called before each insert to set the record's primary key.
* This is false for all adapters but Firebird.
*
* @return boolean
*/
public function prefetchPrimaryKey($tableName = null)
{
return $this->_write->prefetchPrimaryKey($tableName);
}
/*##########################################################################
# Connection Management
##########################################################################*/
/**
* Connect to the db.
* @TODO: Lazy connect?
*
*/
public function connect()
{
$this->_write->connect();
$this->_read->connect();
}
/**
* Is the connection active?
*
* @return boolean
*/
public function isActive()
{
return ($this->_read->isActive() && $this->_write->isActive());
}
/**
* Reconnect to the db.
*/
public function reconnect()
{
$this->disconnect();
$this->connect();
}
/**
* Disconnect from db.
*/
public function disconnect()
{
$this->_read->disconnect();
$this->_write->disconnect();
}
/**
* Provides access to the underlying database connection. Useful for when
* you need to call a proprietary method such as postgresql's
* lo_* methods.
*
* @return resource
*/
public function rawConnection()
{
return $this->_write->rawConnection();
}
/*##########################################################################
# Quoting
##########################################################################*/
/**
* Quotes a string, escaping any special characters.
*
* @param string $string
* @return string
*/
public function quoteString($string)
{
return $this->_read->quoteString($string);
}
/*##########################################################################
# Database Statements
##########################################################################*/
/**
* Returns an array of records with the column names as keys, and
* column values as values.
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return PDOStatement
* @throws Horde_Db_Exception
*/
public function select($sql, $arg1 = null, $arg2 = null)
{
$result = $this->_read->select($sql, $arg1, $arg2);
$this->_lastQuery = $this->_read->getLastQuery();
return $result;
}
/**
* Returns an array of record hashes with the column names as keys and
* column values as values.
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return array
* @throws Horde_Db_Exception
*/
public function selectAll($sql, $arg1 = null, $arg2 = null)
{
$result = $this->_read->selectAll($sql, $arg1, $arg2);
$this->_lastQuery = $this->_read->getLastQuery();
return $result;
}
/**
* Returns a record hash with the column names as keys and column values
* as values.
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return array
* @throws Horde_Db_Exception
*/
public function selectOne($sql, $arg1 = null, $arg2 = null)
{
$result = $this->_read->selectOne($sql, $arg1, $arg2);
$this->_lastQuery = $this->_read->getLastQuery();
return $result;
}
/**
* Returns a single value from a record
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return string
* @throws Horde_Db_Exception
*/
public function selectValue($sql, $arg1 = null, $arg2 = null)
{
$result = $this->_read->selectValue($sql, $arg1, $arg2);
$this->_lastQuery = $this->_read->getLastQuery();
return $result;
}
/**
* Returns an array of the values of the first column in a select:
* selectValues("SELECT id FROM companies LIMIT 3") => [1,2,3]
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return array
* @throws Horde_Db_Exception
*/
public function selectValues($sql, $arg1 = null, $arg2 = null)
{
$result = $this->_read->selectValues($sql, $arg1, $arg2);
$this->_lastQuery = $this->_read->getLastQuery();
return $result;
}
/**
* Returns an array where the keys are the first column of a select, and the
* values are the second column:
*
* selectAssoc("SELECT id, name FROM companies LIMIT 3") => [1 => 'Ford', 2 => 'GM', 3 => 'Chrysler']
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return array
* @throws Horde_Db_Exception
*/
public function selectAssoc($sql, $arg1 = null, $arg2 = null)
{
$result = $this->_read->selectAssoc($sql, $arg1, $arg2);
$this->_lastQuery = $this->_read->getLastQuery();
return $result;
}
/**
* Executes the SQL statement in the context of this connection.
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return PDOStatement
* @throws Horde_Db_Exception
*/
public function execute($sql, $arg1 = null, $arg2 = null)
{
// Can't assume this will always be a read action, use _write.
$result = $this->_write->execute($sql, $arg1, $arg2);
$this->_lastQuery = $this->_write->getLastQuery();
// Once doing writes, keep using the write backend even for reads
// at least during the same request, to help against stale data.
$this->_read = $this->_write;
return $result;
}
/**
* Returns the last auto-generated ID from the affected table.
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a
* query name.
* @param string $arg2 If $arg1 contains bound parameters, the
* query name.
* @param string $pk TODO
* @param integer $idValue TODO
* @param string $sequenceName TODO
*
* @return integer Last inserted ID.
* @throws Horde_Db_Exception
*/
public function insert($sql, $arg1 = null, $arg2 = null, $pk = null,
$idValue = null, $sequenceName = null)
{
$result = $this->_write->insert($sql, $arg1, $arg2, $pk, $idValue, $sequenceName);
$this->_lastQuery = $this->_write->getLastQuery();
// Once doing writes, keep using the write backend even for reads
// at least during the same request, to help against stale data.
$this->_read = $this->_write;
return $result;
}
/**
* Executes the update statement and returns the number of rows affected.
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return integer Number of rows affected.
* @throws Horde_Db_Exception
*/
public function update($sql, $arg1 = null, $arg2 = null)
{
$result = $this->_write->update($sql, $arg1, $arg2);
$this->_lastQuery = $this->_write->getLastQuery();
// Once doing writes, keep using the write backend even for reads
// at least during the same request, to help against stale data.
$this->_read = $this->_write;
return $result;
}
/**
* Executes the delete statement and returns the number of rows affected.
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return integer Number of rows affected.
* @throws Horde_Db_Exception
*/
public function delete($sql, $arg1 = null, $arg2 = null)
{
$result = $this->_write->delete($sql, $arg1, $arg2);
$this->_lastQuery = $this->_write->getLastQuery();
// Once doing writes, keep using the write backend even for reads
// at least during the same request, to help against stale data.
$this->_read = $this->_write;
return $result;
}
/**
* Check if a transaction has been started.
*
* @return boolean True if transaction has been started.
*/
public function transactionStarted()
{
$result = $this->_write->transactionStarted();
$this->_lastQuery = $this->_write->getLastQuery();
return $result;
}
/**
* Begins the transaction (and turns off auto-committing).
*/
public function beginDbTransaction()
{
$result = $this->_write->beginDbTransaction();
$this->_lastQuery = $this->_write->getLastQuery();
return $result;
}
/**
* Commits the transaction (and turns on auto-committing).
*/
public function commitDbTransaction()
{
$result = $this->_write->commitDbTransaction();
$this->_lastQuery = $this->_write->getLastQuery();
return $result;
}
/**
* Rolls back the transaction (and turns on auto-committing). Must be
* done if the transaction block raises an exception or returns false.
*/
public function rollbackDbTransaction()
{
$result = $this->_write->rollbackDbTransaction();
$this->_lastQuery = $this->_write->getLastQuery();
return $result;
}
/**
* Appends +LIMIT+ and +OFFSET+ options to a SQL statement.
*
* @param string $sql SQL statement.
* @param array $options TODO
*
* @return string
*/
public function addLimitOffset($sql, $options)
{
$result = $this->_read->addLimitOffset($sql, $options);
$this->_lastQuery = $this->_write->getLastQuery();
return $result;
}
/**
* Appends a locking clause to an SQL statement.
* This method *modifies* the +sql+ parameter.
*
* # SELECT * FROM suppliers FOR UPDATE
* add_lock! 'SELECT * FROM suppliers', :lock => true
* add_lock! 'SELECT * FROM suppliers', :lock => ' FOR UPDATE'
*
* @param string &$sql SQL statment.
* @param array $options TODO.
*/
public function addLock(&$sql, array $options = array())
{
$this->_write->addLock($sql, $options);
$this->_lastQuery = $this->_write->getLastQuery();
}
}
Horde_Db-2.0.4/lib/Horde/Db/Migration/Base.php 0000664 0001750 0001750 00000010530 12205351473 016740 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Migration
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Migration
*/
class Horde_Db_Migration_Base
{
/**
* The migration version
* @var integer
*/
public $version = null;
/**
* The logger
* @var Horde_Log_Logger
*/
protected $_logger;
/**
* Database connection adapter
* @var Horde_Db_Adapter_Base
*/
protected $_connection;
/*##########################################################################
# Constructor
##########################################################################*/
/**
*/
public function __construct(Horde_Db_Adapter $connection, $version = null)
{
$this->_connection = $connection;
$this->version = $version;
}
/*##########################################################################
# Public
##########################################################################*/
/**
* Proxy methods over to the connection
* @param string $method
* @param array $args
*/
public function __call($method, $args)
{
$a = array();
foreach ($args as $arg) {
if (is_array($arg)) {
$vals = array();
foreach ($arg as $key => $value) {
$vals[] = var_export($key, true) . ' => ' . var_export($value, true);
}
$a[] = 'array(' . implode(', ', $vals) . ')';
} else {
$a[] = var_export($arg, true);
}
}
$this->say("$method(" . implode(", ", $a) . ")");
// benchmark method call
$t = new Horde_Support_Timer();
$t->push();
$result = call_user_func_array(array($this->_connection, $method), $args);
$time = $t->pop();
// print stats
$this->say(sprintf("%.4fs", $time), 'subitem');
if (is_int($result)) {
$this->say("$result rows", 'subitem');
}
return $result;
}
public function upWithBechmarks()
{
$this->migrate('up');
}
public function downWithBenchmarks()
{
$this->migrate('down');
}
/**
* Execute this migration in the named direction
*/
public function migrate($direction)
{
if (!method_exists($this, $direction)) { return; }
if ($direction == 'up') { $this->announce("migrating"); }
if ($direction == 'down') { $this->announce("reverting"); }
$result = null;
$t = new Horde_Support_Timer();
$t->push();
$result = $this->$direction();
$time = $t->pop();
if ($direction == 'up') {
$this->announce("migrated (" . sprintf("%.4fs", $time) . ")");
$this->log();
}
if ($direction == 'down') {
$this->announce("reverted (" . sprintf("%.4fs", $time) . ")");
$this->log();
}
return $result;
}
/**
* @param string $text
*/
public function log($text = '')
{
if ($this->_logger) {
$this->_logger->info($text);
}
}
/**
* @param Horde_Log_Logger $logger
*/
public function setLogger($logger)
{
$this->_logger = $logger;
}
/**
* Announce migration
* @param string $message
*/
public function announce($message)
{
$text = "$this->version " . get_class($this) . ": $message";
$length = 75 - strlen($text) > 0 ? 75 - strlen($text) : 0;
$this->log(sprintf("== %s %s", $text, str_repeat('=', $length)));
}
/**
* @param string $message
* @param boolean $subitem
*/
public function say($message, $subitem = false)
{
$this->log(($subitem ? " ->" : "--") . " $message");
}
}
Horde_Db-2.0.4/lib/Horde/Db/Migration/Exception.php 0000664 0001750 0001750 00000001336 12205351473 020030 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Migration
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Migration
*/
class Horde_Db_Migration_Exception extends Horde_Db_Exception
{
}
Horde_Db-2.0.4/lib/Horde/Db/Migration/Migrator.php 0000664 0001750 0001750 00000023012 12205351473 017651 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Migration
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Migration
*/
class Horde_Db_Migration_Migrator
{
/**
* @var string
*/
protected $_direction = null;
/**
* @var string
*/
protected $_migrationsPath = null;
/**
* @var integer
*/
protected $_targetVersion = null;
/**
* @var string
*/
protected $_schemaTableName = 'schema_info';
/**
* Constructor.
*
* @param Horde_Db_Adapter $connection A DB connection object.
* @param Horde_Log_Logger $logger A logger object.
* @param array $options Additional options for the migrator:
* - migrationsPath: directory with the
* migration files.
* - schemaTableName: table for storing
* the schema version.
*
* @throws Horde_Db_Migration_Exception
*/
public function __construct(Horde_Db_Adapter $connection,
Horde_Log_Logger $logger = null,
array $options = array())
{
if (!$connection->supportsMigrations()) {
throw new Horde_Db_Migration_Exception('This database does not yet support migrations');
}
$this->_connection = $connection;
$this->_logger = $logger ? $logger : new Horde_Support_Stub();
$this->_inflector = new Horde_Support_Inflector();
if (isset($options['migrationsPath'])) {
$this->_migrationsPath = $options['migrationsPath'];
}
if (isset($options['schemaTableName'])) {
$this->_schemaTableName = $options['schemaTableName'];
}
$this->_initializeSchemaInformation();
}
/**
* @param string $targetVersion
*/
public function migrate($targetVersion = null)
{
$currentVersion = $this->getCurrentVersion();
if ($targetVersion == null || $currentVersion < $targetVersion) {
$this->up($targetVersion);
} elseif ($currentVersion > $targetVersion) {
// migrate down
$this->down($targetVersion);
}
}
/**
* @param string $targetVersion
*/
public function up($targetVersion = null)
{
$this->_targetVersion = $targetVersion;
$this->_direction = 'up';
$this->_doMigrate();
}
/**
* @param string $targetVersion
*/
public function down($targetVersion = null)
{
$this->_targetVersion = $targetVersion;
$this->_direction = 'down';
$this->_doMigrate();
}
/**
* @return integer
*/
public function getCurrentVersion()
{
return in_array($this->_schemaTableName, $this->_connection->tables())
? $this->_connection->selectValue('SELECT version FROM ' . $this->_schemaTableName)
: 0;
}
/**
* @return integer
*/
public function getTargetVersion()
{
$migrations = array();
foreach ($this->_getMigrationFiles() as $migrationFile) {
list($version, $name) = $this->_getMigrationVersionAndName($migrationFile);
$this->_assertUniqueMigrationVersion($migrations, $version);
$migrations[$version] = $name;
}
// Sort by version.
uksort($migrations, 'strnatcmp');
return key(array_reverse($migrations, true));
}
/**
* @param string $migrationsPath Path to migration files.
*/
public function setMigrationsPath($migrationsPath)
{
$this->_migrationsPath = $migrationsPath;
}
/**
* @param Horde_Log_Logger $logger
*/
public function setLogger(Horde_Log_Logger $logger)
{
$this->_logger = $logger;
}
/**
* @param Horde_Support_Inflector $inflector
*/
public function setInflector(Horde_Support_Inflector $inflector)
{
$this->_inflector = $inflector;
}
/**
* Performs the migration.
*/
protected function _doMigrate()
{
foreach ($this->_getMigrationClasses() as $migration) {
if ($this->_hasReachedTargetVersion($migration->version)) {
$this->_logger->info('Reached target version: ' . $this->_targetVersion);
return;
}
if ($this->_isIrrelevantMigration($migration->version)) {
continue;
}
$this->_logger->info('Migrating ' . ($this->_direction == 'up' ? 'to ' : 'from ') . get_class($migration) . ' (' . $migration->version . ')');
$migration->migrate($this->_direction);
$this->_setSchemaVersion($migration->version);
}
}
/**
* @return array
*/
protected function _getMigrationClasses()
{
$migrations = array();
foreach ($this->_getMigrationFiles() as $migrationFile) {
require_once $migrationFile;
list($version, $name) = $this->_getMigrationVersionAndName($migrationFile);
$this->_assertUniqueMigrationVersion($migrations, $version);
$migrations[$version] = $this->_getMigrationClass($name, $version);
}
// Sort by version.
uksort($migrations, 'strnatcmp');
$sorted = array_values($migrations);
return $this->_isDown() ? array_reverse($sorted) : $sorted;
}
/**
* @param array $migrations
* @param integer $version
*
* @throws Horde_Db_Migration_Exception
*/
protected function _assertUniqueMigrationVersion($migrations, $version)
{
if (isset($migrations[$version])) {
throw new Horde_Db_Migration_Exception('Multiple migrations have the version number ' . $version);
}
}
/**
* Returns the list of migration files.
*
* @return array
*/
protected function _getMigrationFiles()
{
return array_keys(
iterator_to_array(
new RegexIterator(
new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(
$this->_migrationsPath
)
),
'/' . preg_quote(DIRECTORY_SEPARATOR, '/') . '\d+_.*\.php$/',
RecursiveRegexIterator::MATCH,
RegexIterator::USE_KEY
)
)
);
}
/**
* Actually returns object, and not class.
*
* @param string $migrationName
* @param integer $version
*
* @return Horde_Db_Migration_Base
*/
protected function _getMigrationClass($migrationName, $version)
{
$className = $this->_inflector->camelize($migrationName);
$class = new $className($this->_connection, $version);
$class->setLogger($this->_logger);
return $class;
}
/**
* @param string $migrationFile
*
* @return array ($version, $name)
*/
protected function _getMigrationVersionAndName($migrationFile)
{
preg_match_all('/([0-9]+)_([_a-z0-9]*).php/', $migrationFile, $matches);
return array($matches[1][0], $matches[2][0]);
}
/**
* @TODO
*/
protected function _initializeSchemaInformation()
{
if (in_array($this->_schemaTableName, $this->_connection->tables())) {
return;
}
$schemaTable = $this->_connection->createTable($this->_schemaTableName, array('autoincrementKey' => false));
$schemaTable->column('version', 'integer');
$schemaTable->end();
$this->_connection->insert('INSERT INTO ' . $this->_schemaTableName . ' (version) VALUES (0)');
}
/**
* @param integer $version
*/
protected function _setSchemaVersion($version)
{
$version = $this->_isDown() ? $version - 1 : $version;
if ($version) {
$sql = 'UPDATE ' . $this->_schemaTableName . ' SET version = ' . (int)$version;
$this->_connection->update($sql);
} else {
$this->_connection->dropTable($this->_schemaTableName);
}
}
/**
* @return boolean
*/
protected function _isUp()
{
return $this->_direction == 'up';
}
/**
* @return boolean
*/
protected function _isDown()
{
return $this->_direction == 'down';
}
/**
* @return boolean
*/
protected function _hasReachedTargetVersion($version)
{
if ($this->_targetVersion === null) {
return false;
}
return ($this->_isUp() && $version - 1 >= $this->_targetVersion) ||
($this->_isDown() && $version <= $this->_targetVersion);
}
/**
* @param integer $version
*
* @return boolean
*/
protected function _isIrrelevantMigration($version)
{
return ($this->_isUp() && $version <= self::getCurrentVersion()) ||
($this->_isDown() && $version > self::getCurrentVersion());
}
}
Horde_Db-2.0.4/lib/Horde/Db/Value/Binary.php 0000664 0001750 0001750 00000001710 12205351473 016435 0 ustar jan jan
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
*/
/**
* Encapsulation object for binary values to be used in SQL statements to ensure
* proper quoting, escaping, retrieval, etc.
*
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
*/
class Horde_Db_Value_Binary implements Horde_Db_Value
{
/**
* Binary value to be quoted
* @var string
*/
protected $_value;
/**
* Constructor
*
* @param string $binaryValue
*/
public function __construct($binaryValue)
{
$this->_value = $binaryValue;
}
/**
* @param Horde_Db_Adapter $db
*/
public function quote(Horde_Db_Adapter $db)
{
return $db->quoteBinary($this->_value);
}
}
Horde_Db-2.0.4/lib/Horde/Db/Adapter.php 0000664 0001750 0001750 00000023100 12205351473 015512 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage Adapter
*/
interface Horde_Db_Adapter
{
/**
* Returns the human-readable name of the adapter. Use mixed case - one
* can always use downcase if needed.
*
* @return string
*/
public function adapterName();
/**
* Does this adapter support migrations? Backend specific, as the
* abstract adapter always returns +false+.
*
* @return boolean
*/
public function supportsMigrations();
/**
* Does this adapter support using DISTINCT within COUNT? This is +true+
* for all adapters except sqlite.
*
* @return boolean
*/
public function supportsCountDistinct();
/**
* Should primary key values be selected from their corresponding
* sequence before the insert statement? If true, next_sequence_value
* is called before each insert to set the record's primary key.
* This is false for all adapters but Firebird.
*
* @return boolean
*/
public function prefetchPrimaryKey($tableName = null);
/*##########################################################################
# Connection Management
##########################################################################*/
/**
* Connect to the db.
*/
public function connect();
/**
* Is the connection active?
*
* @return boolean
*/
public function isActive();
/**
* Reconnect to the db.
*/
public function reconnect();
/**
* Disconnect from db.
*/
public function disconnect();
/**
* Provides access to the underlying database connection. Useful for when
* you need to call a proprietary method such as postgresql's
* lo_* methods.
*
* @return resource
*/
public function rawConnection();
/*##########################################################################
# Quoting
##########################################################################*/
/**
* Quotes a string, escaping any special characters.
*
* @param string $string
* @return string
*/
public function quoteString($string);
/*##########################################################################
# Database Statements
##########################################################################*/
/**
* Returns an array of records with the column names as keys, and
* column values as values.
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return Iterator
* @throws Horde_Db_Exception
*/
public function select($sql, $arg1 = null, $arg2 = null);
/**
* Returns an array of record hashes with the column names as keys and
* column values as values.
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return array
* @throws Horde_Db_Exception
*/
public function selectAll($sql, $arg1 = null, $arg2 = null);
/**
* Returns a record hash with the column names as keys and column values
* as values.
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return array
* @throws Horde_Db_Exception
*/
public function selectOne($sql, $arg1 = null, $arg2 = null);
/**
* Returns a single value from a record
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return string
* @throws Horde_Db_Exception
*/
public function selectValue($sql, $arg1 = null, $arg2 = null);
/**
* Returns an array of the values of the first column in a select:
* selectValues("SELECT id FROM companies LIMIT 3") => [1,2,3]
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return array
* @throws Horde_Db_Exception
*/
public function selectValues($sql, $arg1 = null, $arg2 = null);
/**
* Returns an array where the keys are the first column of a select, and the
* values are the second column:
*
* selectAssoc("SELECT id, name FROM companies LIMIT 3") => [1 => 'Ford', 2 => 'GM', 3 => 'Chrysler']
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return array
* @throws Horde_Db_Exception
*/
public function selectAssoc($sql, $arg1 = null, $arg2 = null);
/**
* Executes the SQL statement in the context of this connection.
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return Iterator
* @throws Horde_Db_Exception
*/
public function execute($sql, $arg1 = null, $arg2 = null);
/**
* Returns the last auto-generated ID from the affected table.
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a
* query name.
* @param string $arg2 If $arg1 contains bound parameters, the
* query name.
* @param string $pk TODO
* @param integer $idValue TODO
* @param string $sequenceName TODO
*
* @return integer Last inserted ID.
* @throws Horde_Db_Exception
*/
public function insert($sql, $arg1 = null, $arg2 = null, $pk = null,
$idValue = null, $sequenceName = null);
/**
* Executes the update statement and returns the number of rows affected.
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return integer Number of rows affected.
* @throws Horde_Db_Exception
*/
public function update($sql, $arg1 = null, $arg2 = null);
/**
* Executes the delete statement and returns the number of rows affected.
*
* @param string $sql SQL statement.
* @param mixed $arg1 Either an array of bound parameters or a query
* name.
* @param string $arg2 If $arg1 contains bound parameters, the query
* name.
*
* @return integer Number of rows affected.
* @throws Horde_Db_Exception
*/
public function delete($sql, $arg1 = null, $arg2 = null);
/**
* Check if a transaction has been started.
*
* @return boolean True if transaction has been started.
*/
public function transactionStarted();
/**
* Begins the transaction (and turns off auto-committing).
*/
public function beginDbTransaction();
/**
* Commits the transaction (and turns on auto-committing).
*/
public function commitDbTransaction();
/**
* Rolls back the transaction (and turns on auto-committing). Must be
* done if the transaction block raises an exception or returns false.
*/
public function rollbackDbTransaction();
/**
* Appends +LIMIT+ and +OFFSET+ options to a SQL statement.
*
* @param string $sql SQL statement.
* @param array $options TODO
*
* @return string
*/
public function addLimitOffset($sql, $options);
/**
* Appends a locking clause to an SQL statement.
* This method *modifies* the +sql+ parameter.
*
* # SELECT * FROM suppliers FOR UPDATE
* add_lock! 'SELECT * FROM suppliers', :lock => true
* add_lock! 'SELECT * FROM suppliers', :lock => ' FOR UPDATE'
*
* @param string &$sql SQL statment.
* @param array $options TODO.
*/
public function addLock(&$sql, array $options = array());
}
Horde_Db-2.0.4/lib/Horde/Db/Exception.php 0000664 0001750 0001750 00000001301 12205351473 016067 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
*/
/**
* Db Exception class.
*
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
*/
class Horde_Db_Exception extends Horde_Exception_Wrapped
{
}
Horde_Db-2.0.4/lib/Horde/Db/SearchParser.php 0000664 0001750 0001750 00000013271 12205351473 016524 0 ustar jan jan
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
*/
class Horde_Db_SearchParser
{
/**
* Parses a keyword expression.
*
* @param string $column This is the SQL field name the resulting
* expression should test against.
* @param string $expr This is the keyword expression we want to parse.
*
* @return string The query expression.
* @throws Horde_Db_Exception
*/
static public function parse($column, $expr)
{
/* First pass - scan the string for tokens. Bare words are tokens, or
* the user can quote strings to have embedded spaces, keywords, or
* parentheses. Parentheses can be used for grouping boolean
* operators, and the boolean operators AND, OR, and NOT are all
* recognized.
*
* The tokens are returned in the $tokens array -- an array of strings.
* Each string in the array starts with either a `!' or a `='. `=' is
* a bare word or quoted string we are searching for, and `!' indicates
* a boolean operator or parenthesis. A token that starts with a '.'
* indicates a PostgreSQL word boundary search. */
$tokens = array();
while (!empty($expr)) {
$expr = preg_replace('/^\s+/', '', $expr);
if (empty($expr)) {
break;
}
if (substr($expr,0,1) == '(') {
$expr = substr($expr, 1);
$token = '!(';
} elseif (substr($expr, 0, 1) == ')') {
$expr = substr($expr, 1);
$token = '!)';
} elseif (substr($expr, 0, 1) == ',') {
$expr = substr($expr, 1);
$token = '!OR';
} elseif (preg_match('/^(AND|OR|NOT)([^a-z].*)?$/i', $expr,
$matches)) {
$token = '!' . strtoupper($matches[1]);
$expr = substr($expr, strlen($matches[1]));
} elseif (preg_match('/^"(([^"]|\\[0-7]+|\\[Xx][0-9a-fA-F]+|\\[^Xx0-7])*)"/',
$expr, $matches)) {
$token = '=' . stripcslashes($matches[1]);
$expr = substr($expr, strlen($matches[0]));
} elseif (preg_match('/^[^\\s\\(\\),]+/', $expr, $matches)) {
$token = '=' . $matches[0];
$expr = substr($expr,strlen($token)-1);
} else {
throw new Horde_Db_Exception('Syntax error in search terms');
}
if ($token == '!AND') {
/* !AND is implied by concatenation. */
continue;
}
$tokens[] = $token;
}
/* Call the expression parser. */
return self::_parseKeywords1($column, $tokens);
}
static protected function _parseKeywords1($column, &$tokens)
{
if (count($tokens) == 0) {
throw new Horde_Db_Exception('Empty search terms');
}
$lhs = self::_parseKeywords2($column, $tokens);
if (count($tokens) == 0 || $tokens[0] != '!OR') {
return $lhs;
}
array_shift($tokens);
$rhs = self::_parseKeywords1($column, $tokens);
return "($lhs OR $rhs)";
}
static protected function _parseKeywords2($column, &$tokens)
{
$lhs = self::_parseKeywords3($column, $tokens);
if (sizeof($tokens) == 0 || $tokens[0] == '!)' || $tokens[0] == '!OR') {
return $lhs;
}
$rhs = self::_parseKeywords2($column, $tokens);
return "($lhs AND $rhs)";
}
static protected function _parseKeywords3($column, &$tokens)
{
if ($tokens[0] == '!NOT') {
array_shift($tokens);
$lhs = self::_parseKeywords4($column, $tokens);
if (is_a($lhs, 'PEAR_Error')) {
return $lhs;
}
return "(NOT $lhs)";
}
return self::_parseKeywords4($column, $tokens);
}
static protected function _parseKeywords4($column, &$tokens)
{
if ($tokens[0] == '!(') {
array_shift($tokens);
$lhs = self::_parseKeywords1($column, $tokens);
if (sizeof($tokens) == 0 || $tokens[0] != '!)') {
throw new Horde_Db_Exception('Expected ")"');
}
array_shift($tokens);
return $lhs;
}
if (substr($tokens[0], 0, 1) != '=' &&
substr($tokens[0], 0, 2) != '=.') {
throw new Horde_Db_Exception('Expected bare word or quoted search term');
}
$val = strtolower(substr(array_shift($tokens), 1));
$val = addslashes(ereg_replace("([\\%])", "\\\\1", $val));
return "(LOWER($column) LIKE '%$val%')";
}
}
Horde_Db-2.0.4/lib/Horde/Db/StatementParser.php 0000664 0001750 0001750 00000004635 12205351473 017267 0 ustar jan jan
* @author James Pepin
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
*/
/**
* Class for parsing a stream into individual SQL statements.
*
* @author Chuck Hagenbuch
* @author James Pepin
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
*/
class Horde_Db_StatementParser implements Iterator
{
protected $_count = 0;
protected $_currentStatement;
public function __construct($file)
{
if (is_string($file)) {
$file = new SplFileObject($file, 'r');
}
$this->_file = $file;
}
public function current()
{
if (is_null($this->_currentStatement)) {
$this->rewind();
}
return $this->_currentStatement;
}
public function key()
{
if (is_null($this->_currentStatement)) {
$this->rewind();
}
return $this->_count;
}
public function next()
{
if ($statement = $this->_getNextStatement()) {
$this->_count++;
return $statement;
}
return null;
}
public function rewind()
{
$this->_count = 0;
$this->_currentStatement = null;
$this->_file->rewind();
$this->next();
}
public function valid()
{
return !$this->_file->eof() && $this->_file->isReadable();
}
/**
* Read the next sql statement from our file. Statements are terminated by
* semicolons.
*
* @return string The next SQL statement in the file.
*/
protected function _getNextStatement()
{
$this->_currentStatement = '';
while (!$this->_file->eof()) {
$line = $this->_file->fgets();
if (!trim($line)) { continue; }
if (!$this->_currentStatement && substr($line, 0, 2) == '--') { continue; }
$trimmedline = rtrim($line);
if (substr($trimmedline, -1) == ';') {
// Leave off the ending ;
$this->_currentStatement .= substr($trimmedline, 0, -1);
return $this->_currentStatement;
}
$this->_currentStatement .= $line;
}
return $this->_currentStatement;
}
}
Horde_Db-2.0.4/lib/Horde/Db/Value.php 0000664 0001750 0001750 00000001036 12205351473 015212 0 ustar jan jan
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
*/
/**
* Interface for values with specific quoting rules.
*
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
*/
interface Horde_Db_Value
{
/**
* @param Horde_Db_Adapter $db
*/
public function quote(Horde_Db_Adapter $db);
}
Horde_Db-2.0.4/lib/Horde/Db.php 0000664 0001750 0001750 00000001770 12205351473 014143 0 ustar jan jan
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
*/
/**
* @author Jan Schneider
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
*/
class Horde_Db
{
/**
* Specifies that the fetch method shall return each row as an array
* indexed by column name as returned in the corresponding result set.
*/
const FETCH_ASSOC = 2;
/**
* Specifies that the fetch method shall return each row as an array
* indexed by column number as returned in the corresponding result set,
* starting at column 0.
*/
const FETCH_NUM = 3;
/**
* Specifies that the fetch method shall return each row as an array
* indexed by both column name and number as returned in the corresponding
* result set, starting at column 0.
*/
const FETCH_BOTH = 4;
}
Horde_Db-2.0.4/test/Horde/Db/Adapter/Mysql/ColumnDefinition.php 0000664 0001750 0001750 00000007563 12205351473 022315 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage UnitTests
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @group horde_db
* @category Horde
* @package Db
* @subpackage UnitTests
*/
class Horde_Db_Adapter_Mysql_ColumnDefinition extends Horde_Test_Case
{
public $conn;
public function testConstruct()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->conn, 'col_name', 'string'
);
$this->assertEquals('col_name', $col->getName());
$this->assertEquals('string', $col->getType());
}
public function testToSql()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->conn, 'col_name', 'string'
);
$this->assertEquals('`col_name` varchar(255)', $col->toSql());
}
public function testToSqlLimit()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->conn, 'col_name', 'string', 40
);
$this->assertEquals('`col_name` varchar(40)', $col->toSql());
// set attribute instead
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->conn, 'col_name', 'string'
);
$col->setLimit(40);
$this->assertEquals('`col_name` varchar(40)', $col->toSql());
}
public function testToSqlPrecisionScale()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->conn, 'col_name', 'decimal', null, 5, 2
);
$this->assertEquals('`col_name` decimal(5, 2)', $col->toSql());
// set attribute instead
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->conn, 'col_name', 'decimal'
);
$col->setPrecision(5);
$col->setScale(2);
$this->assertEquals('`col_name` decimal(5, 2)', $col->toSql());
}
public function testToSqlUnsigned()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->conn, 'col_name', 'integer', null, null, null, true
);
$this->assertEquals('`col_name` int(10) UNSIGNED', $col->toSql());
// set attribute instead
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->conn, 'col_name', 'integer'
);
$col->setUnsigned(true);
$this->assertEquals('`col_name` int(10) UNSIGNED', $col->toSql());
}
public function testToSqlNotNull()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->conn, 'col_name', 'string', null, null, null, null, null, false
);
$this->assertEquals('`col_name` varchar(255) NOT NULL', $col->toSql());
// set attribute instead
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->conn, 'col_name', 'string'
);
$col->setNull(false);
$this->assertEquals('`col_name` varchar(255) NOT NULL', $col->toSql());
}
public function testToSqlDefault()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->conn, 'col_name', 'string', null, null, null, null, 'test'
);
$this->assertEquals("`col_name` varchar(255) DEFAULT 'test'", $col->toSql());
// set attribute instead
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->conn, 'col_name', 'string'
);
$col->setDefault('test');
$this->assertEquals("`col_name` varchar(255) DEFAULT 'test'", $col->toSql());
}
}
Horde_Db-2.0.4/test/Horde/Db/Adapter/Mysql/ColumnTest.php 0000664 0001750 0001750 00000022643 12205351473 021140 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage UnitTests
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @group horde_db
* @category Horde
* @package Db
* @subpackage UnitTests
*/
class Horde_Db_Adapter_Mysql_ColumnTest extends PHPUnit_Framework_TestCase
{
/*##########################################################################
# Construction
##########################################################################*/
public function testDefaultNull()
{
$col = new Horde_Db_Adapter_Mysql_Column('name', 'NULL', 'varchar(255)');
$this->assertEquals(true, $col->isNull());
}
public function testNotNull()
{
$col = new Horde_Db_Adapter_Mysql_Column('name', 'NULL', 'varchar(255)', false);
$this->assertEquals(false, $col->isNull());
}
public function testName()
{
$col = new Horde_Db_Adapter_Mysql_Column('name', 'NULL', 'varchar(255)');
$this->assertEquals('name', $col->getName());
}
public function testSqlType()
{
$col = new Horde_Db_Adapter_Mysql_Column('name', 'NULL', 'varchar(255)');
$this->assertEquals('varchar(255)', $col->getSqlType());
}
public function testIsText()
{
$col = new Horde_Db_Adapter_Mysql_Column('test', 'NULL', 'varchar(255)');
$this->assertTrue($col->isText());
$col = new Horde_Db_Adapter_Mysql_Column('test', 'NULL', 'text');
$this->assertTrue($col->isText());
$col = new Horde_Db_Adapter_Mysql_Column('test', 'NULL', 'int(11)');
$this->assertFalse($col->isText());
$col = new Horde_Db_Adapter_Mysql_Column('test', 'NULL', 'float(11,1)');
$this->assertFalse($col->isText());
}
public function testIsNumber()
{
$col = new Horde_Db_Adapter_Mysql_Column('test', 'NULL', 'varchar(255)');
$this->assertFalse($col->isNumber());
$col = new Horde_Db_Adapter_Mysql_Column('test', 'NULL', 'text');
$this->assertFalse($col->isNumber());
$col = new Horde_Db_Adapter_Mysql_Column('test', 'NULL', 'int(11)');
$this->assertTrue($col->isNumber());
$col = new Horde_Db_Adapter_Mysql_Column('test', 'NULL', 'float(11,1)');
$this->assertTrue($col->isNumber());
}
/*##########################################################################
# Types
##########################################################################*/
public function testTypeInteger()
{
$col = new Horde_Db_Adapter_Mysql_Column('age', 'NULL', 'int(11)');
$this->assertEquals('integer', $col->getType());
$this->assertFalse($col->isUnsigned());
}
public function testTypeIntegerUnsigned()
{
$col = new Horde_Db_Adapter_Mysql_Column('age', 'NULL', 'int(10) UNSIGNED');
$this->assertTrue($col->isUnsigned());
}
public function testTypeFloat()
{
$col = new Horde_Db_Adapter_Mysql_Column('age', 'NULL', 'float(11,1)');
$this->assertEquals('float', $col->getType());
}
public function testTypeDecimalPrecisionNone()
{
$col = new Horde_Db_Adapter_Mysql_Column('age', 'NULL', 'decimal(11,0)');
$this->assertEquals('integer', $col->getType());
}
public function testTypeDecimal()
{
$col = new Horde_Db_Adapter_Mysql_Column('age', 'NULL', 'decimal(11,1)');
$this->assertEquals('decimal', $col->getType());
}
public function testTypeDatetime()
{
$col = new Horde_Db_Adapter_Mysql_Column('age', 'NULL', 'datetime');
$this->assertEquals('datetime', $col->getType());
}
public function testTypeTimestamp()
{
$col = new Horde_Db_Adapter_Mysql_Column('age', 'CURRENT_TIMESTAMP', 'timestamp');
$this->assertEquals('timestamp', $col->getType());
}
public function testTypeTime()
{
$col = new Horde_Db_Adapter_Mysql_Column('age', 'NULL', 'time');
$this->assertEquals('time', $col->getType());
}
public function testTypeDate()
{
$col = new Horde_Db_Adapter_Mysql_Column('age', 'NULL', 'date');
$this->assertEquals('date', $col->getType());
}
public function testTypeText()
{
$col = new Horde_Db_Adapter_Mysql_Column('age', 'NULL', 'text');
$this->assertEquals('text', $col->getType());
}
public function testTypeBinary()
{
$col = new Horde_Db_Adapter_Mysql_Column('age', 'NULL', 'blob(255)');
$this->assertEquals('binary', $col->getType());
}
public function testTypeString()
{
$col = new Horde_Db_Adapter_Mysql_Column('name', 'NULL', 'varchar(255)');
$this->assertEquals('string', $col->getType());
}
/*##########################################################################
# Extract Limit
##########################################################################*/
public function testExtractLimitInt()
{
$col = new Horde_Db_Adapter_Mysql_Column('test', 'NULL', 'int(11)');
$this->assertEquals(11, $col->getLimit());
}
public function testExtractLimitVarchar()
{
$col = new Horde_Db_Adapter_Mysql_Column('test', 'NULL', 'varchar(255)');
$this->assertEquals(255, $col->getLimit());
}
public function testExtractLimitDecimal()
{
$col = new Horde_Db_Adapter_Mysql_Column('test', 'NULL', 'decimal(11,1)');
$this->assertEquals('11', $col->getLimit());
}
public function testExtractLimitText()
{
$col = new Horde_Db_Adapter_Mysql_Column('test', 'NULL', 'text');
$this->assertEquals(null, $col->getLimit());
}
public function testExtractLimitNone()
{
$col = new Horde_Db_Adapter_Mysql_Column('test', 'NULL');
$this->assertEquals(null, $col->getLimit());
}
/*##########################################################################
# Extract Precision/Scale
##########################################################################*/
public function testExtractPrecisionScale()
{
$col = new Horde_Db_Adapter_Mysql_Column('test', 'NULL', 'decimal(12,1)');
$this->assertEquals('12', $col->precision());
$this->assertEquals('1', $col->scale());
}
/*##########################################################################
# Type Cast Values
##########################################################################*/
public function testTypeCastInteger()
{
$col = new Horde_Db_Adapter_Mysql_Column('name', '1', 'int(11)', false);
$this->assertEquals(1, $col->getDefault());
}
public function testTypeCastFloat()
{
$col = new Horde_Db_Adapter_Mysql_Column('version', '1.0', 'float(11,1)', false);
$this->assertEquals(1.0, $col->getDefault());
}
public function testTypeCastString()
{
$col = new Horde_Db_Adapter_Mysql_Column('name', 'n/a', 'varchar(255)', false);
$this->assertEquals('n/a', $col->getDefault());
}
public function testTypeCastBooleanFalse()
{
$col = new Horde_Db_Adapter_Mysql_Column('is_active', '0', 'tinyint(1)', false);
$this->assertSame(false, $col->getDefault());
}
public function testTypeCastBooleanTrue()
{
$col = new Horde_Db_Adapter_Mysql_Column('is_active', '1', 'tinyint(1)', false);
$this->assertSame(true, $col->getDefault());
}
/*##########################################################################
# Column Types
##########################################################################*/
public function testColumnTypeEnum()
{
$col = new Horde_Db_Adapter_Mysql_Column('user', 'NULL', "enum('derek', 'mike')");
$this->assertEquals('string', $col->getType());
}
public function testColumnTypeBoolean()
{
$col = new Horde_Db_Adapter_Mysql_Column('is_active', 'NULL', 'tinyint(1)');
$this->assertEquals('boolean', $col->getType());
}
/*##########################################################################
# Defaults
##########################################################################*/
public function testDefaultDatetime()
{
$col = new Horde_Db_Adapter_Mysql_Column('name', '', 'datetime');
$this->assertEquals(null, $col->getDefault());
}
public function testDefaultInteger()
{
$col = new Horde_Db_Adapter_Mysql_Column('name', '', 'int(11)');
$this->assertEquals(null, $col->getDefault());
}
public function testDefaultString()
{
$col = new Horde_Db_Adapter_Mysql_Column('name', '', 'varchar(255)');
$this->assertEquals('', $col->getDefault());
}
public function testDefaultText()
{
$col = new Horde_Db_Adapter_Mysql_Column('name', '', 'text');
$this->assertEquals('', $col->getDefault());
}
public function testDefaultBinary()
{
$col = new Horde_Db_Adapter_Mysql_Column('name', '', 'blob(255)');
$this->assertEquals('', $col->getDefault());
}
}
Horde_Db-2.0.4/test/Horde/Db/Adapter/Mysql/TableDefinition.php 0000664 0001750 0001750 00000003142 12205351473 022074 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage UnitTests
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @group horde_db
* @category Horde
* @package Db
* @subpackage UnitTests
*/
class Horde_Db_Adapter_Mysql_TableDefinition extends Horde_Test_Case
{
public $conn;
/*##########################################################################
# Public methods
##########################################################################*/
public function testConstruct()
{
}
public function testName()
{
}
public function testGetOptions()
{
}
public function testPrimaryKey()
{
}
public function testColumn()
{
}
public function testToSql()
{
}
/*##########################################################################
# Array Access
##########################################################################*/
public function testOffsetExists()
{
}
public function testOffsetGet()
{
}
public function testOffsetSet()
{
}
public function testOffsetUnset()
{
}
}
Horde_Db-2.0.4/test/Horde/Db/Adapter/Pdo/MysqlTest.php 0000664 0001750 0001750 00000161623 12205351473 020427 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @author Jan Schneider
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage UnitTests
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @author Jan Schneider
* @license http://www.horde.org/licenses/bsd
* @group horde_db
* @category Horde
* @package Db
* @subpackage UnitTests
*/
class Horde_Db_Adapter_Pdo_MysqlTest extends Horde_Test_Case
{
protected static $columnTest;
protected static $tableTest;
protected static $skip = true;
protected static $reason = 'The PDO_MySQL adapter is not available';
public static function setUpBeforeClass()
{
if (extension_loaded('pdo') &&
in_array('mysql', PDO::getAvailableDrivers())) {
self::$skip = false;
list($conn,) = self::getConnection();
if (self::$skip) {
return;
}
$conn->disconnect();
}
require_once __DIR__ . '/../Mysql/ColumnDefinition.php';
require_once __DIR__ . '/../Mysql/TableDefinition.php';
self::$columnTest = new Horde_Db_Adapter_Mysql_ColumnDefinition();
self::$tableTest = new Horde_Db_Adapter_Mysql_TableDefinition();
}
public static function getConnection($overrides = array())
{
$config = Horde_Test_Case::getConfig('DB_ADAPTER_PDO_MYSQL_TEST_CONFIG',
null,
array('host' => 'localhost',
'username' => '',
'password' => '',
'dbname' => 'test'));
if (isset($config['db']['adapter']['pdo']['mysql']['test'])) {
$config = $config['db']['adapter']['pdo']['mysql']['test'];
}
if (!is_array($config)) {
self::$skip = true;
self::$reason = 'No configuration for pdo_mysql test';
return;
}
$config = array_merge($config, $overrides);
$conn = new Horde_Db_Adapter_Pdo_Mysql($config);
$cache = new Horde_Cache(new Horde_Cache_Storage_Mock());
$conn->setCache($cache);
return array($conn, $cache);
}
protected function setUp()
{
if (self::$skip) {
$this->markTestSkipped(self::$reason);
}
list($this->_conn, $this->_cache) = self::getConnection();
self::$columnTest->conn = $this->_conn;
self::$tableTest->conn = $this->_conn;
// clear out detritus from any previous test runs.
$this->_dropTestTables();
$table = $this->_conn->createTable('unit_tests');
$table->column('integer_value', 'integer', array('limit' => 11, 'default' => 0));
$table->column('string_value', 'string', array('limit' => 255, 'default' => ''));
$table->column('text_value', 'text', array('null' => false, 'default' => ''));
$table->column('float_value', 'float', array('precision' => 2, 'scale' => 1, 'default' => 0.0));
$table->column('decimal_value', 'decimal', array('precision' => 2, 'scale' => 1, 'default' => 0.0));
$table->column('datetime_value', 'datetime', array('default' => '0000-00-00 00:00:00'));
$table->column('date_value', 'date', array('default' => '0000-00-00'));
$table->column('time_value', 'time', array('default' => '00:00:00'));
$table->column('blob_value', 'binary', array('null' => false, 'default' => ''));
$table->column('boolean_value', 'boolean', array('default' => false));
$table->column('email_value', 'string', array('limit' => 255, 'default' => ''));
$table->end();
$this->_conn->addIndex('unit_tests', 'string_value', array('name' => 'string_value'));
$this->_conn->addIndex('unit_tests', 'integer_value', array('name' => 'integer_value', 'unique' => true));
$this->_conn->addIndex('unit_tests', array('integer_value', 'string_value'), array('name' => 'integer_string'));
// read sql file for statements
$statements = array();
$current_stmt = '';
$fp = fopen(__DIR__ . '/../../fixtures/unit_tests.sql', 'r');
while ($line = fgets($fp, 8192)) {
$line = rtrim(preg_replace('/^(.*)--.*$/s', '\1', $line));
if (!$line) {
continue;
}
$current_stmt .= $line;
if (substr($line, -1) == ';') {
// leave off the ending ;
$statements[] = substr($current_stmt, 0, -1);
$current_stmt = '';
}
}
// run statements
foreach ($statements as $stmt) {
$this->_conn->execute($stmt);
}
}
protected function tearDown()
{
// clean up
$this->_dropTestTables();
// close connection
$this->_conn->disconnect();
}
/*##########################################################################
# Connection
##########################################################################*/
public function testConnect()
{
$this->assertTrue($this->_conn->isActive());
}
public function testDisconnect()
{
$this->_conn->disconnect();
$this->assertFalse($this->_conn->isActive());
$this->_conn->connect();
$this->assertTrue($this->_conn->isActive());
}
public function testReconnect()
{
$this->_conn->reconnect();
$this->assertTrue($this->_conn->isActive());
}
/*##########################################################################
# Accessor
##########################################################################*/
public function testAdapterName()
{
$this->assertEquals('PDO_MySQL', $this->_conn->adapterName());
}
public function testSupportsMigrations()
{
$this->assertTrue($this->_conn->supportsMigrations());
}
public function testSupportsCountDistinct()
{
$this->assertTrue($this->_conn->supportsCountDistinct());
}
public function testGetCharset()
{
$this->assertEquals('utf8', strtolower($this->_conn->getCharset()));
}
/*##########################################################################
# Database Statements
##########################################################################*/
public function testExecute()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->execute($sql);
$row = $result->fetch();
$this->assertEquals(1, $row['id']);
}
public function testSelect()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->select($sql);
$this->assertInstanceOf('Traversable', $result);
$this->assertGreaterThan(0, count($result));
foreach ($result as $row) break;
$this->assertInternalType('array', $row);
$this->assertEquals(1, $row['id']);
}
public function testSelectWithBoundParameters()
{
$sql = "SELECT * FROM unit_tests WHERE id=?";
$result = $this->_conn->select($sql, array(1));
$this->assertInstanceOf('Traversable', $result);
$this->assertGreaterThan(0, count($result));
foreach ($result as $row) break;
$this->assertInternalType('array', $row);
$this->assertEquals(1, $row['id']);
}
public function testSelectWithBoundParametersQuotesString()
{
$sql = "SELECT * FROM unit_tests WHERE string_value=?";
$result = $this->_conn->select($sql, array('name a'));
$this->assertInstanceOf('Traversable', $result);
$this->assertGreaterThan(0, count($result));
foreach ($result as $row) break;
$this->assertInternalType('array', $row);
$this->assertEquals(1, $row['id']);
}
public function testSelectAll()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->selectAll($sql);
$this->assertInternalType('array', $result);
$this->assertGreaterThan(0, count($result));
$this->assertEquals(1, $result[0]['id']);
}
public function testSelectOne()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->selectOne($sql);
$this->assertEquals(1, $result['id']);
}
public function testSelectValue()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->selectValue($sql);
$this->assertEquals(1, $result);
}
public function testSelectValues()
{
$sql = "SELECT * FROM unit_tests";
$result = $this->_conn->selectValues($sql);
$this->assertEquals(array(1, 2, 3, 4, 5, 6), $result);
}
public function testInsert()
{
$sql = "INSERT INTO unit_tests (id, integer_value) VALUES (7, 999)";
$result = $this->_conn->insert($sql);
$this->assertEquals(7, $result);
}
public function testUpdate()
{
$sql = "UPDATE unit_tests SET integer_value=999 WHERE id IN (1)";
$result = $this->_conn->update($sql);
$this->assertEquals(1, $result);
}
public function testDelete()
{
$sql = "DELETE FROM unit_tests WHERE id IN (1,2)";
$result = $this->_conn->delete($sql);
$this->assertEquals(2, $result);
}
public function testTransactionStarted()
{
$this->assertFalse($this->_conn->transactionStarted());
$this->_conn->beginDbTransaction();
$this->assertTrue($this->_conn->transactionStarted());
$this->_conn->commitDbTransaction();
$this->assertFalse($this->_conn->transactionStarted());
}
public function testTransactionCommit()
{
$this->_conn->beginDbTransaction();
$sql = "INSERT INTO unit_tests (id, integer_value) VALUES (7, 999)";
$this->_conn->insert($sql);
$this->_conn->commitDbTransaction();
// make sure it inserted
$sql = "SELECT integer_value FROM unit_tests WHERE id='7'";
$this->assertEquals('999', $this->_conn->selectValue($sql));
}
public function testTransactionRollback()
{
$this->_conn->beginDbTransaction();
$sql = "INSERT INTO unit_tests (id, integer_value) VALUES (7, 999)";
$this->_conn->insert($sql);
$this->_conn->rollbackDbTransaction();
// make sure it inserted
$sql = "SELECT integer_value FROM unit_tests WHERE id='7'";
$this->assertEquals(null, $this->_conn->selectValue($sql));
}
/*##########################################################################
# Quoting
##########################################################################*/
public function testQuoteNull()
{
$this->assertEquals('NULL', $this->_conn->quote(null));
}
public function testQuoteTrue()
{
$this->assertEquals('1', $this->_conn->quote(true));
}
public function testQuoteFalse()
{
$this->assertEquals('0', $this->_conn->quote(false));
}
public function testQuoteString()
{
$this->assertEquals("'my string'", $this->_conn->quote('my string'));
}
public function testQuoteDirtyString()
{
$this->assertEquals("'derek\'s string'", $this->_conn->quote('derek\'s string'));
}
public function testQuoteColumnName()
{
$col = new Horde_Db_Adapter_Mysql_Column('age', 'NULL', 'int(11)');
$this->assertEquals('1', $this->_conn->quote(true, $col));
}
public function testQuoteBinary()
{
// Test string is foo\0ba'r - should be 8 bytes long
$original = base64_decode('Zm9vAGJhJ3I=');
$table = $this->_conn->createTable('binary_testings');
$table->column('data', 'binary', array('null' => false));
$table->end();
$this->_conn->insert('INSERT INTO binary_testings (data) VALUES (?)', array(new Horde_Db_Value_Binary($original)));
$retrieved = $this->_conn->selectValue('SELECT data FROM binary_testings');
$columns = $this->_conn->columns('binary_testings');
$retrieved = $columns['data']->binaryToString($retrieved);
$this->assertEquals($original, $retrieved);
}
/*##########################################################################
# Schema Statements
##########################################################################*/
/**
* We specifically do a manual INSERT here, and then test only the SELECT
* functionality. This allows us to more easily catch INSERT being broken,
* but SELECT actually working fine.
*/
public function testNativeDecimalInsertManualVsAutomatic()
{
$table = $this->_conn->createTable('users');
$table->column('company_id', 'integer', array('limit' => 11));
$table->column('name', 'string', array('limit' => 255, 'default' => ''));
$table->column('first_name', 'string', array('limit' => 40, 'default' => ''));
$table->column('approved', 'boolean', array('default' => true));
$table->column('type', 'string', array('limit' => 255, 'default' => ''));
$table->column('created_at', 'datetime', array('default' => '0000-00-00 00:00:00'));
$table->column('created_on', 'date', array('default' => '0000-00-00'));
$table->column('updated_at', 'datetime', array('default' => '0000-00-00 00:00:00'));
$table->column('updated_on', 'date', array('default' => '0000-00-00'));
$table->end();
$correctValue = 12345678901234567890.0123456789;
$this->_conn->addColumn("users", "wealth", 'decimal', array('precision' => 30, 'scale' => 10));
// do a manual insertion
$this->_conn->execute("INSERT INTO users (wealth) VALUES ('12345678901234567890.0123456789')");
// SELECT @todo - type cast attribute values
$user = (object)$this->_conn->selectOne('SELECT * FROM users');
// assert_kind_of BigDecimal, row.wealth
// If this assert fails, that means the SELECT is broken!
$this->assertEquals($correctValue, $user->wealth);
// Reset to old state
$this->_conn->delete('DELETE FROM users');
// Now use the Adapter insertion
$this->_conn->insert('INSERT INTO users (wealth) VALUES (12345678901234567890.0123456789)');
// SELECT @todo - type cast attribute values
$user = (object)$this->_conn->selectOne('SELECT * FROM users');
// assert_kind_of BigDecimal, row.wealth
// If these asserts fail, that means the INSERT (create function, or cast to SQL) is broken!
$this->assertEquals($correctValue, $user->wealth);
}
public function testNativeTypes()
{
$table = $this->_conn->createTable('users');
$table->column('company_id', 'integer', array('limit' => 11));
$table->column('name', 'string', array('limit' => 255, 'default' => ''));
$table->column('first_name', 'string', array('limit' => 40, 'default' => ''));
$table->column('approved', 'boolean', array('default' => true));
$table->column('type', 'string', array('limit' => 255, 'default' => ''));
$table->column('created_at', 'datetime', array('default' => '0000-00-00 00:00:00'));
$table->column('created_on', 'date', array('default' => '0000-00-00'));
$table->column('updated_at', 'datetime', array('default' => '0000-00-00 00:00:00'));
$table->column('updated_on', 'date', array('default' => '0000-00-00'));
$table->end();
$this->_conn->addColumn("users", "last_name", 'string');
$this->_conn->addColumn("users", "bio", 'text');
$this->_conn->addColumn("users", "age", 'integer');
$this->_conn->addColumn("users", "height", 'float');
$this->_conn->addColumn("users", "wealth", 'decimal', array('precision' => '30', 'scale' => '10'));
$this->_conn->addColumn("users", "birthday", 'datetime');
$this->_conn->addColumn("users", "favorite_day", 'date');
$this->_conn->addColumn("users", "moment_of_truth", 'datetime');
$this->_conn->addColumn("users", "male", 'boolean');
$this->_conn->insert('INSERT INTO users (first_name, last_name, bio, age, height, wealth, birthday, favorite_day, moment_of_truth, male, company_id) ' .
"VALUES ('bob', 'bobsen', 'I was born ....', 18, 1.78, 12345678901234567890.0123456789, '2005-01-01 12:23:40', '1980-03-05', '1582-10-10 21:40:18', 1, 1)");
$bob = (object)$this->_conn->selectOne('SELECT * FROM users');
$this->assertEquals('bob', $bob->first_name);
$this->assertEquals('bobsen', $bob->last_name);
$this->assertEquals('I was born ....', $bob->bio);
$this->assertEquals(18, $bob->age);
// Test for 30 significent digits (beyond the 16 of float), 10 of them
// after the decimal place.
$this->assertEquals('12345678901234567890.0123456789', $bob->wealth);
$this->assertEquals(1, $bob->male);
// @todo - type casting
}
public function testNativeDatabaseTypes()
{
$types = $this->_conn->nativeDatabaseTypes();
$this->assertEquals(array('name' => 'int', 'limit' => 11), $types['integer']);
}
public function testUnabstractedDatabaseDependentTypes()
{
$this->_createTestUsersTable();
$this->_conn->delete('DELETE FROM users');
$this->_conn->addColumn('users', 'intelligence_quotient', 'tinyint');
$this->_conn->insert('INSERT INTO users (intelligence_quotient) VALUES (300)');
$jonnyg = (object)$this->_conn->selectOne('SELECT * FROM users');
$this->assertEquals('127', $jonnyg->intelligence_quotient);
}
public function testTableAliasLength()
{
$len = $this->_conn->tableAliasLength();
$this->assertEquals(255, $len);
}
public function testTableAliasFor()
{
$alias = $this->_conn->tableAliasFor('my_table_name');
$this->assertEquals('my_table_name', $alias);
}
public function testTables()
{
$tables = $this->_conn->tables();
$this->assertTrue(count($tables) > 0);
$this->assertContains('unit_tests', $tables);
}
public function testPrimaryKey()
{
$pk = $this->_conn->primaryKey('unit_tests');
$this->assertEquals('id', (string)$pk);
$this->assertEquals(1, count($pk->columns));
$this->assertEquals('id', $pk->columns[0]);
$table = $this->_conn->createTable('pk_tests', array('autoincrementKey' => false));
$table->column('foo', 'string');
$table->column('bar', 'string');
$table->end();
$pk = $this->_conn->primaryKey('pk_tests');
$this->assertEmpty((string)$pk);
$this->assertEquals(0, count($pk->columns));
$this->_conn->addPrimaryKey('pk_tests', 'foo');
$pk = $this->_conn->primaryKey('pk_tests');
$this->assertEquals('foo', (string)$pk);
$this->assertEquals(1, count($pk->columns));
$this->_conn->removePrimaryKey('pk_tests');
$pk = $this->_conn->primaryKey('pk_tests');
$this->assertEmpty((string)$pk);
$this->assertEquals(0, count($pk->columns));
$this->_conn->addPrimaryKey('pk_tests', array('foo', 'bar'));
$pk = $this->_conn->primaryKey('pk_tests');
$this->assertEquals('foo,bar', (string)$pk);
}
public function testIndexes()
{
$indexes = $this->_conn->indexes('unit_tests');
$this->assertEquals(3, count($indexes));
// unique index
$col = array('integer_value');
$this->assertEquals('unit_tests', $indexes[0]->table);
$this->assertEquals('integer_value', $indexes[0]->name);
$this->assertEquals(true, $indexes[0]->unique);
$this->assertEquals($col, $indexes[0]->columns);
// normal index
$col = array('string_value');
$this->assertEquals('unit_tests', $indexes[1]->table);
$this->assertEquals('string_value', $indexes[1]->name);
$this->assertEquals(false, $indexes[1]->unique);
$this->assertEquals($col, $indexes[1]->columns);
// multi-column index
$col = array('integer_value', 'string_value');
$this->assertEquals('unit_tests', $indexes[2]->table);
$this->assertEquals('integer_string', $indexes[2]->name);
$this->assertEquals(false, $indexes[2]->unique);
$this->assertEquals($col, $indexes[2]->columns);
}
public function testColumns()
{
$columns = $this->_conn->columns('unit_tests');
$this->assertEquals(12, count($columns));
$col = $columns['id'];
$this->assertEquals('id', $col->getName());
$this->assertEquals('integer', $col->getType());
$this->assertEquals(false, $col->isNull());
$this->assertEquals(10, $col->getLimit());
$this->assertEquals(true, $col->isUnsigned());
$this->assertEquals('', $col->getDefault());
$this->assertEquals('int(10) unsigned', $col->getSqlType());
$this->assertEquals(false, $col->isText());
$this->assertEquals(true, $col->isNumber());
}
public function testCreateTable()
{
$this->_createTestTable('sports');
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
}
public function testCreateTableNoPk()
{
$this->_createTestTable('sports', array('autoincrementKey' => false));
try {
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertNull($this->_conn->selectValue($sql));
} catch (Exception $e) {
return;
}
$this->fail("Expected exception for no pk");
}
public function testCreateTableWithNamedPk()
{
$this->_createTestTable('sports', array('autoincrementKey' => 'sports_id'));
$sql = "SELECT sports_id FROM sports WHERE sports_id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
try {
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertNull($this->_conn->selectValue($sql));
} catch (Exception $e) {
return;
}
$this->fail("Expected exception for wrong pk name");
}
public function testCreateTableWithSeparatePk()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'autoincrementKey');
$pkColumn = $table['foo'];
$this->assertEquals('`foo` int(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY', $pkColumn->toSql());
}
public function testCreateTableCompositePk()
{
$table = $this->_conn->createTable('testings', array('autoincrementKey' => array('a_id', 'b_id')));
$table->column('a_id', 'integer');
$table->column('b_id', 'integer');
$table->end();
$pk = $this->_conn->primaryKey('testings');
$this->assertEquals(array('a_id', 'b_id'), $pk->columns);
}
public function testCreateTableForce()
{
$this->_createTestTable('sports');
$this->_createTestTable('sports', array('force' => true));
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
}
public function testCreateTableTemporary()
{
$this->_createTestTable('sports', array('temporary' => true));
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
}
public function testCreateTableAddsId()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string');
$table->end();
$columns = array();
foreach ($this->_conn->columns('testings') as $col) {
$columns[] = $col->getName();
}
sort($columns);
$this->assertEquals(array('foo', 'id'), $columns);
}
public function testCreateTableWithNotNullColumn()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string', array('null' => false));
$table->end();
try {
$this->_conn->execute("INSERT INTO testings (foo) VALUES (NULL)");
} catch (Exception $e) { return; }
$this->fail('Expected exception wasn\'t raised');
}
public function testCreateTableWithDefaults()
{
$table = $this->_conn->createTable('testings');
$table->column('one', 'string', array('default' => 'hello'));
$table->column('two', 'boolean', array('default' => true));
$table->column('three', 'boolean', array('default' => false));
$table->column('four', 'integer', array('default' => 1));
$table->end();
$columns = array();
foreach ($this->_conn->columns('testings') as $col) {
$columns[$col->getName()] = $col;
}
$this->assertEquals('hello', $columns['one']->getDefault());
$this->assertTrue($columns['two']->getDefault());
$this->assertFalse($columns['three']->getDefault());
$this->assertEquals(1, $columns['four']->getDefault());
}
public function testCreateTableWithLimits()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string', array('limit' => 80));
$table->end();
$columns = array();
foreach ($this->_conn->columns('testings') as $col) {
$columns[$col->getName()] = $col;
}
$this->assertEquals(80, $columns['foo']->getLimit());
}
public function testCreateTableWithBinaryColumn()
{
try {
$table = $this->_conn->createTable('binary_testings');
$table->column('data', 'binary', array('null' => false));
$table->end();
} catch (Exception $e) { $this->fail('Unexepected exception raised'); }
$columns = $this->_conn->columns('binary_testings');
foreach ($columns as $c) {
if ($c->getName() == 'data') { $dataColumn = $c; }
}
$this->assertEquals('', $dataColumn->getDefault());
}
public function testRenameTable()
{
// Simple rename then select test
$this->_createTestTable('sports');
$this->_conn->renameTable('sports', 'my_sports');
$sql = "SELECT id FROM my_sports WHERE id = 1";
$this->assertEquals("1", $this->_conn->selectValue($sql));
// Make sure the old table name isn't still there
try {
$sql = "SELECT id FROM sports WHERE id = 1";
$this->_conn->execute($sql);
} catch (Exception $e) {
return;
}
$this->fail("Table exists where it shouldn't have");
// Rename then insert test
$table = $this->_conn->createTable('octopuses');
$table->column('url', 'string');
$table->end();
$this->_conn->renameTable('octopuses', 'octopi');
$sql = "INSERT INTO octopi (id, url) VALUES (1, 'http://www.foreverflying.com/octopus-black7.jpg')";
$this->_conn->execute($sql);
$this->assertEquals('http://www.foreverflying.com/octopus-black7.jpg',
$this->_conn->selectValue("SELECT url FROM octopi WHERE id=1"));
// Make sure the old table name isn't still there
try {
$sql = "SELECT id FROM octopuses WHERE id = 1";
$this->_conn->execute($sql);
} catch (Exception $e) {
return;
}
$this->fail("Table exists where it shouldn't have");
}
public function testRenameTableWithAnIndex()
{
$table = $this->_conn->createTable('octopuses');
$table->column('url', 'string');
$table->end();
$this->_conn->addIndex('octopuses', 'url');
$this->_conn->renameTable('octopuses', 'octopi');
$sql = "INSERT INTO octopi (id, url) VALUES (1, 'http://www.foreverflying.com/octopus-black7.jpg')";
$this->_conn->execute($sql);
$this->assertEquals('http://www.foreverflying.com/octopus-black7.jpg',
$this->_conn->selectValue("SELECT url FROM octopi WHERE id=1"));
$indexes = $this->_conn->indexes('octopi');
$this->assertEquals('url', $indexes[0]->columns[0]);
}
public function testDropTable()
{
$this->_createTestTable('sports');
$this->_conn->dropTable('sports');
try {
$sql = "SELECT id FROM sports WHERE id = 1";
$this->_conn->execute($sql);
} catch (Exception $e) {
return;
}
$this->fail("Table exists where it shouldn't have");
}
public function testAddColumn()
{
$this->_createTestTable('sports');
$this->_conn->addColumn('sports', 'modified_at', 'date');
$this->_conn->update("UPDATE sports SET modified_at = '2007-01-01'");
$sql = "SELECT modified_at FROM sports WHERE id = 1";
$this->assertEquals("2007-01-01", $this->_conn->selectValue($sql));
$this->_conn->addColumn('sports', 'with_default', 'integer', array('default' => 1));
$sql = "SELECT with_default FROM sports WHERE id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
}
public function testRemoveColumn()
{
$this->_createTestTable('sports');
$sql = "SELECT name FROM sports WHERE id = 1";
$this->assertEquals("mlb", $this->_conn->selectValue($sql));
$this->_conn->removeColumn('sports', 'name');
try {
$sql = "SELECT name FROM sports WHERE id = 1";
$this->_conn->execute($sql);
} catch (Exception $e) {
return;
}
$this->fail("Column exists where it shouldn't have");
}
public function testChangeColumn()
{
$this->_createTestUsersTable();
$this->_conn->addColumn('users', 'age', 'integer');
$oldColumns = $this->_conn->columns('users', "User Columns");
$found = false;
foreach ($oldColumns as $c) {
if ($c->getName() == 'age' && $c->getType() == 'integer') { $found = true; }
}
$this->assertTrue($found);
$this->_conn->changeColumn('users', 'age', 'string');
$newColumns = $this->_conn->columns('users', "User Columns");
$found = false;
foreach ($newColumns as $c) {
if ($c->getName() == 'age' && $c->getType() == 'integer') { $found = true; }
}
$this->assertFalse($found);
$found = false;
foreach ($newColumns as $c) {
if ($c->getName() == 'age' && $c->getType() == 'string') { $found = true; }
}
$this->assertTrue($found);
$found = false;
foreach ($oldColumns as $c) {
if ($c->getName() == 'approved' && $c->getType() == 'boolean' &&
$c->getDefault() == true) { $found = true; }
}
$this->assertTrue($found);
// changeColumn() throws exception on error
$this->_conn->changeColumn('users', 'approved', 'boolean', array('default' => false));
$newColumns = $this->_conn->columns('users', "User Columns");
$found = false;
foreach ($newColumns as $c) {
if ($c->getName() == 'approved' && $c->getType() == 'boolean' &&
$c->getDefault() == true) { $found = true; }
}
$this->assertFalse($found);
$found = false;
foreach ($newColumns as $c) {
if ($c->getName() == 'approved' && $c->getType() == 'boolean' &&
$c->getDefault() == false) { $found = true; }
}
$this->assertTrue($found);
// changeColumn() throws exception on error
$this->_conn->changeColumn('users', 'approved', 'boolean', array('default' => true));
}
public function testChangeColumnDefault()
{
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'name');
$this->assertEquals('', $beforeChange->getDefault());
$this->_conn->changeColumnDefault('sports', 'name', 'test');
$afterChange = $this->_getColumn('sports', 'name');
$this->assertEquals('test', $afterChange->getDefault());
}
public function testChangeColumnType()
{
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('tinyint(1)', $beforeChange->getSqlType());
$this->_conn->changeColumn('sports', 'is_college', 'string');
$afterChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('varchar(255)', $afterChange->getSqlType());
$table = $this->_conn->createTable('text_to_binary');
$table->column('data', 'text');
$table->end();
$this->_conn->insert('INSERT INTO text_to_binary (data) VALUES (?)',
array("foo\0bar"));
$this->_conn->changeColumn('text_to_binary', 'data', 'binary');
$afterChange = $this->_getColumn('text_to_binary', 'data');
$this->assertEquals('longblob', $afterChange->getSqlType());
$this->assertEquals(
"foo\0bar",
$this->_conn->selectValue('SELECT data FROM text_to_binary'));
}
public function testChangeColumnLimit()
{
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('tinyint(1)', $beforeChange->getSqlType());
$this->_conn->changeColumn('sports', 'is_college', 'string',
array('limit' => '40'));
$afterChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('varchar(40)', $afterChange->getSqlType());
}
public function testChangeColumnPrecisionScale()
{
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('tinyint(1)', $beforeChange->getSqlType());
$this->_conn->changeColumn('sports', 'is_college', 'decimal',
array('precision' => '5', 'scale' => '2'));
$afterChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('decimal(5,2)', $afterChange->getSqlType());
}
public function testChangeColumnUnsigned()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'integer');
$table->end();
$beforeChange = $this->_getColumn('testings', 'foo');
$this->assertFalse($beforeChange->isUnsigned());
$this->_conn->execute("INSERT INTO testings (id, foo) VALUES (1, -1)");
$this->_conn->changeColumn('testings', 'foo', 'integer', array('unsigned' => true));
$afterChange = $this->_getColumn('testings', 'foo');
$this->assertTrue($afterChange->isUnsigned());
$row = (object)$this->_conn->selectOne('SELECT * FROM testings');
$this->assertEquals(0, $row->foo);
}
public function testRenameColumn()
{
$this->_createTestUsersTable();
$this->_conn->renameColumn('users', 'first_name', 'nick_name');
$this->assertTrue(in_array('nick_name', $this->_columnNames('users')));
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('tinyint(1)', $beforeChange->getSqlType());
$this->_conn->renameColumn('sports', 'is_college', 'is_renamed');
$afterChange = $this->_getColumn('sports', 'is_renamed');
$this->assertEquals('tinyint(1)', $afterChange->getSqlType());
}
public function testRenameColumnWithSqlReservedWord()
{
$this->_createTestUsersTable();
$this->_conn->renameColumn('users', 'first_name', 'group');
$this->assertTrue(in_array('group', $this->_columnNames('users')));
}
public function testAddIndex()
{
$this->_createTestUsersTable();
// Limit size of last_name and key columns to support Firebird index limitations
$this->_conn->addColumn('users', 'last_name', 'string', array('limit' => 100));
$this->_conn->addColumn('users', 'key', 'string', array('limit' => 100));
$this->_conn->addColumn('users', 'administrator', 'boolean');
$this->_conn->addIndex('users', 'last_name');
$this->_conn->removeIndex('users', 'last_name');
$this->_conn->addIndex('users', array('last_name', 'first_name'));
$this->_conn->removeIndex('users', array('column' => array('last_name', 'first_name')));
$this->_conn->addIndex('users', array('last_name', 'first_name'));
$this->_conn->removeIndex('users', array('name' => 'index_users_on_last_name_and_first_name'));
$this->_conn->addIndex('users', array('last_name', 'first_name'));
$this->_conn->removeIndex('users', 'last_name_and_first_name');
// quoting
$this->_conn->addIndex('users', array('key'), array('name' => 'key_idx', 'unique' => true));
$this->_conn->removeIndex('users', array('name' => 'key_idx', 'unique' => true));
$this->_conn->addIndex('users', array('last_name', 'first_name', 'administrator'),
array('name' => "named_admin"));
$this->_conn->removeIndex('users', array('name' => 'named_admin'));
}
public function testAddIndexDefault()
{
$this->_createTestTable('sports');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
$this->_conn->addIndex('sports', 'is_college');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
}
public function testAddIndexMultiColumn()
{
$this->_createTestTable('sports');
$index = $this->_getIndex('sports', array('name', 'is_college'));
$this->assertNull($index);
$this->_conn->addIndex('sports', array('name', 'is_college'));
$index = $this->_getIndex('sports', array('name', 'is_college'));
$this->assertNotNull($index);
}
public function testAddIndexUnique()
{
$this->_createTestTable('sports');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
$this->_conn->addIndex('sports', 'is_college', array('unique' => true));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
$this->assertTrue($index->unique);
}
public function testAddIndexName()
{
$this->_createTestTable('sports');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
$this->_conn->addIndex('sports', 'is_college', array('name' => 'test'));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
$this->assertEquals('test', $index->name);
}
public function testRemoveIndexSingleColumn()
{
$this->_createTestTable('sports');
// add the index
$this->_conn->addIndex('sports', 'is_college');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
// remove it again
$this->_conn->removeIndex('sports', array('column' => 'is_college'));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
}
public function testRemoveIndexMultiColumn()
{
$this->_createTestTable('sports');
// add the index
$this->_conn->addIndex('sports', array('name', 'is_college'));
$index = $this->_getIndex('sports', array('name', 'is_college'));
$this->assertNotNull($index);
// remove it again
$this->_conn->removeIndex('sports', array('column' => array('name', 'is_college')));
$index = $this->_getIndex('sports', array('name', 'is_college'));
$this->assertNull($index);
}
public function testRemoveIndexByName()
{
$this->_createTestTable('sports');
// add the index
$this->_conn->addIndex('sports', 'is_college', array('name' => 'test'));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
// remove it again
$this->_conn->removeIndex('sports', array('name' => 'test'));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
}
public function testIndexNameInvalid()
{
try {
$name = $this->_conn->indexName('sports');
} catch (Horde_Db_Exception $e) {
return;
}
$this->fail("Adding an index with crappy options worked where it shouldn't have");
}
public function testIndexNameBySingleColumn()
{
$name = $this->_conn->indexName('sports', array('column' => 'is_college'));
$this->assertEquals('index_sports_on_is_college', $name);
}
public function testIndexNameByMultiColumn()
{
$name = $this->_conn->indexName('sports', array('column' =>
array('name', 'is_college')));
$this->assertEquals('index_sports_on_name_and_is_college', $name);
}
public function testIndexNameByName()
{
$name = $this->_conn->indexName('sports', array('name' => 'test'));
$this->assertEquals('test', $name);
}
public function testTypeToSqlTypePrimaryKey()
{
$result = $this->_conn->typeToSql('autoincrementKey');
$this->assertEquals('int(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY', $result);
}
public function testTypeToSqlTypeString()
{
$result = $this->_conn->typeToSql('string');
$this->assertEquals('varchar(255)', $result);
}
public function testTypeToSqlTypeText()
{
$result = $this->_conn->typeToSql('text');
$this->assertEquals('text', $result);
}
public function testTypeToSqlTypeBinary()
{
$result = $this->_conn->typeToSql('binary');
$this->assertEquals('longblob', $result);
}
public function testTypeToSqlTypeFloat()
{
$result = $this->_conn->typeToSql('float');
$this->assertEquals('float', $result);
}
public function testTypeToSqlTypeDatetime()
{
$result = $this->_conn->typeToSql('datetime');
$this->assertEquals('datetime', $result);
}
public function testTypeToSqlTypeTimestamp()
{
$result = $this->_conn->typeToSql('timestamp');
$this->assertEquals('datetime', $result);
}
public function testTypeToSqlInt()
{
$result = $this->_conn->typeToSql('integer');
$this->assertEquals('int(11)', $result);
}
public function testTypeToSqlIntUnsigned()
{
$result = $this->_conn->typeToSql('integer', null, null, null, true);
$this->assertEquals('int(10) UNSIGNED', $result);
}
public function testTypeToSqlIntLimit()
{
$result = $this->_conn->typeToSql('integer', '1');
$this->assertEquals('int(1)', $result);
}
public function testTypeToSqlDecimalPrecision()
{
$result = $this->_conn->typeToSql('decimal', null, '5');
$this->assertEquals('decimal(5)', $result);
}
public function testTypeToSqlDecimalScale()
{
$result = $this->_conn->typeToSql('decimal', null, '5', '2');
$this->assertEquals('decimal(5, 2)', $result);
}
public function testTypeToSqlBoolean()
{
$result = $this->_conn->typeToSql('boolean');
$this->assertEquals('tinyint(1)', $result);
}
public function testAddColumnOptions()
{
$result = $this->_conn->addColumnOptions("test", array());
$this->assertEquals("test", $result);
}
public function testAddColumnOptionsDefault()
{
$options = array('default' => '0');
$result = $this->_conn->addColumnOptions("test", $options);
$this->assertEquals("test DEFAULT '0'", $result);
}
public function testAddColumnOptionsNull()
{
$options = array('null' => true);
$result = $this->_conn->addColumnOptions("test", $options);
$this->assertEquals("test", $result);
}
public function testAddColumnOptionsNotNull()
{
$options = array('null' => false);
$result = $this->_conn->addColumnOptions("test", $options);
$this->assertEquals("test NOT NULL", $result);
}
public function testAddColumnNotNullWithoutDefault()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string');
$table->end();
$this->_conn->addColumn('testings', 'bar', 'string', array('null' => false, 'default' => ''));
try {
$this->_conn->execute("INSERT INTO testings (foo, bar) VALUES ('hello', NULL)");
} catch (Exception $e) { return; }
$this->fail('Expected exception wasn\'t raised');
}
public function testAddColumnNotNullWithDefault()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string');
$table->end();
$this->_conn->execute("INSERT INTO testings (id, foo) VALUES ('1', 'hello')");
$this->_conn->addColumn('testings', 'bar', 'string', array('null' => false, 'default' => 'default'));
try {
$this->_conn->execute("INSERT INTO testings (id, foo, bar) VALUES (2, 'hello', NULL)");
} catch (Exception $e) { return; }
$this->fail('Expected exception wasn\'t raised');
}
public function testAddRemoveSingleField()
{
$this->_createTestUsersTable();
$this->assertFalse(in_array('last_name', $this->_columnNames('users')));
$this->_conn->addColumn('users', 'last_name', 'string');
$this->assertTrue(in_array('last_name', $this->_columnNames('users')));
$this->_conn->removeColumn('users', 'last_name');
$this->assertFalse(in_array('last_name', $this->_columnNames('users')));
}
public function testAddRename()
{
$this->_createTestUsersTable();
$this->_conn->delete('DELETE FROM users');
$this->_conn->addColumn('users', 'girlfriend', 'string');
$this->_conn->insert("INSERT INTO users (girlfriend) VALUES ('bobette')");
$this->_conn->renameColumn('users', 'girlfriend', 'exgirlfriend');
$bob = (object)$this->_conn->selectOne('SELECT * FROM users');
$this->assertEquals('bobette', $bob->exgirlfriend);
}
public function testDistinct()
{
$result = $this->_conn->distinct("test");
$this->assertEquals("DISTINCT test", $result);
}
public function testAddOrderByForAssocLimiting()
{
$result = $this->_conn->addOrderByForAssocLimiting("SELECT * FROM documents ",
array('order' => 'name DESC'));
$this->assertEquals("SELECT * FROM documents ORDER BY name DESC", $result);
}
public function testInterval()
{
$this->assertEquals('INTERVAL 1 DAY',
$this->_conn->interval('1 DAY', ''));
}
public function testModifyDate()
{
$modifiedDate = $this->_conn->modifyDate('start', '+', 1, 'DAY');
$this->assertEquals('start + INTERVAL \'1\' DAY', $modifiedDate);
$t = $this->_conn->createTable('dates');
$t->column('start', 'datetime');
$t->column('end', 'datetime');
$t->end();
$this->_conn->insert(
'INSERT INTO dates (start, end) VALUES (?, ?)',
array(
'2011-12-10 00:00:00',
'2011-12-11 00:00:00'
)
);
$this->assertEquals(
1,
$this->_conn->selectValue('SELECT COUNT(*) FROM dates WHERE '
. $modifiedDate . ' = end')
);
}
public function testBuildClause()
{
$this->assertEquals(
'bitmap & 2',
$this->_conn->buildClause('bitmap', '&', 2));
$this->assertEquals(
array('bitmap & ?', array(2)),
$this->_conn->buildClause('bitmap', '&', 2, true));
$this->assertEquals(
'bitmap | 2',
$this->_conn->buildClause('bitmap', '|', 2));
$this->assertEquals(
array('bitmap | ?', array(2)),
$this->_conn->buildClause('bitmap', '|', 2, true));
$this->assertEquals(
"LOWER(name) LIKE LOWER('%search%')",
$this->_conn->buildClause('name', 'LIKE', "search"));
$this->assertEquals(
array("LOWER(name) LIKE LOWER(?)", array('%search%')),
$this->_conn->buildClause('name', 'LIKE', "search", true));
$this->assertEquals(
"LOWER(name) LIKE LOWER('%search\&replace\?%')",
$this->_conn->buildClause('name', 'LIKE', "search&replace?"));
$this->assertEquals(
array("LOWER(name) LIKE LOWER(?)", array('%search&replace?%')),
$this->_conn->buildClause('name', 'LIKE', "search&replace?", true));
$this->assertEquals(
"(LOWER(name) LIKE LOWER('search\&replace\?%') OR LOWER(name) LIKE LOWER('% search\&replace\?%'))",
$this->_conn->buildClause('name', 'LIKE', "search&replace?", false, array('begin' => true)));
$this->assertEquals(
array("(LOWER(name) LIKE LOWER(?) OR LOWER(name) LIKE LOWER(?))",
array('search&replace?%', '% search&replace?%')),
$this->_conn->buildClause('name', 'LIKE', "search&replace?", true, array('begin' => true)));
$this->assertEquals(
'value = 2',
$this->_conn->buildClause('value', '=', 2));
$this->assertEquals(
array('value = ?', array(2)),
$this->_conn->buildClause('value', '=', 2, true));
$this->assertEquals(
"value = 'foo'",
$this->_conn->buildClause('value', '=', 'foo'));
$this->assertEquals(
array('value = ?', array('foo')),
$this->_conn->buildClause('value', '=', 'foo', true));
$this->assertEquals(
"value = 'foo\?bar'",
$this->_conn->buildClause('value', '=', 'foo?bar'));
$this->assertEquals(
array('value = ?', array('foo?bar')),
$this->_conn->buildClause('value', '=', 'foo?bar', true));
}
public function testInsertAndReadInCp1257()
{
list($conn,) = self::getConnection(array('charset' => 'cp1257'));
$table = $conn->createTable('charset_cp1257');
$table->column('text', 'string');
$table->end();
$input = file_get_contents(__DIR__ . '/../../fixtures/charsets/cp1257.txt');
$conn->insert("INSERT INTO charset_cp1257 (text) VALUES (?)", array($input));
$output = $conn->selectValue('SELECT text FROM charset_cp1257');
$this->assertEquals($input, $output);
}
public function testInsertAndReadInUtf8()
{
list($conn,) = self::getConnection(array('charset' => 'utf8'));
$table = $conn->createTable('charset_utf8');
$table->column('text', 'string');
$table->end();
$input = file_get_contents(__DIR__ . '/../../fixtures/charsets/utf8.txt');
$conn->insert("INSERT INTO charset_utf8 (text) VALUES (?)", array($input));
$output = $conn->selectValue('SELECT text FROM charset_utf8');
$this->assertEquals($input, $output);
}
/*##########################################################################
# Table cache
##########################################################################*/
public function testCachedTableIndexes()
{
// remove any current cache.
$this->_cache->set('tables/indexes/cache_table', '');
$this->assertEquals('', $this->_cache->get('tables/indexes/cache_table', 0));
$this->_createTestTable('cache_table');
$idxs = $this->_conn->indexes('cache_table');
$this->assertNotEquals('', $this->_cache->get('tables/indexes/cache_table', 0));
}
public function testCachedTableColumns()
{
// remove any current cache.
$this->_cache->set('tables/columns/cache_table', '');
$this->assertEquals('', $this->_cache->get('tables/columns/cache_table', 0));
$this->_createTestTable('cache_table');
$cols = $this->_conn->columns('cache_table');
$this->assertNotEquals('', $this->_cache->get('tables/columns/cache_table', 0));
}
/*##########################################################################
# Protected
##########################################################################*/
/**
* Create table to perform tests on
*/
protected function _createTestTable($name, $options=array())
{
$table = $this->_conn->createTable($name, $options);
$table->column('name', 'string');
$table->column('is_college', 'boolean');
$table->end();
try {
// make sure table was created
$sql = "INSERT INTO $name
VALUES (1, 'mlb', 0)";
$this->_conn->insert($sql);
} catch (Exception $e) {}
}
protected function _createTestUsersTable()
{
$table = $this->_conn->createTable('users');
$table->column('company_id', 'integer', array('limit' => 11));
$table->column('name', 'string', array('limit' => 255, 'default' => ''));
$table->column('first_name', 'string', array('limit' => 40, 'default' => ''));
$table->column('approved', 'boolean', array('default' => true));
$table->column('type', 'string', array('limit' => 255, 'default' => ''));
$table->column('created_at', 'datetime', array('default' => '0000-00-00 00:00:00'));
$table->column('created_on', 'date', array('default' => '0000-00-00'));
$table->column('updated_at', 'datetime', array('default' => '0000-00-00 00:00:00'));
$table->column('updated_on', 'date', array('default' => '0000-00-00'));
$table->end();
}
/**
* drop test tables
*/
protected function _dropTestTables()
{
$tables = array(
'binary_testings',
'cache_table',
'charset_cp1257',
'charset_utf8',
'dates',
'my_sports',
'octopi',
'pk_tests',
'schema_info',
'sports',
'testings',
'text_to_binary',
'unit_tests',
'users',
);
foreach ($tables as $table) {
try {
$this->_conn->dropTable($table);
} catch (Exception $e) {}
}
}
protected function _columnNames($tableName)
{
$columns = array();
foreach ($this->_conn->columns($tableName) as $c) {
$columns[] = $c->getName();
}
return $columns;
}
/**
* Get a column by name
*/
protected function _getColumn($table, $column)
{
foreach ($this->_conn->columns($table) as $col) {
if ($col->getName() == $column) return $col;
}
}
/**
* Get an index by columns
*/
protected function _getIndex($table, $indexes)
{
$indexes = (array) $indexes;
sort($indexes);
foreach ($this->_conn->indexes($table) as $index) {
$columns = $index->columns;
sort($columns);
if ($columns == $indexes) return $index;
}
}
public function testColumnConstruct()
{
self::$columnTest->testConstruct();
}
public function testColumnToSql()
{
self::$columnTest->testToSql();
}
public function testColumnToSqlLimit()
{
self::$columnTest->testToSqlLimit();
}
public function testColumnToSqlPrecisionScale()
{
self::$columnTest->testToSqlPrecisionScale();
}
public function testColumnToSqlUnsigned()
{
self::$columnTest->testToSqlUnsigned();
}
public function testColumnToSqlNotNull()
{
self::$columnTest->testToSqlNotNull();
}
public function testColumnToSqlDefault()
{
self::$columnTest->testToSqlDefault();
}
public function testTableConstruct()
{
self::$tableTest->testConstruct();
}
public function testTableName()
{
self::$tableTest->testName();
}
public function testTableGetOptions()
{
self::$tableTest->testGetOptions();
}
public function testTablePrimaryKey()
{
self::$tableTest->testPrimaryKey();
}
public function testTableColumn()
{
self::$tableTest->testColumn();
}
public function testTableToSql()
{
self::$tableTest->testToSql();
}
}
Horde_Db-2.0.4/test/Horde/Db/Adapter/Pdo/PgsqlBase.php 0000664 0001750 0001750 00000004342 12205351473 020335 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage UnitTests
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @group horde_db
* @category Horde
* @package Db
* @subpackage UnitTests
*/
class Horde_Db_Adapter_Pdo_PgsqlBase extends Horde_Test_Case
{
protected static $skip = true;
protected static $reason = 'The PDO_PostgreSQL adapter is not available';
protected static $conn;
public static function setUpBeforeClass()
{
if (extension_loaded('pdo') &&
in_array('pgsql', PDO::getAvailableDrivers())) {
self::$skip = false;
self::$conn = self::getConnection();
}
}
public static function getConnection()
{
if (!is_null(self::$conn)) {
return self::$conn;
}
$config = Horde_Test_Case::getConfig('DB_ADAPTER_PDO_PGSQL_TEST_CONFIG',
null,
array('username' => '',
'password' => '',
'dbname' => 'test'));
if (isset($config['db']['adapter']['pdo']['pgsql']['test'])) {
$config = $config['db']['adapter']['pdo']['pgsql']['test'];
}
if (!is_array($config)) {
self::$skip = true;
self::$reason = 'No configuration for pdo_pgsql test';
return;
}
$conn = new Horde_Db_Adapter_Pdo_Pgsql($config);
$cache = new Horde_Cache(new Horde_Cache_Storage_Mock());
$conn->setCache($cache);
return array($conn, $cache);
}
protected function setUp()
{
if (self::$skip) {
$this->markTestSkipped(self::$reason);
}
}
}
Horde_Db-2.0.4/test/Horde/Db/Adapter/Pdo/PgsqlTest.php 0000664 0001750 0001750 00000140535 12205351473 020407 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage UnitTests
*/
require_once __DIR__ . '/PgsqlBase.php';
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @group horde_db
* @category Horde
* @package Db
* @subpackage UnitTests
*/
class Horde_Db_Adapter_Pdo_PgsqlTest extends Horde_Db_Adapter_Pdo_PgsqlBase
{
protected function setUp()
{
parent::setUp();
list($this->_conn, $this->_cache) = self::getConnection();
// clear out detritus from any previous test runs.
$this->_dropTestTables();
$table = $this->_conn->createTable('unit_tests');
$table->column('integer_value', 'integer', array('limit' => 11, 'default' => 0));
$table->column('string_value', 'string', array('limit' => 255, 'default' => ''));
$table->column('text_value', 'text', array('null' => false, 'default' => ''));
$table->column('float_value', 'float', array('precision' => 2, 'scale' => 1, 'default' => 0.0));
$table->column('decimal_value', 'decimal', array('precision' => 2, 'scale' => 1, 'default' => 0.0));
$table->column('datetime_value', 'datetime', array());
$table->column('date_value', 'date', array());
$table->column('time_value', 'time', array('default' => '00:00:00'));
$table->column('blob_value', 'binary', array('null' => false, 'default' => ''));
$table->column('boolean_value', 'boolean', array('default' => false));
$table->column('email_value', 'string', array('limit' => 255, 'default' => ''));
$table->end();
$this->_conn->addIndex('unit_tests', 'string_value', array('name' => 'string_value'));
$this->_conn->addIndex('unit_tests', 'integer_value', array('name' => 'integer_value', 'unique' => true));
$this->_conn->addIndex('unit_tests', array('integer_value', 'string_value'), array('name' => 'integer_string'));
// read sql file for statements
$statements = array();
$current_stmt = '';
$fp = fopen(__DIR__ . '/../../fixtures/unit_tests.sql', 'r');
while ($line = fgets($fp, 8192)) {
$line = rtrim(preg_replace('/^(.*)--.*$/s', '\1', $line));
if (!$line) {
continue;
}
$current_stmt .= $line;
if (substr($line, -1) == ';') {
// leave off the ending ;
$statements[] = substr($current_stmt, 0, -1);
$current_stmt = '';
}
}
// run statements
foreach ($statements as $stmt) {
$this->_conn->execute($stmt);
}
}
protected function tearDown()
{
// clean up
$this->_dropTestTables();
}
/*##########################################################################
# Connection
##########################################################################*/
public function testConnect()
{
$this->assertTrue($this->_conn->isActive());
}
public function testDisconnect()
{
$this->_conn->disconnect();
$this->assertFalse($this->_conn->isActive());
$this->_conn->connect();
$this->assertTrue($this->_conn->isActive());
}
public function testReconnect()
{
$this->_conn->reconnect();
$this->assertTrue($this->_conn->isActive());
}
/*##########################################################################
# Accessor
##########################################################################*/
public function testAdapterName()
{
$this->assertEquals('PDO_PostgreSQL', $this->_conn->adapterName());
}
public function testSupportsMigrations()
{
$this->assertTrue($this->_conn->supportsMigrations());
}
public function testSupportsCountDistinct()
{
$this->assertTrue($this->_conn->supportsCountDistinct());
}
/*##########################################################################
# Database Statements
##########################################################################*/
public function testExecute()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->execute($sql);
$row = $result->fetch();
$this->assertEquals(1, $row['id']);
}
public function testSelect()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->select($sql);
$this->assertInstanceOf('Traversable', $result);
$this->assertGreaterThan(0, count($result));
foreach ($result as $row) break;
$this->assertInternalType('array', $row);
$this->assertEquals(1, $row['id']);
}
public function testSelectWithBoundParameters()
{
$sql = "SELECT * FROM unit_tests WHERE id=?";
$result = $this->_conn->select($sql, array(1));
$this->assertInstanceOf('Traversable', $result);
$this->assertGreaterThan(0, count($result));
foreach ($result as $row) break;
$this->assertInternalType('array', $row);
$this->assertEquals(1, $row['id']);
}
public function testSelectWithBoundParametersQuotesString()
{
$sql = "SELECT * FROM unit_tests WHERE string_value=?";
$result = $this->_conn->select($sql, array('name a'));
$this->assertInstanceOf('Traversable', $result);
$this->assertGreaterThan(0, count($result));
foreach ($result as $row) break;
$this->assertInternalType('array', $row);
$this->assertEquals(1, $row['id']);
}
public function testSelectAll()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->selectAll($sql);
$this->assertInternalType('array', $result);
$this->assertGreaterThan(0, count($result));
$this->assertEquals(1, $result[0]['id']);
}
public function testSelectOne()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->selectOne($sql);
$this->assertEquals(1, $result['id']);
}
public function testSelectValue()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->selectValue($sql);
$this->assertEquals(1, $result);
}
public function testSelectValues()
{
$sql = "SELECT * FROM unit_tests";
$result = $this->_conn->selectValues($sql);
$this->assertEquals(array(1, 2, 3, 4, 5, 6), $result);
}
public function testInsert()
{
$sql = "INSERT INTO unit_tests (id, integer_value) VALUES (7, 999)";
$result = $this->_conn->insert($sql, null, null, null, 7);
$this->assertEquals(7, $result);
}
public function testUpdate()
{
$sql = "UPDATE unit_tests SET integer_value=999 WHERE id IN (1)";
$result = $this->_conn->update($sql);
$this->assertEquals(1, $result);
}
public function testDelete()
{
$sql = "DELETE FROM unit_tests WHERE id IN (1,2)";
$result = $this->_conn->delete($sql);
$this->assertEquals(2, $result);
}
public function testTransactionStarted()
{
$this->assertFalse($this->_conn->transactionStarted());
$this->_conn->beginDbTransaction();
$this->assertTrue($this->_conn->transactionStarted());
$this->_conn->commitDbTransaction();
$this->assertFalse($this->_conn->transactionStarted());
}
public function testTransactionCommit()
{
$this->_conn->beginDbTransaction();
$sql = "INSERT INTO unit_tests (id, integer_value) VALUES (7, 999)";
$this->_conn->insert($sql, null, null, 'id', 7);
$this->_conn->commitDbTransaction();
// make sure it inserted
$sql = "SELECT integer_value FROM unit_tests WHERE id='7'";
$this->assertEquals('999', $this->_conn->selectValue($sql));
}
public function testTransactionRollback()
{
$this->_conn->beginDbTransaction();
$sql = "INSERT INTO unit_tests (id, integer_value) VALUES (7, 999)";
$this->_conn->insert($sql, null, null, 'id', 7);
$this->_conn->rollbackDbTransaction();
// make sure it not inserted
$sql = "SELECT integer_value FROM unit_tests WHERE id='7'";
$this->assertEquals(null, $this->_conn->selectValue($sql));
}
/*##########################################################################
# Quoting
##########################################################################*/
public function testQuoteNull()
{
$this->assertEquals('NULL', $this->_conn->quote(null));
}
public function testQuoteTrue()
{
$this->assertEquals("'t'", $this->_conn->quote(true));
}
public function testQuoteFalse()
{
$this->assertEquals("'f'", $this->_conn->quote(false));
}
public function testQuoteInteger()
{
$this->assertEquals('42', $this->_conn->quote(42));
}
public function testQuoteFloat()
{
$this->assertEquals('42.2', $this->_conn->quote(42.2));
setlocale(LC_NUMERIC, 'de_DE.UTF-8');
$this->assertEquals('42.2', $this->_conn->quote(42.2));
}
public function testQuoteString()
{
$this->assertEquals("'my string'", $this->_conn->quote('my string'));
}
public function testQuoteDirtyString()
{
$this->assertEquals("'derek''s string'", $this->_conn->quote('derek\'s string'));
}
public function testQuoteColumnName()
{
$col = new Horde_Db_Adapter_Postgresql_Column('age', 'NULL', 'int(11)');
$this->assertEquals('1', $this->_conn->quote(true, $col));
}
public function testQuoteBinary()
{
// Test string is foo\0bar\baz'boo\'bee - should be 20 bytes long
$original = base64_decode('Zm9vAGJhclxiYXonYm9vXCdiZWU=');
$table = $this->_conn->createTable('binary_testings');
$table->column('data', 'binary', array('null' => false));
$table->end();
$this->_conn->insert('INSERT INTO binary_testings (data) VALUES (?)', array(new Horde_Db_Value_Binary($original)));
$retrieved = $this->_conn->selectValue('SELECT data FROM binary_testings');
$columns = $this->_conn->columns('binary_testings');
$retrieved = $columns['data']->binaryToString($retrieved);
$this->assertEquals($original, $retrieved);
}
/*##########################################################################
# Schema Statements
##########################################################################*/
public function testNativeDatabaseTypes()
{
$types = $this->_conn->nativeDatabaseTypes();
$this->assertEquals(array('name' => 'integer', 'limit' => null), $types['integer']);
}
public function testTableAliasLength()
{
$len = $this->_conn->tableAliasLength();
$this->assertGreaterThanOrEqual(63, $len);
}
public function testTableAliasFor()
{
$alias = $this->_conn->tableAliasFor('my_table_name');
$this->assertEquals('my_table_name', $alias);
}
public function testSchemaSearchPath()
{
$schemaSearchPath = $this->_conn->getSchemaSearchPath();
$this->assertGreaterThan(0, strlen($schemaSearchPath));
}
public function testTables()
{
$tables = $this->_conn->tables();
$this->assertTrue(count($tables) > 0);
$this->assertContains('unit_tests', $tables);
}
public function testPrimaryKey()
{
$pk = $this->_conn->primaryKey('unit_tests');
$this->assertEquals('id', (string)$pk);
$this->assertEquals(1, count($pk->columns));
$this->assertEquals('id', $pk->columns[0]);
$table = $this->_conn->createTable('pk_tests', array('autoincrementKey' => false));
$table->column('foo', 'string');
$table->column('bar', 'string');
$table->end();
$pk = $this->_conn->primaryKey('pk_tests');
$this->assertEmpty((string)$pk);
$this->assertEquals(0, count($pk->columns));
$this->_conn->addPrimaryKey('pk_tests', 'foo');
$pk = $this->_conn->primaryKey('pk_tests');
$this->assertEquals('foo', (string)$pk);
$this->assertEquals(1, count($pk->columns));
$this->_conn->removePrimaryKey('pk_tests');
$pk = $this->_conn->primaryKey('pk_tests');
$this->assertEmpty((string)$pk);
$this->assertEquals(0, count($pk->columns));
$this->_conn->addPrimaryKey('pk_tests', array('foo', 'bar'));
$pk = $this->_conn->primaryKey('pk_tests');
$this->assertEquals('foo,bar', (string)$pk);
}
public function testIndexes()
{
$indexes = $this->_conn->indexes('unit_tests');
$this->assertEquals(3, count($indexes));
// sort by name so we can predict the order of indexes
usort($indexes, create_function('$a, $b', 'return strcmp($a->name, $b->name);'));
// multi-column index
$col = array('integer_value', 'string_value');
$this->assertEquals('unit_tests', $indexes[0]->table);
$this->assertEquals('integer_string', $indexes[0]->name);
$this->assertEquals(false, $indexes[0]->unique);
$this->assertEquals($col, $indexes[0]->columns);
// unique index
$col = array('integer_value');
$this->assertEquals('unit_tests', $indexes[1]->table);
$this->assertEquals('integer_value', $indexes[1]->name);
$this->assertEquals(true, $indexes[1]->unique);
$this->assertEquals($col, $indexes[1]->columns);
// normal index
$col = array('string_value');
$this->assertEquals('unit_tests', $indexes[2]->table);
$this->assertEquals('string_value', $indexes[2]->name);
$this->assertEquals(false, $indexes[2]->unique);
$this->assertEquals($col, $indexes[2]->columns);
}
public function testColumns()
{
$columns = $this->_conn->columns('unit_tests');
$this->assertEquals(12, count($columns));
$col = $columns['id'];
$this->assertEquals('id', $col->getName());
$this->assertEquals('integer', $col->getType());
$this->assertEquals(false, $col->isNull());
$this->assertEquals(null, $col->getLimit());
$this->assertEquals('', $col->getDefault());
$this->assertEquals('integer', $col->getSqlType());
$this->assertEquals(false, $col->isText());
$this->assertEquals(true, $col->isNumber());
}
public function testCreateTable()
{
$this->_createTestTable('sports');
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
}
public function testCreateTableNoPk()
{
$this->_createTestTable('sports', array('autoincrementKey' => false));
try {
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertNull($this->_conn->selectValue($sql));
} catch (Exception $e) {
return;
}
$this->fail("Expected exception for no pk");
}
public function testCreateTableWithNamedPk()
{
$this->_createTestTable('sports', array('autoincrementKey' => 'sports_id'));
$sql = "SELECT sports_id FROM sports WHERE sports_id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
try {
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertNull($this->_conn->selectValue($sql));
} catch (Exception $e) {
return;
}
$this->fail("Expected exception for wrong pk name");
}
public function testCreateTableWithSeparatePk()
{
$table = $this->_conn->createTable('testings', array('autoincrementKey' => false));
$table->column('foo', 'autoincrementKey');
$table->column('bar', 'integer');
$table->end();
$pkColumn = $table['foo'];
$this->assertEquals('"foo" serial primary key', $pkColumn->toSql());
$this->_conn->insert("INSERT INTO testings (bar) VALUES (1)");
$sql = "SELECT * FROM testings WHERE foo = 1";
$result = $this->_conn->select($sql);
$this->assertEquals(1, count($result));
// This should fail.
try {
$this->_conn->insert("INSERT INTO testings (foo) VALUES (NULL)");
$this->fail("Expected exception for inserting null value");
} catch (Exception $e) {}
// Manually insert a primary key value.
$this->_conn->insert("INSERT INTO testings (foo, bar) VALUES (2, 1)");
$this->_conn->insert("INSERT INTO testings (bar) VALUES (1)");
}
public function testAlterTableWithSeparatePk()
{
$table = $this->_conn->createTable('testings', array('autoincrementKey' => false));
$table->column('foo', 'integer');
$table->column('bar', 'integer');
$table->end();
// Convert 'foo' to auto-increment
$this->_conn->changeColumn('testings', 'foo', 'autoincrementKey');
$this->_conn->insert("INSERT INTO testings (bar) VALUES (1)");
$sql = "SELECT * FROM testings WHERE foo = 1";
$result = $this->_conn->select($sql);
$this->assertEquals(1, count($result));
}
public function testCreateTableCompositePk()
{
$table = $this->_conn->createTable('testings', array('autoincrementKey' => array('a_id', 'b_id')));
$table->column('a_id', 'integer');
$table->column('b_id', 'integer');
$table->end();
$pk = $this->_conn->primaryKey('testings');
$this->assertEquals(array('a_id', 'b_id'), $pk->columns);
}
public function testCreateTableForce()
{
$this->_createTestTable('sports');
$this->_createTestTable('sports', array('force' => true));
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
}
public function testCreateTableTemporary()
{
$this->_createTestTable('sports', array('temporary' => true));
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
}
public function testCreateTableAddsId()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string');
$table->end();
$columns = array();
foreach ($this->_conn->columns('testings') as $col) {
$columns[] = $col->getName();
}
sort($columns);
$this->assertEquals(array('foo', 'id'), $columns);
}
public function testCreateTableWithNotNullColumn()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string', array('null' => false));
$table->end();
try {
$this->_conn->insert("INSERT INTO testings (foo) VALUES (NULL)");
} catch (Exception $e) { return; }
$this->fail('Expected exception wasn\'t raised');
}
public function testCreateTableWithDefaults()
{
$table = $this->_conn->createTable('testings');
$table->column('one', 'string', array('default' => 'hello'));
$table->column('two', 'boolean', array('default' => true));
$table->column('three', 'boolean', array('default' => false));
$table->column('four', 'integer', array('default' => 1));
$table->end();
$columns = array();
foreach ($this->_conn->columns('testings') as $col) {
$columns[$col->getName()] = $col;
}
$this->assertEquals('hello', $columns['one']->getDefault());
$this->assertTrue($columns['two']->getDefault());
$this->assertFalse($columns['three']->getDefault());
$this->assertEquals(1, $columns['four']->getDefault());
}
public function testCreateTableWithLimits()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string', array('limit' => 80));
$table->end();
$columns = array();
foreach ($this->_conn->columns('testings') as $col) {
$columns[$col->getName()] = $col;
}
$this->assertEquals(80, $columns['foo']->getLimit());
}
public function testCreateTableWithBinaryColumn()
{
try {
$table = $this->_conn->createTable('binary_testings');
$table->column('data', 'binary', array('null' => false));
$table->end();
} catch (Exception $e) { $this->fail('Unexepected exception raised'); }
$columns = $this->_conn->columns('binary_testings');
foreach ($columns as $c) {
if ($c->getName() == 'data') { $dataColumn = $c; }
}
$this->assertEquals('', $dataColumn->getDefault());
}
public function testRenameTable()
{
// Simple rename then select test
$this->_createTestTable('sports');
$this->_conn->renameTable('sports', 'my_sports');
$sql = "SELECT id FROM my_sports WHERE id = 1";
$this->assertEquals("1", $this->_conn->selectValue($sql));
// Make sure the old table name isn't still there
try {
$sql = "SELECT id FROM sports WHERE id = 1";
$this->_conn->execute($sql);
} catch (Exception $e) {
return;
}
$this->fail("Table exists where it shouldn't have");
// Rename then insert test
$table = $this->_conn->createTable('octopuses');
$table->column('url', 'string');
$table->end();
$this->_conn->renameTable('octopuses', 'octopi');
$sql = "INSERT INTO octopi (id, url) VALUES (1, 'http://www.foreverflying.com/octopus-black7.jpg')";
$this->_conn->insert($sql);
$this->assertEquals('http://www.foreverflying.com/octopus-black7.jpg',
$this->_conn->selectValue("SELECT url FROM octopi WHERE id=1"));
// Make sure the old table name isn't still there
try {
$sql = "SELECT id FROM octopuses WHERE id = 1";
$this->_conn->execute($sql);
} catch (Exception $e) {
return;
}
$this->fail("Table exists where it shouldn't have");
}
public function testRenameTableWithAnIndex()
{
$table = $this->_conn->createTable('octopuses');
$table->column('url', 'string');
$table->end();
$this->_conn->addIndex('octopuses', 'url');
$this->_conn->renameTable('octopuses', 'octopi');
$sql = "INSERT INTO octopi (id, url) VALUES (1, 'http://www.foreverflying.com/octopus-black7.jpg')";
$this->_conn->insert($sql, null, null, 'id', 1);
$this->assertEquals('http://www.foreverflying.com/octopus-black7.jpg',
$this->_conn->selectValue("SELECT url FROM octopi WHERE id=1"));
$indexes = $this->_conn->indexes('octopi');
$this->assertEquals('url', $indexes[0]->columns[0]);
}
public function testDropTable()
{
$this->_createTestTable('sports');
$this->_conn->dropTable('sports');
try {
$sql = "SELECT id FROM sports WHERE id = 1";
$this->_conn->execute($sql);
} catch (Exception $e) {
return;
}
$this->fail("Table exists where it shouldn't have");
}
public function testAddColumn()
{
$this->_createTestTable('sports');
$this->_conn->addColumn('sports', 'modified_at', 'date');
$this->_conn->update("UPDATE sports SET modified_at = '2007-01-01'");
$sql = "SELECT modified_at FROM sports WHERE id = 1";
$this->assertEquals("2007-01-01", $this->_conn->selectValue($sql));
$this->_conn->addColumn('sports', 'with_default', 'integer', array('default' => 1));
$sql = "SELECT with_default FROM sports WHERE id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
}
public function testRemoveColumn()
{
$this->_createTestTable('sports');
$sql = "SELECT name FROM sports WHERE id = 1";
$this->assertEquals("mlb", $this->_conn->selectValue($sql));
$this->_conn->removeColumn('sports', 'name');
try {
$sql = "SELECT name FROM sports WHERE id = 1";
$this->_conn->execute($sql);
} catch (Exception $e) {
return;
}
$this->fail("Column exists where it shouldn't have");
}
public function testChangeColumn()
{
$this->_createTestUsersTable();
$this->_conn->addColumn('users', 'age', 'integer');
$oldColumns = $this->_conn->columns('users', "User Columns");
$found = false;
foreach ($oldColumns as $c) {
if ($c->getName() == 'age' && $c->getType() == 'integer') { $found = true; }
}
$this->assertTrue($found);
$this->_conn->changeColumn('users', 'age', 'string');
$newColumns = $this->_conn->columns('users', "User Columns");
$found = false;
foreach ($newColumns as $c) {
if ($c->getName() == 'age' && $c->getType() == 'integer') { $found = true; }
}
$this->assertFalse($found);
$found = false;
foreach ($newColumns as $c) {
if ($c->getName() == 'age' && $c->getType() == 'string') { $found = true; }
}
$this->assertTrue($found);
$found = false;
foreach ($oldColumns as $c) {
if ($c->getName() == 'approved' && $c->getType() == 'boolean' &&
$c->getDefault() == true) { $found = true; }
}
$this->assertTrue($found);
// changeColumn() throws exception on error
$this->_conn->changeColumn('users', 'approved', 'boolean', array('default' => false));
$newColumns = $this->_conn->columns('users', "User Columns");
$found = false;
foreach ($newColumns as $c) {
if ($c->getName() == 'approved' && $c->getType() == 'boolean' &&
$c->getDefault() == true) { $found = true; }
}
$this->assertFalse($found);
$found = false;
foreach ($newColumns as $c) {
if ($c->getName() == 'approved' && $c->getType() == 'boolean' &&
$c->getDefault() == false) { $found = true; }
}
$this->assertTrue($found);
// changeColumn() throws exception on error
$this->_conn->changeColumn('users', 'approved', 'boolean', array('default' => true));
}
public function testChangeColumnDefault()
{
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'name');
$this->assertEquals('', $beforeChange->getDefault());
$this->_conn->changeColumnDefault('sports', 'name', 'test');
$afterChange = $this->_getColumn('sports', 'name');
$this->assertEquals('test', $afterChange->getDefault());
}
public function testChangeColumnType()
{
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('boolean', $beforeChange->getSqlType());
$this->_conn->changeColumn('sports', 'is_college', 'string');
$afterChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('character varying(255)', $afterChange->getSqlType());
$table = $this->_conn->createTable('text_to_binary');
$table->column('data', 'text');
$table->end();
$this->_conn->insert('INSERT INTO text_to_binary (data) VALUES (?)',
array("foobar"));
$this->_conn->changeColumn('text_to_binary', 'data', 'binary');
$afterChange = $this->_getColumn('text_to_binary', 'data');
$this->assertEquals('bytea', $afterChange->getSqlType());
$this->assertEquals(
"foobar",
stream_get_contents($this->_conn->selectValue('SELECT data FROM text_to_binary')));
}
public function testChangeColumnLimit()
{
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('boolean', $beforeChange->getSqlType());
$this->_conn->changeColumn('sports', 'is_college', 'string',
array('limit' => '40'));
$afterChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('character varying(40)', $afterChange->getSqlType());
}
public function testChangeColumnPrecisionScale()
{
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('boolean', $beforeChange->getSqlType());
$this->_conn->changeColumn('sports', 'is_college', 'decimal',
array('precision' => '5', 'scale' => '2'));
$afterChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('numeric(5,2)', $afterChange->getSqlType());
}
public function testRenameColumn()
{
$this->_createTestUsersTable();
$this->_conn->renameColumn('users', 'first_name', 'nick_name');
$this->assertTrue(in_array('nick_name', $this->_columnNames('users')));
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('boolean', $beforeChange->getSqlType());
$this->_conn->renameColumn('sports', 'is_college', 'is_renamed');
$afterChange = $this->_getColumn('sports', 'is_renamed');
$this->assertEquals('boolean', $afterChange->getSqlType());
}
public function testRenameColumnWithSqlReservedWord()
{
$this->_createTestUsersTable();
$this->_conn->renameColumn('users', 'first_name', 'group');
$this->assertTrue(in_array('group', $this->_columnNames('users')));
}
public function testAddIndex()
{
$this->_createTestUsersTable();
// Limit size of last_name and key columns to support Firebird index limitations
$this->_conn->addColumn('users', 'last_name', 'string', array('limit' => 100));
$this->_conn->addColumn('users', 'key', 'string', array('limit' => 100));
$this->_conn->addColumn('users', 'administrator', 'boolean');
$this->_conn->addIndex('users', 'last_name');
$this->_conn->removeIndex('users', 'last_name');
$this->_conn->addIndex('users', array('last_name', 'first_name'));
$this->_conn->removeIndex('users', array('column' => array('last_name', 'first_name')));
$this->_conn->addIndex('users', array('last_name', 'first_name'));
$this->_conn->removeIndex('users', array('name' => 'index_users_on_last_name_and_first_name'));
$this->_conn->addIndex('users', array('last_name', 'first_name'));
$this->_conn->removeIndex('users', 'last_name_and_first_name');
// quoting
$this->_conn->addIndex('users', array('key'), array('name' => 'key_idx', 'unique' => true));
$this->_conn->removeIndex('users', array('name' => 'key_idx', 'unique' => true));
$this->_conn->addIndex('users', array('last_name', 'first_name', 'administrator'),
array('name' => "named_admin"));
$this->_conn->removeIndex('users', array('name' => 'named_admin'));
}
public function testAddIndexDefault()
{
$this->_createTestTable('sports');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
$this->_conn->addIndex('sports', 'is_college');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
}
public function testAddIndexMultiColumn()
{
$this->_createTestTable('sports');
$index = $this->_getIndex('sports', array('name', 'is_college'));
$this->assertNull($index);
$this->_conn->addIndex('sports', array('name', 'is_college'));
$index = $this->_getIndex('sports', array('name', 'is_college'));
$this->assertNotNull($index);
}
public function testAddIndexUnique()
{
$this->_createTestTable('sports');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
$this->_conn->addIndex('sports', 'is_college', array('unique' => true));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
$this->assertTrue($index->unique);
}
public function testAddIndexName()
{
$this->_createTestTable('sports');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
$this->_conn->addIndex('sports', 'is_college', array('name' => 'sports_test'));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
$this->assertEquals('sports_test', $index->name);
}
public function testRemoveIndexSingleColumn()
{
$this->_createTestTable('sports');
// add the index
$this->_conn->addIndex('sports', 'is_college');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
// remove it again
$this->_conn->removeIndex('sports', array('column' => 'is_college'));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
}
public function testRemoveIndexMultiColumn()
{
$this->_createTestTable('sports');
// add the index
$this->_conn->addIndex('sports', array('name', 'is_college'));
$index = $this->_getIndex('sports', array('name', 'is_college'));
$this->assertNotNull($index);
// remove it again
$this->_conn->removeIndex('sports', array('column' => array('name', 'is_college')));
$index = $this->_getIndex('sports', array('name', 'is_college'));
$this->assertNull($index);
}
public function testRemoveIndexByName()
{
$this->_createTestTable('sports');
// add the index
$this->_conn->addIndex('sports', 'is_college', array('name' => 'sports_test'));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
// remove it again
$this->_conn->removeIndex('sports', array('name' => 'sports_test'));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
}
public function testIndexNameInvalid()
{
try {
$name = $this->_conn->indexName('sports');
} catch (Horde_Db_Exception $e) {
return;
}
$this->fail("Adding an index with crappy options worked where it shouldn't have");
}
public function testIndexNameBySingleColumn()
{
$name = $this->_conn->indexName('sports', array('column' => 'is_college'));
$this->assertEquals('index_sports_on_is_college', $name);
}
public function testIndexNameByMultiColumn()
{
$name = $this->_conn->indexName('sports', array('column' =>
array('name', 'is_college')));
$this->assertEquals('index_sports_on_name_and_is_college', $name);
}
public function testIndexNameByName()
{
$name = $this->_conn->indexName('sports', array('name' => 'test'));
$this->assertEquals('test', $name);
}
public function testTypeToSqlTypePrimaryKey()
{
$result = $this->_conn->typeToSql('autoincrementKey');
$this->assertEquals('serial primary key', $result);
}
public function testTypeToSqlTypeString()
{
$result = $this->_conn->typeToSql('string');
$this->assertEquals('character varying(255)', $result);
}
public function testTypeToSqlTypeText()
{
$result = $this->_conn->typeToSql('text');
$this->assertEquals('text', $result);
}
public function testTypeToSqlTypeBinary()
{
$result = $this->_conn->typeToSql('binary');
$this->assertEquals('bytea', $result);
}
public function testTypeToSqlTypeFloat()
{
$result = $this->_conn->typeToSql('float');
$this->assertEquals('float', $result);
}
public function testTypeToSqlTypeDatetime()
{
$result = $this->_conn->typeToSql('datetime');
$this->assertEquals('timestamp', $result);
}
public function testTypeToSqlTypeTimestamp()
{
$result = $this->_conn->typeToSql('timestamp');
$this->assertEquals('timestamp', $result);
}
public function testTypeToSqlInt()
{
$result = $this->_conn->typeToSql('integer');
$this->assertEquals('integer', $result);
}
public function testTypeToSqlIntLimit()
{
$result = $this->_conn->typeToSql('integer', '1');
$this->assertEquals('smallint', $result);
}
public function testTypeToSqlDecimalPrecision()
{
$result = $this->_conn->typeToSql('decimal', null, '5');
$this->assertEquals('decimal(5)', $result);
}
public function testTypeToSqlDecimalScale()
{
$result = $this->_conn->typeToSql('decimal', null, '5', '2');
$this->assertEquals('decimal(5, 2)', $result);
}
public function testTypeToSqlBoolean()
{
$result = $this->_conn->typeToSql('boolean');
$this->assertEquals('boolean', $result);
}
public function testAddColumnOptions()
{
$result = $this->_conn->addColumnOptions("test", array());
$this->assertEquals("test", $result);
}
public function testAddColumnOptionsDefault()
{
$options = array('default' => '0');
$result = $this->_conn->addColumnOptions("test", $options);
$this->assertEquals("test DEFAULT '0'", $result);
}
public function testAddColumnOptionsNull()
{
$options = array('null' => true);
$result = $this->_conn->addColumnOptions("test", $options);
$this->assertEquals("test", $result);
}
public function testAddColumnOptionsNotNull()
{
$options = array('null' => false);
$result = $this->_conn->addColumnOptions("test", $options);
$this->assertEquals("test NOT NULL", $result);
}
public function testAddColumnNotNullWithoutDefault()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string');
$table->end();
$this->_conn->addColumn('testings', 'bar', 'string', array('null' => false, 'default' => ''));
try {
$this->_conn->insert("INSERT INTO testings (foo, bar) VALUES ('hello', NULL)");
} catch (Exception $e) { return; }
$this->fail('Expected exception wasn\'t raised');
}
public function testAddColumnNotNullWithDefault()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string');
$table->end();
$this->_conn->insert("INSERT INTO testings (id, foo) VALUES ('1', 'hello')", null, null, 'id', 1);
$this->_conn->addColumn('testings', 'bar', 'string', array('null' => false, 'default' => 'default'));
try {
$this->_conn->insert("INSERT INTO testings (id, foo, bar) VALUES (2, 'hello', NULL)");
} catch (Exception $e) { return; }
$this->fail('Expected exception wasn\'t raised');
}
public function testAddRemoveSingleField()
{
$this->_createTestUsersTable();
$this->assertFalse(in_array('last_name', $this->_columnNames('users')));
$this->_conn->addColumn('users', 'last_name', 'string');
$this->assertTrue(in_array('last_name', $this->_columnNames('users')));
$this->_conn->removeColumn('users', 'last_name');
$this->assertFalse(in_array('last_name', $this->_columnNames('users')));
}
public function testAddRename()
{
$this->_createTestUsersTable();
$this->_conn->delete('DELETE FROM users');
$this->_conn->addColumn('users', 'girlfriend', 'string');
$this->_conn->insert("INSERT INTO users (girlfriend) VALUES ('bobette')");
$this->_conn->renameColumn('users', 'girlfriend', 'exgirlfriend');
$bob = (object)$this->_conn->selectOne('SELECT * FROM users');
$this->assertEquals('bobette', $bob->exgirlfriend);
}
public function testDistinct()
{
$result = $this->_conn->distinct("test");
$this->assertEquals("DISTINCT test", $result);
}
public function testAddOrderByForAssocLimiting()
{
$result = $this->_conn->addOrderByForAssocLimiting("SELECT * FROM documents ",
array('order' => 'name DESC'));
$this->assertEquals("SELECT * FROM documents ORDER BY name DESC", $result);
}
public function testInterval()
{
$this->assertEquals('INTERVAL \'1 DAY \'',
$this->_conn->interval('1 DAY', ''));
}
public function testModifyDate()
{
$modifiedDate = $this->_conn->modifyDate('mystart', '+', 1, 'DAY');
$this->assertEquals('mystart + INTERVAL \'1 DAY\'', $modifiedDate);
$t = $this->_conn->createTable('dates');
$t->column('mystart', 'datetime');
$t->column('myend', 'datetime');
$t->end();
$this->_conn->insert(
'INSERT INTO dates (mystart, myend) VALUES (?, ?)',
array(
'2011-12-10 00:00:00',
'2011-12-11 00:00:00'
)
);
$this->assertEquals(
1,
$this->_conn->selectValue('SELECT COUNT(*) FROM dates WHERE '
. $modifiedDate . ' = myend')
);
}
public function testBuildClause()
{
$this->assertEquals(
"CASE WHEN CAST(bitmap AS VARCHAR) ~ '^-?[0-9]+$' THEN (CAST(bitmap AS INTEGER) & 2) <> 0 ELSE FALSE END",
$this->_conn->buildClause('bitmap', '&', 2));
$this->assertEquals(
array("CASE WHEN CAST(bitmap AS VARCHAR) ~ '^-?[0-9]+$' THEN (CAST(bitmap AS INTEGER) & ?) <> 0 ELSE FALSE END", array(2)),
$this->_conn->buildClause('bitmap', '&', 2, true));
$this->assertEquals(
"CASE WHEN CAST(bitmap AS VARCHAR) ~ '^-?[0-9]+$' THEN (CAST(bitmap AS INTEGER) | 2) <> 0 ELSE FALSE END",
$this->_conn->buildClause('bitmap', '|', 2));
$this->assertEquals(
array("CASE WHEN CAST(bitmap AS VARCHAR) ~ '^-?[0-9]+$' THEN (CAST(bitmap AS INTEGER) | ?) <> 0 ELSE FALSE END", array(2)),
$this->_conn->buildClause('bitmap', '|', 2, true));
$this->assertEquals(
"name ILIKE '%search%'",
$this->_conn->buildClause('name', 'LIKE', "search"));
$this->assertEquals(
array("name ILIKE ?", array('%search%')),
$this->_conn->buildClause('name', 'LIKE', "search", true));
$this->assertEquals(
"name ILIKE '%search\&replace\?%'",
$this->_conn->buildClause('name', 'LIKE', "search&replace?"));
$this->assertEquals(
array("name ILIKE ?", array('%search&replace?%')),
$this->_conn->buildClause('name', 'LIKE', "search&replace?", true));
$this->assertEquals(
"(name ILIKE 'search\&replace\?%' OR name ILIKE '% search\&replace\?%')",
$this->_conn->buildClause('name', 'LIKE', "search&replace?", false, array('begin' => true)));
$this->assertEquals(
array("(name ILIKE ? OR name ILIKE ?)",
array('search&replace?%', '% search&replace?%')),
$this->_conn->buildClause('name', 'LIKE', "search&replace?", true, array('begin' => true)));
$this->assertEquals(
'value = 2',
$this->_conn->buildClause('value', '=', 2));
$this->assertEquals(
array('value = ?', array(2)),
$this->_conn->buildClause('value', '=', 2, true));
$this->assertEquals(
"value = 'foo'",
$this->_conn->buildClause('value', '=', 'foo'));
$this->assertEquals(
array('value = ?', array('foo')),
$this->_conn->buildClause('value', '=', 'foo', true));
$this->assertEquals(
"value = 'foo\?bar'",
$this->_conn->buildClause('value', '=', 'foo?bar'));
$this->assertEquals(
array('value = ?', array('foo?bar')),
$this->_conn->buildClause('value', '=', 'foo?bar', true));
}
/*##########################################################################
# Table cache
##########################################################################*/
public function testCachedTableIndexes()
{
// remove any current cache.
$this->_cache->set('tables/indexes/cache_table', '');
$this->assertEquals('', $this->_cache->get('tables/indexes/cache_table', 0));
$this->_createTestTable('cache_table');
$idxs = $this->_conn->indexes('cache_table');
$this->assertNotEquals('', $this->_cache->get('tables/indexes/cache_table', 0));
}
public function testCachedTableColumns()
{
// remove any current cache.
$this->_cache->set('tables/columns/cache_table', '');
$this->assertEquals('', $this->_cache->get('tables/columns/cache_table'), 0);
$this->_createTestTable('cache_table');
$cols = $this->_conn->columns('cache_table');
$this->assertNotEquals('', $this->_cache->get('tables/columns/cache_table', 0));
}
/*##########################################################################
# Protected
##########################################################################*/
/**
* Create table to perform tests on
*/
protected function _createTestTable($name, $options=array())
{
$table = $this->_conn->createTable($name, $options);
$table->column('name', 'string');
$table->column('is_college', 'boolean');
$table->end();
try {
// make sure table was created
$sql = "INSERT INTO $name
VALUES (1, 'mlb', 'f')";
$this->_conn->insert($sql);
} catch (Exception $e) {}
}
protected function _createTestUsersTable()
{
$table = $this->_conn->createTable('users');
$table->column('company_id', 'integer', array('limit' => 11));
$table->column('name', 'string', array('limit' => 255, 'default' => ''));
$table->column('first_name', 'string', array('limit' => 40, 'default' => ''));
$table->column('approved', 'boolean', array('default' => true));
$table->column('type', 'string', array('limit' => 255, 'default' => ''));
$table->column('created_at', 'datetime', array());
$table->column('created_on', 'date', array());
$table->column('updated_at', 'datetime', array());
$table->column('updated_on', 'date', array());
$table->end();
}
/**
* drop test tables
*/
protected function _dropTestTables()
{
$tables = array(
'binary_testings',
'cache_table',
'dates',
'my_sports',
'octopi',
'pk_tests',
'schema_info',
'sports',
'testings',
'text_to_binary',
'unit_tests',
'users',
);
foreach ($tables as $table) {
try {
$this->_conn->dropTable($table);
} catch (Exception $e) {}
}
}
protected function _columnNames($tableName)
{
$columns = array();
foreach ($this->_conn->columns($tableName) as $c) {
$columns[] = $c->getName();
}
return $columns;
}
/**
* Get a column by name
*/
protected function _getColumn($table, $column)
{
foreach ($this->_conn->columns($table) as $col) {
if ($col->getName() == $column) return $col;
}
}
/**
* Get an index by columns
*/
protected function _getIndex($table, $indexes)
{
$indexes = (array) $indexes;
sort($indexes);
foreach ($this->_conn->indexes($table) as $index) {
$columns = $index->columns;
sort($columns);
if ($columns == $indexes) return $index;
}
}
}
Horde_Db-2.0.4/test/Horde/Db/Adapter/Pdo/SqliteBase.php 0000664 0001750 0001750 00000003354 12205351473 020512 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @author Jan Schneider
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage UnitTests
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @author Jan Schneider
* @license http://www.horde.org/licenses/bsd
* @group horde_db
* @category Horde
* @package Db
* @subpackage UnitTests
*/
class Horde_Db_Adapter_Pdo_SqliteBase extends Horde_Test_Case
{
protected static $skip = true;
protected static $reason = 'The PDO_SQLite adapter is not available';
public static function setUpBeforeClass()
{
if (extension_loaded('pdo') &&
in_array('sqlite', PDO::getAvailableDrivers())) {
self::$skip = false;
list($conn,) = self::getConnection();
$conn->disconnect();
}
}
public static function getConnection($overrides = array())
{
$config = array(
'dbname' => ':memory:',
);
$config = array_merge($config, $overrides);
$conn = new Horde_Db_Adapter_Pdo_Sqlite($config);
$cache = new Horde_Cache(new Horde_Cache_Storage_Mock());
$conn->setCache($cache);
return array($conn, $cache);
}
protected function setUp()
{
if (self::$skip) {
$this->markTestSkipped(self::$reason);
}
}
}
Horde_Db-2.0.4/test/Horde/Db/Adapter/Pdo/SqliteTest.php 0000664 0001750 0001750 00000141444 12205351473 020562 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage UnitTests
*/
require_once __DIR__ . '/SqliteBase.php';
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @group horde_db
* @category Horde
* @package Db
* @subpackage UnitTests
*/
class Horde_Db_Adapter_Pdo_SqliteTest extends Horde_Db_Adapter_Pdo_SqliteBase
{
protected function setUp()
{
parent::setUp();
list($this->_conn, $this->_cache) = self::getConnection();
$table = $this->_conn->createTable('unit_tests');
$table->column('integer_value', 'integer', array('limit' => 11, 'default' => 0));
$table->column('string_value', 'string', array('limit' => 255, 'default' => ''));
$table->column('text_value', 'text', array('null' => false, 'default' => ''));
$table->column('float_value', 'float', array('precision' => 2, 'scale' => 1, 'default' => 0.0));
$table->column('decimal_value', 'decimal', array('precision' => 2, 'scale' => 1, 'default' => 0.0));
$table->column('datetime_value', 'datetime', array('default' => '0000-00-00 00:00:00'));
$table->column('date_value', 'date', array('default' => '0000-00-00'));
$table->column('time_value', 'time', array('default' => '00:00:00'));
$table->column('blob_value', 'binary', array('null' => false, 'default' => ''));
$table->column('boolean_value', 'boolean', array('default' => false));
$table->column('email_value', 'string', array('limit' => 255, 'default' => ''));
$table->end();
$this->_conn->addIndex('unit_tests', 'string_value', array('name' => 'string_value'));
$this->_conn->addIndex('unit_tests', 'integer_value', array('name' => 'integer_value', 'unique' => true));
$this->_conn->addIndex('unit_tests', array('integer_value', 'string_value'), array('name' => 'integer_string'));
// read sql file for statements
$statements = array();
$current_stmt = '';
$fp = fopen(__DIR__ . '/../../fixtures/unit_tests.sql', 'r');
while ($line = fgets($fp, 8192)) {
$line = rtrim(preg_replace('/^(.*)--.*$/s', '\1', $line));
if (!$line) {
continue;
}
$current_stmt .= $line;
if (substr($line, -1) == ';') {
// leave off the ending ;
$statements[] = substr($current_stmt, 0, -1);
$current_stmt = '';
}
}
// run statements
foreach ($statements as $stmt) {
$this->_conn->execute($stmt);
}
}
protected function tearDown()
{
// close connection
$this->_conn->disconnect();
}
/*##########################################################################
# Connection
##########################################################################*/
public function testConnect()
{
$this->assertTrue($this->_conn->isActive());
}
public function testDisconnect()
{
$this->_conn->disconnect();
$this->assertFalse($this->_conn->isActive());
$this->_conn->connect();
$this->assertTrue($this->_conn->isActive());
}
public function testReconnect()
{
$this->_conn->reconnect();
$this->assertTrue($this->_conn->isActive());
}
/*##########################################################################
# Accessor
##########################################################################*/
public function testAdapterName()
{
$this->assertEquals('PDO_SQLite', $this->_conn->adapterName());
}
public function testSupportsMigrations()
{
$this->assertTrue($this->_conn->supportsMigrations());
}
public function testSupportsCountDistinct()
{
$version = $this->_conn->selectValue('SELECT sqlite_version(*)');
if ($version >= '3.2.6') {
$this->assertTrue($this->_conn->supportsCountDistinct());
} else {
$this->assertFalse($this->_conn->supportsCountDistinct());
}
}
/*##########################################################################
# Database Statements
##########################################################################*/
public function testExecute()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->execute($sql);
$row = $result->fetch();
$this->assertEquals(1, $row['id']);
}
public function testSelect()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->select($sql);
$this->assertInstanceOf('Traversable', $result);
$this->assertGreaterThan(0, count($result));
foreach ($result as $row) break;
$this->assertInternalType('array', $row);
$this->assertEquals(1, $row['id']);
}
public function testSelectWithBoundParameters()
{
$sql = "SELECT * FROM unit_tests WHERE id=?";
$result = $this->_conn->select($sql, array(1));
$this->assertInstanceOf('Traversable', $result);
$this->assertGreaterThan(0, count($result));
foreach ($result as $row) break;
$this->assertInternalType('array', $row);
$this->assertEquals(1, $row['id']);
}
public function testSelectWithBoundParametersQuotesString()
{
$sql = "SELECT * FROM unit_tests WHERE string_value=?";
$result = $this->_conn->select($sql, array('name a'));
$this->assertInstanceOf('Traversable', $result);
$this->assertGreaterThan(0, count($result));
foreach ($result as $row) break;
$this->assertInternalType('array', $row);
$this->assertEquals(1, $row['id']);
}
public function testSelectAll()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->selectAll($sql);
$this->assertInternalType('array', $result);
$this->assertGreaterThan(0, count($result));
$this->assertEquals(1, $result[0]['id']);
}
public function testSelectOne()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->selectOne($sql);
$this->assertArrayHasKey('id', $result);
$this->assertEquals(1, $result['id']);
}
public function testSelectValue()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->selectValue($sql);
$this->assertEquals(1, $result);
}
public function testSelectValues()
{
$sql = "SELECT * FROM unit_tests";
$result = $this->_conn->selectValues($sql);
$this->assertEquals(array(1, 2, 3, 4, 5, 6), $result);
}
public function testInsert()
{
$sql = "INSERT INTO unit_tests (id, integer_value) VALUES (7, 999)";
$result = $this->_conn->insert($sql);
$this->assertEquals(7, $result);
}
public function testUpdate()
{
$sql = "UPDATE unit_tests SET integer_value=999 WHERE id IN (1)";
$result = $this->_conn->update($sql);
$this->assertEquals(1, $result);
}
public function testDelete()
{
$sql = "DELETE FROM unit_tests WHERE id IN (1,2)";
$result = $this->_conn->delete($sql);
$this->assertEquals(2, $result);
}
public function testTransactionStarted()
{
$this->assertFalse($this->_conn->transactionStarted());
$this->_conn->beginDbTransaction();
$this->assertTrue($this->_conn->transactionStarted());
$this->_conn->commitDbTransaction();
$this->assertFalse($this->_conn->transactionStarted());
}
public function testTransactionCommit()
{
$this->_conn->beginDbTransaction();
$sql = "INSERT INTO unit_tests (id, integer_value) VALUES (7, 999)";
$this->_conn->insert($sql);
$this->_conn->commitDbTransaction();
// make sure it inserted
$sql = "SELECT integer_value FROM unit_tests WHERE id='7'";
$this->assertEquals('999', $this->_conn->selectValue($sql));
}
public function testTransactionRollback()
{
$this->_conn->beginDbTransaction();
$sql = "INSERT INTO unit_tests (id, integer_value) VALUES (7, 999)";
$this->_conn->insert($sql);
$this->_conn->rollbackDbTransaction();
// make sure it inserted
$sql = "SELECT integer_value FROM unit_tests WHERE id='7'";
$this->assertEquals(null, $this->_conn->selectValue($sql));
}
/*##########################################################################
# Quoting
##########################################################################*/
public function testQuoteNull()
{
$this->assertEquals('NULL', $this->_conn->quote(null));
}
public function testQuoteTrue()
{
$this->assertEquals('1', $this->_conn->quote(true));
}
public function testQuoteFalse()
{
$this->assertEquals('0', $this->_conn->quote(false));
}
public function testQuoteInteger()
{
$this->assertEquals('42', $this->_conn->quote(42));
}
public function testQuoteFloat()
{
$this->assertEquals('42.2', $this->_conn->quote(42.2));
setlocale(LC_NUMERIC, 'de_DE.UTF-8');
$this->assertEquals('42.2', $this->_conn->quote(42.2));
}
public function testQuoteString()
{
$this->assertEquals("'my string'", $this->_conn->quote('my string'));
}
public function testQuoteDirtyString()
{
$this->assertEquals("'derek''s string'", $this->_conn->quote('derek\'s string'));
}
public function testQuoteColumnName()
{
$col = new Horde_Db_Adapter_Sqlite_Column('age', 'NULL', 'int(11)');
$this->assertEquals('1', $this->_conn->quote(true, $col));
}
public function testQuoteBinary()
{
// Test string is foo\0ba'r - should be 8 bytes long
$original = base64_decode('Zm9vAGJhJ3I=');
$table = $this->_conn->createTable('binary_testings');
$table->column('data', 'binary', array('null' => false));
$table->end();
$this->_conn->insert('INSERT INTO binary_testings (data) VALUES (?)', array(new Horde_Db_Value_Binary($original)));
$retrieved = $this->_conn->selectValue('SELECT data FROM binary_testings');
$columns = $this->_conn->columns('binary_testings');
$retrieved = $columns['data']->binaryToString($retrieved);
$this->assertEquals($original, $retrieved);
}
/*##########################################################################
# Schema Statements
##########################################################################*/
public function testNativeDatabaseTypes()
{
$types = $this->_conn->nativeDatabaseTypes();
$this->assertEquals(array('name' => 'int', 'limit' => null), $types['integer']);
}
public function testTableAliasLength()
{
$len = $this->_conn->tableAliasLength();
$this->assertEquals(255, $len);
}
public function testTableAliasFor()
{
$alias = $this->_conn->tableAliasFor('my_table_name');
$this->assertEquals('my_table_name', $alias);
}
public function testTables()
{
$tables = $this->_conn->tables();
$this->assertTrue(count($tables) > 0);
$this->assertContains('unit_tests', $tables);
}
public function testPrimaryKey()
{
$pk = $this->_conn->primaryKey('unit_tests');
$this->assertEquals('id', (string)$pk);
$this->assertEquals(1, count($pk->columns));
$this->assertEquals('id', $pk->columns[0]);
$table = $this->_conn->createTable('pk_tests', array('autoincrementKey' => false));
$table->column('foo', 'string');
$table->column('bar', 'string');
$table->end();
$pk = $this->_conn->primaryKey('pk_tests');
$this->assertEmpty((string)$pk);
$this->assertEquals(0, count($pk->columns));
$this->_conn->addPrimaryKey('pk_tests', 'foo');
$pk = $this->_conn->primaryKey('pk_tests');
$this->assertEquals('foo', (string)$pk);
$this->assertEquals(1, count($pk->columns));
$this->_conn->removePrimaryKey('pk_tests');
$pk = $this->_conn->primaryKey('pk_tests');
$this->assertEmpty((string)$pk);
$this->assertEquals(0, count($pk->columns));
$this->_conn->addPrimaryKey('pk_tests', array('foo', 'bar'));
$pk = $this->_conn->primaryKey('pk_tests');
$this->assertEquals('foo,bar', (string)$pk);
}
public function testIndexes()
{
$indexes = $this->_conn->indexes('unit_tests');
$this->assertEquals(3, count($indexes));
// sort indexes alphabetically
usort($indexes, create_function('$a, $b', 'return strcmp($a->name, $b->name);'));
// multi-column index
$col = array('integer_value', 'string_value');
$this->assertEquals('unit_tests', $indexes[0]->table);
$this->assertEquals('integer_string', $indexes[0]->name);
$this->assertEquals(false, $indexes[0]->unique);
$this->assertEquals($col, $indexes[0]->columns);
// unique index
$col = array('integer_value');
$this->assertEquals('unit_tests', $indexes[1]->table);
$this->assertEquals('integer_value', $indexes[1]->name);
$this->assertEquals(true, $indexes[1]->unique);
$this->assertEquals($col, $indexes[1]->columns);
// normal index
$col = array('string_value');
$this->assertEquals('unit_tests', $indexes[2]->table);
$this->assertEquals('string_value', $indexes[2]->name);
$this->assertEquals(false, $indexes[2]->unique);
$this->assertEquals($col, $indexes[2]->columns);
}
public function testColumns()
{
$columns = $this->_conn->columns('unit_tests');
$this->assertEquals(12, count($columns));
$col = $columns['id'];
$this->assertEquals('id', $col->getName());
$this->assertEquals('integer', $col->getType());
$this->assertEquals(false, $col->isNull());
$this->assertEquals(null, $col->getLimit());
$this->assertEquals('', $col->getDefault());
$this->assertEquals('INTEGER', $col->getSqlType());
$this->assertEquals(false, $col->isText());
$this->assertEquals(true, $col->isNumber());
}
public function testCreateTable()
{
$this->_createTestTable('sports');
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
}
public function testCreateTableNoPk()
{
$this->_createTestTable('sports', array('autoincrementKey' => false));
try {
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertNull($this->_conn->selectValue($sql));
} catch (Exception $e) {
return;
}
$this->fail("Expected exception for no pk");
}
public function testCreateTableWithNamedPk()
{
$this->_createTestTable('sports', array('autoincrementKey' => 'sports_id'));
$sql = "SELECT sports_id FROM sports WHERE sports_id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
try {
$sql = "SELECT id FROM sports WHERE id = 1";
$this->_conn->selectValue($sql);
$this->fail("Expected exception for wrong pk name");
} catch (Exception $e) {
}
$sql = "INSERT INTO sports ('name', 'is_college') VALUES ('foo', 1)";
$this->assertEquals(2, $this->_conn->insert($sql));
}
public function testCreateTableWithSeparatePk()
{
$table = $this->_conn->createTable('testings', array('autoincrementKey' => false));
$table->column('foo', 'autoincrementKey');
$table->column('bar', 'string');
$pkColumn = $table['foo'];
$this->assertEquals('"foo" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL', $pkColumn->toSql());
$table->end();
$sql = "INSERT INTO testings ('bar') VALUES ('baz')";
$this->assertEquals(1, $this->_conn->insert($sql));
$this->assertEquals(2, $this->_conn->insert($sql));
}
public function testCreateTableWithSeparatePk2()
{
$table = $this->_conn->createTable('testings', array('autoincrementKey' => false));
$table->column('foo', 'integer', array('null' => false, 'autoincrement' => true));
$table->column('bar', 'string');
$table->primaryKey('foo');
$pkColumn = $table['foo'];
$this->assertEquals('"foo" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL', $pkColumn->toSql());
$table->end();
$sql = "INSERT INTO testings ('bar') VALUES ('baz')";
$this->assertEquals(1, $this->_conn->insert($sql));
$this->assertEquals(2, $this->_conn->insert($sql));
}
public function testCreateTableCompositePk()
{
$table = $this->_conn->createTable('testings', array('autoincrementKey' => array('a_id', 'b_id')));
$table->column('a_id', 'integer');
$table->column('b_id', 'integer');
$table->end();
$pk = $this->_conn->primaryKey('testings');
$this->assertEquals(array('a_id', 'b_id'), $pk->columns);
}
public function testCreateTableForce()
{
$this->_createTestTable('sports');
$this->_createTestTable('sports', array('force' => true));
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
}
public function testCreateTableTemporary()
{
$this->_createTestTable('sports', array('temporary' => true));
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
}
public function testCreateTableAddsId()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string');
$table->end();
$columns = array();
foreach ($this->_conn->columns('testings') as $col) {
$columns[] = $col->getName();
}
sort($columns);
$this->assertEquals(array('foo', 'id'), $columns);
}
public function testCreateTableWithNotNullColumn()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string', array('null' => false));
$table->end();
try {
$this->_conn->execute("INSERT INTO testings (foo) VALUES (NULL)");
} catch (Exception $e) { return; }
$this->fail('Expected exception wasn\'t raised');
}
public function testCreateTableWithDefaults()
{
$table = $this->_conn->createTable('testings');
$table->column('one', 'string', array('default' => 'hello'));
$table->column('two', 'boolean', array('default' => true));
$table->column('three', 'boolean', array('default' => false));
$table->column('four', 'integer', array('default' => 1));
$table->end();
$columns = array();
foreach ($this->_conn->columns('testings') as $col) {
$columns[$col->getName()] = $col;
}
$this->assertEquals('hello', $columns['one']->getDefault());
$this->assertTrue($columns['two']->getDefault());
$this->assertFalse($columns['three']->getDefault());
$this->assertEquals(1, $columns['four']->getDefault());
}
public function testCreateTableWithLimits()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string', array('limit' => 80));
$table->end();
$columns = array();
foreach ($this->_conn->columns('testings') as $col) {
$columns[$col->getName()] = $col;
}
$this->assertEquals(80, $columns['foo']->getLimit());
}
public function testCreateTableWithBinaryColumn()
{
try {
$table = $this->_conn->createTable('binary_testings');
$table->column('data', 'binary', array('null' => false));
$table->end();
} catch (Exception $e) { $this->fail('Unexepected exception raised'); }
$columns = $this->_conn->columns('binary_testings');
foreach ($columns as $c) {
if ($c->getName() == 'data') { $dataColumn = $c; }
}
$this->assertEquals('', $dataColumn->getDefault());
}
public function testRenameTable()
{
// Simple rename then select test
$this->_createTestTable('sports');
$this->_conn->renameTable('sports', 'my_sports');
$sql = "SELECT id FROM my_sports WHERE id = 1";
$this->assertEquals("1", $this->_conn->selectValue($sql));
// Make sure the old table name isn't still there
try {
$sql = "SELECT id FROM sports WHERE id = 1";
$this->_conn->execute($sql);
} catch (Exception $e) {
return;
}
$this->fail("Table exists where it shouldn't have");
// Rename then insert test
$table = $this->_conn->createTable('octopuses');
$table->column('url', 'string');
$table->end();
$this->_conn->renameTable('octopuses', 'octopi');
$sql = "INSERT INTO octopi (id, url) VALUES (1, 'http://www.foreverflying.com/octopus-black7.jpg')";
$this->_conn->execute($sql);
$this->assertEquals('http://www.foreverflying.com/octopus-black7.jpg',
$this->_conn->selectValue("SELECT url FROM octopi WHERE id=1"));
// Make sure the old table name isn't still there
try {
$sql = "SELECT id FROM octopuses WHERE id = 1";
$this->_conn->execute($sql);
} catch (Exception $e) {
return;
}
$this->fail("Table exists where it shouldn't have");
}
public function testRenameTableWithAnIndex()
{
$table = $this->_conn->createTable('octopuses');
$table->column('url', 'string');
$table->end();
$this->_conn->addIndex('octopuses', 'url');
$this->_conn->renameTable('octopuses', 'octopi');
$sql = "INSERT INTO octopi (id, url) VALUES (1, 'http://www.foreverflying.com/octopus-black7.jpg')";
$this->_conn->execute($sql);
$this->assertEquals('http://www.foreverflying.com/octopus-black7.jpg',
$this->_conn->selectValue("SELECT url FROM octopi WHERE id=1"));
$indexes = $this->_conn->indexes('octopi');
$this->assertEquals('url', $indexes[0]->columns[0]);
}
public function testDropTable()
{
$this->_createTestTable('sports');
$this->_conn->dropTable('sports');
try {
$sql = "SELECT id FROM sports WHERE id = 1";
$this->_conn->execute($sql);
} catch (Exception $e) {
return;
}
$this->fail("Table exists where it shouldn't have");
}
public function testAddColumn()
{
$this->_createTestTable('sports');
$this->_conn->addColumn('sports', 'modified_at', 'date');
$this->_conn->update("UPDATE sports SET modified_at = '2007-01-01'");
$sql = "SELECT modified_at FROM sports WHERE id = 1";
$this->assertEquals("2007-01-01", $this->_conn->selectValue($sql));
$this->_conn->addColumn('sports', 'with_default', 'integer', array('default' => 1));
$sql = "SELECT with_default FROM sports WHERE id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
}
public function testRemoveColumn()
{
$this->_createTestTable('sports');
$sql = "SELECT name FROM sports WHERE id = 1";
$this->assertEquals("mlb", $this->_conn->selectValue($sql));
$this->_conn->removeColumn('sports', 'name');
try {
$sql = "SELECT name FROM sports WHERE id = 1";
$this->_conn->execute($sql);
} catch (Exception $e) {
return;
}
$this->fail("Column exists where it shouldn't have");
}
public function testChangeColumn()
{
$this->_createTestUsersTable();
$this->_conn->addColumn('users', 'age', 'integer');
$oldColumns = $this->_conn->columns('users', "User Columns");
$found = false;
foreach ($oldColumns as $c) {
if ($c->getName() == 'age' && $c->getType() == 'integer') { $found = true; }
}
$this->assertTrue($found);
$this->_conn->changeColumn('users', 'age', 'string');
$newColumns = $this->_conn->columns('users', "User Columns");
$found = false;
foreach ($newColumns as $c) {
if ($c->getName() == 'age' && $c->getType() == 'integer') { $found = true; }
}
$this->assertFalse($found);
$found = false;
foreach ($newColumns as $c) {
if ($c->getName() == 'age' && $c->getType() == 'string') { $found = true; }
}
$this->assertTrue($found);
$found = false;
foreach ($oldColumns as $c) {
if ($c->getName() == 'approved' && $c->getType() == 'boolean' &&
$c->getDefault() == true) { $found = true; }
}
$this->assertTrue($found);
// changeColumn() throws exception on error
$this->_conn->changeColumn('users', 'approved', 'boolean', array('default' => false));
$newColumns = $this->_conn->columns('users', "User Columns");
$found = false;
foreach ($newColumns as $c) {
if ($c->getName() == 'approved' && $c->getType() == 'boolean' &&
$c->getDefault() == true) { $found = true; }
}
$this->assertFalse($found);
$found = false;
foreach ($newColumns as $c) {
if ($c->getName() == 'approved' && $c->getType() == 'boolean' &&
$c->getDefault() == false) { $found = true; }
}
$this->assertTrue($found);
// changeColumn() throws exception on error
$this->_conn->changeColumn('users', 'approved', 'boolean', array('default' => true));
}
public function testChangeColumnDefault()
{
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'name');
$this->assertEquals('', $beforeChange->getDefault());
$this->_conn->changeColumnDefault('sports', 'name', 'test');
$afterChange = $this->_getColumn('sports', 'name');
$this->assertEquals('test', $afterChange->getDefault());
}
public function testChangeColumnType()
{
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('boolean', $beforeChange->getSqlType());
$this->_conn->changeColumn('sports', 'is_college', 'string');
$afterChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('varchar(255)', $afterChange->getSqlType());
$table = $this->_conn->createTable('text_to_binary');
$table->column('data', 'text');
$table->end();
$this->_conn->insert('INSERT INTO text_to_binary (data) VALUES (?)',
array("foobar"));
$this->_conn->changeColumn('text_to_binary', 'data', 'binary');
$afterChange = $this->_getColumn('text_to_binary', 'data');
$this->assertEquals('blob', $afterChange->getSqlType());
$this->assertEquals(
"foobar",
$this->_conn->selectValue('SELECT data FROM text_to_binary'));
}
public function testChangeColumnLimit()
{
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('boolean', $beforeChange->getSqlType());
$this->_conn->changeColumn('sports', 'is_college', 'string',
array('limit' => '40'));
$afterChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('varchar(40)', $afterChange->getSqlType());
}
public function testChangeColumnPrecisionScale()
{
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('boolean', $beforeChange->getSqlType());
$this->_conn->changeColumn('sports', 'is_college', 'decimal',
array('precision' => '5', 'scale' => '2'));
$afterChange = $this->_getColumn('sports', 'is_college');
$this->assertRegExp('/^decimal\(5,\s*2\)$/', $afterChange->getSqlType());
}
public function testRenameColumn()
{
$this->_createTestUsersTable();
$this->_conn->renameColumn('users', 'first_name', 'nick_name');
$this->assertTrue(in_array('nick_name', $this->_columnNames('users')));
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('boolean', $beforeChange->getSqlType());
$this->_conn->renameColumn('sports', 'is_college', 'is_renamed');
$afterChange = $this->_getColumn('sports', 'is_renamed');
$this->assertEquals('boolean', $afterChange->getSqlType());
}
public function testRenameColumnWithSqlReservedWord()
{
$this->_createTestUsersTable();
$this->_conn->renameColumn('users', 'first_name', 'group');
$this->assertTrue(in_array('group', $this->_columnNames('users')));
}
public function testAddIndex()
{
$this->_createTestUsersTable();
// Limit size of last_name and key columns to support Firebird index limitations
$this->_conn->addColumn('users', 'last_name', 'string', array('limit' => 100));
$this->_conn->addColumn('users', 'key', 'string', array('limit' => 100));
$this->_conn->addColumn('users', 'administrator', 'boolean');
$this->_conn->addIndex('users', 'last_name');
$this->_conn->removeIndex('users', 'last_name');
$this->_conn->addIndex('users', array('last_name', 'first_name'));
$this->_conn->removeIndex('users', array('column' => array('last_name', 'first_name')));
$this->_conn->addIndex('users', array('last_name', 'first_name'));
$this->_conn->removeIndex('users', array('name' => 'index_users_on_last_name_and_first_name'));
$this->_conn->addIndex('users', array('last_name', 'first_name'));
$this->_conn->removeIndex('users', 'last_name_and_first_name');
// quoting
$this->_conn->addIndex('users', array('key'), array('name' => 'key_idx', 'unique' => true));
$this->_conn->removeIndex('users', array('name' => 'key_idx', 'unique' => true));
$this->_conn->addIndex('users', array('last_name', 'first_name', 'administrator'),
array('name' => "named_admin"));
$this->_conn->removeIndex('users', array('name' => 'named_admin'));
}
public function testAddIndexDefault()
{
$this->_createTestTable('sports');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
$this->_conn->addIndex('sports', 'is_college');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
}
public function testAddIndexMultiColumn()
{
$this->_createTestTable('sports');
$index = $this->_getIndex('sports', array('name', 'is_college'));
$this->assertNull($index);
$this->_conn->addIndex('sports', array('name', 'is_college'));
$index = $this->_getIndex('sports', array('name', 'is_college'));
$this->assertNotNull($index);
}
public function testAddIndexUnique()
{
$this->_createTestTable('sports');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
$this->_conn->addIndex('sports', 'is_college', array('unique' => true));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
$this->assertTrue($index->unique);
}
public function testAddIndexName()
{
$this->_createTestTable('sports');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
$this->_conn->addIndex('sports', 'is_college', array('name' => 'test'));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
$this->assertEquals('test', $index->name);
}
public function testRemoveIndexSingleColumn()
{
$this->_createTestTable('sports');
// add the index
$this->_conn->addIndex('sports', 'is_college');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
// remove it again
$this->_conn->removeIndex('sports', array('column' => 'is_college'));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
}
public function testRemoveIndexMultiColumn()
{
$this->_createTestTable('sports');
// add the index
$this->_conn->addIndex('sports', array('name', 'is_college'));
$index = $this->_getIndex('sports', array('name', 'is_college'));
$this->assertNotNull($index);
// remove it again
$this->_conn->removeIndex('sports', array('column' => array('name', 'is_college')));
$index = $this->_getIndex('sports', array('name', 'is_college'));
$this->assertNull($index);
}
public function testRemoveIndexByName()
{
$this->_createTestTable('sports');
// add the index
$this->_conn->addIndex('sports', 'is_college', array('name' => 'test'));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
// remove it again
$this->_conn->removeIndex('sports', array('name' => 'test'));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
}
public function testIndexNameInvalid()
{
try {
$name = $this->_conn->indexName('sports');
} catch (Horde_Db_Exception $e) {
return;
}
$this->fail("Adding an index with crappy options worked where it shouldn't have");
}
public function testIndexNameBySingleColumn()
{
$name = $this->_conn->indexName('sports', array('column' => 'is_college'));
$this->assertEquals('index_sports_on_is_college', $name);
}
public function testIndexNameByMultiColumn()
{
$name = $this->_conn->indexName('sports', array('column' =>
array('name', 'is_college')));
$this->assertEquals('index_sports_on_name_and_is_college', $name);
}
public function testIndexNameByName()
{
$name = $this->_conn->indexName('sports', array('name' => 'test'));
$this->assertEquals('test', $name);
}
public function testTypeToSqlTypePrimaryKey()
{
$result = $this->_conn->typeToSql('autoincrementKey');
$this->assertEquals('INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL', $result);
}
public function testTypeToSqlTypeString()
{
$result = $this->_conn->typeToSql('string');
$this->assertEquals('varchar(255)', $result);
}
public function testTypeToSqlTypeText()
{
$result = $this->_conn->typeToSql('text');
$this->assertEquals('text', $result);
}
public function testTypeToSqlTypeBinary()
{
$result = $this->_conn->typeToSql('binary');
$this->assertEquals('blob', $result);
}
public function testTypeToSqlTypeFloat()
{
$result = $this->_conn->typeToSql('float');
$this->assertEquals('float', $result);
}
public function testTypeToSqlTypeDatetime()
{
$result = $this->_conn->typeToSql('datetime');
$this->assertEquals('datetime', $result);
}
public function testTypeToSqlTypeTimestamp()
{
$result = $this->_conn->typeToSql('timestamp');
$this->assertEquals('datetime', $result);
}
public function testTypeToSqlInt()
{
$result = $this->_conn->typeToSql('integer');
$this->assertEquals('int', $result);
}
public function testTypeToSqlIntLimit()
{
$result = $this->_conn->typeToSql('integer', '1');
$this->assertEquals('int(1)', $result);
}
public function testTypeToSqlDecimalPrecision()
{
$result = $this->_conn->typeToSql('decimal', null, '5');
$this->assertEquals('decimal(5)', $result);
}
public function testTypeToSqlDecimalScale()
{
$result = $this->_conn->typeToSql('decimal', null, '5', '2');
$this->assertEquals('decimal(5, 2)', $result);
}
public function testTypeToSqlBoolean()
{
$result = $this->_conn->typeToSql('boolean');
$this->assertEquals('boolean', $result);
}
public function testAddColumnOptions()
{
$result = $this->_conn->addColumnOptions('test', array());
$this->assertEquals('test', $result);
}
public function testAddColumnOptionsDefault()
{
$options = array('default' => '0');
$result = $this->_conn->addColumnOptions('test', $options);
$this->assertEquals("test DEFAULT '0'", $result);
}
public function testAddColumnOptionsNull()
{
$options = array('null' => true);
$result = $this->_conn->addColumnOptions('test', $options);
$this->assertEquals('test', $result);
}
public function testAddColumnOptionsNotNull()
{
$options = array('null' => false);
$result = $this->_conn->addColumnOptions('test', $options);
$this->assertEquals('test NOT NULL', $result);
}
public function testAddColumnNotNullWithoutDefault()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string');
$table->end();
$this->_conn->addColumn('testings', 'bar', 'string', array('null' => false, 'default' => ''));
try {
$this->_conn->execute("INSERT INTO testings (foo, bar) VALUES ('hello', NULL)");
} catch (Exception $e) { return; }
$this->fail('Expected exception wasn\'t raised');
}
public function testAddColumnNotNullWithDefault()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string');
$table->end();
$this->_conn->execute("INSERT INTO testings (id, foo) VALUES ('1', 'hello')");
$this->_conn->addColumn('testings', 'bar', 'string', array('null' => false, 'default' => 'default'));
try {
$this->_conn->execute("INSERT INTO testings (id, foo, bar) VALUES (2, 'hello', NULL)");
} catch (Exception $e) { return; }
$this->fail('Expected exception wasn\'t raised');
}
public function testAddRemoveSingleField()
{
$this->_createTestUsersTable();
$this->assertFalse(in_array('last_name', $this->_columnNames('users')));
$this->_conn->addColumn('users', 'last_name', 'string');
$this->assertTrue(in_array('last_name', $this->_columnNames('users')));
$this->_conn->removeColumn('users', 'last_name');
$this->assertFalse(in_array('last_name', $this->_columnNames('users')));
}
public function testAddRename()
{
$this->_createTestUsersTable();
$this->_conn->delete('DELETE FROM users');
$this->_conn->addColumn('users', 'girlfriend', 'string');
$this->_conn->insert("INSERT INTO users (girlfriend) VALUES ('bobette')");
$this->_conn->renameColumn('users', 'girlfriend', 'exgirlfriend');
$bob = (object)$this->_conn->selectOne('SELECT * FROM users');
$this->assertEquals('bobette', $bob->exgirlfriend);
}
public function testDistinct()
{
$result = $this->_conn->distinct('test');
$this->assertEquals('DISTINCT test', $result);
}
public function testAddOrderByForAssocLimiting()
{
$result = $this->_conn->addOrderByForAssocLimiting('SELECT * FROM documents ',
array('order' => 'name DESC'));
$this->assertEquals('SELECT * FROM documents ORDER BY name DESC', $result);
}
public function testModifyDate()
{
$modifiedDate = $this->_conn->modifyDate('start', '+', 1, 'DAY');
$this->assertEquals('datetime(start, \'+1 days\')', $modifiedDate);
$t = $this->_conn->createTable('dates');
$t->column('start', 'datetime');
$t->column('end', 'datetime');
$t->end();
$this->_conn->insert(
'INSERT INTO dates (start, end) VALUES (?, ?)',
array(
'2011-12-10 00:00:00',
'2011-12-11 00:00:00'
)
);
$this->assertEquals(
1,
$this->_conn->selectValue('SELECT COUNT(*) FROM dates WHERE '
. $modifiedDate . ' = end')
);
$this->assertEquals(
'datetime(start, \'+2 seconds\')',
$this->_conn->modifyDate('start', '+', 2, 'SECOND'));
$this->assertEquals(
'datetime(start, \'+3 minutes\')',
$this->_conn->modifyDate('start', '+', 3, 'MINUTE'));
$this->assertEquals(
'datetime(start, \'+4 hours\')',
$this->_conn->modifyDate('start', '+', 4, 'HOUR'));
$this->assertEquals(
'datetime(start, \'-2 months\')',
$this->_conn->modifyDate('start', '-', 2, 'MONTH'));
$this->assertEquals(
'datetime(start, \'-3 years\')',
$this->_conn->modifyDate('start', '-', 3, 'YEAR'));
}
public function testBuildClause()
{
$this->assertEquals(
'bitmap & 2',
$this->_conn->buildClause('bitmap', '&', 2));
$this->assertEquals(
array('bitmap & ?', array(2)),
$this->_conn->buildClause('bitmap', '&', 2, true));
$this->assertEquals(
'bitmap | 2',
$this->_conn->buildClause('bitmap', '|', 2));
$this->assertEquals(
array('bitmap | ?', array(2)),
$this->_conn->buildClause('bitmap', '|', 2, true));
$this->assertEquals(
"LOWER(name) LIKE LOWER('%search%')",
$this->_conn->buildClause('name', 'LIKE', "search"));
$this->assertEquals(
array("LOWER(name) LIKE LOWER(?)", array('%search%')),
$this->_conn->buildClause('name', 'LIKE', "search", true));
$this->assertEquals(
"LOWER(name) LIKE LOWER('%search\&replace\?%')",
$this->_conn->buildClause('name', 'LIKE', "search&replace?"));
$this->assertEquals(
array("LOWER(name) LIKE LOWER(?)", array('%search&replace?%')),
$this->_conn->buildClause('name', 'LIKE', "search&replace?", true));
$this->assertEquals(
"(LOWER(name) LIKE LOWER('search\&replace\?%') OR LOWER(name) LIKE LOWER('% search\&replace\?%'))",
$this->_conn->buildClause('name', 'LIKE', "search&replace?", false, array('begin' => true)));
$this->assertEquals(
array("(LOWER(name) LIKE LOWER(?) OR LOWER(name) LIKE LOWER(?))",
array('search&replace?%', '% search&replace?%')),
$this->_conn->buildClause('name', 'LIKE', "search&replace?", true, array('begin' => true)));
$this->assertEquals(
'value = 2',
$this->_conn->buildClause('value', '=', 2));
$this->assertEquals(
array('value = ?', array(2)),
$this->_conn->buildClause('value', '=', 2, true));
$this->assertEquals(
"value = 'foo'",
$this->_conn->buildClause('value', '=', 'foo'));
$this->assertEquals(
array('value = ?', array('foo')),
$this->_conn->buildClause('value', '=', 'foo', true));
$this->assertEquals(
"value = 'foo\?bar'",
$this->_conn->buildClause('value', '=', 'foo?bar'));
$this->assertEquals(
array('value = ?', array('foo?bar')),
$this->_conn->buildClause('value', '=', 'foo?bar', true));
}
public function testInsertAndReadInCp1257()
{
list($conn,) = self::getConnection(array('charset' => 'cp1257'));
$table = $conn->createTable('charset_cp1257');
$table->column('text', 'string');
$table->end();
$input = file_get_contents(__DIR__ . '/../../fixtures/charsets/cp1257.txt');
$conn->insert("INSERT INTO charset_cp1257 (text) VALUES (?)", array($input));
$output = $conn->selectValue('SELECT text FROM charset_cp1257');
$this->assertEquals($input, $output);
}
public function testInsertAndReadInUtf8()
{
list($conn,) = self::getConnection(array('charset' => 'utf8'));
$table = $conn->createTable('charset_utf8');
$table->column('text', 'string');
$table->end();
$input = file_get_contents(__DIR__ . '/../../fixtures/charsets/utf8.txt');
$conn->insert("INSERT INTO charset_utf8 (text) VALUES (?)", array($input));
$output = $conn->selectValue('SELECT text FROM charset_utf8');
$this->assertEquals($input, $output);
}
/*##########################################################################
# Table cache
##########################################################################*/
public function testCachedTableIndexes()
{
// remove any current cache.
$this->_cache->set('tables/indexes/cache_table', '');
$this->assertEquals('', $this->_cache->get('tables/indexes/cache_table', 0));
$this->_createTestTable('cache_table');
$idxs = $this->_conn->indexes('cache_table');
$this->assertNotEquals('', $this->_cache->get('tables/indexes/cache_table', 0));
}
public function testCachedTableColumns()
{
// remove any current cache.
$this->_cache->set('tables/columns/cache_table', '');
$this->assertEquals('', $this->_cache->get('tables/columns/cache_table', 0));
$this->_createTestTable('cache_table');
$cols = $this->_conn->columns('cache_table');
$this->assertNotEquals('', $this->_cache->get('tables/columns/cache_table', 0));
}
/*##########################################################################
# Protected
##########################################################################*/
/**
* Create table to perform tests on
*/
protected function _createTestTable($name, $options=array())
{
$table = $this->_conn->createTable($name, $options);
$table->column('name', 'string');
$table->column('is_college', 'boolean');
$table->end();
try {
// make sure table was created
$sql = "INSERT INTO $name
VALUES (1, 'mlb', 0)";
$this->_conn->insert($sql);
} catch (Exception $e) {}
}
protected function _createTestUsersTable()
{
$table = $this->_conn->createTable('users');
$table->column('company_id', 'integer', array('limit' => 11));
$table->column('name', 'string', array('limit' => 255, 'default' => ''));
$table->column('first_name', 'string', array('limit' => 40, 'default' => ''));
$table->column('approved', 'boolean', array('default' => true));
$table->column('type', 'string', array('limit' => 255, 'default' => ''));
$table->column('created_at', 'datetime', array('default' => '0000-00-00 00:00:00'));
$table->column('created_on', 'date', array('default' => '0000-00-00'));
$table->column('updated_at', 'datetime', array('default' => '0000-00-00 00:00:00'));
$table->column('updated_on', 'date', array('default' => '0000-00-00'));
$table->end();
}
protected function _columnNames($tableName)
{
$columns = array();
foreach ($this->_conn->columns($tableName) as $c) {
$columns[] = $c->getName();
}
return $columns;
}
/**
* Get a column by name
*/
protected function _getColumn($table, $column)
{
foreach ($this->_conn->columns($table) as $col) {
if ($col->getName() == $column) return $col;
}
}
/**
* Get an index by columns
*/
protected function _getIndex($table, $indexes)
{
$indexes = (array) $indexes;
sort($indexes);
foreach ($this->_conn->indexes($table) as $index) {
$columns = $index->columns;
sort($columns);
if ($columns == $indexes) return $index;
}
}
}
Horde_Db-2.0.4/test/Horde/Db/Adapter/Postgresql/ColumnDefinitionTest.php 0000664 0001750 0001750 00000007147 12205351473 024211 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage UnitTests
*/
require_once __DIR__ . '/../Pdo/PgsqlBase.php';
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @group horde_db
* @category Horde
* @package Db
* @subpackage UnitTests
*/
class Horde_Db_Adapter_Postgresql_ColumnDefinitionTest extends Horde_Db_Adapter_Pdo_PgsqlBase
{
protected function setUp()
{
parent::setUp();
list($this->_conn,) = self::getConnection();
}
public function testConstruct()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->_conn, 'col_name', 'string'
);
$this->assertEquals('col_name', $col->getName());
$this->assertEquals('string', $col->getType());
}
public function testToSql()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->_conn, 'col_name', 'string'
);
$this->assertEquals('"col_name" character varying(255)', $col->toSql());
}
public function testToSqlLimit()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->_conn, 'col_name', 'string', 40
);
$this->assertEquals('"col_name" character varying(40)', $col->toSql());
// set attribute instead
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->_conn, 'col_name', 'string'
);
$col->setLimit(40);
$this->assertEquals('"col_name" character varying(40)', $col->toSql());
}
public function testToSqlPrecisionScale()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->_conn, 'col_name', 'decimal', null, 5, 2
);
$this->assertEquals('"col_name" decimal(5, 2)', $col->toSql());
// set attribute instead
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->_conn, 'col_name', 'decimal'
);
$col->setPrecision(5);
$col->setScale(2);
$this->assertEquals('"col_name" decimal(5, 2)', $col->toSql());
}
public function testToSqlNotNull()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->_conn, 'col_name', 'string', null, null, null, null, null, false
);
$this->assertEquals('"col_name" character varying(255) NOT NULL', $col->toSql());
// set attribute instead
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->_conn, 'col_name', 'string'
);
$col->setNull(false);
$this->assertEquals('"col_name" character varying(255) NOT NULL', $col->toSql());
}
public function testToSqlDefault()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->_conn, 'col_name', 'string', null, null, null, null, 'test'
);
$this->assertEquals('"col_name" character varying(255) DEFAULT \'test\'', $col->toSql());
// set attribute instead
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->_conn, 'col_name', 'string'
);
$col->setDefault('test');
$this->assertEquals('"col_name" character varying(255) DEFAULT \'test\'', $col->toSql());
}
}
Horde_Db-2.0.4/test/Horde/Db/Adapter/Postgresql/ColumnTest.php 0000664 0001750 0001750 00000022232 12205351473 022170 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage UnitTests
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @group horde_db
* @category Horde
* @package Db
* @subpackage UnitTests
*/
class Horde_Db_Adapter_Postgresql_ColumnTest extends Horde_Test_Case
{
/*##########################################################################
# Construction
##########################################################################*/
public function testDefaultNull()
{
$col = new Horde_Db_Adapter_Postgresql_Column('name', 'NULL', 'character varying(255)');
$this->assertEquals(true, $col->isNull());
}
public function testNotNull()
{
$col = new Horde_Db_Adapter_Postgresql_Column('name', 'NULL', 'character varying(255)', false);
$this->assertEquals(false, $col->isNull());
}
public function testName()
{
$col = new Horde_Db_Adapter_Postgresql_Column('name', 'NULL', 'character varying(255)');
$this->assertEquals('name', $col->getName());
}
public function testSqlType()
{
$col = new Horde_Db_Adapter_Postgresql_Column('name', 'NULL', 'character varying(255)');
$this->assertEquals('character varying(255)', $col->getSqlType());
}
public function testIsText()
{
$col = new Horde_Db_Adapter_Postgresql_Column('test', 'NULL', 'character varying(255)');
$this->assertTrue($col->isText());
$col = new Horde_Db_Adapter_Postgresql_Column('test', 'NULL', 'text');
$this->assertTrue($col->isText());
$col = new Horde_Db_Adapter_Postgresql_Column('test', 'NULL', 'int(11)');
$this->assertFalse($col->isText());
$col = new Horde_Db_Adapter_Postgresql_Column('test', 'NULL', 'float(11,1)');
$this->assertFalse($col->isText());
}
public function testIsNumber()
{
$col = new Horde_Db_Adapter_Postgresql_Column('test', 'NULL', 'character varying(255)');
$this->assertFalse($col->isNumber());
$col = new Horde_Db_Adapter_Postgresql_Column('test', 'NULL', 'text');
$this->assertFalse($col->isNumber());
$col = new Horde_Db_Adapter_Postgresql_Column('test', 'NULL', 'int(11)');
$this->assertTrue($col->isNumber());
$col = new Horde_Db_Adapter_Postgresql_Column('test', 'NULL', 'float(11,1)');
$this->assertTrue($col->isNumber());
}
/*##########################################################################
# Types
##########################################################################*/
public function testTypeInteger()
{
$col = new Horde_Db_Adapter_Postgresql_Column('age', 'NULL', 'int(11)');
$this->assertEquals('integer', $col->getType());
}
public function testTypeFloat()
{
$col = new Horde_Db_Adapter_Postgresql_Column('age', 'NULL', 'float(11,1)');
$this->assertEquals('float', $col->getType());
}
public function testTypeDecimalPrecisionNone()
{
$col = new Horde_Db_Adapter_Postgresql_Column('age', 'NULL', 'decimal(11,0)');
$this->assertEquals('integer', $col->getType());
}
public function testTypeDecimal()
{
$col = new Horde_Db_Adapter_Postgresql_Column('age', 'NULL', 'decimal(11,1)');
$this->assertEquals('decimal', $col->getType());
}
public function testTypeDatetime()
{
$col = new Horde_Db_Adapter_Postgresql_Column('age', 'NULL', 'datetime');
$this->assertEquals('datetime', $col->getType());
}
public function testTypeTimestamp()
{
$col = new Horde_Db_Adapter_Postgresql_Column('age', 'CURRENT_TIMESTAMP', 'timestamp');
$this->assertEquals('timestamp', $col->getType());
}
public function testTypeTime()
{
$col = new Horde_Db_Adapter_Postgresql_Column('age', 'NULL', 'time');
$this->assertEquals('time', $col->getType());
}
public function testTypeDate()
{
$col = new Horde_Db_Adapter_Postgresql_Column('age', 'NULL', 'date');
$this->assertEquals('date', $col->getType());
}
public function testTypeText()
{
$col = new Horde_Db_Adapter_Postgresql_Column('age', 'NULL', 'text');
$this->assertEquals('text', $col->getType());
}
public function testTypeBinary()
{
$col = new Horde_Db_Adapter_Postgresql_Column('age', 'NULL', 'blob(255)');
$this->assertEquals('binary', $col->getType());
}
public function testTypeString()
{
$col = new Horde_Db_Adapter_Postgresql_Column('name', 'NULL', 'character varying(255)');
$this->assertEquals('string', $col->getType());
}
/*##########################################################################
# Extract Limit
##########################################################################*/
public function testExtractLimitInt()
{
$col = new Horde_Db_Adapter_Postgresql_Column('test', 'NULL', 'int(11)');
$this->assertEquals(11, $col->getLimit());
}
public function testExtractLimitVarchar()
{
$col = new Horde_Db_Adapter_Postgresql_Column('test', 'NULL', 'character varying(255)');
$this->assertEquals(255, $col->getLimit());
}
public function testExtractLimitDecimal()
{
$col = new Horde_Db_Adapter_Postgresql_Column('test', 'NULL', 'decimal(11,1)');
$this->assertEquals('11', $col->getLimit());
}
public function testExtractLimitText()
{
$col = new Horde_Db_Adapter_Postgresql_Column('test', 'NULL', 'text');
$this->assertEquals(null, $col->getLimit());
}
public function testExtractLimitNone()
{
$col = new Horde_Db_Adapter_Postgresql_Column('test', 'NULL');
$this->assertEquals(null, $col->getLimit());
}
/*##########################################################################
# Extract Precision/Scale
##########################################################################*/
public function testExtractPrecisionScale()
{
$col = new Horde_Db_Adapter_Postgresql_Column('test', 'NULL', 'decimal(12,1)');
$this->assertEquals('12', $col->precision());
$this->assertEquals('1', $col->scale());
}
/*##########################################################################
# Type Cast Values
##########################################################################*/
public function testTypeCastInteger()
{
$col = new Horde_Db_Adapter_Postgresql_Column('name', '1', 'int(11)', false);
$this->assertEquals(1, $col->getDefault());
}
public function testTypeCastFloat()
{
$col = new Horde_Db_Adapter_Postgresql_Column('version', '1.0', 'float(11,1)', false);
$this->assertEquals(1.0, $col->getDefault());
}
public function testTypeCastString()
{
$col = new Horde_Db_Adapter_Postgresql_Column('name', "'n/a'::character varying", 'character varying(255)', false);
$this->assertEquals('n/a', $col->getDefault());
}
public function testTypeCastBooleanFalse()
{
$col = new Horde_Db_Adapter_Postgresql_Column('is_active', '0', 'boolean', false);
$this->assertSame(false, $col->getDefault());
}
public function testTypeCastBooleanTrue()
{
$col = new Horde_Db_Adapter_Postgresql_Column('is_active', '1', 'boolean', false);
$this->assertSame(true, $col->getDefault());
}
/*##########################################################################
# Column Types
##########################################################################*/
/*@TODO tests for PostgreSQL-specific column types */
/*##########################################################################
# Defaults
##########################################################################*/
public function testDefaultDatetime()
{
$col = new Horde_Db_Adapter_Postgresql_Column('name', '', 'datetime');
$this->assertEquals(null, $col->getDefault());
}
public function testDefaultInteger()
{
$col = new Horde_Db_Adapter_Postgresql_Column('name', '', 'int(11)');
$this->assertEquals(null, $col->getDefault());
}
public function testDefaultString()
{
$col = new Horde_Db_Adapter_Postgresql_Column('name', '', 'character varying(255)');
$this->assertEquals('', $col->getDefault());
}
public function testDefaultText()
{
$col = new Horde_Db_Adapter_Postgresql_Column('name', '', 'text');
$this->assertEquals('', $col->getDefault());
}
public function testDefaultBinary()
{
$col = new Horde_Db_Adapter_Postgresql_Column('name', '', 'blob(255)');
$this->assertEquals('', $col->getDefault());
}
}
Horde_Db-2.0.4/test/Horde/Db/Adapter/Postgresql/TableDefinitionTest.php 0000664 0001750 0001750 00000003423 12205351473 023774 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage UnitTests
*/
require_once __DIR__ . '/../Pdo/PgsqlBase.php';
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @group horde_db
* @category Horde
* @package Db
* @subpackage UnitTests
*/
class Horde_Db_Adapter_Postgresql_TableDefinitionTest extends Horde_Db_Adapter_Pdo_PgsqlBase
{
protected function setUp()
{
parent::setUp();
list($this->_conn,) = self::getConnection();
}
/*##########################################################################
# Public methods
##########################################################################*/
public function testConstruct()
{
}
public function testName()
{
}
public function testGetOptions()
{
}
public function testPrimaryKey()
{
}
public function testColumn()
{
}
public function testToSql()
{
}
/*##########################################################################
# Array Access
##########################################################################*/
public function testOffsetExists()
{
}
public function testOffsetGet()
{
}
public function testOffsetSet()
{
}
public function testOffsetUnset()
{
}
}
Horde_Db-2.0.4/test/Horde/Db/Adapter/Sqlite/ColumnDefinitionTest.php 0000664 0001750 0001750 00000007636 12205351473 023312 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage UnitTests
*/
require_once __DIR__ . '/../Pdo/SqliteBase.php';
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @group horde_db
* @category Horde
* @package Db
* @subpackage UnitTests
*/
class Horde_Db_Adapter_Sqlite_ColumnDefinitionTest extends Horde_Db_Adapter_Pdo_SqliteBase
{
protected function setUp()
{
parent::setUp();
list($this->_conn,) = self::getConnection();
}
protected function tearDown()
{
// close connection
$this->_conn->disconnect();
}
public function testConstruct()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->_conn, 'col_name', 'string'
);
$this->assertEquals('col_name', $col->getName());
$this->assertEquals('string', $col->getType());
}
public function testToSql()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->_conn, 'col_name', 'string'
);
$this->assertEquals('"col_name" varchar(255)', $col->toSql());
}
public function testToSqlLimit()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->_conn, 'col_name', 'string', 40
);
$this->assertEquals('"col_name" varchar(40)', $col->toSql());
// set attribute instead
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->_conn, 'col_name', 'string'
);
$col->setLimit(40);
$this->assertEquals('"col_name" varchar(40)', $col->toSql());
}
public function testToSqlPrecisionScale()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->_conn, 'col_name', 'decimal', null, 5, 2
);
$this->assertEquals('"col_name" decimal(5, 2)', $col->toSql());
// set attribute instead
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->_conn, 'col_name', 'decimal'
);
$col->setPrecision(5);
$col->setScale(2);
$this->assertEquals('"col_name" decimal(5, 2)', $col->toSql());
}
public function testToSqlNotNull()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->_conn, 'col_name', 'string', null, null, null, null, null, false
);
$this->assertEquals('"col_name" varchar(255) NOT NULL', $col->toSql());
// set attribute instead
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->_conn, 'col_name', 'string'
);
$col->setNull(false);
$this->assertEquals('"col_name" varchar(255) NOT NULL', $col->toSql());
// set attribute to the default (true)
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->_conn, 'col_name', 'string'
);
$col->setNull(true);
$this->assertEquals('"col_name" varchar(255)', $col->toSql());
}
public function testToSqlDefault()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->_conn, 'col_name', 'string', null, null, null, null, 'test', null
);
$this->assertEquals('"col_name" varchar(255) DEFAULT \'test\'', $col->toSql());
// set attribute instead
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
$this->_conn, 'col_name', 'string'
);
$col->setDefault('test');
$this->assertEquals('"col_name" varchar(255) DEFAULT \'test\'', $col->toSql());
}
}
Horde_Db-2.0.4/test/Horde/Db/Adapter/Sqlite/ColumnTest.php 0000664 0001750 0001750 00000021206 12205351473 021266 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage UnitTests
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @group horde_db
* @category Horde
* @package Db
* @subpackage UnitTests
*/
class Horde_Db_Adapter_Sqlite_ColumnTest extends Horde_Test_Case
{
/*##########################################################################
# Construction
##########################################################################*/
public function testDefaultNull()
{
$col = new Horde_Db_Adapter_Sqlite_Column('name', 'NULL', 'varchar(255)');
$this->assertEquals(true, $col->isNull());
}
public function testNotNull()
{
$col = new Horde_Db_Adapter_Sqlite_Column('name', 'NULL', 'varchar(255)', false);
$this->assertEquals(false, $col->isNull());
}
public function testName()
{
$col = new Horde_Db_Adapter_Sqlite_Column('name', 'NULL', 'varchar(255)');
$this->assertEquals('name', $col->getName());
}
public function testSqlType()
{
$col = new Horde_Db_Adapter_Sqlite_Column('name', 'NULL', 'varchar(255)');
$this->assertEquals('varchar(255)', $col->getSqlType());
}
public function testIsText()
{
$col = new Horde_Db_Adapter_Sqlite_Column('test', 'NULL', 'varchar(255)');
$this->assertTrue($col->isText());
$col = new Horde_Db_Adapter_Sqlite_Column('test', 'NULL', 'text');
$this->assertTrue($col->isText());
$col = new Horde_Db_Adapter_Sqlite_Column('test', 'NULL', 'int(11)');
$this->assertFalse($col->isText());
$col = new Horde_Db_Adapter_Sqlite_Column('test', 'NULL', 'float(11,1)');
$this->assertFalse($col->isText());
}
public function testIsNumber()
{
$col = new Horde_Db_Adapter_Sqlite_Column('test', 'NULL', 'varchar(255)');
$this->assertFalse($col->isNumber());
$col = new Horde_Db_Adapter_Sqlite_Column('test', 'NULL', 'text');
$this->assertFalse($col->isNumber());
$col = new Horde_Db_Adapter_Sqlite_Column('test', 'NULL', 'int(11)');
$this->assertTrue($col->isNumber());
$col = new Horde_Db_Adapter_Sqlite_Column('test', 'NULL', 'float(11,1)');
$this->assertTrue($col->isNumber());
}
/*##########################################################################
# Types
##########################################################################*/
public function testTypeInteger()
{
$col = new Horde_Db_Adapter_Sqlite_Column('age', 'NULL', 'int(11)');
$this->assertEquals('integer', $col->getType());
}
public function testTypeFloat()
{
$col = new Horde_Db_Adapter_Sqlite_Column('age', 'NULL', 'float(11,1)');
$this->assertEquals('float', $col->getType());
}
public function testTypeDecimalPrecisionNone()
{
$col = new Horde_Db_Adapter_Sqlite_Column('age', 'NULL', 'decimal(11,0)');
$this->assertEquals('integer', $col->getType());
}
public function testTypeDecimal()
{
$col = new Horde_Db_Adapter_Sqlite_Column('age', 'NULL', 'decimal(11,1)');
$this->assertEquals('decimal', $col->getType());
}
public function testTypeDatetime()
{
$col = new Horde_Db_Adapter_Sqlite_Column('age', 'NULL', 'datetime');
$this->assertEquals('datetime', $col->getType());
}
public function testTypeTimestamp()
{
$col = new Horde_Db_Adapter_Sqlite_Column('age', 'CURRENT_TIMESTAMP', 'timestamp');
$this->assertEquals('timestamp', $col->getType());
}
public function testTypeTime()
{
$col = new Horde_Db_Adapter_Sqlite_Column('age', 'NULL', 'time');
$this->assertEquals('time', $col->getType());
}
public function testTypeDate()
{
$col = new Horde_Db_Adapter_Sqlite_Column('age', 'NULL', 'date');
$this->assertEquals('date', $col->getType());
}
public function testTypeText()
{
$col = new Horde_Db_Adapter_Sqlite_Column('age', 'NULL', 'text');
$this->assertEquals('text', $col->getType());
}
public function testTypeBinary()
{
$col = new Horde_Db_Adapter_Sqlite_Column('age', 'NULL', 'blob(255)');
$this->assertEquals('binary', $col->getType());
}
public function testTypeString()
{
$col = new Horde_Db_Adapter_Sqlite_Column('name', 'NULL', 'varchar(255)');
$this->assertEquals('string', $col->getType());
}
/*##########################################################################
# Extract Limit
##########################################################################*/
public function testExtractLimitInt()
{
$col = new Horde_Db_Adapter_Sqlite_Column('test', 'NULL', 'int(11)');
$this->assertEquals(11, $col->getLimit());
}
public function testExtractLimitVarchar()
{
$col = new Horde_Db_Adapter_Sqlite_Column('test', 'NULL', 'varchar(255)');
$this->assertEquals(255, $col->getLimit());
}
public function testExtractLimitDecimal()
{
$col = new Horde_Db_Adapter_Sqlite_Column('test', 'NULL', 'decimal(11,1)');
$this->assertEquals('11', $col->getLimit());
}
public function testExtractLimitText()
{
$col = new Horde_Db_Adapter_Sqlite_Column('test', 'NULL', 'text');
$this->assertEquals(null, $col->getLimit());
}
public function testExtractLimitNone()
{
$col = new Horde_Db_Adapter_Sqlite_Column('test', 'NULL');
$this->assertEquals(null, $col->getLimit());
}
/*##########################################################################
# Extract Precision/Scale
##########################################################################*/
public function testExtractPrecisionScale()
{
$col = new Horde_Db_Adapter_Sqlite_Column('test', 'NULL', 'decimal(12,1)');
$this->assertEquals('12', $col->precision());
$this->assertEquals('1', $col->scale());
}
/*##########################################################################
# Type Cast Values
##########################################################################*/
public function testTypeCastInteger()
{
$col = new Horde_Db_Adapter_Sqlite_Column('name', '1', 'int(11)', false);
$this->assertEquals(1, $col->getDefault());
}
public function testTypeCastFloat()
{
$col = new Horde_Db_Adapter_Sqlite_Column('version', '1.0', 'float(11,1)', false);
$this->assertEquals(1.0, $col->getDefault());
}
public function testTypeCastString()
{
$col = new Horde_Db_Adapter_Sqlite_Column('name', 'n/a', 'varchar(255)', false);
$this->assertEquals('n/a', $col->getDefault());
}
public function testTypeCastBooleanFalse()
{
$col = new Horde_Db_Adapter_Sqlite_Column('is_active', 'f', 'boolean', false);
$this->assertSame(false, $col->getDefault());
}
public function testTypeCastBooleanTrue()
{
$col = new Horde_Db_Adapter_Sqlite_Column('is_active', 't', 'boolean', false);
$this->assertSame(true, $col->getDefault());
}
/*##########################################################################
# Defaults
##########################################################################*/
public function testDefaultDatetime()
{
$col = new Horde_Db_Adapter_Sqlite_Column('name', '', 'datetime');
$this->assertEquals(null, $col->getDefault());
}
public function testDefaultInteger()
{
$col = new Horde_Db_Adapter_Sqlite_Column('name', '', 'int(11)');
$this->assertEquals(null, $col->getDefault());
}
public function testDefaultString()
{
$col = new Horde_Db_Adapter_Sqlite_Column('name', '', 'varchar(255)');
$this->assertEquals('', $col->getDefault());
}
public function testDefaultText()
{
$col = new Horde_Db_Adapter_Sqlite_Column('name', '', 'text');
$this->assertEquals('', $col->getDefault());
}
public function testDefaultBinary()
{
$col = new Horde_Db_Adapter_Sqlite_Column('name', '', 'blob(255)');
$this->assertEquals('', $col->getDefault());
}
}
Horde_Db-2.0.4/test/Horde/Db/Adapter/Sqlite/TableDefinitionTest.php 0000664 0001750 0001750 00000003600 12205351473 023067 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage UnitTests
*/
require_once __DIR__ . '/../Pdo/SqliteBase.php';
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @group horde_db
* @category Horde
* @package Db
* @subpackage UnitTests
*/
class Horde_Db_Adapter_Sqlite_TableDefinitionTest extends Horde_Db_Adapter_Pdo_SqliteBase
{
protected function setUp()
{
parent::setUp();
list($this->_conn,) = self::getConnection();
}
protected function tearDown()
{
// close connection
$this->_conn->disconnect();
}
/*##########################################################################
# Public methods
##########################################################################*/
public function testConstruct()
{
}
public function testName()
{
}
public function testGetOptions()
{
}
public function testPrimaryKey()
{
}
public function testColumn()
{
}
public function testToSql()
{
}
/*##########################################################################
# Array Access
##########################################################################*/
public function testOffsetExists()
{
}
public function testOffsetGet()
{
}
public function testOffsetSet()
{
}
public function testOffsetUnset()
{
}
}
Horde_Db-2.0.4/test/Horde/Db/Adapter/conf.php.dist 0000644 0001750 0001750 00000002103 12205351473 017610 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @author Jan Schneider
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage UnitTests
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @author Jan Schneider
* @license http://www.horde.org/licenses/bsd
* @group horde_db
* @category Horde
* @package Db
* @subpackage UnitTests
*/
class Horde_Db_Adapter_MysqliTest extends Horde_Test_Case
{
protected static $columnTest;
protected static $tableTest;
protected static $skip = true;
protected static $reason = 'The MySQLi adapter is not available';
public static function setUpBeforeClass()
{
if (extension_loaded('mysqli')) {
self::$skip = false;
list($conn,) = self::getConnection();
if (self::$skip) {
return;
}
$conn->disconnect();
}
require_once __DIR__ . '/Mysql/ColumnDefinition.php';
require_once __DIR__ . '/Mysql/TableDefinition.php';
self::$columnTest = new Horde_Db_Adapter_Mysql_ColumnDefinition();
self::$tableTest = new Horde_Db_Adapter_Mysql_TableDefinition();
}
public static function getConnection($overrides = array())
{
$config = Horde_Test_Case::getConfig('DB_ADAPTER_MYSQLI_TEST_CONFIG',
null,
array('host' => 'localhost',
'username' => '',
'password' => '',
'dbname' => 'test'));
if (isset($config['db']['adapter']['mysqli']['test'])) {
$config = $config['db']['adapter']['mysqli']['test'];
}
if (!is_array($config)) {
self::$skip = true;
self::$reason = 'No configuration for mysqli test';
return;
}
$config = array_merge($config, $overrides);
$conn = new Horde_Db_Adapter_Mysqli($config);
$cache = new Horde_Cache(new Horde_Cache_Storage_Mock());
$conn->setCache($cache);
return array($conn, $cache);
}
protected function setUp()
{
if (self::$skip) {
$this->markTestSkipped(self::$reason);
}
list($this->_conn, $this->_cache) = self::getConnection();
self::$columnTest->conn = $this->_conn;
self::$tableTest->conn = $this->_conn;
// clear out detritus from any previous test runs.
$this->_dropTestTables();
$table = $this->_conn->createTable('unit_tests');
$table->column('integer_value', 'integer', array('limit' => 11, 'default' => 0));
$table->column('string_value', 'string', array('limit' => 255, 'default' => ''));
$table->column('text_value', 'text', array('null' => false, 'default' => ''));
$table->column('float_value', 'float', array('precision' => 2, 'scale' => 1, 'default' => 0.0));
$table->column('decimal_value', 'decimal', array('precision' => 2, 'scale' => 1, 'default' => 0.0));
$table->column('datetime_value', 'datetime', array('default' => '0000-00-00 00:00:00'));
$table->column('date_value', 'date', array('default' => '0000-00-00'));
$table->column('time_value', 'time', array('default' => '00:00:00'));
$table->column('blob_value', 'binary', array('null' => false, 'default' => ''));
$table->column('boolean_value', 'boolean', array('default' => false));
$table->column('email_value', 'string', array('limit' => 255, 'default' => ''));
$table->end();
$this->_conn->addIndex('unit_tests', 'string_value', array('name' => 'string_value'));
$this->_conn->addIndex('unit_tests', 'integer_value', array('name' => 'integer_value', 'unique' => true));
$this->_conn->addIndex('unit_tests', array('integer_value', 'string_value'), array('name' => 'integer_string'));
// read sql file for statements
$statements = array();
$current_stmt = '';
$fp = fopen(__DIR__ . '/../fixtures/unit_tests.sql', 'r');
while ($line = fgets($fp, 8192)) {
$line = rtrim(preg_replace('/^(.*)--.*$/s', '\1', $line));
if (!$line) {
continue;
}
$current_stmt .= $line;
if (substr($line, -1) == ';') {
// leave off the ending ;
$statements[] = substr($current_stmt, 0, -1);
$current_stmt = '';
}
}
// run statements
foreach ($statements as $stmt) {
$this->_conn->execute($stmt);
}
}
protected function tearDown()
{
// clean up
$this->_dropTestTables();
// close connection
$this->_conn->disconnect();
}
/*##########################################################################
# Connection
##########################################################################*/
public function testConnect()
{
$this->assertTrue($this->_conn->isActive());
}
public function testDisconnect()
{
$this->_conn->disconnect();
$this->assertFalse($this->_conn->isActive());
$this->_conn->connect();
$this->assertTrue($this->_conn->isActive());
}
public function testReconnect()
{
$this->_conn->reconnect();
$this->assertTrue($this->_conn->isActive());
}
/*##########################################################################
# Accessor
##########################################################################*/
public function testAdapterName()
{
$this->assertEquals('MySQLi', $this->_conn->adapterName());
}
public function testSupportsMigrations()
{
$this->assertTrue($this->_conn->supportsMigrations());
}
public function testSupportsCountDistinct()
{
$this->assertTrue($this->_conn->supportsCountDistinct());
}
public function testGetCharset()
{
$this->assertEquals('utf8', strtolower($this->_conn->getCharset()));
}
/*##########################################################################
# Database Statements
##########################################################################*/
public function testExecute()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->execute($sql);
$row = $result->fetch_assoc();
$this->assertEquals(1, $row['id']);
}
public function testSelect()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->select($sql);
$this->assertInstanceOf('Traversable', $result);
$this->assertGreaterThan(0, count($result));
foreach ($result as $row) break;
$this->assertInternalType('array', $row);
$this->assertEquals(1, $row['id']);
}
public function testSelectWithBoundParameters()
{
$sql = "SELECT * FROM unit_tests WHERE id=?";
$result = $this->_conn->select($sql, array(1));
$this->assertInstanceOf('Traversable', $result);
$this->assertGreaterThan(0, count($result));
foreach ($result as $row) break;
$this->assertInternalType('array', $row);
$this->assertEquals(1, $row['id']);
}
public function testSelectWithBoundParametersQuotesString()
{
$sql = "SELECT * FROM unit_tests WHERE string_value=?";
$result = $this->_conn->select($sql, array('name a'));
$this->assertInstanceOf('Traversable', $result);
$this->assertGreaterThan(0, count($result));
foreach ($result as $row) break;
$this->assertInternalType('array', $row);
$this->assertEquals(1, $row['id']);
}
public function testSelectAll()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->selectAll($sql);
$this->assertInternalType('array', $result);
$this->assertGreaterThan(0, count($result));
$this->assertEquals(1, $result[0]['id']);
}
public function testSelectOne()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->selectOne($sql);
$this->assertEquals(1, $result['id']);
}
public function testSelectValue()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->selectValue($sql);
$this->assertEquals(1, $result);
}
public function testSelectValues()
{
$sql = "SELECT * FROM unit_tests";
$result = $this->_conn->selectValues($sql);
$this->assertEquals(array(1, 2, 3, 4, 5, 6), $result);
}
public function testInsert()
{
$sql = "INSERT INTO unit_tests (id, integer_value) VALUES (7, 999)";
$result = $this->_conn->insert($sql);
$this->assertEquals(7, $result);
}
public function testUpdate()
{
$sql = "UPDATE unit_tests SET integer_value=999 WHERE id IN (1)";
$result = $this->_conn->update($sql);
$this->assertEquals(1, $result);
}
public function testDelete()
{
$sql = "DELETE FROM unit_tests WHERE id IN (1,2)";
$result = $this->_conn->delete($sql);
$this->assertEquals(2, $result);
}
public function testTransactionStarted()
{
$this->assertFalse($this->_conn->transactionStarted());
$this->_conn->beginDbTransaction();
$this->assertTrue($this->_conn->transactionStarted());
$this->_conn->commitDbTransaction();
$this->assertFalse($this->_conn->transactionStarted());
}
public function testTransactionCommit()
{
$this->_conn->beginDbTransaction();
$sql = "INSERT INTO unit_tests (id, integer_value) VALUES (7, 999)";
$this->_conn->insert($sql);
$this->_conn->commitDbTransaction();
// make sure it inserted
$sql = "SELECT integer_value FROM unit_tests WHERE id='7'";
$this->assertEquals('999', $this->_conn->selectValue($sql));
// query without transaction and with new connection (see bug #10578).
$sql = "INSERT INTO unit_tests (id, integer_value) VALUES (8, 1000)";
$this->_conn->insert($sql);
// make sure it inserted
$this->_conn->reconnect();
$sql = "SELECT integer_value FROM unit_tests WHERE id='8'";
$this->assertEquals('1000', $this->_conn->selectValue($sql));
}
public function testTransactionRollback()
{
$this->_conn->beginDbTransaction();
$sql = "INSERT INTO unit_tests (id, integer_value) VALUES (7, 999)";
$this->_conn->insert($sql);
$this->_conn->rollbackDbTransaction();
// make sure it inserted
$sql = "SELECT integer_value FROM unit_tests WHERE id='7'";
$this->assertEquals(null, $this->_conn->selectValue($sql));
// query without transaction and with new connection (see bug #10578).
$sql = "INSERT INTO unit_tests (id, integer_value) VALUES (7, 999)";
$this->_conn->insert($sql);
// make sure it inserted
$this->_conn->reconnect();
$sql = "SELECT integer_value FROM unit_tests WHERE id='7'";
$this->assertEquals(999, $this->_conn->selectValue($sql));
}
/*##########################################################################
# Quoting
##########################################################################*/
public function testQuoteNull()
{
$this->assertEquals('NULL', $this->_conn->quote(null));
}
public function testQuoteTrue()
{
$this->assertEquals('1', $this->_conn->quote(true));
}
public function testQuoteFalse()
{
$this->assertEquals('0', $this->_conn->quote(false));
}
public function testQuoteInteger()
{
$this->assertEquals('42', $this->_conn->quote(42));
}
public function testQuoteFloat()
{
$this->assertEquals('42.2', $this->_conn->quote(42.2));
setlocale(LC_NUMERIC, 'de_DE.UTF-8');
$this->assertEquals('42.2', $this->_conn->quote(42.2));
}
public function testQuoteString()
{
$this->assertEquals("'my string'", $this->_conn->quote('my string'));
}
public function testQuoteDirtyString()
{
$this->assertEquals("'derek\'s string'", $this->_conn->quote('derek\'s string'));
}
public function testQuoteColumnName()
{
$col = new Horde_Db_Adapter_Mysql_Column('age', 'NULL', 'int(11)');
$this->assertEquals('1', $this->_conn->quote(true, $col));
}
public function testQuoteBinary()
{
// Test string is foo\0ba'r - should be 8 bytes long
$original = base64_decode('Zm9vAGJhJ3I=');
$table = $this->_conn->createTable('binary_testings');
$table->column('data', 'binary', array('null' => false));
$table->end();
$this->_conn->insert('INSERT INTO binary_testings (data) VALUES (?)', array(new Horde_Db_Value_Binary($original)));
$retrieved = $this->_conn->selectValue('SELECT data FROM binary_testings');
$columns = $this->_conn->columns('binary_testings');
$retrieved = $columns['data']->binaryToString($retrieved);
$this->assertEquals($original, $retrieved);
}
/*##########################################################################
# Schema Statements
##########################################################################*/
/**
* We specifically do a manual INSERT here, and then test only the SELECT
* functionality. This allows us to more easily catch INSERT being broken,
* but SELECT actually working fine.
*/
public function testNativeDecimalInsertManualVsAutomatic()
{
$this->_createTestUsersTable();
$correctValue = 12345678901234567890.0123456789;
$this->_conn->addColumn("users", "wealth", 'decimal', array('precision' => 30, 'scale' => 10));
// do a manual insertion
$this->_conn->execute("INSERT INTO users (wealth) VALUES ('12345678901234567890.0123456789')");
// SELECT @todo - type cast attribute values
$user = (object)$this->_conn->selectOne('SELECT * FROM users');
// assert_kind_of BigDecimal, row.wealth
// If this assert fails, that means the SELECT is broken!
$this->assertEquals($correctValue, $user->wealth);
// Reset to old state
$this->_conn->delete('DELETE FROM users');
// Now use the Adapter insertion
$this->_conn->insert('INSERT INTO users (wealth) VALUES (12345678901234567890.0123456789)');
// SELECT @todo - type cast attribute values
$user = (object)$this->_conn->selectOne('SELECT * FROM users');
// assert_kind_of BigDecimal, row.wealth
// If these asserts fail, that means the INSERT (create function, or cast to SQL) is broken!
$this->assertEquals($correctValue, $user->wealth);
}
public function testNativeTypes()
{
$this->_createTestUsersTable();
$this->_conn->addColumn("users", "last_name", 'string');
$this->_conn->addColumn("users", "bio", 'text');
$this->_conn->addColumn("users", "age", 'integer');
$this->_conn->addColumn("users", "height", 'float');
$this->_conn->addColumn("users", "wealth", 'decimal', array('precision' => '30', 'scale' => '10'));
$this->_conn->addColumn("users", "birthday", 'datetime');
$this->_conn->addColumn("users", "favorite_day", 'date');
$this->_conn->addColumn("users", "moment_of_truth", 'datetime');
$this->_conn->addColumn("users", "male", 'boolean');
$this->_conn->insert('INSERT INTO users (first_name, last_name, bio, age, height, wealth, birthday, favorite_day, moment_of_truth, male, company_id) ' .
"VALUES ('bob', 'bobsen', 'I was born ....', 18, 1.78, 12345678901234567890.0123456789, '2005-01-01 12:23:40', '1980-03-05', '1582-10-10 21:40:18', 1, 1)");
$bob = (object)$this->_conn->selectOne('SELECT * FROM users');
$this->assertEquals('bob', $bob->first_name);
$this->assertEquals('bobsen', $bob->last_name);
$this->assertEquals('I was born ....', $bob->bio);
$this->assertEquals(18, $bob->age);
// Test for 30 significent digits (beyond the 16 of float), 10 of them
// after the decimal place.
$this->assertEquals('12345678901234567890.0123456789', $bob->wealth);
$this->assertEquals(1, $bob->male);
// @todo - type casting
}
public function testNativeDatabaseTypes()
{
$types = $this->_conn->nativeDatabaseTypes();
$this->assertEquals(array('name' => 'int', 'limit' => 11), $types['integer']);
}
public function testUnabstractedDatabaseDependentTypes()
{
$this->_createTestUsersTable();
$this->_conn->delete('DELETE FROM users');
$this->_conn->addColumn('users', 'intelligence_quotient', 'tinyint');
$this->_conn->insert('INSERT INTO users (intelligence_quotient) VALUES (300)');
$jonnyg = (object)$this->_conn->selectOne('SELECT * FROM users');
$this->assertEquals('127', $jonnyg->intelligence_quotient);
}
public function testTableAliasLength()
{
$len = $this->_conn->tableAliasLength();
$this->assertEquals(255, $len);
}
public function testTableAliasFor()
{
$alias = $this->_conn->tableAliasFor('my_table_name');
$this->assertEquals('my_table_name', $alias);
}
public function testTables()
{
$tables = $this->_conn->tables();
$this->assertTrue(count($tables) > 0);
$this->assertContains('unit_tests', $tables);
}
public function testPrimaryKey()
{
$pk = $this->_conn->primaryKey('unit_tests');
$this->assertEquals('id', (string)$pk);
$this->assertEquals(1, count($pk->columns));
$this->assertEquals('id', $pk->columns[0]);
$table = $this->_conn->createTable('pk_tests', array('autoincrementKey' => false));
$table->column('foo', 'string');
$table->column('bar', 'string');
$table->end();
$pk = $this->_conn->primaryKey('pk_tests');
$this->assertEmpty((string)$pk);
$this->assertEquals(0, count($pk->columns));
$this->_conn->addPrimaryKey('pk_tests', 'foo');
$pk = $this->_conn->primaryKey('pk_tests');
$this->assertEquals('foo', (string)$pk);
$this->assertEquals(1, count($pk->columns));
$this->_conn->removePrimaryKey('pk_tests');
$pk = $this->_conn->primaryKey('pk_tests');
$this->assertEmpty((string)$pk);
$this->assertEquals(0, count($pk->columns));
$this->_conn->addPrimaryKey('pk_tests', array('foo', 'bar'));
$pk = $this->_conn->primaryKey('pk_tests');
$this->assertEquals('foo,bar', (string)$pk);
}
public function testIndexes()
{
$indexes = $this->_conn->indexes('unit_tests');
$this->assertEquals(3, count($indexes));
// unique index
$col = array('integer_value');
$this->assertEquals('unit_tests', $indexes[0]->table);
$this->assertEquals('integer_value', $indexes[0]->name);
$this->assertEquals(true, $indexes[0]->unique);
$this->assertEquals($col, $indexes[0]->columns);
// normal index
$col = array('string_value');
$this->assertEquals('unit_tests', $indexes[1]->table);
$this->assertEquals('string_value', $indexes[1]->name);
$this->assertEquals(false, $indexes[1]->unique);
$this->assertEquals($col, $indexes[1]->columns);
// multi-column index
$col = array('integer_value', 'string_value');
$this->assertEquals('unit_tests', $indexes[2]->table);
$this->assertEquals('integer_string', $indexes[2]->name);
$this->assertEquals(false, $indexes[2]->unique);
$this->assertEquals($col, $indexes[2]->columns);
}
public function testColumns()
{
$columns = $this->_conn->columns('unit_tests');
$this->assertEquals(12, count($columns));
$col = $columns['id'];
$this->assertEquals('id', $col->getName());
$this->assertEquals('integer', $col->getType());
$this->assertEquals(false, $col->isNull());
$this->assertEquals(10, $col->getLimit());
$this->assertEquals(true, $col->isUnsigned());
$this->assertEquals('', $col->getDefault());
$this->assertEquals('int(10) unsigned', $col->getSqlType());
$this->assertEquals(false, $col->isText());
$this->assertEquals(true, $col->isNumber());
}
public function testCreateTable()
{
$this->_createTestTable('sports');
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
}
public function testCreateTableNoPk()
{
$this->_createTestTable('sports', array('autoincrementKey' => false));
try {
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertNull($this->_conn->selectValue($sql));
} catch (Exception $e) {
return;
}
$this->fail("Expected exception for no pk");
}
public function testCreateTableWithNamedPk()
{
$this->_createTestTable('sports', array('autoincrementKey' => 'sports_id'));
$sql = "SELECT sports_id FROM sports WHERE sports_id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
try {
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertNull($this->_conn->selectValue($sql));
} catch (Exception $e) {
return;
}
$this->fail("Expected exception for wrong pk name");
}
public function testCreateTableWithSeparatePk()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'autoincrementKey');
$pkColumn = $table['foo'];
$this->assertEquals('`foo` int(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY', $pkColumn->toSql());
}
public function testCreateTableCompositePk()
{
$table = $this->_conn->createTable('testings', array('autoincrementKey' => array('a_id', 'b_id')));
$table->column('a_id', 'integer');
$table->column('b_id', 'integer');
$table->end();
$pk = $this->_conn->primaryKey('testings');
$this->assertEquals(array('a_id', 'b_id'), $pk->columns);
}
public function testCreateTableForce()
{
$this->_createTestTable('sports');
$this->_createTestTable('sports', array('force' => true));
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
}
public function testCreateTableTemporary()
{
$this->_createTestTable('sports', array('temporary' => true));
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
}
public function testCreateTableAddsId()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string');
$table->end();
$columns = array();
foreach ($this->_conn->columns('testings') as $col) {
$columns[] = $col->getName();
}
sort($columns);
$this->assertEquals(array('foo', 'id'), $columns);
}
public function testCreateTableWithNotNullColumn()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string', array('null' => false));
$table->end();
try {
$this->_conn->execute("INSERT INTO testings (foo) VALUES (NULL)");
} catch (Exception $e) { return; }
$this->fail('Expected exception wasn\'t raised');
}
public function testCreateTableWithDefaults()
{
$table = $this->_conn->createTable('testings');
$table->column('one', 'string', array('default' => 'hello'));
$table->column('two', 'boolean', array('default' => true));
$table->column('three', 'boolean', array('default' => false));
$table->column('four', 'integer', array('default' => 1));
$table->end();
$columns = array();
foreach ($this->_conn->columns('testings') as $col) {
$columns[$col->getName()] = $col;
}
$this->assertEquals('hello', $columns['one']->getDefault());
$this->assertTrue($columns['two']->getDefault());
$this->assertFalse($columns['three']->getDefault());
$this->assertEquals(1, $columns['four']->getDefault());
}
public function testCreateTableWithLimits()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string', array('limit' => 80));
$table->end();
$columns = array();
foreach ($this->_conn->columns('testings') as $col) {
$columns[$col->getName()] = $col;
}
$this->assertEquals(80, $columns['foo']->getLimit());
}
public function testCreateTableWithBinaryColumn()
{
try {
$table = $this->_conn->createTable('binary_testings');
$table->column('data', 'binary', array('null' => false));
$table->end();
} catch (Exception $e) { $this->fail('Unexepected exception raised'); }
$columns = $this->_conn->columns('binary_testings');
foreach ($columns as $c) {
if ($c->getName() == 'data') { $dataColumn = $c; }
}
$this->assertEquals('', $dataColumn->getDefault());
}
public function testRenameTable()
{
// Simple rename then select test
$this->_createTestTable('sports');
$this->_conn->renameTable('sports', 'my_sports');
$sql = "SELECT id FROM my_sports WHERE id = 1";
$this->assertEquals("1", $this->_conn->selectValue($sql));
// Make sure the old table name isn't still there
try {
$sql = "SELECT id FROM sports WHERE id = 1";
$this->_conn->execute($sql);
} catch (Exception $e) {
return;
}
$this->fail("Table exists where it shouldn't have");
// Rename then insert test
$table = $this->_conn->createTable('octopuses');
$table->column('url', 'string');
$table->end();
$this->_conn->renameTable('octopuses', 'octopi');
$sql = "INSERT INTO octopi (id, url) VALUES (1, 'http://www.foreverflying.com/octopus-black7.jpg')";
$this->_conn->execute($sql);
$this->assertEquals('http://www.foreverflying.com/octopus-black7.jpg',
$this->_conn->selectValue("SELECT url FROM octopi WHERE id=1"));
// Make sure the old table name isn't still there
try {
$sql = "SELECT id FROM octopuses WHERE id = 1";
$this->_conn->execute($sql);
} catch (Exception $e) {
return;
}
$this->fail("Table exists where it shouldn't have");
}
public function testRenameTableWithAnIndex()
{
$table = $this->_conn->createTable('octopuses');
$table->column('url', 'string');
$table->end();
$this->_conn->addIndex('octopuses', 'url');
$this->_conn->renameTable('octopuses', 'octopi');
$sql = "INSERT INTO octopi (id, url) VALUES (1, 'http://www.foreverflying.com/octopus-black7.jpg')";
$this->_conn->execute($sql);
$this->assertEquals('http://www.foreverflying.com/octopus-black7.jpg',
$this->_conn->selectValue("SELECT url FROM octopi WHERE id=1"));
$indexes = $this->_conn->indexes('octopi');
$this->assertEquals('url', $indexes[0]->columns[0]);
}
public function testDropTable()
{
$this->_createTestTable('sports');
$this->_conn->dropTable('sports');
try {
$sql = "SELECT id FROM sports WHERE id = 1";
$this->_conn->execute($sql);
} catch (Exception $e) {
return;
}
$this->fail("Table exists where it shouldn't have");
}
public function testAddColumn()
{
$this->_createTestTable('sports');
$this->_conn->addColumn('sports', 'modified_at', 'date');
$this->_conn->update("UPDATE sports SET modified_at = '2007-01-01'");
$sql = "SELECT modified_at FROM sports WHERE id = 1";
$this->assertEquals("2007-01-01", $this->_conn->selectValue($sql));
$this->_conn->addColumn('sports', 'with_default', 'integer', array('default' => 1));
$sql = "SELECT with_default FROM sports WHERE id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
}
public function testRemoveColumn()
{
$this->_createTestTable('sports');
$sql = "SELECT name FROM sports WHERE id = 1";
$this->assertEquals("mlb", $this->_conn->selectValue($sql));
$this->_conn->removeColumn('sports', 'name');
try {
$sql = "SELECT name FROM sports WHERE id = 1";
$this->_conn->execute($sql);
} catch (Exception $e) {
return;
}
$this->fail("Column exists where it shouldn't have");
}
public function testChangeColumn()
{
$this->_createTestUsersTable();
$this->_conn->addColumn('users', 'age', 'integer');
$oldColumns = $this->_conn->columns('users', "User Columns");
$found = false;
foreach ($oldColumns as $c) {
if ($c->getName() == 'age' && $c->getType() == 'integer') { $found = true; }
}
$this->assertTrue($found);
$this->_conn->changeColumn('users', 'age', 'string');
$newColumns = $this->_conn->columns('users', "User Columns");
$found = false;
foreach ($newColumns as $c) {
if ($c->getName() == 'age' && $c->getType() == 'integer') { $found = true; }
}
$this->assertFalse($found);
$found = false;
foreach ($newColumns as $c) {
if ($c->getName() == 'age' && $c->getType() == 'string') { $found = true; }
}
$this->assertTrue($found);
$found = false;
foreach ($oldColumns as $c) {
if ($c->getName() == 'approved' && $c->getType() == 'boolean' &&
$c->getDefault() == true) { $found = true; }
}
$this->assertTrue($found);
// changeColumn() throws exception on error
$this->_conn->changeColumn('users', 'approved', 'boolean', array('default' => false));
$newColumns = $this->_conn->columns('users', "User Columns");
$found = false;
foreach ($newColumns as $c) {
if ($c->getName() == 'approved' && $c->getType() == 'boolean' &&
$c->getDefault() == true) { $found = true; }
}
$this->assertFalse($found);
$found = false;
foreach ($newColumns as $c) {
if ($c->getName() == 'approved' && $c->getType() == 'boolean' &&
$c->getDefault() == false) { $found = true; }
}
$this->assertTrue($found);
// changeColumn() throws exception on error
$this->_conn->changeColumn('users', 'approved', 'boolean', array('default' => true));
}
public function testChangeColumnDefault()
{
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'name');
$this->assertEquals('', $beforeChange->getDefault());
$this->_conn->changeColumnDefault('sports', 'name', 'test');
$afterChange = $this->_getColumn('sports', 'name');
$this->assertEquals('test', $afterChange->getDefault());
}
public function testChangeColumnType()
{
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('tinyint(1)', $beforeChange->getSqlType());
$this->_conn->changeColumn('sports', 'is_college', 'string');
$afterChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('varchar(255)', $afterChange->getSqlType());
$table = $this->_conn->createTable('text_to_binary');
$table->column('data', 'text');
$table->end();
$this->_conn->insert('INSERT INTO text_to_binary (data) VALUES (?)',
array("foo\0bar"));
$this->_conn->changeColumn('text_to_binary', 'data', 'binary');
$afterChange = $this->_getColumn('text_to_binary', 'data');
$this->assertEquals('longblob', $afterChange->getSqlType());
$this->assertEquals(
"foo\0bar",
$this->_conn->selectValue('SELECT data FROM text_to_binary'));
}
public function testChangeColumnLimit()
{
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('tinyint(1)', $beforeChange->getSqlType());
$this->_conn->changeColumn('sports', 'is_college', 'string',
array('limit' => '40'));
$afterChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('varchar(40)', $afterChange->getSqlType());
}
public function testChangeColumnPrecisionScale()
{
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('tinyint(1)', $beforeChange->getSqlType());
$this->_conn->changeColumn('sports', 'is_college', 'decimal',
array('precision' => '5', 'scale' => '2'));
$afterChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('decimal(5,2)', $afterChange->getSqlType());
}
public function testChangeColumnUnsigned()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'integer');
$table->end();
$beforeChange = $this->_getColumn('testings', 'foo');
$this->assertFalse($beforeChange->isUnsigned());
$this->_conn->execute("INSERT INTO testings (id, foo) VALUES (1, -1)");
$this->_conn->changeColumn('testings', 'foo', 'integer', array('unsigned' => true));
$afterChange = $this->_getColumn('testings', 'foo');
$this->assertTrue($afterChange->isUnsigned());
$row = (object)$this->_conn->selectOne('SELECT * FROM testings');
$this->assertEquals(0, $row->foo);
}
public function testRenameColumn()
{
$this->_createTestUsersTable();
$this->_conn->renameColumn('users', 'first_name', 'nick_name');
$this->assertTrue(in_array('nick_name', $this->_columnNames('users')));
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('tinyint(1)', $beforeChange->getSqlType());
$this->_conn->renameColumn('sports', 'is_college', 'is_renamed');
$afterChange = $this->_getColumn('sports', 'is_renamed');
$this->assertEquals('tinyint(1)', $afterChange->getSqlType());
}
public function testRenameColumnWithSqlReservedWord()
{
$this->_createTestUsersTable();
$this->_conn->renameColumn('users', 'first_name', 'group');
$this->assertTrue(in_array('group', $this->_columnNames('users')));
}
public function testAddIndex()
{
$this->_createTestUsersTable();
// Limit size of last_name and key columns to support Firebird index limitations
$this->_conn->addColumn('users', 'last_name', 'string', array('limit' => 100));
$this->_conn->addColumn('users', 'key', 'string', array('limit' => 100));
$this->_conn->addColumn('users', 'administrator', 'boolean');
$this->_conn->addIndex('users', 'last_name');
$this->_conn->removeIndex('users', 'last_name');
$this->_conn->addIndex('users', array('last_name', 'first_name'));
$this->_conn->removeIndex('users', array('column' => array('last_name', 'first_name')));
$this->_conn->addIndex('users', array('last_name', 'first_name'));
$this->_conn->removeIndex('users', array('name' => 'index_users_on_last_name_and_first_name'));
$this->_conn->addIndex('users', array('last_name', 'first_name'));
$this->_conn->removeIndex('users', 'last_name_and_first_name');
// quoting
$this->_conn->addIndex('users', array('key'), array('name' => 'key_idx', 'unique' => true));
$this->_conn->removeIndex('users', array('name' => 'key_idx', 'unique' => true));
$this->_conn->addIndex('users', array('last_name', 'first_name', 'administrator'),
array('name' => "named_admin"));
$this->_conn->removeIndex('users', array('name' => 'named_admin'));
}
public function testAddIndexDefault()
{
$this->_createTestTable('sports');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
$this->_conn->addIndex('sports', 'is_college');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
}
public function testAddIndexMultiColumn()
{
$this->_createTestTable('sports');
$index = $this->_getIndex('sports', array('name', 'is_college'));
$this->assertNull($index);
$this->_conn->addIndex('sports', array('name', 'is_college'));
$index = $this->_getIndex('sports', array('name', 'is_college'));
$this->assertNotNull($index);
}
public function testAddIndexUnique()
{
$this->_createTestTable('sports');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
$this->_conn->addIndex('sports', 'is_college', array('unique' => true));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
$this->assertTrue($index->unique);
}
public function testAddIndexName()
{
$this->_createTestTable('sports');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
$this->_conn->addIndex('sports', 'is_college', array('name' => 'test'));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
$this->assertEquals('test', $index->name);
}
public function testRemoveIndexSingleColumn()
{
$this->_createTestTable('sports');
// add the index
$this->_conn->addIndex('sports', 'is_college');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
// remove it again
$this->_conn->removeIndex('sports', array('column' => 'is_college'));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
}
public function testRemoveIndexMultiColumn()
{
$this->_createTestTable('sports');
// add the index
$this->_conn->addIndex('sports', array('name', 'is_college'));
$index = $this->_getIndex('sports', array('name', 'is_college'));
$this->assertNotNull($index);
// remove it again
$this->_conn->removeIndex('sports', array('column' => array('name', 'is_college')));
$index = $this->_getIndex('sports', array('name', 'is_college'));
$this->assertNull($index);
}
public function testRemoveIndexByName()
{
$this->_createTestTable('sports');
// add the index
$this->_conn->addIndex('sports', 'is_college', array('name' => 'test'));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
// remove it again
$this->_conn->removeIndex('sports', array('name' => 'test'));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
}
public function testIndexNameInvalid()
{
try {
$name = $this->_conn->indexName('sports');
} catch (Horde_Db_Exception $e) {
return;
}
$this->fail("Adding an index with crappy options worked where it shouldn't have");
}
public function testIndexNameBySingleColumn()
{
$name = $this->_conn->indexName('sports', array('column' => 'is_college'));
$this->assertEquals('index_sports_on_is_college', $name);
}
public function testIndexNameByMultiColumn()
{
$name = $this->_conn->indexName('sports', array('column' =>
array('name', 'is_college')));
$this->assertEquals('index_sports_on_name_and_is_college', $name);
}
public function testIndexNameByName()
{
$name = $this->_conn->indexName('sports', array('name' => 'test'));
$this->assertEquals('test', $name);
}
public function testTypeToSqlTypePrimaryKey()
{
$result = $this->_conn->typeToSql('autoincrementKey');
$this->assertEquals('int(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY', $result);
}
public function testTypeToSqlTypeString()
{
$result = $this->_conn->typeToSql('string');
$this->assertEquals('varchar(255)', $result);
}
public function testTypeToSqlTypeText()
{
$result = $this->_conn->typeToSql('text');
$this->assertEquals('text', $result);
}
public function testTypeToSqlTypeBinary()
{
$result = $this->_conn->typeToSql('binary');
$this->assertEquals('longblob', $result);
}
public function testTypeToSqlTypeFloat()
{
$result = $this->_conn->typeToSql('float');
$this->assertEquals('float', $result);
}
public function testTypeToSqlTypeDatetime()
{
$result = $this->_conn->typeToSql('datetime');
$this->assertEquals('datetime', $result);
}
public function testTypeToSqlTypeTimestamp()
{
$result = $this->_conn->typeToSql('timestamp');
$this->assertEquals('datetime', $result);
}
public function testTypeToSqlInt()
{
$result = $this->_conn->typeToSql('integer');
$this->assertEquals('int(11)', $result);
}
public function testTypeToSqlIntUnsigned()
{
$result = $this->_conn->typeToSql('integer', null, null, null, true);
$this->assertEquals('int(10) UNSIGNED', $result);
}
public function testTypeToSqlIntLimit()
{
$result = $this->_conn->typeToSql('integer', '1');
$this->assertEquals('int(1)', $result);
}
public function testTypeToSqlDecimalPrecision()
{
$result = $this->_conn->typeToSql('decimal', null, '5');
$this->assertEquals('decimal(5)', $result);
}
public function testTypeToSqlDecimalScale()
{
$result = $this->_conn->typeToSql('decimal', null, '5', '2');
$this->assertEquals('decimal(5, 2)', $result);
}
public function testTypeToSqlBoolean()
{
$result = $this->_conn->typeToSql('boolean');
$this->assertEquals('tinyint(1)', $result);
}
public function testAddColumnOptions()
{
$result = $this->_conn->addColumnOptions("test", array());
$this->assertEquals("test", $result);
}
public function testAddColumnOptionsDefault()
{
$options = array('default' => '0');
$result = $this->_conn->addColumnOptions("test", $options);
$this->assertEquals("test DEFAULT '0'", $result);
}
public function testAddColumnOptionsNull()
{
$options = array('null' => true);
$result = $this->_conn->addColumnOptions("test", $options);
$this->assertEquals("test", $result);
}
public function testAddColumnOptionsNotNull()
{
$options = array('null' => false);
$result = $this->_conn->addColumnOptions("test", $options);
$this->assertEquals("test NOT NULL", $result);
}
public function testAddColumnNotNullWithoutDefault()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string');
$table->end();
$this->_conn->addColumn('testings', 'bar', 'string', array('null' => false, 'default' => ''));
try {
$this->_conn->execute("INSERT INTO testings (foo, bar) VALUES ('hello', NULL)");
} catch (Exception $e) { return; }
$this->fail('Expected exception wasn\'t raised');
}
public function testAddColumnNotNullWithDefault()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string');
$table->end();
$this->_conn->execute("INSERT INTO testings (id, foo) VALUES ('1', 'hello')");
$this->_conn->addColumn('testings', 'bar', 'string', array('null' => false, 'default' => 'default'));
try {
$this->_conn->execute("INSERT INTO testings (id, foo, bar) VALUES (2, 'hello', NULL)");
} catch (Exception $e) { return; }
$this->fail('Expected exception wasn\'t raised');
}
public function testAddRemoveSingleField()
{
$this->_createTestUsersTable();
$this->assertFalse(in_array('last_name', $this->_columnNames('users')));
$this->_conn->addColumn('users', 'last_name', 'string');
$this->assertTrue(in_array('last_name', $this->_columnNames('users')));
$this->_conn->removeColumn('users', 'last_name');
$this->assertFalse(in_array('last_name', $this->_columnNames('users')));
}
public function testAddRename()
{
$this->_createTestUsersTable();
$this->_conn->delete('DELETE FROM users');
$this->_conn->addColumn('users', 'girlfriend', 'string');
$this->_conn->insert("INSERT INTO users (girlfriend) VALUES ('bobette')");
$this->_conn->renameColumn('users', 'girlfriend', 'exgirlfriend');
$bob = (object)$this->_conn->selectOne('SELECT * FROM users');
$this->assertEquals('bobette', $bob->exgirlfriend);
}
public function testDistinct()
{
$result = $this->_conn->distinct("test");
$this->assertEquals("DISTINCT test", $result);
}
public function testAddOrderByForAssocLimiting()
{
$result = $this->_conn->addOrderByForAssocLimiting("SELECT * FROM documents ",
array('order' => 'name DESC'));
$this->assertEquals("SELECT * FROM documents ORDER BY name DESC", $result);
}
public function testInterval()
{
$this->assertEquals('INTERVAL 1 DAY',
$this->_conn->interval('1 DAY', ''));
}
public function testModifyDate()
{
$modifiedDate = $this->_conn->modifyDate('start', '+', 1, 'DAY');
$this->assertEquals('start + INTERVAL \'1\' DAY', $modifiedDate);
$t = $this->_conn->createTable('dates');
$t->column('start', 'datetime');
$t->column('end', 'datetime');
$t->end();
$this->_conn->insert(
'INSERT INTO dates (start, end) VALUES (?, ?)',
array(
'2011-12-10 00:00:00',
'2011-12-11 00:00:00'
)
);
$this->assertEquals(
1,
$this->_conn->selectValue('SELECT COUNT(*) FROM dates WHERE '
. $modifiedDate . ' = end')
);
}
public function testBuildClause()
{
$this->assertEquals(
'bitmap & 2',
$this->_conn->buildClause('bitmap', '&', 2));
$this->assertEquals(
array('bitmap & ?', array(2)),
$this->_conn->buildClause('bitmap', '&', 2, true));
$this->assertEquals(
'bitmap | 2',
$this->_conn->buildClause('bitmap', '|', 2));
$this->assertEquals(
array('bitmap | ?', array(2)),
$this->_conn->buildClause('bitmap', '|', 2, true));
$this->assertEquals(
"LOWER(name) LIKE LOWER('%search%')",
$this->_conn->buildClause('name', 'LIKE', "search"));
$this->assertEquals(
array("LOWER(name) LIKE LOWER(?)", array('%search%')),
$this->_conn->buildClause('name', 'LIKE', "search", true));
$this->assertEquals(
"LOWER(name) LIKE LOWER('%search\&replace\?%')",
$this->_conn->buildClause('name', 'LIKE', "search&replace?"));
$this->assertEquals(
array("LOWER(name) LIKE LOWER(?)", array('%search&replace?%')),
$this->_conn->buildClause('name', 'LIKE', "search&replace?", true));
$this->assertEquals(
"(LOWER(name) LIKE LOWER('search\&replace\?%') OR LOWER(name) LIKE LOWER('% search\&replace\?%'))",
$this->_conn->buildClause('name', 'LIKE', "search&replace?", false, array('begin' => true)));
$this->assertEquals(
array("(LOWER(name) LIKE LOWER(?) OR LOWER(name) LIKE LOWER(?))",
array('search&replace?%', '% search&replace?%')),
$this->_conn->buildClause('name', 'LIKE', "search&replace?", true, array('begin' => true)));
$this->assertEquals(
'value = 2',
$this->_conn->buildClause('value', '=', 2));
$this->assertEquals(
array('value = ?', array(2)),
$this->_conn->buildClause('value', '=', 2, true));
$this->assertEquals(
"value = 'foo'",
$this->_conn->buildClause('value', '=', 'foo'));
$this->assertEquals(
array('value = ?', array('foo')),
$this->_conn->buildClause('value', '=', 'foo', true));
$this->assertEquals(
"value = 'foo\?bar'",
$this->_conn->buildClause('value', '=', 'foo?bar'));
$this->assertEquals(
array('value = ?', array('foo?bar')),
$this->_conn->buildClause('value', '=', 'foo?bar', true));
}
public function testInsertAndReadInCp1257()
{
list($conn,) = self::getConnection(array('charset' => 'cp1257'));
$table = $conn->createTable('charset_cp1257');
$table->column('text', 'string');
$table->end();
$input = file_get_contents(__DIR__ . '/../fixtures/charsets/cp1257.txt');
$conn->insert("INSERT INTO charset_cp1257 (text) VALUES (?)", array($input));
$output = $conn->selectValue('SELECT text FROM charset_cp1257');
$this->assertEquals($input, $output);
}
public function testInsertAndReadInUtf8()
{
list($conn,) = self::getConnection(array('charset' => 'utf8'));
$table = $conn->createTable('charset_utf8');
$table->column('text', 'string');
$table->end();
$input = file_get_contents(__DIR__ . '/../fixtures/charsets/utf8.txt');
$conn->insert("INSERT INTO charset_utf8 (text) VALUES (?)", array($input));
$output = $conn->selectValue('SELECT text FROM charset_utf8');
$this->assertEquals($input, $output);
}
/*##########################################################################
# Table cache
##########################################################################*/
public function testCachedTableIndexes()
{
// remove any current cache.
$this->_cache->set('tables/indexes/cache_table', '');
$this->assertEquals('', $this->_cache->get('tables/indexes/cache_table'));
$this->_createTestTable('cache_table');
$idxs = $this->_conn->indexes('cache_table');
$this->assertNotEquals('', $this->_cache->get('tables/indexes/cache_table'));
}
public function testCachedTableColumns()
{
// remove any current cache.
$this->_cache->set('tables/columns/cache_table', '');
$this->assertEquals('', $this->_cache->get('tables/columns/cache_table'));
$this->_createTestTable('cache_table');
$cols = $this->_conn->columns('cache_table');
$this->assertNotEquals('', $this->_cache->get('tables/columns/cache_table'));
}
/*##########################################################################
# Protected
##########################################################################*/
/**
* Create table to perform tests on
*/
protected function _createTestTable($name, $options=array())
{
$table = $this->_conn->createTable($name, $options);
$table->column('name', 'string');
$table->column('is_college', 'boolean');
$table->end();
try {
// make sure table was created
$sql = "INSERT INTO $name
VALUES (1, 'mlb', 0)";
$this->_conn->insert($sql);
} catch (Exception $e) {}
}
protected function _createTestUsersTable()
{
$table = $this->_conn->createTable('users');
$table->column('company_id', 'integer', array('limit' => 11));
$table->column('name', 'string', array('limit' => 255, 'default' => ''));
$table->column('first_name', 'string', array('limit' => 40, 'default' => ''));
$table->column('approved', 'boolean', array('default' => true));
$table->column('type', 'string', array('limit' => 255, 'default' => ''));
$table->column('created_at', 'datetime', array('default' => '0000-00-00 00:00:00'));
$table->column('created_on', 'date', array('default' => '0000-00-00'));
$table->column('updated_at', 'datetime', array('default' => '0000-00-00 00:00:00'));
$table->column('updated_on', 'date', array('default' => '0000-00-00'));
$table->end();
}
/**
* drop test tables
*/
protected function _dropTestTables()
{
$tables = array(
'binary_testings',
'cache_table',
'charset_cp1257',
'charset_utf8',
'dates',
'my_sports',
'octopi',
'pk_tests',
'schema_info',
'sports',
'testings',
'text_to_binary',
'unit_tests',
'users',
);
foreach ($tables as $table) {
try {
$this->_conn->dropTable($table);
} catch (Exception $e) {}
}
}
protected function _columnNames($tableName)
{
$columns = array();
foreach ($this->_conn->columns($tableName) as $c) {
$columns[] = $c->getName();
}
return $columns;
}
/**
* Get a column by name
*/
protected function _getColumn($table, $column)
{
foreach ($this->_conn->columns($table) as $col) {
if ($col->getName() == $column) return $col;
}
}
/**
* Get an index by columns
*/
protected function _getIndex($table, $indexes)
{
$indexes = (array) $indexes;
sort($indexes);
foreach ($this->_conn->indexes($table) as $index) {
$columns = $index->columns;
sort($columns);
if ($columns == $indexes) return $index;
}
}
public function testColumnConstruct()
{
self::$columnTest->testConstruct();
}
public function testColumnToSql()
{
self::$columnTest->testToSql();
}
public function testColumnToSqlLimit()
{
self::$columnTest->testToSqlLimit();
}
public function testColumnToSqlPrecisionScale()
{
self::$columnTest->testToSqlPrecisionScale();
}
public function testColumnToSqlUnsigned()
{
self::$columnTest->testToSqlUnsigned();
}
public function testColumnToSqlNotNull()
{
self::$columnTest->testToSqlNotNull();
}
public function testColumnToSqlDefault()
{
self::$columnTest->testToSqlDefault();
}
public function testTableConstruct()
{
self::$tableTest->testConstruct();
}
public function testTableName()
{
self::$tableTest->testName();
}
public function testTableGetOptions()
{
self::$tableTest->testGetOptions();
}
public function testTablePrimaryKey()
{
self::$tableTest->testPrimaryKey();
}
public function testTableColumn()
{
self::$tableTest->testColumn();
}
public function testTableToSql()
{
self::$tableTest->testToSql();
}
}
Horde_Db-2.0.4/test/Horde/Db/Adapter/MysqlTest.php 0000664 0001750 0001750 00000160202 12205351473 017675 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @author Jan Schneider
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage UnitTests
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @author Jan Schneider
* @license http://www.horde.org/licenses/bsd
* @group horde_db
* @category Horde
* @package Db
* @subpackage UnitTests
*/
class Horde_Db_Adapter_MysqlTest extends Horde_Test_Case
{
protected static $columnTest;
protected static $tableTest;
protected static $skip = true;
protected static $reason = 'The MySQL adapter is not available';
public static function setUpBeforeClass()
{
if (extension_loaded('mysql')) {
self::$skip = false;
list($conn,) = self::getConnection();
if (self::$skip) {
return;
}
$conn->disconnect();
}
require_once __DIR__ . '/Mysql/ColumnDefinition.php';
require_once __DIR__ . '/Mysql/TableDefinition.php';
self::$columnTest = new Horde_Db_Adapter_Mysql_ColumnDefinition();
self::$tableTest = new Horde_Db_Adapter_Mysql_TableDefinition();
}
public static function getConnection($overrides = array())
{
$config = Horde_Test_Case::getConfig('DB_ADAPTER_MYSQL_TEST_CONFIG',
null,
array('host' => 'localhost',
'username' => '',
'password' => '',
'dbname' => 'test'));
if (isset($config['db']['adapter']['mysql']['test'])) {
$config = $config['db']['adapter']['mysql']['test'];
}
if (!is_array($config)) {
self::$skip = true;
self::$reason = 'No configuration for mysql test';
return;
}
$config = array_merge($config, $overrides);
$conn = new Horde_Db_Adapter_Mysql($config);
$cache = new Horde_Cache(new Horde_Cache_Storage_Mock());
$conn->setCache($cache);
return array($conn, $cache);
}
protected function setUp()
{
if (self::$skip) {
$this->markTestSkipped(self::$reason);
}
list($this->_conn, $this->_cache) = self::getConnection();
self::$columnTest->conn = $this->_conn;
self::$tableTest->conn = $this->_conn;
// clear out detritus from any previous test runs.
$this->_dropTestTables();
$table = $this->_conn->createTable('unit_tests');
$table->column('integer_value', 'integer', array('limit' => 11, 'default' => 0));
$table->column('string_value', 'string', array('limit' => 255, 'default' => ''));
$table->column('text_value', 'text', array('null' => false, 'default' => ''));
$table->column('float_value', 'float', array('precision' => 2, 'scale' => 1, 'default' => 0.0));
$table->column('decimal_value', 'decimal', array('precision' => 2, 'scale' => 1, 'default' => 0.0));
$table->column('datetime_value', 'datetime', array('default' => '0000-00-00 00:00:00'));
$table->column('date_value', 'date', array('default' => '0000-00-00'));
$table->column('time_value', 'time', array('default' => '00:00:00'));
$table->column('blob_value', 'binary', array('null' => false, 'default' => ''));
$table->column('boolean_value', 'boolean', array('default' => false));
$table->column('email_value', 'string', array('limit' => 255, 'default' => ''));
$table->end();
$this->_conn->addIndex('unit_tests', 'string_value', array('name' => 'string_value'));
$this->_conn->addIndex('unit_tests', 'integer_value', array('name' => 'integer_value', 'unique' => true));
$this->_conn->addIndex('unit_tests', array('integer_value', 'string_value'), array('name' => 'integer_string'));
// read sql file for statements
$statements = array();
$current_stmt = '';
$fp = fopen(__DIR__ . '/../fixtures/unit_tests.sql', 'r');
while ($line = fgets($fp, 8192)) {
$line = rtrim(preg_replace('/^(.*)--.*$/s', '\1', $line));
if (!$line) {
continue;
}
$current_stmt .= $line;
if (substr($line, -1) == ';') {
// leave off the ending ;
$statements[] = substr($current_stmt, 0, -1);
$current_stmt = '';
}
}
// run statements
foreach ($statements as $stmt) {
$this->_conn->execute($stmt);
}
}
protected function tearDown()
{
// clean up
$this->_dropTestTables();
// close connection
$this->_conn->disconnect();
}
/*##########################################################################
# Connection
##########################################################################*/
public function testConnect()
{
$this->assertTrue($this->_conn->isActive());
}
public function testDisconnect()
{
$this->_conn->disconnect();
$this->assertFalse($this->_conn->isActive());
$this->_conn->connect();
$this->assertTrue($this->_conn->isActive());
}
public function testReconnect()
{
$this->_conn->reconnect();
$this->assertTrue($this->_conn->isActive());
}
/*##########################################################################
# Accessor
##########################################################################*/
public function testAdapterName()
{
$this->assertEquals('MySQL', $this->_conn->adapterName());
}
public function testSupportsMigrations()
{
$this->assertTrue($this->_conn->supportsMigrations());
}
public function testSupportsCountDistinct()
{
$this->assertTrue($this->_conn->supportsCountDistinct());
}
public function testGetCharset()
{
$this->assertEquals('utf8', strtolower($this->_conn->getCharset()));
}
/*##########################################################################
# Database Statements
##########################################################################*/
public function testExecute()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->execute($sql);
$row = mysql_fetch_assoc($result);
$this->assertEquals(1, $row['id']);
}
public function testSelect()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->select($sql);
$this->assertInstanceOf('Traversable', $result);
$this->assertGreaterThan(0, count($result));
foreach ($result as $row) break;
$this->assertInternalType('array', $row);
$this->assertEquals(1, $row['id']);
}
public function testSelectWithBoundParameters()
{
$sql = "SELECT * FROM unit_tests WHERE id=?";
$result = $this->_conn->select($sql, array(1));
$this->assertInstanceOf('Traversable', $result);
$this->assertGreaterThan(0, count($result));
foreach ($result as $row) break;
$this->assertInternalType('array', $row);
$this->assertEquals(1, $row['id']);
}
public function testSelectWithBoundParametersQuotesString()
{
$sql = "SELECT * FROM unit_tests WHERE string_value=?";
$result = $this->_conn->select($sql, array('name a'));
$this->assertInstanceOf('Traversable', $result);
$this->assertGreaterThan(0, count($result));
foreach ($result as $row) break;
$this->assertInternalType('array', $row);
$this->assertEquals(1, $row['id']);
}
public function testSelectAll()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->selectAll($sql);
$this->assertInternalType('array', $result);
$this->assertGreaterThan(0, count($result));
$this->assertEquals(1, $result[0]['id']);
}
public function testSelectOne()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->selectOne($sql);
$this->assertEquals(1, $result['id']);
}
public function testSelectValue()
{
$sql = "SELECT * FROM unit_tests WHERE id='1'";
$result = $this->_conn->selectValue($sql);
$this->assertEquals(1, $result);
}
public function testSelectValues()
{
$sql = "SELECT * FROM unit_tests";
$result = $this->_conn->selectValues($sql);
$this->assertEquals(array(1, 2, 3, 4, 5, 6), $result);
}
public function testInsert()
{
$sql = "INSERT INTO unit_tests (id, integer_value) VALUES (7, 999)";
$result = $this->_conn->insert($sql);
$this->assertEquals(7, $result);
}
public function testUpdate()
{
$sql = "UPDATE unit_tests SET integer_value=999 WHERE id IN (1)";
$result = $this->_conn->update($sql);
$this->assertEquals(1, $result);
}
public function testDelete()
{
$sql = "DELETE FROM unit_tests WHERE id IN (1,2)";
$result = $this->_conn->delete($sql);
$this->assertEquals(2, $result);
}
public function testTransactionStarted()
{
$this->assertFalse($this->_conn->transactionStarted());
$this->_conn->beginDbTransaction();
$this->assertTrue($this->_conn->transactionStarted());
$this->_conn->commitDbTransaction();
$this->assertFalse($this->_conn->transactionStarted());
}
public function testTransactionCommit()
{
$this->_conn->beginDbTransaction();
$sql = "INSERT INTO unit_tests (id, integer_value) VALUES (7, 999)";
$this->_conn->insert($sql);
$this->_conn->commitDbTransaction();
// make sure it inserted
$sql = "SELECT integer_value FROM unit_tests WHERE id='7'";
$this->assertEquals('999', $this->_conn->selectValue($sql));
}
public function testTransactionRollback()
{
$this->_conn->beginDbTransaction();
$sql = "INSERT INTO unit_tests (id, integer_value) VALUES (7, 999)";
$this->_conn->insert($sql);
$this->_conn->rollbackDbTransaction();
// make sure it inserted
$sql = "SELECT integer_value FROM unit_tests WHERE id='7'";
$this->assertEquals(null, $this->_conn->selectValue($sql));
}
/*##########################################################################
# Quoting
##########################################################################*/
public function testQuoteNull()
{
$this->assertEquals('NULL', $this->_conn->quote(null));
}
public function testQuoteTrue()
{
$this->assertEquals('1', $this->_conn->quote(true));
}
public function testQuoteFalse()
{
$this->assertEquals('0', $this->_conn->quote(false));
}
public function testQuoteInteger()
{
$this->assertEquals('42', $this->_conn->quote(42));
}
public function testQuoteFloat()
{
$this->assertEquals('42.2', $this->_conn->quote(42.2));
setlocale(LC_NUMERIC, 'de_DE.UTF-8');
$this->assertEquals('42.2', $this->_conn->quote(42.2));
}
public function testQuoteString()
{
$this->assertEquals("'my string'", $this->_conn->quote('my string'));
}
public function testQuoteDirtyString()
{
$this->assertEquals("'derek\'s string'", $this->_conn->quote('derek\'s string'));
}
public function testQuoteColumnName()
{
$col = new Horde_Db_Adapter_Mysql_Column('age', 'NULL', 'int(11)');
$this->assertEquals('1', $this->_conn->quote(true, $col));
}
public function testQuoteBinary()
{
// Test string is foo\0ba'r - should be 8 bytes long
$original = base64_decode('Zm9vAGJhJ3I=');
$table = $this->_conn->createTable('binary_testings');
$table->column('data', 'binary', array('null' => false));
$table->end();
$this->_conn->insert('INSERT INTO binary_testings (data) VALUES (?)', array(new Horde_Db_Value_Binary($original)));
$retrieved = $this->_conn->selectValue('SELECT data FROM binary_testings');
$columns = $this->_conn->columns('binary_testings');
$retrieved = $columns['data']->binaryToString($retrieved);
$this->assertEquals($original, $retrieved);
}
/*##########################################################################
# Schema Statements
##########################################################################*/
/**
* We specifically do a manual INSERT here, and then test only the SELECT
* functionality. This allows us to more easily catch INSERT being broken,
* but SELECT actually working fine.
*/
public function testNativeDecimalInsertManualVsAutomatic()
{
$this->_createTestUsersTable();
$correctValue = 12345678901234567890.0123456789;
$this->_conn->addColumn("users", "wealth", 'decimal', array('precision' => 30, 'scale' => 10));
// do a manual insertion
$this->_conn->execute("INSERT INTO users (wealth) VALUES ('12345678901234567890.0123456789')");
// SELECT @todo - type cast attribute values
$user = (object)$this->_conn->selectOne('SELECT * FROM users');
// assert_kind_of BigDecimal, row.wealth
// If this assert fails, that means the SELECT is broken!
$this->assertEquals($correctValue, $user->wealth);
// Reset to old state
$this->_conn->delete('DELETE FROM users');
// Now use the Adapter insertion
$this->_conn->insert('INSERT INTO users (wealth) VALUES (12345678901234567890.0123456789)');
// SELECT @todo - type cast attribute values
$user = (object)$this->_conn->selectOne('SELECT * FROM users');
// assert_kind_of BigDecimal, row.wealth
// If these asserts fail, that means the INSERT (create function, or cast to SQL) is broken!
$this->assertEquals($correctValue, $user->wealth);
}
public function testNativeTypes()
{
$this->_createTestUsersTable();
$this->_conn->addColumn("users", "last_name", 'string');
$this->_conn->addColumn("users", "bio", 'text');
$this->_conn->addColumn("users", "age", 'integer');
$this->_conn->addColumn("users", "height", 'float');
$this->_conn->addColumn("users", "wealth", 'decimal', array('precision' => '30', 'scale' => '10'));
$this->_conn->addColumn("users", "birthday", 'datetime');
$this->_conn->addColumn("users", "favorite_day", 'date');
$this->_conn->addColumn("users", "moment_of_truth", 'datetime');
$this->_conn->addColumn("users", "male", 'boolean');
$this->_conn->insert('INSERT INTO users (first_name, last_name, bio, age, height, wealth, birthday, favorite_day, moment_of_truth, male, company_id) ' .
"VALUES ('bob', 'bobsen', 'I was born ....', 18, 1.78, 12345678901234567890.0123456789, '2005-01-01 12:23:40', '1980-03-05', '1582-10-10 21:40:18', 1, 1)");
$bob = (object)$this->_conn->selectOne('SELECT * FROM users');
$this->assertEquals('bob', $bob->first_name);
$this->assertEquals('bobsen', $bob->last_name);
$this->assertEquals('I was born ....', $bob->bio);
$this->assertEquals(18, $bob->age);
// Test for 30 significent digits (beyond the 16 of float), 10 of them
// after the decimal place.
$this->assertEquals('12345678901234567890.0123456789', $bob->wealth);
$this->assertEquals(1, $bob->male);
// @todo - type casting
}
public function testNativeDatabaseTypes()
{
$types = $this->_conn->nativeDatabaseTypes();
$this->assertEquals(array('name' => 'int', 'limit' => 11), $types['integer']);
}
public function testUnabstractedDatabaseDependentTypes()
{
$this->_createTestUsersTable();
$this->_conn->delete('DELETE FROM users');
$this->_conn->addColumn('users', 'intelligence_quotient', 'tinyint');
$this->_conn->insert('INSERT INTO users (intelligence_quotient) VALUES (300)');
$jonnyg = (object)$this->_conn->selectOne('SELECT * FROM users');
$this->assertEquals('127', $jonnyg->intelligence_quotient);
}
public function testTableAliasLength()
{
$len = $this->_conn->tableAliasLength();
$this->assertEquals(255, $len);
}
public function testTableAliasFor()
{
$alias = $this->_conn->tableAliasFor('my_table_name');
$this->assertEquals('my_table_name', $alias);
}
public function testTables()
{
$tables = $this->_conn->tables();
$this->assertTrue(count($tables) > 0);
$this->assertContains('unit_tests', $tables);
}
public function testPrimaryKey()
{
$pk = $this->_conn->primaryKey('unit_tests');
$this->assertEquals('id', (string)$pk);
$this->assertEquals(1, count($pk->columns));
$this->assertEquals('id', $pk->columns[0]);
$table = $this->_conn->createTable('pk_tests', array('autoincrementKey' => false));
$table->column('foo', 'string');
$table->column('bar', 'string');
$table->end();
$pk = $this->_conn->primaryKey('pk_tests');
$this->assertEmpty((string)$pk);
$this->assertEquals(0, count($pk->columns));
$this->_conn->addPrimaryKey('pk_tests', 'foo');
$pk = $this->_conn->primaryKey('pk_tests');
$this->assertEquals('foo', (string)$pk);
$this->assertEquals(1, count($pk->columns));
$this->_conn->removePrimaryKey('pk_tests');
$pk = $this->_conn->primaryKey('pk_tests');
$this->assertEmpty((string)$pk);
$this->assertEquals(0, count($pk->columns));
$this->_conn->addPrimaryKey('pk_tests', array('foo', 'bar'));
$pk = $this->_conn->primaryKey('pk_tests');
$this->assertEquals('foo,bar', (string)$pk);
}
public function testIndexes()
{
$indexes = $this->_conn->indexes('unit_tests');
$this->assertEquals(3, count($indexes));
// unique index
$col = array('integer_value');
$this->assertEquals('unit_tests', $indexes[0]->table);
$this->assertEquals('integer_value', $indexes[0]->name);
$this->assertEquals(true, $indexes[0]->unique);
$this->assertEquals($col, $indexes[0]->columns);
// normal index
$col = array('string_value');
$this->assertEquals('unit_tests', $indexes[1]->table);
$this->assertEquals('string_value', $indexes[1]->name);
$this->assertEquals(false, $indexes[1]->unique);
$this->assertEquals($col, $indexes[1]->columns);
// multi-column index
$col = array('integer_value', 'string_value');
$this->assertEquals('unit_tests', $indexes[2]->table);
$this->assertEquals('integer_string', $indexes[2]->name);
$this->assertEquals(false, $indexes[2]->unique);
$this->assertEquals($col, $indexes[2]->columns);
}
public function testColumns()
{
$columns = $this->_conn->columns('unit_tests');
$this->assertEquals(12, count($columns));
$col = $columns['id'];
$this->assertEquals('id', $col->getName());
$this->assertEquals('integer', $col->getType());
$this->assertEquals(false, $col->isNull());
$this->assertEquals(10, $col->getLimit());
$this->assertEquals(true, $col->isUnsigned());
$this->assertEquals('', $col->getDefault());
$this->assertEquals('int(10) unsigned', $col->getSqlType());
$this->assertEquals(false, $col->isText());
$this->assertEquals(true, $col->isNumber());
}
public function testCreateTable()
{
$this->_createTestTable('sports');
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
}
public function testCreateTableNoPk()
{
$this->_createTestTable('sports', array('autoincrementKey' => false));
try {
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertNull($this->_conn->selectValue($sql));
} catch (Exception $e) {
return;
}
$this->fail("Expected exception for no pk");
}
public function testCreateTableWithNamedPk()
{
$this->_createTestTable('sports', array('autoincrementKey' => 'sports_id'));
$sql = "SELECT sports_id FROM sports WHERE sports_id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
try {
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertNull($this->_conn->selectValue($sql));
} catch (Exception $e) {
return;
}
$this->fail("Expected exception for wrong pk name");
}
public function testCreateTableWithSeparatePk()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'autoincrementKey');
$pkColumn = $table['foo'];
$this->assertEquals('`foo` int(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY', $pkColumn->toSql());
}
public function testCreateTableCompositePk()
{
$table = $this->_conn->createTable('testings', array('autoincrementKey' => array('a_id', 'b_id')));
$table->column('a_id', 'integer');
$table->column('b_id', 'integer');
$table->end();
$pk = $this->_conn->primaryKey('testings');
$this->assertEquals(array('a_id', 'b_id'), $pk->columns);
}
public function testCreateTableForce()
{
$this->_createTestTable('sports');
$this->_createTestTable('sports', array('force' => true));
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
}
public function testCreateTableTemporary()
{
$this->_createTestTable('sports', array('temporary' => true));
$sql = "SELECT id FROM sports WHERE id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
}
public function testCreateTableAddsId()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string');
$table->end();
$columns = array();
foreach ($this->_conn->columns('testings') as $col) {
$columns[] = $col->getName();
}
sort($columns);
$this->assertEquals(array('foo', 'id'), $columns);
}
public function testCreateTableWithNotNullColumn()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string', array('null' => false));
$table->end();
try {
$this->_conn->execute("INSERT INTO testings (foo) VALUES (NULL)");
} catch (Exception $e) { return; }
$this->fail('Expected exception wasn\'t raised');
}
public function testCreateTableWithDefaults()
{
$table = $this->_conn->createTable('testings');
$table->column('one', 'string', array('default' => 'hello'));
$table->column('two', 'boolean', array('default' => true));
$table->column('three', 'boolean', array('default' => false));
$table->column('four', 'integer', array('default' => 1));
$table->end();
$columns = array();
foreach ($this->_conn->columns('testings') as $col) {
$columns[$col->getName()] = $col;
}
$this->assertEquals('hello', $columns['one']->getDefault());
$this->assertTrue($columns['two']->getDefault());
$this->assertFalse($columns['three']->getDefault());
$this->assertEquals(1, $columns['four']->getDefault());
}
public function testCreateTableWithLimits()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string', array('limit' => 80));
$table->end();
$columns = array();
foreach ($this->_conn->columns('testings') as $col) {
$columns[$col->getName()] = $col;
}
$this->assertEquals(80, $columns['foo']->getLimit());
}
public function testCreateTableWithBinaryColumn()
{
try {
$table = $this->_conn->createTable('binary_testings');
$table->column('data', 'binary', array('null' => false));
$table->end();
} catch (Exception $e) { $this->fail('Unexepected exception raised'); }
$columns = $this->_conn->columns('binary_testings');
foreach ($columns as $c) {
if ($c->getName() == 'data') { $dataColumn = $c; }
}
$this->assertEquals('', $dataColumn->getDefault());
}
public function testRenameTable()
{
// Simple rename then select test
$this->_createTestTable('sports');
$this->_conn->renameTable('sports', 'my_sports');
$sql = "SELECT id FROM my_sports WHERE id = 1";
$this->assertEquals("1", $this->_conn->selectValue($sql));
// Make sure the old table name isn't still there
try {
$sql = "SELECT id FROM sports WHERE id = 1";
$this->_conn->execute($sql);
} catch (Exception $e) {
return;
}
$this->fail("Table exists where it shouldn't have");
// Rename then insert test
$table = $this->_conn->createTable('octopuses');
$table->column('url', 'string');
$table->end();
$this->_conn->renameTable('octopuses', 'octopi');
$sql = "INSERT INTO octopi (id, url) VALUES (1, 'http://www.foreverflying.com/octopus-black7.jpg')";
$this->_conn->execute($sql);
$this->assertEquals('http://www.foreverflying.com/octopus-black7.jpg',
$this->_conn->selectValue("SELECT url FROM octopi WHERE id=1"));
// Make sure the old table name isn't still there
try {
$sql = "SELECT id FROM octopuses WHERE id = 1";
$this->_conn->execute($sql);
} catch (Exception $e) {
return;
}
$this->fail("Table exists where it shouldn't have");
}
public function testRenameTableWithAnIndex()
{
$table = $this->_conn->createTable('octopuses');
$table->column('url', 'string');
$table->end();
$this->_conn->addIndex('octopuses', 'url');
$this->_conn->renameTable('octopuses', 'octopi');
$sql = "INSERT INTO octopi (id, url) VALUES (1, 'http://www.foreverflying.com/octopus-black7.jpg')";
$this->_conn->execute($sql);
$this->assertEquals('http://www.foreverflying.com/octopus-black7.jpg',
$this->_conn->selectValue("SELECT url FROM octopi WHERE id=1"));
$indexes = $this->_conn->indexes('octopi');
$this->assertEquals('url', $indexes[0]->columns[0]);
}
public function testDropTable()
{
$this->_createTestTable('sports');
$this->_conn->dropTable('sports');
try {
$sql = "SELECT id FROM sports WHERE id = 1";
$this->_conn->execute($sql);
} catch (Exception $e) {
return;
}
$this->fail("Table exists where it shouldn't have");
}
public function testAddColumn()
{
$this->_createTestTable('sports');
$this->_conn->addColumn('sports', 'modified_at', 'date');
$this->_conn->update("UPDATE sports SET modified_at = '2007-01-01'");
$sql = "SELECT modified_at FROM sports WHERE id = 1";
$this->assertEquals("2007-01-01", $this->_conn->selectValue($sql));
$this->_conn->addColumn('sports', 'with_default', 'integer', array('default' => 1));
$sql = "SELECT with_default FROM sports WHERE id = 1";
$this->assertEquals(1, $this->_conn->selectValue($sql));
}
public function testRemoveColumn()
{
$this->_createTestTable('sports');
$sql = "SELECT name FROM sports WHERE id = 1";
$this->assertEquals("mlb", $this->_conn->selectValue($sql));
$this->_conn->removeColumn('sports', 'name');
try {
$sql = "SELECT name FROM sports WHERE id = 1";
$this->_conn->execute($sql);
} catch (Exception $e) {
return;
}
$this->fail("Column exists where it shouldn't have");
}
public function testChangeColumn()
{
$this->_createTestUsersTable();
$this->_conn->addColumn('users', 'age', 'integer');
$oldColumns = $this->_conn->columns('users', "User Columns");
$found = false;
foreach ($oldColumns as $c) {
if ($c->getName() == 'age' && $c->getType() == 'integer') {
$found = true;
}
}
$this->assertTrue($found);
$this->_conn->changeColumn('users', 'age', 'string');
$newColumns = $this->_conn->columns('users', "User Columns");
$found = false;
foreach ($newColumns as $c) {
if ($c->getName() == 'age' && $c->getType() == 'integer') {
$found = true;
}
}
$this->assertFalse($found);
$found = false;
foreach ($newColumns as $c) {
if ($c->getName() == 'age' && $c->getType() == 'string') {
$found = true;
}
}
$this->assertTrue($found);
$found = false;
foreach ($oldColumns as $c) {
if ($c->getName() == 'approved' &&
$c->getType() == 'boolean' &&
$c->getDefault() == true) {
$found = true;
}
}
$this->assertTrue($found);
// changeColumn() throws exception on error
$this->_conn->changeColumn('users', 'approved', 'boolean', array('default' => false));
$newColumns = $this->_conn->columns('users', "User Columns");
$found = false;
foreach ($newColumns as $c) {
if ($c->getName() == 'approved' &&
$c->getType() == 'boolean' &&
$c->getDefault() == true) {
$found = true;
}
}
$this->assertFalse($found);
$found = false;
foreach ($newColumns as $c) {
if ($c->getName() == 'approved' &&
$c->getType() == 'boolean' &&
$c->getDefault() == false) {
$found = true;
}
}
$this->assertTrue($found);
// changeColumn() throws exception on error
$this->_conn->changeColumn('users', 'approved', 'boolean', array('default' => true));
// Test converting to autoincrementKey
$this->_conn->changeColumn('users', 'id', 'integer');
$this->_conn->changeColumn('users', 'id', 'autoincrementKey');
// Test with non-existant primary key
$this->_conn->changeColumn('users', 'id', 'integer');
$this->_conn->execute('ALTER TABLE users DROP PRIMARY KEY');
$this->_conn->changeColumn('users', 'id', 'autoincrementKey');
}
public function testChangeColumnDefault()
{
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'name');
$this->assertEquals('', $beforeChange->getDefault());
$this->_conn->changeColumnDefault('sports', 'name', 'test');
$afterChange = $this->_getColumn('sports', 'name');
$this->assertEquals('test', $afterChange->getDefault());
}
public function testChangeColumnType()
{
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('tinyint(1)', $beforeChange->getSqlType());
$this->_conn->changeColumn('sports', 'is_college', 'string');
$afterChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('varchar(255)', $afterChange->getSqlType());
$table = $this->_conn->createTable('text_to_binary');
$table->column('data', 'text');
$table->end();
$this->_conn->insert('INSERT INTO text_to_binary (data) VALUES (?)',
array("foo\0bar"));
$this->_conn->changeColumn('text_to_binary', 'data', 'binary');
$afterChange = $this->_getColumn('text_to_binary', 'data');
$this->assertEquals('longblob', $afterChange->getSqlType());
$this->assertEquals(
"foo\0bar",
$this->_conn->selectValue('SELECT data FROM text_to_binary'));
}
public function testChangeColumnLimit()
{
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('tinyint(1)', $beforeChange->getSqlType());
$this->_conn->changeColumn('sports', 'is_college', 'string',
array('limit' => '40'));
$afterChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('varchar(40)', $afterChange->getSqlType());
}
public function testChangeColumnPrecisionScale()
{
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('tinyint(1)', $beforeChange->getSqlType());
$this->_conn->changeColumn('sports', 'is_college', 'decimal',
array('precision' => '5', 'scale' => '2'));
$afterChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('decimal(5,2)', $afterChange->getSqlType());
}
public function testChangeColumnUnsigned()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'integer');
$table->end();
$beforeChange = $this->_getColumn('testings', 'foo');
$this->assertFalse($beforeChange->isUnsigned());
$this->_conn->execute("INSERT INTO testings (id, foo) VALUES (1, -1)");
$this->_conn->changeColumn('testings', 'foo', 'integer', array('unsigned' => true));
$afterChange = $this->_getColumn('testings', 'foo');
$this->assertTrue($afterChange->isUnsigned());
$row = (object)$this->_conn->selectOne('SELECT * FROM testings');
$this->assertEquals(0, $row->foo);
}
public function testRenameColumn()
{
$this->_createTestUsersTable();
$this->_conn->renameColumn('users', 'first_name', 'nick_name');
$this->assertTrue(in_array('nick_name', $this->_columnNames('users')));
$this->_createTestTable('sports');
$beforeChange = $this->_getColumn('sports', 'is_college');
$this->assertEquals('tinyint(1)', $beforeChange->getSqlType());
$this->_conn->renameColumn('sports', 'is_college', 'is_renamed');
$afterChange = $this->_getColumn('sports', 'is_renamed');
$this->assertEquals('tinyint(1)', $afterChange->getSqlType());
}
public function testRenameColumnWithSqlReservedWord()
{
$this->_createTestUsersTable();
$this->_conn->renameColumn('users', 'first_name', 'group');
$this->assertTrue(in_array('group', $this->_columnNames('users')));
}
public function testAddIndex()
{
$this->_createTestUsersTable();
// Limit size of last_name and key columns to support Firebird index limitations
$this->_conn->addColumn('users', 'last_name', 'string', array('limit' => 100));
$this->_conn->addColumn('users', 'key', 'string', array('limit' => 100));
$this->_conn->addColumn('users', 'administrator', 'boolean');
$this->_conn->addIndex('users', 'last_name');
$this->_conn->removeIndex('users', 'last_name');
$this->_conn->addIndex('users', array('last_name', 'first_name'));
$this->_conn->removeIndex('users', array('column' => array('last_name', 'first_name')));
$this->_conn->addIndex('users', array('last_name', 'first_name'));
$this->_conn->removeIndex('users', array('name' => 'index_users_on_last_name_and_first_name'));
$this->_conn->addIndex('users', array('last_name', 'first_name'));
$this->_conn->removeIndex('users', 'last_name_and_first_name');
// quoting
$this->_conn->addIndex('users', array('key'), array('name' => 'key_idx', 'unique' => true));
$this->_conn->removeIndex('users', array('name' => 'key_idx', 'unique' => true));
$this->_conn->addIndex('users', array('last_name', 'first_name', 'administrator'),
array('name' => "named_admin"));
$this->_conn->removeIndex('users', array('name' => 'named_admin'));
}
public function testAddIndexDefault()
{
$this->_createTestTable('sports');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
$this->_conn->addIndex('sports', 'is_college');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
}
public function testAddIndexMultiColumn()
{
$this->_createTestTable('sports');
$index = $this->_getIndex('sports', array('name', 'is_college'));
$this->assertNull($index);
$this->_conn->addIndex('sports', array('name', 'is_college'));
$index = $this->_getIndex('sports', array('name', 'is_college'));
$this->assertNotNull($index);
}
public function testAddIndexUnique()
{
$this->_createTestTable('sports');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
$this->_conn->addIndex('sports', 'is_college', array('unique' => true));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
$this->assertTrue($index->unique);
}
public function testAddIndexName()
{
$this->_createTestTable('sports');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
$this->_conn->addIndex('sports', 'is_college', array('name' => 'test'));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
$this->assertEquals('test', $index->name);
}
public function testRemoveIndexSingleColumn()
{
$this->_createTestTable('sports');
// add the index
$this->_conn->addIndex('sports', 'is_college');
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
// remove it again
$this->_conn->removeIndex('sports', array('column' => 'is_college'));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
}
public function testRemoveIndexMultiColumn()
{
$this->_createTestTable('sports');
// add the index
$this->_conn->addIndex('sports', array('name', 'is_college'));
$index = $this->_getIndex('sports', array('name', 'is_college'));
$this->assertNotNull($index);
// remove it again
$this->_conn->removeIndex('sports', array('column' => array('name', 'is_college')));
$index = $this->_getIndex('sports', array('name', 'is_college'));
$this->assertNull($index);
}
public function testRemoveIndexByName()
{
$this->_createTestTable('sports');
// add the index
$this->_conn->addIndex('sports', 'is_college', array('name' => 'test'));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNotNull($index);
// remove it again
$this->_conn->removeIndex('sports', array('name' => 'test'));
$index = $this->_getIndex('sports', 'is_college');
$this->assertNull($index);
}
public function testIndexNameInvalid()
{
try {
$name = $this->_conn->indexName('sports');
} catch (Horde_Db_Exception $e) {
return;
}
$this->fail("Adding an index with crappy options worked where it shouldn't have");
}
public function testIndexNameBySingleColumn()
{
$name = $this->_conn->indexName('sports', array('column' => 'is_college'));
$this->assertEquals('index_sports_on_is_college', $name);
}
public function testIndexNameByMultiColumn()
{
$name = $this->_conn->indexName('sports', array('column' =>
array('name', 'is_college')));
$this->assertEquals('index_sports_on_name_and_is_college', $name);
}
public function testIndexNameByName()
{
$name = $this->_conn->indexName('sports', array('name' => 'test'));
$this->assertEquals('test', $name);
}
public function testTypeToSqlTypePrimaryKey()
{
$result = $this->_conn->typeToSql('autoincrementKey');
$this->assertEquals('int(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY', $result);
}
public function testTypeToSqlTypeString()
{
$result = $this->_conn->typeToSql('string');
$this->assertEquals('varchar(255)', $result);
}
public function testTypeToSqlTypeText()
{
$result = $this->_conn->typeToSql('text');
$this->assertEquals('text', $result);
}
public function testTypeToSqlTypeBinary()
{
$result = $this->_conn->typeToSql('binary');
$this->assertEquals('longblob', $result);
}
public function testTypeToSqlTypeFloat()
{
$result = $this->_conn->typeToSql('float');
$this->assertEquals('float', $result);
}
public function testTypeToSqlTypeDatetime()
{
$result = $this->_conn->typeToSql('datetime');
$this->assertEquals('datetime', $result);
}
public function testTypeToSqlTypeTimestamp()
{
$result = $this->_conn->typeToSql('timestamp');
$this->assertEquals('datetime', $result);
}
public function testTypeToSqlInt()
{
$result = $this->_conn->typeToSql('integer');
$this->assertEquals('int(11)', $result);
}
public function testTypeToSqlIntUnsigned()
{
$result = $this->_conn->typeToSql('integer', null, null, null, true);
$this->assertEquals('int(10) UNSIGNED', $result);
}
public function testTypeToSqlIntLimit()
{
$result = $this->_conn->typeToSql('integer', '1');
$this->assertEquals('int(1)', $result);
}
public function testTypeToSqlDecimalPrecision()
{
$result = $this->_conn->typeToSql('decimal', null, '5');
$this->assertEquals('decimal(5)', $result);
}
public function testTypeToSqlDecimalScale()
{
$result = $this->_conn->typeToSql('decimal', null, '5', '2');
$this->assertEquals('decimal(5, 2)', $result);
}
public function testTypeToSqlBoolean()
{
$result = $this->_conn->typeToSql('boolean');
$this->assertEquals('tinyint(1)', $result);
}
public function testAddColumnOptions()
{
$result = $this->_conn->addColumnOptions("test", array());
$this->assertEquals("test", $result);
}
public function testAddColumnOptionsDefault()
{
$options = array('default' => '0');
$result = $this->_conn->addColumnOptions("test", $options);
$this->assertEquals("test DEFAULT '0'", $result);
}
public function testAddColumnOptionsNull()
{
$options = array('null' => true);
$result = $this->_conn->addColumnOptions("test", $options);
$this->assertEquals("test", $result);
}
public function testAddColumnOptionsNotNull()
{
$options = array('null' => false);
$result = $this->_conn->addColumnOptions("test", $options);
$this->assertEquals("test NOT NULL", $result);
}
public function testAddColumnNotNullWithoutDefault()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string');
$table->end();
$this->_conn->addColumn('testings', 'bar', 'string', array('null' => false, 'default' => ''));
try {
$this->_conn->execute("INSERT INTO testings (foo, bar) VALUES ('hello', NULL)");
} catch (Exception $e) { return; }
$this->fail('Expected exception wasn\'t raised');
}
public function testAddColumnNotNullWithDefault()
{
$table = $this->_conn->createTable('testings');
$table->column('foo', 'string');
$table->end();
$this->_conn->execute("INSERT INTO testings (id, foo) VALUES ('1', 'hello')");
$this->_conn->addColumn('testings', 'bar', 'string', array('null' => false, 'default' => 'default'));
try {
$this->_conn->execute("INSERT INTO testings (id, foo, bar) VALUES (2, 'hello', NULL)");
} catch (Exception $e) { return; }
$this->fail('Expected exception wasn\'t raised');
}
public function testAddRemoveSingleField()
{
$this->_createTestUsersTable();
$this->assertFalse(in_array('last_name', $this->_columnNames('users')));
$this->_conn->addColumn('users', 'last_name', 'string');
$this->assertTrue(in_array('last_name', $this->_columnNames('users')));
$this->_conn->removeColumn('users', 'last_name');
$this->assertFalse(in_array('last_name', $this->_columnNames('users')));
}
public function testAddRename()
{
$this->_createTestUsersTable();
$this->_conn->delete('DELETE FROM users');
$this->_conn->addColumn('users', 'girlfriend', 'string');
$this->_conn->insert("INSERT INTO users (girlfriend) VALUES ('bobette')");
$this->_conn->renameColumn('users', 'girlfriend', 'exgirlfriend');
$bob = (object)$this->_conn->selectOne('SELECT * FROM users');
$this->assertEquals('bobette', $bob->exgirlfriend);
}
public function testDistinct()
{
$result = $this->_conn->distinct("test");
$this->assertEquals("DISTINCT test", $result);
}
public function testAddOrderByForAssocLimiting()
{
$result = $this->_conn->addOrderByForAssocLimiting("SELECT * FROM documents ",
array('order' => 'name DESC'));
$this->assertEquals("SELECT * FROM documents ORDER BY name DESC", $result);
}
public function testInterval()
{
$this->assertEquals('INTERVAL 1 DAY',
$this->_conn->interval('1 DAY', ''));
}
public function testModifyDate()
{
$modifiedDate = $this->_conn->modifyDate('start', '+', 1, 'DAY');
$this->assertEquals('start + INTERVAL \'1\' DAY', $modifiedDate);
$t = $this->_conn->createTable('dates');
$t->column('start', 'datetime');
$t->column('end', 'datetime');
$t->end();
$this->_conn->insert(
'INSERT INTO dates (start, end) VALUES (?, ?)',
array(
'2011-12-10 00:00:00',
'2011-12-11 00:00:00'
)
);
$this->assertEquals(
1,
$this->_conn->selectValue('SELECT COUNT(*) FROM dates WHERE '
. $modifiedDate . ' = end')
);
}
public function testBuildClause()
{
$this->assertEquals(
'bitmap & 2',
$this->_conn->buildClause('bitmap', '&', 2));
$this->assertEquals(
array('bitmap & ?', array(2)),
$this->_conn->buildClause('bitmap', '&', 2, true));
$this->assertEquals(
'bitmap | 2',
$this->_conn->buildClause('bitmap', '|', 2));
$this->assertEquals(
array('bitmap | ?', array(2)),
$this->_conn->buildClause('bitmap', '|', 2, true));
$this->assertEquals(
"LOWER(name) LIKE LOWER('%search%')",
$this->_conn->buildClause('name', 'LIKE', "search"));
$this->assertEquals(
array("LOWER(name) LIKE LOWER(?)", array('%search%')),
$this->_conn->buildClause('name', 'LIKE', "search", true));
$this->assertEquals(
"LOWER(name) LIKE LOWER('%search\&replace\?%')",
$this->_conn->buildClause('name', 'LIKE', "search&replace?"));
$this->assertEquals(
array("LOWER(name) LIKE LOWER(?)", array('%search&replace?%')),
$this->_conn->buildClause('name', 'LIKE', "search&replace?", true));
$this->assertEquals(
"(LOWER(name) LIKE LOWER('search\&replace\?%') OR LOWER(name) LIKE LOWER('% search\&replace\?%'))",
$this->_conn->buildClause('name', 'LIKE', "search&replace?", false, array('begin' => true)));
$this->assertEquals(
array("(LOWER(name) LIKE LOWER(?) OR LOWER(name) LIKE LOWER(?))",
array('search&replace?%', '% search&replace?%')),
$this->_conn->buildClause('name', 'LIKE', "search&replace?", true, array('begin' => true)));
$this->assertEquals(
'value = 2',
$this->_conn->buildClause('value', '=', 2));
$this->assertEquals(
array('value = ?', array(2)),
$this->_conn->buildClause('value', '=', 2, true));
$this->assertEquals(
"value = 'foo'",
$this->_conn->buildClause('value', '=', 'foo'));
$this->assertEquals(
array('value = ?', array('foo')),
$this->_conn->buildClause('value', '=', 'foo', true));
$this->assertEquals(
"value = 'foo\?bar'",
$this->_conn->buildClause('value', '=', 'foo?bar'));
$this->assertEquals(
array('value = ?', array('foo?bar')),
$this->_conn->buildClause('value', '=', 'foo?bar', true));
}
public function testInsertAndReadInCp1257()
{
list($conn,) = self::getConnection(array('charset' => 'cp1257'));
$table = $conn->createTable('charset_cp1257');
$table->column('text', 'string');
$table->end();
$input = file_get_contents(__DIR__ . '/../fixtures/charsets/cp1257.txt');
$conn->insert("INSERT INTO charset_cp1257 (text) VALUES (?)", array($input));
$output = $conn->selectValue('SELECT text FROM charset_cp1257');
$this->assertEquals($input, $output);
}
public function testInsertAndReadInUtf8()
{
list($conn,) = self::getConnection(array('charset' => 'utf8'));
$table = $conn->createTable('charset_utf8');
$table->column('text', 'string');
$table->end();
$input = file_get_contents(__DIR__ . '/../fixtures/charsets/utf8.txt');
$conn->insert("INSERT INTO charset_utf8 (text) VALUES (?)", array($input));
$output = $conn->selectValue('SELECT text FROM charset_utf8');
$this->assertEquals($input, $output);
}
/*##########################################################################
# Table cache
##########################################################################*/
public function testCachedTableIndexes()
{
// remove any current cache.
$this->_cache->set('tables/indexes/cache_table', '');
$this->assertEquals('', $this->_cache->get('tables/indexes/cache_table', 0));
$this->_createTestTable('cache_table');
$idxs = $this->_conn->indexes('cache_table');
$this->assertNotEquals('', $this->_cache->get('tables/indexes/cache_table', 0));
}
public function testCachedTableColumns()
{
// remove any current cache.
$this->_cache->set('tables/columns/cache_table', '');
$this->assertEquals('', $this->_cache->get('tables/columns/cache_table', 0));
$this->_createTestTable('cache_table');
$cols = $this->_conn->columns('cache_table');
$this->assertNotEquals('', $this->_cache->get('tables/columns/cache_table', 0));
}
/*##########################################################################
# Protected
##########################################################################*/
/**
* Create table to perform tests on
*/
protected function _createTestTable($name, $options=array())
{
$table = $this->_conn->createTable($name, $options);
$table->column('name', 'string');
$table->column('is_college', 'boolean');
$table->end();
try {
// make sure table was created
$sql = "INSERT INTO $name
VALUES (1, 'mlb', 0)";
$this->_conn->insert($sql);
} catch (Exception $e) {}
}
protected function _createTestUsersTable()
{
$table = $this->_conn->createTable('users');
$table->column('company_id', 'integer', array('limit' => 11));
$table->column('name', 'string', array('limit' => 255, 'default' => ''));
$table->column('first_name', 'string', array('limit' => 40, 'default' => ''));
$table->column('approved', 'boolean', array('default' => true));
$table->column('type', 'string', array('limit' => 255, 'default' => ''));
$table->column('created_at', 'datetime', array('default' => '0000-00-00 00:00:00'));
$table->column('created_on', 'date', array('default' => '0000-00-00'));
$table->column('updated_at', 'datetime', array('default' => '0000-00-00 00:00:00'));
$table->column('updated_on', 'date', array('default' => '0000-00-00'));
$table->end();
}
/**
* drop test tables
*/
protected function _dropTestTables()
{
$tables = array(
'binary_testings',
'cache_table',
'charset_cp1257',
'charset_utf8',
'dates',
'my_sports',
'octopi',
'pk_tests',
'schema_info',
'sports',
'testings',
'text_to_binary',
'unit_tests',
'users',
);
foreach ($tables as $table) {
try {
$this->_conn->dropTable($table);
} catch (Exception $e) {}
}
}
protected function _columnNames($tableName)
{
$columns = array();
foreach ($this->_conn->columns($tableName) as $c) {
$columns[] = $c->getName();
}
return $columns;
}
/**
* Get a column by name
*/
protected function _getColumn($table, $column)
{
foreach ($this->_conn->columns($table) as $col) {
if ($col->getName() == $column) return $col;
}
}
/**
* Get an index by columns
*/
protected function _getIndex($table, $indexes)
{
$indexes = (array) $indexes;
sort($indexes);
foreach ($this->_conn->indexes($table) as $index) {
$columns = $index->columns;
sort($columns);
if ($columns == $indexes) return $index;
}
}
public function testColumnConstruct()
{
self::$columnTest->testConstruct();
}
public function testColumnToSql()
{
self::$columnTest->testToSql();
}
public function testColumnToSqlLimit()
{
self::$columnTest->testToSqlLimit();
}
public function testColumnToSqlPrecisionScale()
{
self::$columnTest->testToSqlPrecisionScale();
}
public function testColumnToSqlUnsigned()
{
self::$columnTest->testToSqlUnsigned();
}
public function testColumnToSqlNotNull()
{
self::$columnTest->testToSqlNotNull();
}
public function testColumnToSqlDefault()
{
self::$columnTest->testToSqlDefault();
}
public function testTableConstruct()
{
self::$tableTest->testConstruct();
}
public function testTableName()
{
self::$tableTest->testName();
}
public function testTableGetOptions()
{
self::$tableTest->testGetOptions();
}
public function testTablePrimaryKey()
{
self::$tableTest->testPrimaryKey();
}
public function testTableColumn()
{
self::$tableTest->testColumn();
}
public function testTableToSql()
{
self::$tableTest->testToSql();
}
}
Horde_Db-2.0.4/test/Horde/Db/fixtures/charsets/cp1257.txt 0000644 0001750 0001750 00000000011 12205351473 020773 0 ustar jan jan Að þinau
Horde_Db-2.0.4/test/Horde/Db/fixtures/charsets/utf8.txt 0000644 0001750 0001750 00000000004 12205351473 020742 0 ustar jan jan ☃
Horde_Db-2.0.4/test/Horde/Db/fixtures/migrations/1_users_have_last_names1.php 0000644 0001750 0001750 00000000376 12205351473 025253 0 ustar jan jan addColumn('users', 'last_name', 'string');
}
public function down()
{
$this->removeColumn('users', 'last_name');
}
} Horde_Db-2.0.4/test/Horde/Db/fixtures/migrations/2_we_need_reminders1.php 0000644 0001750 0001750 00000000524 12205351473 024353 0 ustar jan jan createTable('reminders');
$t->column('content', 'text');
$t->column('remind_at', 'datetime');
$t->end();
}
public function down()
{
$this->dropTable('reminders');
}
} Horde_Db-2.0.4/test/Horde/Db/fixtures/migrations/3_innocent_jointable1.php 0000644 0001750 0001750 00000000614 12205351473 024542 0 ustar jan jan createTable('users_reminders', array('autoincrementKey' => false));
$t->column('reminder_id', 'integer');
$t->column('user_id', 'integer');
$t->end();
}
public function down()
{
$this->dropTable('users_reminders');
}
} Horde_Db-2.0.4/test/Horde/Db/fixtures/migrations_with_decimal/1_give_me_big_numbers.php 0000644 0001750 0001750 00000001273 12205351473 027315 0 ustar jan jan createTable('big_numbers');
$table->column('bank_balance', 'decimal', array('precision' => 10, 'scale' => 2));
$table->column('big_bank_balance', 'decimal', array('precision' => 15, 'scale' => 2));
$table->column('world_population', 'decimal', array('precision' => 10));
$table->column('my_house_population', 'decimal', array('precision' => 2));
$table->column('value_of_e', 'decimal');
$table->end();
}
public function down()
{
$this->dropTable('big_numbers');
}
} Horde_Db-2.0.4/test/Horde/Db/fixtures/migrations_with_duplicate/1_users_have_last_names2.php 0000644 0001750 0001750 00000000376 12205351473 030341 0 ustar jan jan addColumn('users', 'last_name', 'string');
}
public function down()
{
$this->removeColumn('users', 'last_name');
}
} Horde_Db-2.0.4/test/Horde/Db/fixtures/migrations_with_duplicate/2_we_need_reminders2.php 0000644 0001750 0001750 00000000524 12205351473 027441 0 ustar jan jan createTable('reminders');
$t->column('content', 'text');
$t->column('remind_at', 'datetime');
$t->end();
}
public function down()
{
$this->dropTable('reminders');
}
} Horde_Db-2.0.4/test/Horde/Db/fixtures/migrations_with_duplicate/3_foo.php 0000644 0001750 0001750 00000000201 12205351473 024455 0 ustar jan jan createTable('users_reminders', array('autoincrementKey' => false));
$t->column('reminder_id', 'integer');
$t->column('user_id', 'integer');
$t->end();
}
public function down()
{
$this->dropTable('users_reminders');
}
} Horde_Db-2.0.4/test/Horde/Db/fixtures/migrations_with_missing_versions/1_users_have_last_names3.php 0000644 0001750 0001750 00000000376 12205351473 031771 0 ustar jan jan addColumn('users', 'last_name', 'string');
}
public function down()
{
$this->removeColumn('users', 'last_name');
}
} Horde_Db-2.0.4/test/Horde/Db/fixtures/migrations_with_missing_versions/3_we_need_reminders.php 0000644 0001750 0001750 00000000523 12205351473 031006 0 ustar jan jan createTable('reminders');
$t->column('content', 'text');
$t->column('remind_at', 'datetime');
$t->end();
}
public function down()
{
$this->dropTable('reminders');
}
}
Horde_Db-2.0.4/test/Horde/Db/fixtures/migrations_with_missing_versions/4_innocent_jointable3.php 0000644 0001750 0001750 00000000614 12205351473 031261 0 ustar jan jan createTable('users_reminders', array('autoincrementKey' => false));
$t->column('reminder_id', 'integer');
$t->column('user_id', 'integer');
$t->end();
}
public function down()
{
$this->dropTable('users_reminders');
}
}
././@LongLink 0 0 0 147 0 003740 L Horde_Db-2.0.4/test/Horde/Db/fixtures/migrations_with_missing_versions/1000_users_have_middle_names.php Horde_Db-2.0.4/test/Horde/Db/fixtures/migrations_with_missing_versions/1000_users_have_middle_names.0000644 0001750 0001750 00000000403 12205351473 031700 0 ustar jan jan addColumn('users', 'middle_name', 'string');
}
public function down()
{
$this->removeColumn('users', 'middle_name');
}
} Horde_Db-2.0.4/test/Horde/Db/fixtures/drop_create_table.sql 0000644 0001750 0001750 00000001140 12205351473 021660 0 ustar jan jan -- MySQL dump 10.11
--
-- Host: localhost Database: eemaster
-- ------------------------------------------------------
-- Server version 5.0.27-standard
--
-- Table structure for table `exp_actions`
--
DROP TABLE IF EXISTS `exp_actions`;
SET @saved_cs_client = @@character_set_client;
SET character_set_client = utf8;
CREATE TABLE `exp_actions` (
`action_id` int(4) unsigned NOT NULL auto_increment,
`class` varchar(50) NOT NULL,
`method` varchar(50) NOT NULL,
PRIMARY KEY (`action_id`)
) ENGINE=MyISAM AUTO_INCREMENT=20 DEFAULT CHARSET=latin1;
SET character_set_client = @saved_cs_client;
Horde_Db-2.0.4/test/Horde/Db/fixtures/unit_tests.sql 0000664 0001750 0001750 00000023551 12205351473 020437 0 ustar jan jan --
-- Copyright 2007 Maintainable Software, LLC
-- Copyright 2008-2013 Horde LLC (http://www.horde.org/)
--
-- @author Mike Naberezny
-- @author Derek DeVries
-- @author Chuck Hagenbuch
-- @license http://www.horde.org/licenses/bsd
-- @category Horde
-- @package Db
-- @subpackage UnitTests
--
INSERT INTO unit_tests (id, integer_value, string_value, text_value, float_value, decimal_value, datetime_value, date_value, time_value, blob_value, boolean_value, email_value) VALUES ('1', '1', 'name a', 'string a', '1.2', '1.2', '2005-12-23 12:34:23', '2005-12-23', '12:34:23', 'some blob data', '1', 'foo@example.com');
INSERT INTO unit_tests (id, integer_value, string_value, text_value, float_value, decimal_value, datetime_value, date_value, time_value, blob_value, boolean_value, email_value) VALUES ('2', '2', 'name b', 'string b', '1.2', '1.2', '2005-12-23 12:34:23', '2005-12-23', '12:34:23', 'some blob data', '0', 'foo@example.com');
INSERT INTO unit_tests (id, integer_value, string_value, text_value, float_value, decimal_value, datetime_value, date_value, time_value, blob_value, boolean_value, email_value) VALUES ('3', '3', 'name c', 'string a', '1.2', '1.2', '2005-12-23 12:34:23', '2005-12-23', '12:34:23', 'some blob data', '1', 'foo@example.com');
INSERT INTO unit_tests (id, integer_value, string_value, text_value, float_value, decimal_value, datetime_value, date_value, time_value, blob_value, boolean_value, email_value) VALUES ('4', '4', 'name d', 'string b', '1.2', '1.2', '2005-12-23 12:34:23', '2005-12-23', '12:34:23', 'some blob data', '0', 'foo@example.com');
INSERT INTO unit_tests (id, integer_value, string_value, text_value, float_value, decimal_value, datetime_value, date_value, time_value, blob_value, boolean_value, email_value) VALUES ('5', '5', 'name e', 'string b', '1.2', '1.2', '2005-12-23 12:34:23', '2005-12-23', '12:34:23', 'some blob data', '1', 'foo@example.com');
INSERT INTO unit_tests (id, integer_value, string_value, text_value, float_value, decimal_value, datetime_value, date_value, time_value, blob_value, boolean_value, email_value) VALUES ('6', '6', 'name f', 'string b', '1.2', '1.2', '2005-12-23 12:34:23', '2005-12-23', '12:34:23', 'some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data some clob data', '0', 'foo@example.com');
Horde_Db-2.0.4/test/Horde/Db/Migration/BaseTest.php 0000664 0001750 0001750 00000014542 12205351473 020020 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage UnitTests
*/
require_once dirname(__DIR__) . '/fixtures/migrations/1_users_have_last_names1.php';
require_once dirname(__DIR__) . '/fixtures/migrations/2_we_need_reminders1.php';
require_once dirname(__DIR__) . '/fixtures/migrations_with_decimal/1_give_me_big_numbers.php';
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @group horde_db
* @category Horde
* @package Db
* @subpackage UnitTests
*/
class Horde_Db_Migration_BaseTest extends PHPUnit_Framework_TestCase
{
public function setUp()
{
try {
$this->_conn = new Horde_Db_Adapter_Pdo_Sqlite(array(
'dbname' => ':memory:',
));
} catch (Horde_Db_Exception $e) {
$this->markTestSkipped('The sqlite adapter is not available');
}
$table = $this->_conn->createTable('users');
$table->column('company_id', 'integer', array('limit' => 11));
$table->column('name', 'string', array('limit' => 255, 'default' => ''));
$table->column('first_name', 'string', array('limit' => 40, 'default' => ''));
$table->column('approved', 'boolean', array('default' => true));
$table->column('type', 'string', array('limit' => 255, 'default' => ''));
$table->column('created_at', 'datetime', array('default' => '0000-00-00 00:00:00'));
$table->column('created_on', 'date', array('default' => '0000-00-00'));
$table->column('updated_at', 'datetime', array('default' => '0000-00-00 00:00:00'));
$table->column('updated_on', 'date', array('default' => '0000-00-00'));
$table->end();
}
public function testChangeColumnWithNilDefault()
{
$this->_conn->addColumn('users', 'contributor', 'boolean', array('default' => true));
$users = $this->_conn->table('users');
$this->assertTrue($users->contributor->getDefault());
// changeColumn() throws exception on error
$this->_conn->changeColumn('users', 'contributor', 'boolean', array('default' => null));
$users = $this->_conn->table('users');
$this->assertNull($users->contributor->getDefault());
}
public function testChangeColumnWithNewDefault()
{
$this->_conn->addColumn('users', 'administrator', 'boolean', array('default' => true));
$users = $this->_conn->table('users');
$this->assertTrue($users->administrator->getDefault());
// changeColumn() throws exception on error
$this->_conn->changeColumn('users', 'administrator', 'boolean', array('default' => false));
$users = $this->_conn->table('users');
$this->assertFalse($users->administrator->getDefault());
}
public function testChangeColumnDefault()
{
$this->_conn->changeColumnDefault('users', 'first_name', 'Tester');
$users = $this->_conn->table('users');
$this->assertEquals('Tester', $users->first_name->getDefault());
}
public function testChangeColumnDefaultToNull()
{
$this->_conn->changeColumnDefault('users', 'first_name', null);
$users = $this->_conn->table('users');
$this->assertNull($users->first_name->getDefault());
}
public function testAddTable()
{
$e = null;
try {
$this->_conn->selectValues("SELECT * FROM reminders");
} catch (Exception $e) {}
$this->assertInstanceOf('Horde_Db_Exception', $e);
$m = new WeNeedReminders1($this->_conn);
$m->up();
$this->_conn->insert("INSERT INTO reminders (content, remind_at) VALUES ('hello world', '2005-01-01 11:10:01')");
$reminder = (object)$this->_conn->selectOne('SELECT * FROM reminders');
$this->assertEquals('hello world', $reminder->content);
$m->down();
$e = null;
try {
$this->_conn->selectValues("SELECT * FROM reminders");
} catch (Exception $e) {}
$this->assertInstanceOf('Horde_Db_Exception', $e);
}
public function testAddTableWithDecimals()
{
$e = null;
try {
$this->_conn->selectValues("SELECT * FROM big_numbers");
} catch (Exception $e) {}
$this->assertInstanceOf('Horde_Db_Exception', $e);
$m = new GiveMeBigNumbers($this->_conn);
$m->up();
$this->_conn->insert('INSERT INTO big_numbers (bank_balance, big_bank_balance, world_population, my_house_population, value_of_e) VALUES (1586.43, 1000234000567.95, 6000000000, 3, 2.7182818284590452353602875)');
$b = (object)$this->_conn->selectOne('SELECT * FROM big_numbers');
$this->assertNotNull($b->bank_balance);
$this->assertNotNull($b->big_bank_balance);
$this->assertNotNull($b->world_population);
$this->assertNotNull($b->my_house_population);
$this->assertNotNull($b->value_of_e);
$m->down();
$e = null;
try {
$this->_conn->selectValues("SELECT * FROM big_numbers");
} catch (Exception $e) {}
$this->assertInstanceOf('Horde_Db_Exception', $e);
}
public function testAutoincrement()
{
$t = $this->_conn->createTable('imp_sentmail', array('autoincrementKey' => array('sentmail_id')));
$t->column('sentmail_id', 'bigint', array('null' => false));
$t->column('sentmail_foo', 'string');
$t->end();
$migration = new Horde_Db_Migration_Base($this->_conn, null);
$migration->changeColumn('imp_sentmail', 'sentmail_id', 'autoincrementKey');
$columns = $this->_conn->columns('imp_sentmail');
$this->assertEquals(2, count($columns));
$this->assertTrue(isset($columns['sentmail_id']));
$this->assertEquals(array('sentmail_id'),
$this->_conn->primaryKey('imp_sentmail')->columns);
$this->_conn->insert('INSERT INTO imp_sentmail (sentmail_foo) VALUES (?)', array('bar'));
}
}
Horde_Db-2.0.4/test/Horde/Db/Migration/MigratorTest.php 0000664 0001750 0001750 00000020003 12205351473 020717 0 ustar jan jan
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @category Horde
* @package Db
* @subpackage UnitTests
*/
/**
* @author Mike Naberezny
* @author Derek DeVries
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd
* @group horde_db
* @category Horde
* @package Db
* @subpackage UnitTests
*/
class Horde_Db_Migration_MigratorTest extends Horde_Test_Case
{
public function setUp()
{
try {
$this->_conn = new Horde_Db_Adapter_Pdo_Sqlite(array(
'dbname' => ':memory:',
));
} catch (Horde_Db_Exception $e) {
$this->markTestSkipped('The sqlite adapter is not available');
}
$table = $this->_conn->createTable('users');
$table->column('company_id', 'integer', array('limit' => 11));
$table->column('name', 'string', array('limit' => 255, 'default' => ''));
$table->column('first_name', 'string', array('limit' => 40, 'default' => ''));
$table->column('approved', 'boolean', array('default' => true));
$table->column('type', 'string', array('limit' => 255, 'default' => ''));
$table->column('created_at', 'datetime', array('default' => '0000-00-00 00:00:00'));
$table->column('created_on', 'date', array('default' => '0000-00-00'));
$table->column('updated_at', 'datetime', array('default' => '0000-00-00 00:00:00'));
$table->column('updated_on', 'date', array('default' => '0000-00-00'));
$table->end();
}
public function testInitializeSchemaInformation()
{
$dir = dirname(__DIR__).'/fixtures/migrations/';
$migrator = new Horde_Db_Migration_Migrator($this->_conn, null, array('migrationsPath' => $dir));
$sql = "SELECT version FROM schema_info";
$this->assertEquals(0, $this->_conn->selectValue($sql));
}
public function testMigrator()
{
$columns = $this->_columnNames('users');
$this->assertFalse(in_array('last_name', $columns));
$e = null;
try {
$this->_conn->selectValues("SELECT * FROM reminders");
} catch (Exception $e) {}
$this->assertInstanceOf('Horde_Db_Exception', $e);
$dir = dirname(__DIR__).'/fixtures/migrations/';
$migrator = new Horde_Db_Migration_Migrator($this->_conn, null, array('migrationsPath' => $dir));
$migrator->up();
$this->assertEquals(3, $migrator->getCurrentVersion());
$columns = $this->_columnNames('users');
$this->assertTrue(in_array('last_name', $columns));
$this->_conn->insert("INSERT INTO reminders (content, remind_at) VALUES ('hello world', '2005-01-01 02:22:23')");
$reminder = (object)$this->_conn->selectOne('SELECT * FROM reminders');
$this->assertEquals('hello world', $reminder->content);
$dir = dirname(__DIR__).'/fixtures/migrations/';
$migrator = new Horde_Db_Migration_Migrator($this->_conn, null, array('migrationsPath' => $dir));
$migrator->down();
$this->assertEquals(0, $migrator->getCurrentVersion());
$columns = $this->_columnNames('users');
$this->assertFalse(in_array('last_name', $columns));
$e = null;
try {
$this->_conn->selectValues("SELECT * FROM reminders");
} catch (Exception $e) {}
$this->assertInstanceOf('Horde_Db_Exception', $e);
}
public function testOneUp()
{
$e = null;
try {
$this->_conn->selectValues("SELECT * FROM reminders");
} catch (Exception $e) {}
$this->assertInstanceOf('Horde_Db_Exception', $e);
$dir = dirname(__DIR__).'/fixtures/migrations/';
$migrator = new Horde_Db_Migration_Migrator($this->_conn, null, array('migrationsPath' => $dir));
$migrator->up(1);
$this->assertEquals(1, $migrator->getCurrentVersion());
$columns = $this->_columnNames('users');
$this->assertTrue(in_array('last_name', $columns));
$e = null;
try {
$this->_conn->selectValues("SELECT * FROM reminders");
} catch (Exception $e) {}
$this->assertInstanceOf('Horde_Db_Exception', $e);
$migrator->up(2);
$this->assertEquals(2, $migrator->getCurrentVersion());
$this->_conn->insert("INSERT INTO reminders (content, remind_at) VALUES ('hello world', '2005-01-01 02:22:23')");
$reminder = (object)$this->_conn->selectOne('SELECT * FROM reminders');
$this->assertEquals('hello world', $reminder->content);
}
public function testOneDown()
{
$dir = dirname(__DIR__).'/fixtures/migrations/';
$migrator = new Horde_Db_Migration_Migrator($this->_conn, null, array('migrationsPath' => $dir));
$migrator->up();
$migrator->down(1);
$columns = $this->_columnNames('users');
$this->assertTrue(in_array('last_name', $columns));
}
public function testOneUpOneDown()
{
$dir = dirname(__DIR__).'/fixtures/migrations/';
$migrator = new Horde_Db_Migration_Migrator($this->_conn, null, array('migrationsPath' => $dir));
$migrator->up(1);
$migrator->down(0);
$columns = $this->_columnNames('users');
$this->assertFalse(in_array('last_name', $columns));
}
public function testMigratorGoingDownDueToVersionTarget()
{
$dir = dirname(__DIR__).'/fixtures/migrations/';
$migrator = new Horde_Db_Migration_Migrator($this->_conn, null, array('migrationsPath' => $dir));
$migrator->up(1);
$migrator->down(0);
$columns = $this->_columnNames('users');
$this->assertFalse(in_array('last_name', $columns));
$e = null;
try {
$this->_conn->selectValues("SELECT * FROM reminders");
} catch (Exception $e) {}
$this->assertInstanceOf('Horde_Db_Exception', $e);
$migrator = new Horde_Db_Migration_Migrator($this->_conn, null, array('migrationsPath' => $dir));
$migrator->up();
$columns = $this->_columnNames('users');
$this->assertTrue(in_array('last_name', $columns));
$this->_conn->insert("INSERT INTO reminders (content, remind_at) VALUES ('hello world', '2005-01-01 02:22:23')");
$reminder = (object)$this->_conn->selectOne('SELECT * FROM reminders');
$this->assertEquals('hello world', $reminder->content);
}
public function testWithDuplicates()
{
try {
$dir = dirname(__DIR__).'/fixtures/migrations_with_duplicate/';
$migrator = new Horde_Db_Migration_Migrator($this->_conn, null, array('migrationsPath' => $dir));
$migrator->up();
} catch (Exception $e) { return; }
$this->fail('Expected exception wasn\'t raised');
}
public function testWithMissingVersionNumbers()
{
$dir = dirname(__DIR__).'/fixtures/migrations_with_missing_versions/';
$migrator = new Horde_Db_Migration_Migrator($this->_conn, null, array('migrationsPath' => $dir));
$migrator->migrate(500);
$this->assertEquals(4, $migrator->getCurrentVersion());
$migrator->migrate(2);
$this->assertEquals(2, $migrator->getCurrentVersion());
$e = null;
try {
$this->_conn->selectValues("SELECT * FROM reminders");
} catch (Exception $e) {}
$this->assertInstanceOf('Horde_Db_Exception', $e);
$columns = $this->_columnNames('users');
$this->assertTrue(in_array('last_name', $columns));
}
protected function _columnNames($tableName)
{
$columns = array();
foreach ($this->_conn->columns($tableName) as $c) {
$columns[] = $c->getName();
}
return $columns;
}
}
Horde_Db-2.0.4/test/Horde/Db/AllTests.php 0000664 0001750 0001750 00000000132 12205351473 016076 0 ustar jan jan run();
Horde_Db-2.0.4/test/Horde/Db/bootstrap.php 0000664 0001750 0001750 00000000143 12205351473 016362 0 ustar jan jan
Horde_Db-2.0.4/test/Horde/Db/StatementParserTest.php 0000664 0001750 0001750 00000002475 12205351473 020340 0 ustar jan jan assertParser($expected, 'drop_create_table.sql');
}
public function assertParser(array $expectedStatements, $filename)
{
$file = new SplFileObject(__DIR__ . '/fixtures/' . $filename, 'r');
$parser = new Horde_Db_StatementParser($file);
foreach ($expectedStatements as $i => $expected) {
// Strip any whitespace before comparing the strings.
$this->assertEquals(preg_replace('/\s/', '', $expected),
preg_replace('/\s/', '', $parser->next()),
"Parser differs on statement #$i");
}
}
}