+++ /dev/null
-<?php
-/**
- * Copyright 2007 Maintainable Software, LLC
- * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Db
- * @subpackage Adapter
- */
-
-/**
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Db
- * @subpackage Adapter
- */
-class Horde_Db_Adapter_Abstract_Column
-{
- protected $_name;
- protected $_type;
- protected $_null;
- protected $_limit;
- protected $_precision;
- protected $_scale;
- protected $_default;
- protected $_sqlType;
- protected $_isText;
- protected $_isNumber;
-
-
- /*##########################################################################
- # Construct/Destruct
- ##########################################################################*/
-
- /**
- * Construct
- *
- * @param string $name The column's name, such as <tt>supplier_id</tt> in <tt>supplier_id int(11)</tt>.
- * @param string $default The type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
- * @param string $sqlType Only used to extract the column's length, if necessary. For example +60+ in <tt>company_name varchar(60)</tt>.
- * @param boolean $null Determines if this column allows +NULL+ values.
- */
- public function __construct($name, $default, $sqlType = null, $null = true)
- {
- $this->_name = $name;
- $this->_sqlType = $sqlType;
- $this->_null = $null;
- $this->_limit = $this->_extractLimit($sqlType);
- $this->_precision = $this->_extractPrecision($sqlType);
- $this->_scale = $this->_extractScale($sqlType);
- $this->_type = $this->_simplifiedType($sqlType);
- $this->_default = $this->extractDefault($default);
-
- $this->_isText = $this->_type == 'text' || $this->_type == 'string';
- $this->_isNumber = $this->_type == 'float' || $this->_type == 'integer' || $this->_type == 'decimal';
- }
-
- /**
- * @return boolean
- */
- public function isText()
- {
- return $this->_isText;
- }
-
- /**
- * @return boolean
- */
- public function isNumber()
- {
- return $this->_isNumber;
- }
-
- /**
- * Casts value (which is a String) to an appropriate instance.
- */
- public function typeCast($value)
- {
- if ($value === null) return null;
-
- switch ($this->_type) {
- case 'string':
- case 'text':
- return $value;
- case 'integer':
- return strlen($value) ? (int)$value : null;
- case 'float':
- return strlen($value) ? (float)$value : null;
- case 'decimal':
- return $this->valueToDecimal($value);
- case 'datetime':
- case 'timestamp':
- return $this->stringToTime($value);
- case 'time':
- return $this->stringToDummyTime($value);
- case 'date':
- return $this->stringToDate($value);
- case 'binary':
- return $this->binaryToString($value);
- case 'boolean':
- return $this->valueToBoolean($value);
- default:
- return $value;
- }
- }
-
- public function extractDefault($default)
- {
- return $this->typeCast($default);
- }
-
-
- /*##########################################################################
- # Accessor
- ##########################################################################*/
-
- /**
- * @return string
- */
- public function getName()
- {
- return $this->_name;
- }
-
- /**
- * @return string
- */
- public function getDefault()
- {
- return $this->_default;
- }
-
- /**
- * @return string
- */
- public function getType()
- {
- return $this->_type;
- }
-
- /**
- * @return int
- */
- public function getLimit()
- {
- return $this->_limit;
- }
-
- /**
- * @return int
- */
- public function precision()
- {
- return $this->_precision;
- }
-
- /**
- * @return int
- */
- public function scale()
- {
- return $this->_scale;
- }
-
- /**
- * @return boolean
- */
- public function isNull()
- {
- return $this->_null;
- }
-
- /**
- * @return string
- */
- public function getSqlType()
- {
- return $this->_sqlType;
- }
-
-
- /*##########################################################################
- # Type Juggling
- ##########################################################################*/
-
- /**
- * Used to convert from Strings to BLOBs
- *
- * @return string
- */
- public function stringToBinary($value)
- {
- return $value;
- }
-
- /**
- * Used to convert from BLOBs to Strings
- *
- * @return string
- */
- public function binaryToString($value)
- {
- return $value;
- }
-
- /**
- * @param string $string
- * @return Horde_Date
- */
- public function stringToDate($string)
- {
- if (empty($string) ||
- // preserve '0000-00-00' (http://bugs.php.net/bug.php?id=45647)
- preg_replace('/[^\d]/', '', $string) == 0) {
- return null;
- }
-
- $d = new Horde_Date($string);
- $d->setDefaultFormat('Y-m-d');
-
- return $d;
- }
-
- /**
- * @param string $string
- * @return Horde_Date
- */
- public function stringToTime($string)
- {
- if (empty($string) ||
- // preserve '0000-00-00 00:00:00' (http://bugs.php.net/bug.php?id=45647)
- preg_replace('/[^\d]/', '', $string) == 0) {
- return null;
- }
-
- return new Horde_Date($string);
- }
-
- /**
- * @TODO Return a Horde_Date object instead?
- *
- * @param string $string
- * @return Horde_Date
- */
- public function stringToDummyTime($value)
- {
- if (empty($string)) {
- return null;
- }
- return $this->stringToTime('2000-01-01 ' . $string);
- }
-
- /**
- * @param mixed $value
- * @return boolean
- */
- public function valueToBoolean($value)
- {
- if ($value === true || $value === false) {
- return $value;
- }
-
- $value = strtolower($value);
- return $value == 'true' || $value == 't' || $value == '1';
- }
-
- /**
- * @param mixed $value
- * @return decimal
- */
- public function valueToDecimal($value)
- {
- return (float)$value;
- }
-
-
- /*##########################################################################
- # Protected
- ##########################################################################*/
-
- /**
- * @param string $sqlType
- * @return int
- */
- protected function _extractLimit($sqlType)
- {
- if (preg_match("/\((.*)\)/", $sqlType, $matches)) {
- return (int)$matches[1];
- }
- return null;
- }
-
- /**
- * @param string $sqlType
- * @return int
- */
- protected function _extractPrecision($sqlType)
- {
- if (preg_match("/^(numeric|decimal|number)\((\d+)(,\d+)?\)/i", $sqlType, $matches)) {
- return (int)$matches[2];
- }
- return null;
- }
-
- /**
- * @param string $sqlType
- * @return int
- */
- protected function _extractScale($sqlType)
- {
- switch (true) {
- case preg_match("/^(numeric|decimal|number)\((\d+)\)/i", $sqlType):
- return 0;
- case preg_match("/^(numeric|decimal|number)\((\d+)(,(\d+))\)/i",
- $sqlType, $match):
- return (int)$match[4];
- }
- }
-
- /**
- * @param string $fieldType
- * @return string
- */
- protected function _simplifiedType($fieldType)
- {
- switch (true) {
- case preg_match('/int/i', $fieldType):
- return 'integer';
- case preg_match('/float|double/i', $fieldType):
- return 'float';
- case preg_match('/decimal|numeric|number/i', $fieldType):
- return $this->_scale == 0 ? 'integer' : 'decimal';
- case preg_match('/datetime/i', $fieldType):
- return 'datetime';
- case preg_match('/timestamp/i', $fieldType):
- return 'timestamp';
- case preg_match('/time/i', $fieldType):
- return 'time';
- case preg_match('/date/i', $fieldType):
- return 'date';
- case preg_match('/clob|text/i', $fieldType):
- return 'text';
- case preg_match('/blob|binary/i', $fieldType):
- return 'binary';
- case preg_match('/char|string/i', $fieldType):
- return 'string';
- case preg_match('/boolean/i', $fieldType):
- return 'boolean';
- }
- }
-
-}
+++ /dev/null
-<?php
-/**
- * Copyright 2007 Maintainable Software, LLC
- * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Db
- * @subpackage Adapter
- */
-
-/**
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Db
- * @subpackage Adapter
- */
-class Horde_Db_Adapter_Abstract_ColumnDefinition
-{
- protected $_base = null;
- protected $_name = null;
- protected $_type = null;
- protected $_limit = null;
- protected $_precision = null;
- protected $_scale = null;
- protected $_default = null;
- protected $_null = null;
-
- /**
- * Construct
- */
- public function __construct($base, $name, $type, $limit=null,
- $precision=null, $scale=null, $default=null, $null=null)
- {
- // protected
- $this->_base = $base;
-
- // public
- $this->_name = $name;
- $this->_type = $type;
- $this->_limit = $limit;
- $this->_precision = $precision;
- $this->_scale = $scale;
- $this->_default = $default;
- $this->_null = $null;
- }
-
- /*##########################################################################
- # Public
- ##########################################################################*/
-
- /**
- * @return string
- */
- public function toSql()
- {
- $sql = $this->_base->quoteColumnName($this->_name).' ';
- try {
- $sql .= $this->_base->typeToSql($this->_type, $this->_limit,
- $this->_precision, $this->_scale);
- } catch (Exception $e) {
- $sql .= $this->_type;
- }
- return $this->_addColumnOptions($sql, array('null' => $this->_null,
- 'default' => $this->_default));
- }
-
- /**
- * @return string
- */
- public function __toString()
- {
- return $this->toSql();
- }
-
-
- /*##########################################################################
- # Accessor
- ##########################################################################*/
-
- /**
- * @return string
- */
- public function getName()
- {
- return $this->_name;
- }
-
- /**
- * @return string
- */
- public function getDefault()
- {
- return $this->_default;
- }
-
- /**
- * @return string
- */
- public function getType()
- {
- return $this->_type;
- }
-
- /**
- * @return string
- */
- public function getSqlType()
- {
- try {
- return $this->_base->typeToSql($this->_type, $this->_limit, $this->_precision, $this->_scale);
- } catch (Exception $e) {
- return $this->_type;
- }
- }
-
- /**
- * @return int
- */
- public function getLimit()
- {
- return $this->_limit;
- }
-
- /**
- * @return int
- */
- public function precision()
- {
- return $this->_precision;
- }
-
- /**
- * @return int
- */
- public function scale()
- {
- return $this->_scale;
- }
-
- /**
- * @return boolean
- */
- public function isNull()
- {
- return $this->_null;
- }
-
- /**
- * @param string
- */
- public function setName($name)
- {
- $this->_name = $name;
- }
-
- /**
- * @param string
- */
- public function setDefault($default)
- {
- $this->_default = $default;
- }
-
- /**
- * @param string
- */
- public function setType($type)
- {
- $this->_type = $type;
- }
-
- /**
- * @param int
- */
- public function setLimit($limit)
- {
- $this->_limit = $limit;
- }
-
- /**
- * @param int
- */
- public function setPrecision($precision)
- {
- $this->_precision = $precision;
- }
-
- /**
- * @param int
- */
- public function setScale($scale)
- {
- $this->_scale = $scale;
- }
-
- /**
- * @param boolean
- */
- public function setNull($null)
- {
- $this->_null = $null;
- }
-
-
- /*##########################################################################
- # Schema Statements
- ##########################################################################*/
-
- /**
- * @param string $sql
- * @param array $options
- */
- protected function _addColumnOptions($sql, $options)
- {
- return $this->_base->addColumnOptions($sql,
- array_merge($options, array('column' => $this))
- );
- }
-
-}
+++ /dev/null
-<?php
-/**
- * Copyright 2007 Maintainable Software, LLC
- * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Db
- * @subpackage Adapter
- */
-
-/**
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Db
- * @subpackage Adapter
- */
-class Horde_Db_Adapter_Abstract_Index
-{
- public $table;
- public $name;
- public $unique;
- public $primary;
- public $columns;
-
-
- /*##########################################################################
- # Construct/Destruct
- ##########################################################################*/
-
- /**
- * Construct
- *
- * @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
- */
- public function __construct($table, $name, $primary, $unique, $columns)
- {
- $this->table = $table;
- $this->name = $name;
- $this->primary = $primary;
- $this->unique = $unique;
- $this->columns = $columns;
- }
-
-
- /*##########################################################################
- # Accessor
- ##########################################################################*/
-
- /**
- * @return string
- */
- public function getName()
- {
- return $this->name;
- }
-
-
- /*##########################################################################
- # Casting
- ##########################################################################*/
-
- /**
- * Comma-separated list of the columns in the primary key
- *
- * @return string
- */
- public function __toString()
- {
- return implode(',', $this->columns);
- }
-
-}
+++ /dev/null
-<?php
-/**
- * Copyright 2007 Maintainable Software, LLC
- * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Db
- * @subpackage Adapter
- */
-
-/**
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Db
- * @subpackage Adapter
- */
-abstract class Horde_Db_Adapter_Abstract_Schema
-{
- /**
- * @var Cache object
- */
- protected $_cache = null;
-
- /**
- * @var Logger
- */
- protected $_logger = null;
-
- /**
- * @var Horde_Db_Adapter_Abstract
- */
- protected $_adapter = null;
-
- /**
- * @var array
- */
- protected $_adapterMethods = array();
-
-
- /*##########################################################################
- # Construct/Destruct
- ##########################################################################*/
-
- /**
- * @param Horde_Db_Adapter_Abstract $adapter
- * @param array $config
- */
- public function __construct($adapter, $config = array())
- {
- $this->_adapter = $adapter;
- $this->_adapterMethods = array_flip(get_class_methods($adapter));
-
- $this->_cache = isset($config['cache']) ? $config['cache'] : new Horde_Support_Stub;
- $this->_logger = isset($config['logger']) ? $config['logger'] : new Horde_Support_Stub;
- }
-
-
- /*##########################################################################
- # Object composition
- ##########################################################################*/
-
- /**
- * Delegate calls to the adapter object.
- *
- * @param string $method
- * @param array $args
- */
- 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.'"');
- }
-
-
- /*##########################################################################
- # Quoting
- ##########################################################################*/
-
- /**
- * Quotes the column value to help prevent
- * {SQL injection attacks}[http://en.wikipedia.org/wiki/SQL_injection].
- *
- * @param string $value
- * @param string $column
- * @return string
- */
- public function quote($value, $column=null)
- {
- if (is_object($value) && is_callable(array($value, 'quotedId'))) {
- return $value->quotedId();
- }
-
- $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_int($value) || is_float($value)) {
- return $value;
- /*@TODO
- else
- if value.acts_like?(:date) || value.acts_like?(:time)
- "'#{quoted_date(value)}'"
- else
- "#{quoted_string_prefix}'#{quote_string(value.to_yaml)}'"
- end
- */
- } 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'));
- } else {
- /*@TODO
- when String, ActiveSupport::Multibyte::Chars
- value = value.to_s
- if column && column.type == :binary && column.class.respond_to?(:string_to_binary)
- "#{quoted_string_prefix}'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode)
- elsif column && [:integer, :float].include?(column.type)
- value = column.type == :integer ? value.to_i : value.to_f
- value.to_s
- else
- "#{quoted_string_prefix}'#{quote_string(value)}'" # ' (for ruby-mode)
- end
- */
- return $this->_adapter->quoteString($value);
- }
- }
-
- /**
- * Quotes a string, escaping any ' (single quote) and \ (backslash)
- * characters..
- *
- * @param string $string
- * @return string
- */
- public function quoteString($string)
- {
- return "'".str_replace(array('\\', '\''), array('\\\\', '\\\''), $string)."'";
- }
-
- /**
- * Returns a quoted form of the column name. This is highly adapter
- * specific.
- *
- * @param string $name
- * @return string
- */
- abstract public function quoteColumnName($name);
-
- /**
- * Returns a quoted form of the table name. Defaults to column name quoting.
- *
- * @param string $name
- * @return string
- */
- public function quoteTableName($name)
- {
- return $this->quoteColumnName($name);
- }
-
- /**
- * @return string
- */
- public function quoteTrue()
- {
- return "'t'";
- }
-
- /**
- * @return string
- */
- public function quoteFalse()
- {
- return "'f'";
- }
-
- /**
- * @return string
- */
- public function quoteDate($value)
- {
- return $this->_adapter->quoteString((string)$value);
- }
-
- /**
- * @return string
- */
- public function quotedStringPrefix()
- {
- return '';
- }
-
-
- /*##########################################################################
- # 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.
- *
- * @return array
- */
- public function nativeDatabaseTypes()
- {
- return array();
- }
-
- /**
- * This is the maximum length a table alias can be
- *
- * @return int
- */
- public function tableAliasLength()
- {
- return 255;
- }
-
- /**
- * Truncates a table alias according to the limits of the current adapter.
- *
- * @param string $tableName
- * @return string
- */
- public function tableAliasFor($tableName)
- {
- $alias = substr($tableName, 0, $this->tableAliasLength());
- return str_replace('.', '_', $alias);
- }
-
- /**
- * @param string $name
- * @return array
- */
- abstract public function tables($name = null);
-
- /**
- * Get a Horde_Db_Adapter_Abstract_Table object for the table.
- *
- * @param string $tableName
- * @param string $name
- *
- * @return Horde_Db_Adapter_Abstract_Table
- */
- public function table($tableName, $name = null)
- {
- return $this->componentFactory('Table', array(
- $tableName,
- $this->primaryKey($tableName),
- $this->columns($tableName, $name),
- $this->indexes($tableName, $name),
- ));
- }
-
- /**
- * Return a table's primary key
- */
- abstract public function primaryKey($tableName, $name = null);
-
- /**
- * Returns an array of indexes for the given table.
- *
- * @param string $tableName
- * @param string $name
- * @return array
- */
- abstract public function indexes($tableName, $name = null);
-
- /**
- * Returns an array of Horde_Db_Adapter_Abstract_Column objects for the
- * table specified by +table_name+. See the concrete implementation for
- * details on the expected parameter values.
- *
- * @param string $tableName
- * @param string $name
- * @return array
- */
- abstract public function columns($tableName, $name = null);
-
- /**
- * Creates a new table
- * There are two ways to work with #create_table. You can use the block
- * form or the regular form, like this:
- *
- * === Block form
- * # create_table() yields a TableDefinition instance
- * create_table(:suppliers) do |t|
- * t.column :name, :string, :limit => 60
- * # Other fields here
- * end
- *
- * === Regular form
- * create_table(:suppliers)
- * add_column(:suppliers, :name, :string, {:limit => 60})
- *
- * The +options+ hash can include the following keys:
- * [<tt>:id</tt>]
- * Set to true or false to add/not add a primary key column
- * automatically. Defaults to true.
- * [<tt>:primary_key</tt>]
- * The name of the primary key, if one is to be added automatically.
- * Defaults to +id+.
- * [<tt>:options</tt>]
- * Any extra options you want appended to the table definition.
- * [<tt>:temporary</tt>]
- * Make a temporary table.
- * [<tt>:force</tt>]
- * 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)
- * create_table(:suppliers, :options => 'ENGINE=InnoDB DEFAULT CHARSET=utf8')
- * generates:
- * CREATE TABLE suppliers (
- * id int(11) DEFAULT NULL auto_increment PRIMARY KEY
- * ) ENGINE=InnoDB DEFAULT CHARSET=utf8
- *
- * ====== Rename the primary key column
- * create_table(:objects, :primary_key => 'guid') do |t|
- * t.column :name, :string, :limit => 80
- * end
- * generates:
- * CREATE TABLE objects (
- * guid int(11) DEFAULT NULL auto_increment PRIMARY KEY,
- * name varchar(80)
- * )
- *
- * ====== Do not add a primary key column
- * create_table(:categories_suppliers, :id => false) do |t|
- * t.column :category_id, :integer
- * t.column :supplier_id, :integer
- * end
- * generates:
- * CREATE TABLE categories_suppliers_join (
- * category_id int,
- * supplier_id int
- * )
- *
- * See also TableDefinition#column for details on how to create columns.
- *
- * @param string $name
- * @param array $options
- */
- public function createTable($name, $options=array())
- {
- $pk = isset($options['primaryKey']) && $options['primaryKey'] === false ? false : 'id';
- $tableDefinition =
- $this->componentFactory('TableDefinition', array($name, $this, $options));
- if ($pk != false) {
- $tableDefinition->primaryKey($pk);
- }
- return $tableDefinition;
- }
-
- /**
- * Execute table creation
- *
- * @param string $name
- * @param array $options
- */
- public function endTable($name, $options=array())
- {
- if ($name instanceof Horde_Db_Adapter_Abstract_TableDefinition) {
- $tableDefinition = $name;
- $options = array_merge($tableDefinition->getOptions(), $options);
- } else {
- $tableDefinition = $this->createTable($name, $options);
- }
-
- // drop previous
- if (isset($options['force'])) {
- $this->dropTable($tableDefinition->getName(), $options);
- }
-
- $temp = !empty($options['temporary']) ? 'TEMPORARY' : null;
- $opts = !empty($options['options']) ? $options['options'] : null;
-
- $sql = "CREATE $temp TABLE ".$this->quoteTableName($tableDefinition->getName())." (\n".
- $tableDefinition->toSql()."\n".
- ") $opts";
- return $this->execute($sql);
- }
-
- /**
- * Renames a table.
- * ===== Example
- * rename_table('octopuses', 'octopi')
- *
- * @param string $name
- * @param string $newName
- */
- abstract public function renameTable($name, $newName);
-
- /**
- * Drops a table from the database.
- *
- * @param string $name
- */
- public function dropTable($name)
- {
- $this->_clearTableCache($name);
- return $this->execute('DROP TABLE ' . $this->quoteTableName($name));
- }
-
- /**
- * Adds a new column to the named table.
- * See TableDefinition#column for details of the options you can use.
- *
- * @param string $tableName
- * @param string $columnName
- * @param string $type
- * @param array $options
- */
- public function addColumn($tableName, $columnName, $type, $options=array())
- {
- $this->_clearTableCache($tableName);
-
- $limit = isset($options['limit']) ? $options['limit'] : null;
- $precision = isset($options['precision']) ? $options['precision'] : null;
- $scale = isset($options['scale']) ? $options['scale'] : null;
-
- $sql = 'ALTER TABLE ' . $this->quoteTableName($tableName) .
- ' ADD '.$this->quoteColumnName($columnName) .
- ' '.$this->typeToSql($type, $limit, $precision, $scale);
- $sql = $this->addColumnOptions($sql, $options);
- return $this->execute($sql);
- }
-
- /**
- * Removes the column from the table definition.
- * ===== Examples
- * remove_column(:suppliers, :qualification)
- *
- * @param string $tableName
- * @param string $columnName
- */
- public function removeColumn($tableName, $columnName)
- {
- $this->_clearTableCache($tableName);
-
- $sql = 'ALTER TABLE ' . $this->quoteTableName($tableName).' DROP '.$this->quoteColumnName($columnName);
- return $this->execute($sql);
- }
-
- /**
- * Changes the column's definition according to the new options.
- * See TableDefinition#column for details of the options you can use.
- * ===== Examples
- * change_column(:suppliers, :name, :string, :limit => 80)
- * change_column(:accounts, :description, :text)
- *
- * @param string $tableName
- * @param string $columnName
- * @param string $type
- * @param array $options
- */
- 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
- * DatabaseStatements#execute the apppropriate SQL statement yourself.
- * ===== Examples
- * change_column_default(:suppliers, :qualification, 'new')
- * change_column_default(:accounts, :authorized, 1)
- *
- * @param string $tableName
- * @param string $columnName
- * @param string $default
- */
- abstract public function changeColumnDefault($tableName, $columnName, $default);
-
- /**
- * Renames a column.
- * ===== Example
- * rename_column(:suppliers, :description, :name)
- *
- * @param string $tableName
- * @param string $columnName
- * @param string $newColumnName
- */
- abstract public function renameColumn($tableName, $columnName, $newColumnName);
-
- /**
- * Adds a new index to the table. +column_name+ can be a single Symbol, or
- * an Array of Symbols.
- *
- * 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+, +: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
- * add_index(:suppliers, :name)
- * generates
- * CREATE INDEX suppliers_name_index ON suppliers(name)
- *
- * ====== Creating a unique index
- * add_index(:accounts, [:branch_id, :party_id], :unique => true)
- * generates
- * CREATE UNIQUE INDEX accounts_branch_id_index ON accounts(branch_id, party_id)
- *
- * ====== Creating a named index
- * add_index(:accounts, [:branch_id, :party_id], :unique => true, :name => 'by_branch_party')
- * generates
- * CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id)
- *
- * @param string $tableName
- * @param string $columnName
- * @param array $options
- */
- public function addIndex($tableName, $columnName, $options=array())
- {
- $this->_clearTableCache($tableName);
-
- $columnNames = (array)($columnName);
- $indexName = $this->indexName($tableName, array('column' => $columnNames));
-
- $indexType = !empty($options['unique']) ? "UNIQUE" : null;
- $indexName = !empty($options['name']) ? $options['name'] : $indexName;
-
- foreach ($columnNames as $colName) {
- $quotedCols[] = $this->quoteColumnName($colName);
- }
- $quotedColumnNames = implode(', ', $quotedCols);
- $sql = "CREATE $indexType INDEX ".$this->quoteColumnName($indexName).
- 'ON '.$this->quoteTableName($tableName) . " ($quotedColumnNames)";
- return $this->execute($sql);
- }
-
- /**
- * Remove the given index from the table.
- *
- * Remove the suppliers_name_index in the suppliers table (legacy support, use the second or third forms).
- * remove_index :suppliers, :name
- * Remove the index named accounts_branch_id in the accounts table.
- * remove_index :accounts, :column => :branch_id
- * Remove the index named by_branch_party in the accounts table.
- * remove_index :accounts, :name => :by_branch_party
- *
- * You can remove an index on multiple columns by specifying the first column.
- * add_index :accounts, [:username, :password]
- * remove_index :accounts, :username
- *
- * @param string $tableName
- * @param array $options
- */
- public function removeIndex($tableName, $options=array())
- {
- $this->_clearTableCache($tableName);
-
- $index = $this->indexName($tableName, $options);
- $sql = "DROP INDEX ".$this->quoteColumnName($index).' ON ' . $this->quoteTableName($tableName);
- return $this->execute($sql);
- }
-
- /**
- * Get the name of the index
- *
- * @param string $tableName
- * @param array $options
- */
- 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);
-
- } elseif (isset($options['name'])) {
- return $options['name'];
-
- } else {
- throw new Horde_Db_Exception('You must specify the index name');
- }
- }
-
- /**
- * Returns a string of <tt>CREATE TABLE</tt> SQL statement(s) for recreating the
- * entire structure of the database.
- *
- * @param string $table
- * @return string
- */
- abstract public function structureDump($table = null);
-
- /**
- * Recreate the given db
- *
- * @param string $name
- */
- public function recreateDatabase($name)
- {
- $this->dropDatabase($name);
- return $this->createDatabase($name);
- }
-
- /**
- * Create the given db
- *
- * @param string $name
- */
- abstract public function createDatabase($name);
-
- /**
- * Drop the given db
- *
- * @param string $name
- */
- abstract public function dropDatabase($name);
-
- /**
- * Get the name of the current db
- *
- * @return string
- */
- abstract public function currentDatabase();
-
- /**
- * Should not be called normally, but this operation is non-destructive.
- * The migrations module handles this automatically.
- */
- public function initializeSchemaInformation()
- {
- try {
- $this->execute("CREATE TABLE schema_info (".
- " version ".$this->typeToSql('integer').
- ")");
- return $this->execute("INSERT INTO schema_info (version) VALUES (0)");
- } catch (Exception $e) {}
- }
-
- /**
- * The sql for this column type
- *
- * @param string $type
- * @param string $limit
- */
- public function typeToSql($type, $limit=null, $precision=null, $scale=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 ($limit = !empty($limit) ? $limit : $nativeLimit) {
- $sql .= "($limit)";
- }
- }
- return $sql;
- }
-
- /**
- * Add default/null options to column sql
- *
- * @param string $sql
- * @param array $options
- */
- public function addColumnOptions($sql, $options)
- {
- 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;
- }
-
- /**
- * SELECT DISTINCT clause for a given set of columns and a given
- * ORDER BY clause. Both PostgreSQL and Oracle override this for
- * custom DISTINCT syntax.
- *
- * $connection->distinct("posts.id", "posts.created_at desc")
- *
- * @param string $columns
- * @param string $orderBy
- */
- public function distinct($columns, $orderBy=null)
- {
- return "DISTINCT $columns";
- }
-
- /**
- * ORDER BY clause for the passed order option.
- * PostgreSQL overrides this due to its stricter standards compliance.
- *
- * @param string $sql
- * @param array $options
- * @return string
- */
- public function addOrderByForAssocLimiting($sql, $options)
- {
- return $sql.'ORDER BY '.$options['order'];
- }
-
-
- /*##########################################################################
- # Protected
- ##########################################################################*/
-
- /**
- * We need to clear cache for tables when altering them at all
- */
- protected function _clearTableCache($tableName)
- {
- $this->_cache->set("tables/columns/$tableName", null);
- $this->_cache->set("tables/indexes/$tableName", null);
- }
-
-}
+++ /dev/null
-<?php
-/**
- * Copyright 2007 Maintainable Software, LLC
- * Copyright 2008 The Horde Project (http://www.horde.org/)
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Db
- * @subpackage Adapter
- */
-
-/**
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Db
- * @subpackage Adapter
- */
-class Horde_Db_Adapter_Abstract_Table
-{
- protected $_name;
- protected $_primaryKey;
- protected $_columns;
- protected $_indexes;
-
-
- /*##########################################################################
- # Construct/Destruct
- ##########################################################################*/
-
- /**
- * Construct
- *
- * @param string $name The table's name, such as <tt>supplier_id</tt> in <tt>supplier_id int(11)</tt>.
- */
- 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_Abstract_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;
- }
-
-
- /*##########################################################################
- # Protected
- ##########################################################################*/
-
-}
+++ /dev/null
-<?php
-/**
- * Copyright 2007 Maintainable Software, LLC
- * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Db
- * @subpackage Adapter
- */
-
-/**
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Db
- * @subpackage Adapter
- */
-class Horde_Db_Adapter_Abstract_TableDefinition implements ArrayAccess
-{
- protected $_name = null;
- protected $_base = null;
- protected $_options = null;
- protected $_columns = null;
-
- /**
- * Class Constructor
- *
- * @param string $name
- * @param Horde_Db_Adapter_Abstract_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)
- {
- $natives = $this->_native();
- $this->column($name, $natives['primaryKey']);
- }
-
- /**
- * Instantiates a new column for the table.
- * The +type+ parameter must be one of the following values:
- * <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
- * <tt>:integer</tt>, <tt>:float</tt>, <tt>:datetime</tt>,
- * <tt>:timestamp</tt>, <tt>:time</tt>, <tt>:date</tt>,
- * <tt>:binary</tt>, <tt>:boolean</tt>.
- *
- * Available options are (none of these exists by default):
- * * <tt>:limit</tt>:
- * Requests a maximum column length (<tt>:string</tt>, <tt>:text</tt>,
- * <tt>:binary</tt> or <tt>:integer</tt> columns only)
- * * <tt>:default</tt>:
- * The column's default value. You cannot explicitely set the default
- * value to +NULL+. Simply leave off this option if you want a +NULL+
- * default value.
- * * <tt>:null</tt>:
- * Allows or disallows +NULL+ values in the column. This option could
- * have been named <tt>:null_allowed</tt>.
- *
- * This method returns <tt>self</tt>.
- *
- * ===== Examples
- * # Assuming def is an instance of TableDefinition
- * def.column(:granted, :boolean)
- * #=> granted BOOLEAN
- *
- * def.column(:picture, :binary, :limit => 2.megabytes)
- * #=> picture BLOB(2097152)
- *
- * def.column(:sales_stage, :string, :limit => 20, :default => 'new', :null => false)
- * #=> sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL
- *
- * @return TableDefinition
- */
- public function column($name, $type, $options=array())
- {
- if ($this[$name]) {
- $column = $this[$name];
- } else {
- $column = $this->_base->componentFactory('ColumnDefinition', array(
- $this->_base, $name, $type));
- }
-
- $natives = $this->_native();
- $opt = $options;
-
- if (isset($opt['limit']) || isset($natives[$type])) {
- $nativeLimit = isset($natives[$type]['limit']) ? $natives[$type]['limit'] : null;
- $column->setLimit(isset($opt['limit']) ? $opt['limit'] : $nativeLimit);
- }
-
- $column->setPrecision(isset($opt['precision']) ? $opt['precision'] : null);
- $column->setScale(isset($opt['scale']) ? $opt['scale'] : null);
- $column->setDefault(isset($opt['default']) ? $opt['default'] : null);
- $column->setNull(isset($opt['null']) ? $opt['null'] : null);
-
- $this[$name] ? $this[$name] = $column : $this->_columns[] = $column;
- return $this;
- }
-
- /**
- * 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(); }
-
- return " ".implode(", \n ", $cols);
- }
-
-
- /*##########################################################################
- # 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_Abstract_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]);
- }
- }
- }
-
-
- /*##########################################################################
- # Protected
- ##########################################################################*/
-
- /**
- * Get the types
- */
- protected function _native()
- {
- return $this->_base->nativeDatabaseTypes();
- }
-
-}
protected $_logger = null;
/**
- * @var Horde_Db_Adapter_Abstract_Schema
+ * @var Horde_Db_Adapter_Base_Schema
*/
protected $_schema = null;
if (class_exists($class)) {
$class = new ReflectionClass($class);
} else {
- $class = new ReflectionClass('Horde_Db_Adapter_Abstract_' . $component);
+ $class = new ReflectionClass('Horde_Db_Adapter_Base_' . $component);
}
return $class->newInstanceArgs($args);
*/
public function adapterName()
{
- return 'Abstract';
+ return 'Base';
}
/**
--- /dev/null
+<?php
+/**
+ * Copyright 2007 Maintainable Software, LLC
+ * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @author Derek DeVries <derek@maintainable.com>
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php
+ * @category Horde
+ * @package Horde_Db
+ * @subpackage Adapter
+ */
+
+/**
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @author Derek DeVries <derek@maintainable.com>
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php
+ * @category Horde
+ * @package Horde_Db
+ * @subpackage Adapter
+ */
+class Horde_Db_Adapter_Base_Column
+{
+ protected $_name;
+ protected $_type;
+ protected $_null;
+ protected $_limit;
+ protected $_precision;
+ protected $_scale;
+ protected $_default;
+ protected $_sqlType;
+ protected $_isText;
+ protected $_isNumber;
+
+
+ /*##########################################################################
+ # Construct/Destruct
+ ##########################################################################*/
+
+ /**
+ * Construct
+ *
+ * @param string $name The column's name, such as <tt>supplier_id</tt> in <tt>supplier_id int(11)</tt>.
+ * @param string $default The type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
+ * @param string $sqlType Only used to extract the column's length, if necessary. For example +60+ in <tt>company_name varchar(60)</tt>.
+ * @param boolean $null Determines if this column allows +NULL+ values.
+ */
+ public function __construct($name, $default, $sqlType = null, $null = true)
+ {
+ $this->_name = $name;
+ $this->_sqlType = $sqlType;
+ $this->_null = $null;
+ $this->_limit = $this->_extractLimit($sqlType);
+ $this->_precision = $this->_extractPrecision($sqlType);
+ $this->_scale = $this->_extractScale($sqlType);
+ $this->_type = $this->_simplifiedType($sqlType);
+ $this->_default = $this->extractDefault($default);
+
+ $this->_isText = $this->_type == 'text' || $this->_type == 'string';
+ $this->_isNumber = $this->_type == 'float' || $this->_type == 'integer' || $this->_type == 'decimal';
+ }
+
+ /**
+ * @return boolean
+ */
+ public function isText()
+ {
+ return $this->_isText;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function isNumber()
+ {
+ return $this->_isNumber;
+ }
+
+ /**
+ * Casts value (which is a String) to an appropriate instance.
+ */
+ public function typeCast($value)
+ {
+ if ($value === null) return null;
+
+ switch ($this->_type) {
+ case 'string':
+ case 'text':
+ return $value;
+ case 'integer':
+ return strlen($value) ? (int)$value : null;
+ case 'float':
+ return strlen($value) ? (float)$value : null;
+ case 'decimal':
+ return $this->valueToDecimal($value);
+ case 'datetime':
+ case 'timestamp':
+ return $this->stringToTime($value);
+ case 'time':
+ return $this->stringToDummyTime($value);
+ case 'date':
+ return $this->stringToDate($value);
+ case 'binary':
+ return $this->binaryToString($value);
+ case 'boolean':
+ return $this->valueToBoolean($value);
+ default:
+ return $value;
+ }
+ }
+
+ public function extractDefault($default)
+ {
+ return $this->typeCast($default);
+ }
+
+
+ /*##########################################################################
+ # Accessor
+ ##########################################################################*/
+
+ /**
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * @return string
+ */
+ public function getDefault()
+ {
+ return $this->_default;
+ }
+
+ /**
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->_type;
+ }
+
+ /**
+ * @return int
+ */
+ public function getLimit()
+ {
+ return $this->_limit;
+ }
+
+ /**
+ * @return int
+ */
+ public function precision()
+ {
+ return $this->_precision;
+ }
+
+ /**
+ * @return int
+ */
+ public function scale()
+ {
+ return $this->_scale;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function isNull()
+ {
+ return $this->_null;
+ }
+
+ /**
+ * @return string
+ */
+ public function getSqlType()
+ {
+ return $this->_sqlType;
+ }
+
+
+ /*##########################################################################
+ # Type Juggling
+ ##########################################################################*/
+
+ /**
+ * Used to convert from Strings to BLOBs
+ *
+ * @return string
+ */
+ public function stringToBinary($value)
+ {
+ return $value;
+ }
+
+ /**
+ * Used to convert from BLOBs to Strings
+ *
+ * @return string
+ */
+ public function binaryToString($value)
+ {
+ return $value;
+ }
+
+ /**
+ * @param string $string
+ * @return Horde_Date
+ */
+ public function stringToDate($string)
+ {
+ if (empty($string) ||
+ // preserve '0000-00-00' (http://bugs.php.net/bug.php?id=45647)
+ preg_replace('/[^\d]/', '', $string) == 0) {
+ return null;
+ }
+
+ $d = new Horde_Date($string);
+ $d->setDefaultFormat('Y-m-d');
+
+ return $d;
+ }
+
+ /**
+ * @param string $string
+ * @return Horde_Date
+ */
+ public function stringToTime($string)
+ {
+ if (empty($string) ||
+ // preserve '0000-00-00 00:00:00' (http://bugs.php.net/bug.php?id=45647)
+ preg_replace('/[^\d]/', '', $string) == 0) {
+ return null;
+ }
+
+ return new Horde_Date($string);
+ }
+
+ /**
+ * @TODO Return a Horde_Date object instead?
+ *
+ * @param string $string
+ * @return Horde_Date
+ */
+ public function stringToDummyTime($value)
+ {
+ if (empty($string)) {
+ return null;
+ }
+ return $this->stringToTime('2000-01-01 ' . $string);
+ }
+
+ /**
+ * @param mixed $value
+ * @return boolean
+ */
+ public function valueToBoolean($value)
+ {
+ if ($value === true || $value === false) {
+ return $value;
+ }
+
+ $value = strtolower($value);
+ return $value == 'true' || $value == 't' || $value == '1';
+ }
+
+ /**
+ * @param mixed $value
+ * @return decimal
+ */
+ public function valueToDecimal($value)
+ {
+ return (float)$value;
+ }
+
+
+ /*##########################################################################
+ # Protected
+ ##########################################################################*/
+
+ /**
+ * @param string $sqlType
+ * @return int
+ */
+ protected function _extractLimit($sqlType)
+ {
+ if (preg_match("/\((.*)\)/", $sqlType, $matches)) {
+ return (int)$matches[1];
+ }
+ return null;
+ }
+
+ /**
+ * @param string $sqlType
+ * @return int
+ */
+ protected function _extractPrecision($sqlType)
+ {
+ if (preg_match("/^(numeric|decimal|number)\((\d+)(,\d+)?\)/i", $sqlType, $matches)) {
+ return (int)$matches[2];
+ }
+ return null;
+ }
+
+ /**
+ * @param string $sqlType
+ * @return int
+ */
+ protected function _extractScale($sqlType)
+ {
+ switch (true) {
+ case preg_match("/^(numeric|decimal|number)\((\d+)\)/i", $sqlType):
+ return 0;
+ case preg_match("/^(numeric|decimal|number)\((\d+)(,(\d+))\)/i",
+ $sqlType, $match):
+ return (int)$match[4];
+ }
+ }
+
+ /**
+ * @param string $fieldType
+ * @return string
+ */
+ protected function _simplifiedType($fieldType)
+ {
+ switch (true) {
+ case preg_match('/int/i', $fieldType):
+ return 'integer';
+ case preg_match('/float|double/i', $fieldType):
+ return 'float';
+ case preg_match('/decimal|numeric|number/i', $fieldType):
+ return $this->_scale == 0 ? 'integer' : 'decimal';
+ case preg_match('/datetime/i', $fieldType):
+ return 'datetime';
+ case preg_match('/timestamp/i', $fieldType):
+ return 'timestamp';
+ case preg_match('/time/i', $fieldType):
+ return 'time';
+ case preg_match('/date/i', $fieldType):
+ return 'date';
+ case preg_match('/clob|text/i', $fieldType):
+ return 'text';
+ case preg_match('/blob|binary/i', $fieldType):
+ return 'binary';
+ case preg_match('/char|string/i', $fieldType):
+ return 'string';
+ case preg_match('/boolean/i', $fieldType):
+ return 'boolean';
+ }
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * Copyright 2007 Maintainable Software, LLC
+ * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @author Derek DeVries <derek@maintainable.com>
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php
+ * @category Horde
+ * @package Horde_Db
+ * @subpackage Adapter
+ */
+
+/**
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @author Derek DeVries <derek@maintainable.com>
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php
+ * @category Horde
+ * @package Horde_Db
+ * @subpackage Adapter
+ */
+class Horde_Db_Adapter_Base_ColumnDefinition
+{
+ protected $_base = null;
+ protected $_name = null;
+ protected $_type = null;
+ protected $_limit = null;
+ protected $_precision = null;
+ protected $_scale = null;
+ protected $_default = null;
+ protected $_null = null;
+
+ /**
+ * Construct
+ */
+ public function __construct($base, $name, $type, $limit=null,
+ $precision=null, $scale=null, $default=null, $null=null)
+ {
+ // protected
+ $this->_base = $base;
+
+ // public
+ $this->_name = $name;
+ $this->_type = $type;
+ $this->_limit = $limit;
+ $this->_precision = $precision;
+ $this->_scale = $scale;
+ $this->_default = $default;
+ $this->_null = $null;
+ }
+
+ /*##########################################################################
+ # Public
+ ##########################################################################*/
+
+ /**
+ * @return string
+ */
+ public function toSql()
+ {
+ $sql = $this->_base->quoteColumnName($this->_name).' ';
+ try {
+ $sql .= $this->_base->typeToSql($this->_type, $this->_limit,
+ $this->_precision, $this->_scale);
+ } catch (Exception $e) {
+ $sql .= $this->_type;
+ }
+ return $this->_addColumnOptions($sql, array('null' => $this->_null,
+ 'default' => $this->_default));
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->toSql();
+ }
+
+
+ /*##########################################################################
+ # Accessor
+ ##########################################################################*/
+
+ /**
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * @return string
+ */
+ public function getDefault()
+ {
+ return $this->_default;
+ }
+
+ /**
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->_type;
+ }
+
+ /**
+ * @return string
+ */
+ public function getSqlType()
+ {
+ try {
+ return $this->_base->typeToSql($this->_type, $this->_limit, $this->_precision, $this->_scale);
+ } catch (Exception $e) {
+ return $this->_type;
+ }
+ }
+
+ /**
+ * @return int
+ */
+ public function getLimit()
+ {
+ return $this->_limit;
+ }
+
+ /**
+ * @return int
+ */
+ public function precision()
+ {
+ return $this->_precision;
+ }
+
+ /**
+ * @return int
+ */
+ public function scale()
+ {
+ return $this->_scale;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function isNull()
+ {
+ return $this->_null;
+ }
+
+ /**
+ * @param string
+ */
+ public function setName($name)
+ {
+ $this->_name = $name;
+ }
+
+ /**
+ * @param string
+ */
+ public function setDefault($default)
+ {
+ $this->_default = $default;
+ }
+
+ /**
+ * @param string
+ */
+ public function setType($type)
+ {
+ $this->_type = $type;
+ }
+
+ /**
+ * @param int
+ */
+ public function setLimit($limit)
+ {
+ $this->_limit = $limit;
+ }
+
+ /**
+ * @param int
+ */
+ public function setPrecision($precision)
+ {
+ $this->_precision = $precision;
+ }
+
+ /**
+ * @param int
+ */
+ public function setScale($scale)
+ {
+ $this->_scale = $scale;
+ }
+
+ /**
+ * @param boolean
+ */
+ public function setNull($null)
+ {
+ $this->_null = $null;
+ }
+
+
+ /*##########################################################################
+ # Schema Statements
+ ##########################################################################*/
+
+ /**
+ * @param string $sql
+ * @param array $options
+ */
+ protected function _addColumnOptions($sql, $options)
+ {
+ return $this->_base->addColumnOptions($sql,
+ array_merge($options, array('column' => $this))
+ );
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * Copyright 2007 Maintainable Software, LLC
+ * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @author Derek DeVries <derek@maintainable.com>
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php
+ * @category Horde
+ * @package Horde_Db
+ * @subpackage Adapter
+ */
+
+/**
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @author Derek DeVries <derek@maintainable.com>
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php
+ * @category Horde
+ * @package Horde_Db
+ * @subpackage Adapter
+ */
+class Horde_Db_Adapter_Base_Index
+{
+ public $table;
+ public $name;
+ public $unique;
+ public $primary;
+ public $columns;
+
+
+ /*##########################################################################
+ # Construct/Destruct
+ ##########################################################################*/
+
+ /**
+ * Construct
+ *
+ * @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
+ */
+ public function __construct($table, $name, $primary, $unique, $columns)
+ {
+ $this->table = $table;
+ $this->name = $name;
+ $this->primary = $primary;
+ $this->unique = $unique;
+ $this->columns = $columns;
+ }
+
+
+ /*##########################################################################
+ # Accessor
+ ##########################################################################*/
+
+ /**
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+
+ /*##########################################################################
+ # Casting
+ ##########################################################################*/
+
+ /**
+ * Comma-separated list of the columns in the primary key
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return implode(',', $this->columns);
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * Copyright 2007 Maintainable Software, LLC
+ * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @author Derek DeVries <derek@maintainable.com>
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php
+ * @category Horde
+ * @package Horde_Db
+ * @subpackage Adapter
+ */
+
+/**
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @author Derek DeVries <derek@maintainable.com>
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php
+ * @category Horde
+ * @package Horde_Db
+ * @subpackage Adapter
+ */
+abstract class Horde_Db_Adapter_Base_Schema
+{
+ /**
+ * @var Cache object
+ */
+ protected $_cache = null;
+
+ /**
+ * @var Logger
+ */
+ protected $_logger = null;
+
+ /**
+ * @var Horde_Db_Adapter_Base
+ */
+ protected $_adapter = null;
+
+ /**
+ * @var array
+ */
+ protected $_adapterMethods = array();
+
+
+ /*##########################################################################
+ # Construct/Destruct
+ ##########################################################################*/
+
+ /**
+ * @param Horde_Db_Adapter_Base $adapter
+ * @param array $config
+ */
+ public function __construct($adapter, $config = array())
+ {
+ $this->_adapter = $adapter;
+ $this->_adapterMethods = array_flip(get_class_methods($adapter));
+
+ $this->_cache = isset($config['cache']) ? $config['cache'] : new Horde_Support_Stub;
+ $this->_logger = isset($config['logger']) ? $config['logger'] : new Horde_Support_Stub;
+ }
+
+
+ /*##########################################################################
+ # Object composition
+ ##########################################################################*/
+
+ /**
+ * Delegate calls to the adapter object.
+ *
+ * @param string $method
+ * @param array $args
+ */
+ 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.'"');
+ }
+
+
+ /*##########################################################################
+ # Quoting
+ ##########################################################################*/
+
+ /**
+ * Quotes the column value to help prevent
+ * {SQL injection attacks}[http://en.wikipedia.org/wiki/SQL_injection].
+ *
+ * @param string $value
+ * @param string $column
+ * @return string
+ */
+ public function quote($value, $column=null)
+ {
+ if (is_object($value) && is_callable(array($value, 'quotedId'))) {
+ return $value->quotedId();
+ }
+
+ $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_int($value) || is_float($value)) {
+ return $value;
+ /*@TODO
+ else
+ if value.acts_like?(:date) || value.acts_like?(:time)
+ "'#{quoted_date(value)}'"
+ else
+ "#{quoted_string_prefix}'#{quote_string(value.to_yaml)}'"
+ end
+ */
+ } 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'));
+ } else {
+ /*@TODO
+ when String, ActiveSupport::Multibyte::Chars
+ value = value.to_s
+ if column && column.type == :binary && column.class.respond_to?(:string_to_binary)
+ "#{quoted_string_prefix}'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode)
+ elsif column && [:integer, :float].include?(column.type)
+ value = column.type == :integer ? value.to_i : value.to_f
+ value.to_s
+ else
+ "#{quoted_string_prefix}'#{quote_string(value)}'" # ' (for ruby-mode)
+ end
+ */
+ return $this->_adapter->quoteString($value);
+ }
+ }
+
+ /**
+ * Quotes a string, escaping any ' (single quote) and \ (backslash)
+ * characters..
+ *
+ * @param string $string
+ * @return string
+ */
+ public function quoteString($string)
+ {
+ return "'".str_replace(array('\\', '\''), array('\\\\', '\\\''), $string)."'";
+ }
+
+ /**
+ * Returns a quoted form of the column name. This is highly adapter
+ * specific.
+ *
+ * @param string $name
+ * @return string
+ */
+ abstract public function quoteColumnName($name);
+
+ /**
+ * Returns a quoted form of the table name. Defaults to column name quoting.
+ *
+ * @param string $name
+ * @return string
+ */
+ public function quoteTableName($name)
+ {
+ return $this->quoteColumnName($name);
+ }
+
+ /**
+ * @return string
+ */
+ public function quoteTrue()
+ {
+ return "'t'";
+ }
+
+ /**
+ * @return string
+ */
+ public function quoteFalse()
+ {
+ return "'f'";
+ }
+
+ /**
+ * @return string
+ */
+ public function quoteDate($value)
+ {
+ return $this->_adapter->quoteString((string)$value);
+ }
+
+ /**
+ * @return string
+ */
+ public function quotedStringPrefix()
+ {
+ return '';
+ }
+
+
+ /*##########################################################################
+ # 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.
+ *
+ * @return array
+ */
+ public function nativeDatabaseTypes()
+ {
+ return array();
+ }
+
+ /**
+ * This is the maximum length a table alias can be
+ *
+ * @return int
+ */
+ public function tableAliasLength()
+ {
+ return 255;
+ }
+
+ /**
+ * Truncates a table alias according to the limits of the current adapter.
+ *
+ * @param string $tableName
+ * @return string
+ */
+ public function tableAliasFor($tableName)
+ {
+ $alias = substr($tableName, 0, $this->tableAliasLength());
+ return str_replace('.', '_', $alias);
+ }
+
+ /**
+ * @param string $name
+ * @return array
+ */
+ abstract public function tables($name = null);
+
+ /**
+ * Get a Horde_Db_Adapter_Base_Table object for the table.
+ *
+ * @param string $tableName
+ * @param string $name
+ *
+ * @return Horde_Db_Adapter_Base_Table
+ */
+ public function table($tableName, $name = null)
+ {
+ return $this->componentFactory('Table', array(
+ $tableName,
+ $this->primaryKey($tableName),
+ $this->columns($tableName, $name),
+ $this->indexes($tableName, $name),
+ ));
+ }
+
+ /**
+ * Return a table's primary key
+ */
+ abstract public function primaryKey($tableName, $name = null);
+
+ /**
+ * Returns an array of indexes for the given table.
+ *
+ * @param string $tableName
+ * @param string $name
+ * @return array
+ */
+ abstract public function indexes($tableName, $name = null);
+
+ /**
+ * Returns an array of Horde_Db_Adapter_Base_Column objects for the
+ * table specified by +table_name+. See the concrete implementation for
+ * details on the expected parameter values.
+ *
+ * @param string $tableName
+ * @param string $name
+ * @return array
+ */
+ abstract public function columns($tableName, $name = null);
+
+ /**
+ * Creates a new table
+ * There are two ways to work with #create_table. You can use the block
+ * form or the regular form, like this:
+ *
+ * === Block form
+ * # create_table() yields a TableDefinition instance
+ * create_table(:suppliers) do |t|
+ * t.column :name, :string, :limit => 60
+ * # Other fields here
+ * end
+ *
+ * === Regular form
+ * create_table(:suppliers)
+ * add_column(:suppliers, :name, :string, {:limit => 60})
+ *
+ * The +options+ hash can include the following keys:
+ * [<tt>:id</tt>]
+ * Set to true or false to add/not add a primary key column
+ * automatically. Defaults to true.
+ * [<tt>:primary_key</tt>]
+ * The name of the primary key, if one is to be added automatically.
+ * Defaults to +id+.
+ * [<tt>:options</tt>]
+ * Any extra options you want appended to the table definition.
+ * [<tt>:temporary</tt>]
+ * Make a temporary table.
+ * [<tt>:force</tt>]
+ * 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)
+ * create_table(:suppliers, :options => 'ENGINE=InnoDB DEFAULT CHARSET=utf8')
+ * generates:
+ * CREATE TABLE suppliers (
+ * id int(11) DEFAULT NULL auto_increment PRIMARY KEY
+ * ) ENGINE=InnoDB DEFAULT CHARSET=utf8
+ *
+ * ====== Rename the primary key column
+ * create_table(:objects, :primary_key => 'guid') do |t|
+ * t.column :name, :string, :limit => 80
+ * end
+ * generates:
+ * CREATE TABLE objects (
+ * guid int(11) DEFAULT NULL auto_increment PRIMARY KEY,
+ * name varchar(80)
+ * )
+ *
+ * ====== Do not add a primary key column
+ * create_table(:categories_suppliers, :id => false) do |t|
+ * t.column :category_id, :integer
+ * t.column :supplier_id, :integer
+ * end
+ * generates:
+ * CREATE TABLE categories_suppliers_join (
+ * category_id int,
+ * supplier_id int
+ * )
+ *
+ * See also TableDefinition#column for details on how to create columns.
+ *
+ * @param string $name
+ * @param array $options
+ */
+ public function createTable($name, $options=array())
+ {
+ $pk = isset($options['primaryKey']) && $options['primaryKey'] === false ? false : 'id';
+ $tableDefinition =
+ $this->componentFactory('TableDefinition', array($name, $this, $options));
+ if ($pk != false) {
+ $tableDefinition->primaryKey($pk);
+ }
+ return $tableDefinition;
+ }
+
+ /**
+ * Execute table creation
+ *
+ * @param string $name
+ * @param array $options
+ */
+ 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
+ if (isset($options['force'])) {
+ $this->dropTable($tableDefinition->getName(), $options);
+ }
+
+ $temp = !empty($options['temporary']) ? 'TEMPORARY' : null;
+ $opts = !empty($options['options']) ? $options['options'] : null;
+
+ $sql = "CREATE $temp TABLE ".$this->quoteTableName($tableDefinition->getName())." (\n".
+ $tableDefinition->toSql()."\n".
+ ") $opts";
+ return $this->execute($sql);
+ }
+
+ /**
+ * Renames a table.
+ * ===== Example
+ * rename_table('octopuses', 'octopi')
+ *
+ * @param string $name
+ * @param string $newName
+ */
+ abstract public function renameTable($name, $newName);
+
+ /**
+ * Drops a table from the database.
+ *
+ * @param string $name
+ */
+ public function dropTable($name)
+ {
+ $this->_clearTableCache($name);
+ return $this->execute('DROP TABLE ' . $this->quoteTableName($name));
+ }
+
+ /**
+ * Adds a new column to the named table.
+ * See TableDefinition#column for details of the options you can use.
+ *
+ * @param string $tableName
+ * @param string $columnName
+ * @param string $type
+ * @param array $options
+ */
+ public function addColumn($tableName, $columnName, $type, $options=array())
+ {
+ $this->_clearTableCache($tableName);
+
+ $limit = isset($options['limit']) ? $options['limit'] : null;
+ $precision = isset($options['precision']) ? $options['precision'] : null;
+ $scale = isset($options['scale']) ? $options['scale'] : null;
+
+ $sql = 'ALTER TABLE ' . $this->quoteTableName($tableName) .
+ ' ADD '.$this->quoteColumnName($columnName) .
+ ' '.$this->typeToSql($type, $limit, $precision, $scale);
+ $sql = $this->addColumnOptions($sql, $options);
+ return $this->execute($sql);
+ }
+
+ /**
+ * Removes the column from the table definition.
+ * ===== Examples
+ * remove_column(:suppliers, :qualification)
+ *
+ * @param string $tableName
+ * @param string $columnName
+ */
+ public function removeColumn($tableName, $columnName)
+ {
+ $this->_clearTableCache($tableName);
+
+ $sql = 'ALTER TABLE ' . $this->quoteTableName($tableName).' DROP '.$this->quoteColumnName($columnName);
+ return $this->execute($sql);
+ }
+
+ /**
+ * Changes the column's definition according to the new options.
+ * See TableDefinition#column for details of the options you can use.
+ * ===== Examples
+ * change_column(:suppliers, :name, :string, :limit => 80)
+ * change_column(:accounts, :description, :text)
+ *
+ * @param string $tableName
+ * @param string $columnName
+ * @param string $type
+ * @param array $options
+ */
+ 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
+ * DatabaseStatements#execute the apppropriate SQL statement yourself.
+ * ===== Examples
+ * change_column_default(:suppliers, :qualification, 'new')
+ * change_column_default(:accounts, :authorized, 1)
+ *
+ * @param string $tableName
+ * @param string $columnName
+ * @param string $default
+ */
+ abstract public function changeColumnDefault($tableName, $columnName, $default);
+
+ /**
+ * Renames a column.
+ * ===== Example
+ * rename_column(:suppliers, :description, :name)
+ *
+ * @param string $tableName
+ * @param string $columnName
+ * @param string $newColumnName
+ */
+ abstract public function renameColumn($tableName, $columnName, $newColumnName);
+
+ /**
+ * Adds a new index to the table. +column_name+ can be a single Symbol, or
+ * an Array of Symbols.
+ *
+ * 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+, +: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
+ * add_index(:suppliers, :name)
+ * generates
+ * CREATE INDEX suppliers_name_index ON suppliers(name)
+ *
+ * ====== Creating a unique index
+ * add_index(:accounts, [:branch_id, :party_id], :unique => true)
+ * generates
+ * CREATE UNIQUE INDEX accounts_branch_id_index ON accounts(branch_id, party_id)
+ *
+ * ====== Creating a named index
+ * add_index(:accounts, [:branch_id, :party_id], :unique => true, :name => 'by_branch_party')
+ * generates
+ * CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id)
+ *
+ * @param string $tableName
+ * @param string $columnName
+ * @param array $options
+ */
+ public function addIndex($tableName, $columnName, $options=array())
+ {
+ $this->_clearTableCache($tableName);
+
+ $columnNames = (array)($columnName);
+ $indexName = $this->indexName($tableName, array('column' => $columnNames));
+
+ $indexType = !empty($options['unique']) ? "UNIQUE" : null;
+ $indexName = !empty($options['name']) ? $options['name'] : $indexName;
+
+ foreach ($columnNames as $colName) {
+ $quotedCols[] = $this->quoteColumnName($colName);
+ }
+ $quotedColumnNames = implode(', ', $quotedCols);
+ $sql = "CREATE $indexType INDEX ".$this->quoteColumnName($indexName).
+ 'ON '.$this->quoteTableName($tableName) . " ($quotedColumnNames)";
+ return $this->execute($sql);
+ }
+
+ /**
+ * Remove the given index from the table.
+ *
+ * Remove the suppliers_name_index in the suppliers table (legacy support, use the second or third forms).
+ * remove_index :suppliers, :name
+ * Remove the index named accounts_branch_id in the accounts table.
+ * remove_index :accounts, :column => :branch_id
+ * Remove the index named by_branch_party in the accounts table.
+ * remove_index :accounts, :name => :by_branch_party
+ *
+ * You can remove an index on multiple columns by specifying the first column.
+ * add_index :accounts, [:username, :password]
+ * remove_index :accounts, :username
+ *
+ * @param string $tableName
+ * @param array $options
+ */
+ public function removeIndex($tableName, $options=array())
+ {
+ $this->_clearTableCache($tableName);
+
+ $index = $this->indexName($tableName, $options);
+ $sql = "DROP INDEX ".$this->quoteColumnName($index).' ON ' . $this->quoteTableName($tableName);
+ return $this->execute($sql);
+ }
+
+ /**
+ * Get the name of the index
+ *
+ * @param string $tableName
+ * @param array $options
+ */
+ 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);
+
+ } elseif (isset($options['name'])) {
+ return $options['name'];
+
+ } else {
+ throw new Horde_Db_Exception('You must specify the index name');
+ }
+ }
+
+ /**
+ * Returns a string of <tt>CREATE TABLE</tt> SQL statement(s) for recreating the
+ * entire structure of the database.
+ *
+ * @param string $table
+ * @return string
+ */
+ abstract public function structureDump($table = null);
+
+ /**
+ * Recreate the given db
+ *
+ * @param string $name
+ */
+ public function recreateDatabase($name)
+ {
+ $this->dropDatabase($name);
+ return $this->createDatabase($name);
+ }
+
+ /**
+ * Create the given db
+ *
+ * @param string $name
+ */
+ abstract public function createDatabase($name);
+
+ /**
+ * Drop the given db
+ *
+ * @param string $name
+ */
+ abstract public function dropDatabase($name);
+
+ /**
+ * Get the name of the current db
+ *
+ * @return string
+ */
+ abstract public function currentDatabase();
+
+ /**
+ * Should not be called normally, but this operation is non-destructive.
+ * The migrations module handles this automatically.
+ */
+ public function initializeSchemaInformation()
+ {
+ try {
+ $this->execute("CREATE TABLE schema_info (".
+ " version ".$this->typeToSql('integer').
+ ")");
+ return $this->execute("INSERT INTO schema_info (version) VALUES (0)");
+ } catch (Exception $e) {}
+ }
+
+ /**
+ * The sql for this column type
+ *
+ * @param string $type
+ * @param string $limit
+ */
+ public function typeToSql($type, $limit=null, $precision=null, $scale=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 ($limit = !empty($limit) ? $limit : $nativeLimit) {
+ $sql .= "($limit)";
+ }
+ }
+ return $sql;
+ }
+
+ /**
+ * Add default/null options to column sql
+ *
+ * @param string $sql
+ * @param array $options
+ */
+ public function addColumnOptions($sql, $options)
+ {
+ 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;
+ }
+
+ /**
+ * SELECT DISTINCT clause for a given set of columns and a given
+ * ORDER BY clause. Both PostgreSQL and Oracle override this for
+ * custom DISTINCT syntax.
+ *
+ * $connection->distinct("posts.id", "posts.created_at desc")
+ *
+ * @param string $columns
+ * @param string $orderBy
+ */
+ public function distinct($columns, $orderBy=null)
+ {
+ return "DISTINCT $columns";
+ }
+
+ /**
+ * ORDER BY clause for the passed order option.
+ * PostgreSQL overrides this due to its stricter standards compliance.
+ *
+ * @param string $sql
+ * @param array $options
+ * @return string
+ */
+ public function addOrderByForAssocLimiting($sql, $options)
+ {
+ return $sql.'ORDER BY '.$options['order'];
+ }
+
+
+ /*##########################################################################
+ # Protected
+ ##########################################################################*/
+
+ /**
+ * We need to clear cache for tables when altering them at all
+ */
+ protected function _clearTableCache($tableName)
+ {
+ $this->_cache->set("tables/columns/$tableName", null);
+ $this->_cache->set("tables/indexes/$tableName", null);
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * Copyright 2007 Maintainable Software, LLC
+ * Copyright 2008 The Horde Project (http://www.horde.org/)
+ *
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @author Derek DeVries <derek@maintainable.com>
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php
+ * @category Horde
+ * @package Horde_Db
+ * @subpackage Adapter
+ */
+
+/**
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @author Derek DeVries <derek@maintainable.com>
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php
+ * @category Horde
+ * @package Horde_Db
+ * @subpackage Adapter
+ */
+class Horde_Db_Adapter_Base_Table
+{
+ protected $_name;
+ protected $_primaryKey;
+ protected $_columns;
+ protected $_indexes;
+
+
+ /*##########################################################################
+ # Construct/Destruct
+ ##########################################################################*/
+
+ /**
+ * Construct
+ *
+ * @param string $name The table's name, such as <tt>supplier_id</tt> in <tt>supplier_id int(11)</tt>.
+ */
+ 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;
+ }
+
+
+ /*##########################################################################
+ # Protected
+ ##########################################################################*/
+
+}
--- /dev/null
+<?php
+/**
+ * Copyright 2007 Maintainable Software, LLC
+ * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @author Derek DeVries <derek@maintainable.com>
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php
+ * @category Horde
+ * @package Horde_Db
+ * @subpackage Adapter
+ */
+
+/**
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @author Derek DeVries <derek@maintainable.com>
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php
+ * @category Horde
+ * @package Horde_Db
+ * @subpackage Adapter
+ */
+class Horde_Db_Adapter_Base_TableDefinition implements ArrayAccess
+{
+ protected $_name = null;
+ protected $_base = null;
+ protected $_options = null;
+ protected $_columns = null;
+
+ /**
+ * Class 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)
+ {
+ $natives = $this->_native();
+ $this->column($name, $natives['primaryKey']);
+ }
+
+ /**
+ * Instantiates a new column for the table.
+ * The +type+ parameter must be one of the following values:
+ * <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
+ * <tt>:integer</tt>, <tt>:float</tt>, <tt>:datetime</tt>,
+ * <tt>:timestamp</tt>, <tt>:time</tt>, <tt>:date</tt>,
+ * <tt>:binary</tt>, <tt>:boolean</tt>.
+ *
+ * Available options are (none of these exists by default):
+ * * <tt>:limit</tt>:
+ * Requests a maximum column length (<tt>:string</tt>, <tt>:text</tt>,
+ * <tt>:binary</tt> or <tt>:integer</tt> columns only)
+ * * <tt>:default</tt>:
+ * The column's default value. You cannot explicitely set the default
+ * value to +NULL+. Simply leave off this option if you want a +NULL+
+ * default value.
+ * * <tt>:null</tt>:
+ * Allows or disallows +NULL+ values in the column. This option could
+ * have been named <tt>:null_allowed</tt>.
+ *
+ * This method returns <tt>self</tt>.
+ *
+ * ===== Examples
+ * # Assuming def is an instance of TableDefinition
+ * def.column(:granted, :boolean)
+ * #=> granted BOOLEAN
+ *
+ * def.column(:picture, :binary, :limit => 2.megabytes)
+ * #=> picture BLOB(2097152)
+ *
+ * def.column(:sales_stage, :string, :limit => 20, :default => 'new', :null => false)
+ * #=> sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL
+ *
+ * @return TableDefinition
+ */
+ public function column($name, $type, $options=array())
+ {
+ if ($this[$name]) {
+ $column = $this[$name];
+ } else {
+ $column = $this->_base->componentFactory('ColumnDefinition', array(
+ $this->_base, $name, $type));
+ }
+
+ $natives = $this->_native();
+ $opt = $options;
+
+ if (isset($opt['limit']) || isset($natives[$type])) {
+ $nativeLimit = isset($natives[$type]['limit']) ? $natives[$type]['limit'] : null;
+ $column->setLimit(isset($opt['limit']) ? $opt['limit'] : $nativeLimit);
+ }
+
+ $column->setPrecision(isset($opt['precision']) ? $opt['precision'] : null);
+ $column->setScale(isset($opt['scale']) ? $opt['scale'] : null);
+ $column->setDefault(isset($opt['default']) ? $opt['default'] : null);
+ $column->setNull(isset($opt['null']) ? $opt['null'] : null);
+
+ $this[$name] ? $this[$name] = $column : $this->_columns[] = $column;
+ return $this;
+ }
+
+ /**
+ * 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(); }
+
+ return " ".implode(", \n ", $cols);
+ }
+
+
+ /*##########################################################################
+ # 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]);
+ }
+ }
+ }
+
+
+ /*##########################################################################
+ # Protected
+ ##########################################################################*/
+
+ /**
+ * Get the types
+ */
+ protected function _native()
+ {
+ return $this->_base->nativeDatabaseTypes();
+ }
+
+}
* @package Horde_Db
* @subpackage Adapter
*/
-class Horde_Db_Adapter_Mssql_Schema extends Horde_Db_Adapter_Abstract_Schema
+class Horde_Db_Adapter_Mssql_Schema extends Horde_Db_Adapter_Base_Schema
{
/*##########################################################################
# Quoting
* @package Horde_Db
* @subpackage Adapter
*/
-class Horde_Db_Adapter_Mysql_Column extends Horde_Db_Adapter_Abstract_Column
+class Horde_Db_Adapter_Mysql_Column extends Horde_Db_Adapter_Base_Column
{
/**
* @var array
* @package Horde_Db
* @subpackage Adapter
*/
-class Horde_Db_Adapter_Mysql_Schema extends Horde_Db_Adapter_Abstract_Schema
+class Horde_Db_Adapter_Mysql_Schema extends Horde_Db_Adapter_Base_Schema
{
/*##########################################################################
# Quoting
* @package Horde_Db
* @subpackage Adapter
*/
-class Horde_Db_Adapter_Mysqli extends Horde_Db_Adapter_Abstract
+class Horde_Db_Adapter_Mysqli extends Horde_Db_Adapter_Base
{
/**
* Mysqli database connection object.
* @package Horde_Db
* @subpackage Adapter
*/
-class Horde_Db_Adapter_Oracle_Schema extends Horde_Db_Adapter_Abstract_Schema
+class Horde_Db_Adapter_Oracle_Schema extends Horde_Db_Adapter_Base_Schema
{
/*##########################################################################
# Quoting
* @package Horde_Db
* @subpackage Adapter
*/
-class Horde_Db_Adapter_Postgresql_Column extends Horde_Db_Adapter_Abstract_Column
+class Horde_Db_Adapter_Postgresql_Column extends Horde_Db_Adapter_Base_Column
{
/*##########################################################################
# Constants
* @package Horde_Db
* @subpackage Adapter
*/
-class Horde_Db_Adapter_Postgresql_Schema extends Horde_Db_Adapter_Abstract_Schema
+class Horde_Db_Adapter_Postgresql_Schema extends Horde_Db_Adapter_Base_Schema
{
/**
* @var string
* @package Horde_Db
* @subpackage Adapter
*/
-class Horde_Db_Adapter_Sqlite_Column extends Horde_Db_Adapter_Abstract_Column
+class Horde_Db_Adapter_Sqlite_Column extends Horde_Db_Adapter_Base_Column
{
/**
* @var array
* @package Horde_Db
* @subpackage Adapter
*/
-class Horde_Db_Adapter_Sqlite_Schema extends Horde_Db_Adapter_Abstract_Schema
+class Horde_Db_Adapter_Sqlite_Schema extends Horde_Db_Adapter_Base_Schema
{
/*##########################################################################
# Quoting
<dir name="Horde">
<dir name="Db">
<dir name="Adapter">
- <dir name="Abstract">
+ <dir name="Base">
<file name="Column.php" role="php" />
<file name="ColumnDefinition.php" role="php" />
<file name="Index.php" role="php" />
<file name="Schema.php" role="php" />
<file name="Table.php" role="php" />
<file name="TableDefinition.php" role="php" />
- </dir> <!-- /lib/Horde/Db/Adapter/Abstract -->
+ </dir> <!-- /lib/Horde/Db/Adapter/Base -->
<dir name="Mssql">
<file name="Schema.php" role="php" />
</dir> <!-- /lib/Horde/Db/Adapter/Mssql -->
</dependencies>
<phprelease>
<filelist>
- <install name="lib/Horde/Db/Adapter/Abstract/Column.php" as="Horde/Db/Adapter/Abstract/Column.php" />
- <install name="lib/Horde/Db/Adapter/Abstract/ColumnDefinition.php" as="Horde/Db/Adapter/Abstract/ColumnDefinition.php" />
- <install name="lib/Horde/Db/Adapter/Abstract/Index.php" as="Horde/Db/Adapter/Abstract/Index.php" />
- <install name="lib/Horde/Db/Adapter/Abstract/Schema.php" as="Horde/Db/Adapter/Abstract/Schema.php" />
- <install name="lib/Horde/Db/Adapter/Abstract/Table.php" as="Horde/Db/Adapter/Abstract/Table.php" />
- <install name="lib/Horde/Db/Adapter/Abstract/TableDefinition.php" as="Horde/Db/Adapter/Abstract/TableDefinition.php" />
+ <install name="lib/Horde/Db/Adapter/Base/Column.php" as="Horde/Db/Adapter/Base/Column.php" />
+ <install name="lib/Horde/Db/Adapter/Base/ColumnDefinition.php" as="Horde/Db/Adapter/Base/ColumnDefinition.php" />
+ <install name="lib/Horde/Db/Adapter/Base/Index.php" as="Horde/Db/Adapter/Base/Index.php" />
+ <install name="lib/Horde/Db/Adapter/Base/Schema.php" as="Horde/Db/Adapter/Base/Schema.php" />
+ <install name="lib/Horde/Db/Adapter/Base/Table.php" as="Horde/Db/Adapter/Base/Table.php" />
+ <install name="lib/Horde/Db/Adapter/Base/TableDefinition.php" as="Horde/Db/Adapter/Base/TableDefinition.php" />
<install name="lib/Horde/Db/Adapter/Base.php" as="Horde/Db/Adapter/Base.php" />
<install name="lib/Horde/Db/Adapter/Mssql/Schema.php" as="Horde/Db/Adapter/Mssql/Schema.php" />