* @version CVS: $Id: DataObject.php 336751 2015-05-12 04:39:50Z alan_k $
* @link http://pear.php.net/package/DB_DataObject
*/
-
+
/* ===========================================================================
*
* ===========================================================================
*/
-/**
- * The main "DB_DataObject" class is really a base class for your own tables classes
- *
- * // Set up the class by creating an ini file (refer to the manual for more details
- * [DB_DataObject]
- * database = mysql:/username:password@host/database
- * schema_location = /home/myapplication/database
- * class_location = /home/myapplication/DBTables/
- * clase_prefix = DBTables_
- *
- *
- * //Start and initialize...................... - dont forget the &
- * $config = parse_ini_file('example.ini',true);
- * $options = &PEAR::getStaticProperty('DB_DataObject','options');
- * $options = $config['DB_DataObject'];
- *
- * // example of a class (that does not use the 'auto generated tables data')
- * class mytable extends DB_DataObject {
- * // mandatory - set the table
- * var $_database_dsn = "mysql://username:password@localhost/database";
- * var $__table = "mytable";
- * function table() {
- * return array(
- * 'id' => 1, // integer or number
- * 'name' => 2, // string
- * );
- * }
- * function keys() {
- * return array('id');
- * }
- * }
- *
- * // use in the application
- *
- *
- * Simple get one row
- *
- * $instance = new mytable;
- * $instance->get("id",12);
- * echo $instance->somedata;
- *
- *
- * Get multiple rows
- *
- * $instance = new mytable;
- * $instance->whereAdd("ID > 12");
- * $instance->whereAdd("ID < 14");
- * $instance->find();
- * while ($instance->fetch()) {
- * echo $instance->somedata;
- * }
-
-
/**
* Needed classes
* - we use getStaticProperty from PEAR pretty extensively (cant remove it ATM)
define('DB_DATAOBJECT_FETCHMODE_ASSOC', 2);
-
-
-
/**
* these are constants for the get_table array
* user to determine what type of escaping is required around the object vars.
* - config = aliased view of PEAR::getStaticPropery('DB_DataObject','options') * done for performance.
* - array of loaded classes by autoload method - to stop it doing file access request over and over again!
*/
-$GLOBALS['_DB_DATAOBJECT']['RESULTS'] = array();
+$GLOBALS['_DB_DATAOBJECT']['RESULTS'] = array();
$GLOBALS['_DB_DATAOBJECT']['RESULTSEQ'] = 1;
$GLOBALS['_DB_DATAOBJECT']['RESULTFIELDS'] = array();
$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'] = array();
$GLOBALS['_DB_DATAOBJECT']['QUERYENDTIME'] = 0;
-
// this will be horrifically slow!!!!
// these two are BC/FC handlers for call in PHP4/5
-
+
if (!defined('DB_DATAOBJECT_NO_OVERLOAD')) {
class DB_DataObject_Overload
{
$this->_call($method, $args, $return);
return $return;
}
+
public function __sleep()
{
- return array_keys(get_object_vars($this)) ;
+ return array_keys(get_object_vars($this));
}
}
} else {
}
-
-
-
-
+/*
+*
+* @package DB_DataObject
+* @author Alan Knowles <alan@akbkhome.com>
+* @since PHP 4.0
+*/
- /*
- *
- * @package DB_DataObject
- * @author Alan Knowles <alan@akbkhome.com>
- * @since PHP 4.0
- */
-
class DB_DataObject extends DB_DataObject_Overload
{
/**
/* Major Public Methods */
/* (designed to be optionally then called with parent::method()) */
/* ============================================================= */
-
-
/**
- * Get a result using key, value.
+ * The Database connection dsn (as described in the PEAR DB)
+ * only used really if you are writing a very simple application/test..
+ * try not to use this - it is better stored in configuration files..
*
- * for example
- * $object->get("ID",1234);
- * Returns Number of rows located (usually 1) for success,
- * and puts all the table columns into this classes variables
+ * @access private
+ * @var string
+ */
+ public $_database_dsn = '';
+ /**
+ * The Database connection id (md5 sum of databasedsn)
*
- * see the fetch example on how to extend this.
+ * @access private
+ * @var string
+ */
+ public $_database_dsn_md5 = '';
+ /**
+ * The Database name
+ * created in __connection
*
- * if no value is entered, it is assumed that $key is a value
- * and get will then use the first key in keys()
- * to obtain the key.
+ * @access private
+ * @var string
+ */
+ public $_database = '';
+ /**
+ * The QUERY rules
+ * This replaces alot of the private variables
+ * used to build a query, it is unset after find() is run.
+ *
+ *
+ *
+ * @access private
+ * @var array
+ */
+ public $_query = array(
+ 'condition' => '', // the WHERE condition
+ 'group_by' => '', // the GROUP BY condition
+ 'order_by' => '', // the ORDER BY condition
+ 'having' => '', // the HAVING condition
+ 'useindex' => '', // the USE INDEX condition
+ 'limit_start' => '', // the LIMIT condition
+ 'limit_count' => '', // the LIMIT condition
+ 'data_select' => '*', // the columns to be SELECTed
+ 'unions' => array(), // the added unions,
+ 'derive_table' => '', // derived table name (BETA)
+ 'derive_select' => '', // derived table select (BETA)
+ );
+ /**
+ * Database result id (references global $_DB_DataObject[results]
+ *
+ * @access private
+ * @var integer
+ */
+ public $_DB_resultid;
+ /**
+ * ResultFields - on the last call to fetch(), resultfields is sent here,
+ * so we can clean up the memory.
*
- * @param string $k column
- * @param string $v value
* @access public
- * @return int No. of rows
+ * @var array
*/
- public function get($k = null, $v = null)
- {
- global $_DB_DATAOBJECT;
- if (empty($_DB_DATAOBJECT['CONFIG'])) {
- DB_DataObject::_loadConfig();
- }
- $keys = array();
-
- if ($v === null) {
- $v = $k;
- $keys = $this->keys();
- if (!$keys) {
- $this->raiseError("No Keys available for {$this->tableName()}", DB_DATAOBJECT_ERROR_INVALIDCONFIG);
- return false;
- }
- $k = $keys[0];
- }
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug("$k $v " .print_r($keys, true), "GET");
- }
-
- if ($v === null) {
- $this->raiseError("No Value specified for get", DB_DATAOBJECT_ERROR_INVALIDARGS);
- return false;
- }
- $this->$k = $v;
- return $this->find(1);
- }
-
+ public $_resultFields = false;
/**
- * Get the value of the primary id
+ * Have the links been loaded?
+ * if they have it contains a array of those variables.
*
- * While I normally use 'id' as the PRIMARY KEY value, some database use
- * {table}_id as the column name.
+ * @access private
+ * @var boolean | array
+ */
+ public $_link_loaded = false;
+ /**
+ * The JOIN condition
*
- * To save a bit of typing,
+ * @access private
+ * @var string
+ */
+ public $_join = '';
+ /**
+ * Last Error that has occured
+ * - use $this->_lastError or
+ * $last_error = PEAR::getStaticProperty('DB_DataObject','lastError');
*
- * $id = $do->pid();
+ * @access public
+ * @var object PEAR_Error (or false)
+ */
+ public $_lastError = false;
+
+ /**
+ * sets and returns debug level
+ * eg. DB_DataObject::debugLevel(4);
*
- * @return the id
+ * @param int $v level
+ * @access public
+ * @return int|none
*/
- public function pid()
+ public static function debugLevel($v = null)
{
- $keys = $this->keys();
- if (!$keys) {
- $this->raiseError(
- "No Keys available for {$this->tableName()}",
- DB_DATAOBJECT_ERROR_INVALIDCONFIG
- );
- return false;
+ global $_DB_DATAOBJECT;
+ if (empty($_DB_DATAOBJECT['CONFIG'])) {
+ (new DB_DataObject)->_loadConfig();
}
- $k = $keys[0];
- if (empty($this->$k)) { // we do not
- $this->raiseError(
- "pid() called on Object where primary key value not available",
- DB_DATAOBJECT_ERROR_NODATA
- );
- return false;
+ if ($v !== null) {
+ $r = isset($_DB_DATAOBJECT['CONFIG']['debug']) ? $_DB_DATAOBJECT['CONFIG']['debug'] : 0;
+ $_DB_DATAOBJECT['CONFIG']['debug'] = $v;
+ return $r;
}
- return $this->$k;
+ return isset($_DB_DATAOBJECT['CONFIG']['debug']) ? $_DB_DATAOBJECT['CONFIG']['debug'] : 0;
}
-
-
/**
- * build the basic select query.
+ * Define the global $_DB_DATAOBJECT['CONFIG'] as an alias to PEAR::getStaticProperty('DB_DataObject','options');
*
- * @access private
+ * After Profiling DB_DataObject, I discoved that the debug calls where taking
+ * considerable time (well 0.1 ms), so this should stop those calls happening. as
+ * all calls to debug are wrapped with direct variable queries rather than actually calling the funciton
+ * THIS STILL NEEDS FURTHER INVESTIGATION
+ *
+ * @access public
+ * @return void an error object
*/
-
- public function _build_select()
+ public function _loadConfig()
{
global $_DB_DATAOBJECT;
- $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
- if ($quoteIdentifiers) {
- $this->_connect();
- $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
- }
- $tn = ($quoteIdentifiers ? $DB->quoteIdentifier($this->tableName()) : $this->tableName()) ;
- if (!empty($this->_query['derive_table']) && !empty($this->_query['derive_select'])) {
-
- // this is a derived select..
- // not much support in the api yet..
-
- $sql = 'SELECT ' .
- $this->_query['derive_select']
- .' FROM ( SELECT'.
- $this->_query['data_select'] . " \n" .
- " FROM $tn " . $this->_query['useindex'] . " \n" .
- $this->_join . " \n" .
- $this->_query['condition'] . " \n" .
- $this->_query['group_by'] . " \n" .
- $this->_query['having'] . " \n" .
- ') ' . $this->_query['derive_table'];
-
- return $sql;
- }
-
-
-
- $sql = 'SELECT ' .
- $this->_query['data_select'] . " \n" .
- " FROM $tn " . $this->_query['useindex'] . " \n" .
- $this->_join . " \n" .
- $this->_query['condition'] . " \n" .
- $this->_query['group_by'] . " \n" .
- $this->_query['having'] . " \n";
-
- return $sql;
+
+ $_DB_DATAOBJECT['CONFIG'] = &(new PEAR)->getStaticProperty('DB_DataObject', 'options');
+ return null;
}
-
/**
- * find results, either normal or crosstable
- *
- * for example
- *
- * $object = new mytable();
- * $object->ID = 1;
- * $object->find();
- *
- *
- * will set $object->N to number of rows, and expects next command to fetch rows
- * will return $object->N
- *
- * if an error occurs $object->N will be set to false and return value will also be false;
- * if numRows is not supported it will
- *
- *
- * @param boolean $n Fetch first result
- * @access public
- * @return mixed (number of rows returned, or true if numRows fetching is not supported)
+ * (deprecated - use ::get / and your own caching method)
+ * @param $class
+ * @param $k
+ * @param null $v
+ * @return bool
*/
- public function find($n = false)
+ public static function staticGet($class, $k, $v = null)
{
+ $lclass = strtolower($class);
global $_DB_DATAOBJECT;
- if ($this->_query === false) {
- $this->raiseError(
- "You cannot do two queries on the same object (copy it before finding)",
- DB_DATAOBJECT_ERROR_INVALIDARGS
- );
- return false;
- }
-
if (empty($_DB_DATAOBJECT['CONFIG'])) {
- DB_DataObject::_loadConfig();
+ (new DB_DataObject)->_loadConfig();
}
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug($n, "find", 1);
+
+ $key = "$k:$v";
+ if ($v === null) {
+ $key = $k;
}
- if (!strlen($this->tableName())) {
- // xdebug can backtrace this!
- trigger_error("NO \$__table SPECIFIED in class definition", E_USER_ERROR);
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ (new DB_DataObject)->debug("$class $key", "STATIC GET - TRY CACHE");
}
- $this->N = 0;
- $query_before = $this->_query;
- $this->_build_condition($this->table()) ;
-
-
- $this->_connect();
- $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
-
-
- $sql = $this->_build_select();
-
- foreach ($this->_query['unions'] as $union_ar) {
- $sql .= $union_ar[1] . $union_ar[0]->_build_select() . " \n";
+ if (!empty($_DB_DATAOBJECT['CACHE'][$lclass][$key])) {
+ return $_DB_DATAOBJECT['CACHE'][$lclass][$key];
}
-
- $sql .= $this->_query['order_by'] . " \n";
-
-
- /* We are checking for method modifyLimitQuery as it is PEAR DB specific */
- if ((!isset($_DB_DATAOBJECT['CONFIG']['db_driver'])) ||
- ($_DB_DATAOBJECT['CONFIG']['db_driver'] == 'DB')) {
- /* PEAR DB specific */
-
- if (isset($this->_query['limit_start']) && strlen($this->_query['limit_start'] . $this->_query['limit_count'])) {
- $sql = $DB->modifyLimitQuery($sql, $this->_query['limit_start'], $this->_query['limit_count']);
- }
- } else {
- /* theoretically MDB2! */
- if (isset($this->_query['limit_start']) && strlen($this->_query['limit_start'] . $this->_query['limit_count'])) {
- $DB->setLimit($this->_query['limit_count'], $this->_query['limit_start']);
- }
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ (new DB_DataObject)->debug("$class $key", "STATIC GET - NOT IN CACHE");
}
-
-
- $err = $this->_query($sql);
- if (is_a($err, 'PEAR_Error')) {
- return false;
- }
-
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug("CHECK autofetchd $n", "find", 1);
- }
-
- // find(true)
-
- $ret = $this->N;
- if (!$ret && !empty($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid])) {
- // clear up memory if nothing found!?
- unset($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]);
+
+ $obj = DB_DataObject::factory(substr($class, strlen($_DB_DATAOBJECT['CONFIG']['class_prefix'])));
+ if ((new PEAR)->isError($obj)) {
+ $dor = new DB_DataObject();
+ $dor->raiseError("could not autoload $class", DB_DATAOBJECT_ERROR_NOCLASS);
+ $r = false;
+ return $r;
}
-
- if ($n && $this->N > 0) {
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug("ABOUT TO AUTOFETCH", "find", 1);
- }
- $fs = $this->fetch();
- // if fetch returns false (eg. failed), then the backend doesnt support numRows (eg. ret=true)
- // - hence find() also returns false..
- $ret = ($ret === true) ? $fs : $ret;
+
+ if (!isset($_DB_DATAOBJECT['CACHE'][$lclass])) {
+ $_DB_DATAOBJECT['CACHE'][$lclass] = array();
}
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug("DONE", "find", 1);
+ if (!$obj->get($k, $v)) {
+ $dor = new DB_DataObject();
+ $dor->raiseError("No Data return from get $k $v", DB_DATAOBJECT_ERROR_NODATA);
+
+ $r = false;
+ return $r;
}
- $this->_query = $query_before;
- return $ret;
+ $_DB_DATAOBJECT['CACHE'][$lclass][$key] = $obj;
+ return $_DB_DATAOBJECT['CACHE'][$lclass][$key];
}
/**
- * fetches next row into this objects var's
- *
- * returns 1 on success 0 on failure
- *
- *
- *
- * Example
- * $object = new mytable();
- * $object->name = "fred";
- * $object->find();
- * $store = array();
- * while ($object->fetch()) {
- * echo $this->ID;
- * $store[] = $object; // builds an array of object lines.
- * }
+ * Debugger. - use this in your extended classes to output debugging information.
*
- * to add features to a fetch
- * function fetch () {
- * $ret = parent::fetch();
- * $this->date_formated = date('dmY',$this->date);
- * return $ret;
- * }
+ * Uses DB_DataObject::DebugLevel(x) to turn it on
*
- * @access public
- * @return boolean on success
+ * @param string $message - message to output
+ * @param int $logtype - bold at start
+ * @param int $level - output level
+ * @return void
+ * @access public
*/
- public function fetch()
+ public function debug($message, $logtype = 0, $level = 1)
{
global $_DB_DATAOBJECT;
- if (empty($_DB_DATAOBJECT['CONFIG'])) {
- DB_DataObject::_loadConfig();
- }
- if (empty($this->N)) {
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug("No data returned from FIND (eg. N is 0)", "FETCH", 3);
- }
- return false;
- }
-
- if (empty($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]) ||
- !is_object($result = $_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid])) {
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug('fetched on object after fetch completed (no results found)');
- }
- return false;
- }
-
-
- $array = $result->fetchRow(DB_DATAOBJECT_FETCHMODE_ASSOC);
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug(serialize($array), "FETCH");
- }
-
- // fetched after last row..
- if ($array === null) {
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $t= explode(' ', microtime());
-
- $this->debug(
- "Last Data Fetch'ed after " .
- ($t[0]+$t[1]- $_DB_DATAOBJECT['QUERYENDTIME']) .
- " seconds",
- "FETCH",
- 1
- );
- }
- // reduce the memory usage a bit... (but leave the id in, so count() works ok on it)
- unset($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]);
-
- // we need to keep a copy of resultfields locally so toArray() still works
- // however we dont want to keep it in the global cache..
-
- if (!empty($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid])) {
- $this->_resultFields = $_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid];
- unset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid]);
- }
- // this is probably end of data!!
- //DB_DataObject::raiseError("fetch: no data returned", DB_DATAOBJECT_ERROR_NODATA);
- return false;
- }
- // make sure resultFields is always empty..
- $this->_resultFields = false;
-
- if (!isset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid])) {
- // note: we dont declare this to keep the print_r size down.
- $_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid]= array_flip(array_keys($array));
- }
- $replace = array('.', ' ');
- foreach ($array as $k=>$v) {
- // use strpos as str_replace is slow.
- $kk = (strpos($k, '.') === false && strpos($k, ' ') === false) ?
- $k : str_replace($replace, '_', $k);
-
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug("$kk = ". $array[$k], "fetchrow LINE", 3);
- }
- $this->$kk = $array[$k];
+
+ if (empty($_DB_DATAOBJECT['CONFIG']['debug']) ||
+ (is_numeric($_DB_DATAOBJECT['CONFIG']['debug']) && $_DB_DATAOBJECT['CONFIG']['debug'] < $level)) {
+ return null;
}
-
- // set link flag
- $this->_link_loaded=false;
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug("{$this->tableName()} DONE", "fetchrow", 2);
+ // this is a bit flaky due to php's wonderfull class passing around crap..
+ // but it's about as good as it gets..
+ $class = (isset($this) && is_a($this, 'DB_DataObject')) ? get_class($this) : 'DB_DataObject';
+
+ if (!is_string($message)) {
+ $message = print_r($message, true);
}
- if (($this->_query !== false) && empty($_DB_DATAOBJECT['CONFIG']['keep_query_after_fetch'])) {
- $this->_query = false;
+ if (!is_numeric($_DB_DATAOBJECT['CONFIG']['debug']) && is_callable($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ return call_user_func($_DB_DATAOBJECT['CONFIG']['debug'], $class, $message, $logtype, $level);
}
- return true;
- }
-
- /**
- * fetches all results as an array,
- *
- * return format is dependant on args.
- * if selectAdd() has not been called on the object, then it will add the correct columns to the query.
- *
- * A) Array of values (eg. a list of 'id')
- *
- * $x = DB_DataObject::factory('mytable');
- * $x->whereAdd('something = 1')
- * $ar = $x->fetchAll('id');
- * -- returns array(1,2,3,4,5)
- *
- * B) Array of values (not from table)
- *
- * $x = DB_DataObject::factory('mytable');
- * $x->whereAdd('something = 1');
- * $x->selectAdd();
- * $x->selectAdd('distinct(group_id) as group_id');
- * $ar = $x->fetchAll('group_id');
- * -- returns array(1,2,3,4,5)
- * *
- * C) A key=>value associative array
- *
- * $x = DB_DataObject::factory('mytable');
- * $x->whereAdd('something = 1')
- * $ar = $x->fetchAll('id','name');
- * -- returns array(1=>'fred',2=>'blogs',3=> .......
- *
- * D) array of objects
- * $x = DB_DataObject::factory('mytable');
- * $x->whereAdd('something = 1');
- * $ar = $x->fetchAll();
- *
- * E) array of arrays (for example)
- * $x = DB_DataObject::factory('mytable');
- * $x->whereAdd('something = 1');
- * $ar = $x->fetchAll(false,false,'toArray');
- *
- *
- * @param string|false $k key
- * @param string|false $v value
- * @param string|false $method method to call on each result to get array value (eg. 'toArray')
- * @access public
- * @return array format dependant on arguments, may be empty
- */
- public function fetchAll($k= false, $v = false, $method = false)
- {
- // should it even do this!!!?!?
- if ($k !== false &&
- ( // only do this is we have not been explicit..
- empty($this->_query['data_select']) ||
- ($this->_query['data_select'] == '*')
- )
- ) {
- $this->selectAdd();
- $this->selectAdd($k);
- if ($v !== false) {
- $this->selectAdd($v);
- }
+ if (!ini_get('html_errors')) {
+ echo "$class : $logtype : $message\n";
+ flush();
+ return null;
}
-
- $this->find();
- $ret = array();
- while ($this->fetch()) {
- if ($v !== false) {
- $ret[$this->$k] = $this->$v;
- continue;
- }
- $ret[] = $k === false ?
- ($method == false ? clone($this) : $this->$method())
- : $this->$k;
+ if (!is_string($message)) {
+ $message = print_r($message, true);
}
- return $ret;
+ $colorize = ($logtype == 'ERROR') ? '<font color="red">' : '<font>';
+ echo "<code>{$colorize}<B>$class: $logtype:</B> " . nl2br(htmlspecialchars($message)) . "</font></code><BR>\n";
}
-
-
+
/**
- * Adds a condition to the WHERE statement, defaults to AND
+ * classic factory method for loading a table class
+ * usage: $do = DB_DataObject::factory('person')
+ * WARNING - this may emit a include error if the file does not exist..
+ * use @ to silence it (if you are sure it is acceptable)
+ * eg. $do = @DB_DataObject::factory('person')
*
- * $object->whereAdd(); //reset or cleaer ewhwer
- * $object->whereAdd("ID > 20");
- * $object->whereAdd("age > 20","OR");
+ * table name can bedatabasename/table
+ * - and allow modular dataobjects to be written..
+ * (this also helps proxy creation)
*
- * @param string $cond condition
- * @param string $logic optional logic "OR" (defaults to "AND")
- * @access public
- * @return string|PEAR::Error - previous condition or Error when invalid args found
+ * Experimental Support for Multi-Database factory eg. mydatabase.mytable
+ *
+ *
+ * @param string $table tablename (use blank to create a new instance of the same class.)
+ * @access private
+ * @return DataObject|PEAR|PEAR_Error|true
*/
- public function whereAdd($cond = false, $logic = 'AND')
+
+
+ public static function factory($table = '')
{
- // for PHP5.2.3 - there is a bug with setting array properties of an object.
- $_query = $this->_query;
-
- if (!isset($this->_query) || ($_query === false)) {
- return $this->raiseError(
- "You cannot do two queries on the same object (clone it before finding)",
- DB_DATAOBJECT_ERROR_INVALIDARGS
- );
- }
-
- if ($cond === false) {
- $r = $this->_query['condition'];
- $_query['condition'] = '';
- $this->_query = $_query;
- return preg_replace('/^\s+WHERE\s+/', '', $r);
+ global $_DB_DATAOBJECT;
+
+
+ // multi-database support.. - experimental.
+ $database = '';
+
+ if (strpos($table, '/') !== false) {
+ list($database, $table) = explode('.', $table, 2);
}
- // check input...= 0 or ' ' == error!
- if (!trim($cond)) {
- return $this->raiseError("WhereAdd: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
+
+ if (empty($_DB_DATAOBJECT['CONFIG'])) {
+ (new DB_DataObject)->_loadConfig();
}
- $r = $_query['condition'];
- if ($_query['condition']) {
- $_query['condition'] .= " {$logic} ( {$cond} )";
- $this->_query = $_query;
- return $r;
+ // no configuration available for database
+ if (!empty($database) && empty($_DB_DATAOBJECT['CONFIG']['database_' . $database])) {
+ $do = new DB_DataObject();
+ $do->raiseError(
+ "unable to find database_{$database} in Configuration, It is required for factory with database",
+ 0,
+ PEAR_ERROR_DIE
+ );
}
- $_query['condition'] = " WHERE ( {$cond} ) ";
- $this->_query = $_query;
- return $r;
- }
- /**
- * Adds a 'IN' condition to the WHERE statement
- *
- * $object->whereAddIn('id', $array, 'int'); //minimal usage
- * $object->whereAddIn('price', $array, 'float', 'OR'); // cast to float, and call whereAdd with 'OR'
- * $object->whereAddIn('name', $array, 'string'); // quote strings
- *
- * @param string $key key column to match
- * @param array $list list of values to match
- * @param string $type string|int|integer|float|bool cast to type.
- * @param string $logic optional logic to call whereAdd with eg. "OR" (defaults to "AND")
- * @access public
- * @return string|PEAR::Error - previous condition or Error when invalid args found
- */
- public function whereAddIn($key, $list, $type, $logic = 'AND')
- {
- $not = '';
- if ($key[0] == '!') {
- $not = 'NOT ';
- $key = substr($key, 1);
- }
- // fix type for short entry.
- $type = $type == 'int' ? 'integer' : $type;
- if ($type == 'string') {
- $this->_connect();
+ /*
+ if ($table === '') {
+ if (is_a($this,'DB_DataObject') && strlen($this->tableName())) {
+ $table = $this->tableName();
+ } else {
+ return DB_DataObject::raiseError(
+ "factory did not recieve a table name",
+ DB_DATAOBJECT_ERROR_INVALIDARGS);
+ }
}
- $ar = array();
- foreach ($list as $k) {
- settype($k, $type);
- $ar[] = $type == 'string' ? $this->_quote($k) : $k;
- }
-
- if (!$ar) {
- return $not ? $this->_query['condition'] : $this->whereAdd("1=0");
- }
- return $this->whereAdd("$key $not IN (". implode(',', $ar). ')', $logic);
- }
+ */
+ // does this need multi db support??
+ $cp = isset($_DB_DATAOBJECT['CONFIG']['class_prefix']) ?
+ explode(PATH_SEPARATOR, $_DB_DATAOBJECT['CONFIG']['class_prefix']) : '';
-
-
- /**
- * Adds a order by condition
- *
- * $object->orderBy(); //clears order by
- * $object->orderBy("ID");
- * $object->orderBy("ID,age");
- *
- * @param string $order Order
- * @access public
- * @return none|PEAR::Error - invalid args only
- */
- public function orderBy($order = false)
- {
- if ($this->_query === false) {
- $this->raiseError(
- "You cannot do two queries on the same object (copy it before finding)",
- DB_DATAOBJECT_ERROR_INVALIDARGS
- );
- return false;
+ //print_r($cp);
+
+ // multiprefix support.
+ $tbl = preg_replace('/[^A-Z0-9]/i', '_', ucfirst($table));
+ if (is_array($cp)) {
+ $class = array();
+ foreach ($cp as $cpr) {
+ $ce = substr(phpversion(), 0, 1) > 4 ? class_exists($cpr . $tbl, false) : class_exists($cpr . $tbl);
+ if ($ce) {
+ $class = $cpr . $tbl;
+ break;
+ }
+ $class[] = $cpr . $tbl;
+ }
+ } else {
+ $class = $tbl;
+ $ce = substr(phpversion(), 0, 1) > 4 ? class_exists($class, false) : class_exists($class);
}
- if ($order === false) {
- $this->_query['order_by'] = '';
- return;
+
+
+ $rclass = $ce ? $class : (new DB_DataObject)->_autoloadClass($class, $table);
+ // proxy = full|light
+ if (!$rclass && isset($_DB_DATAOBJECT['CONFIG']['proxy'])) {
+ (new DB_DataObject)->debug("FAILED TO Autoload $database.$table - using proxy.", "FACTORY", 1);
+
+
+ $proxyMethod = 'getProxy' . $_DB_DATAOBJECT['CONFIG']['proxy'];
+ // if you have loaded (some other way) - dont try and load it again..
+ class_exists('DB_DataObject_Generator') ? '' :
+ //require_once 'DB/DataObject/Generator.php';
+ require_once 'Generator.php';
+
+ $d = new DB_DataObject;
+
+ $d->__table = $table;
+
+ $ret = $d->_connect();
+ if (is_object($ret) && is_a($ret, 'PEAR_Error')) {
+ return $ret;
+ }
+
+ $x = new DB_DataObject_Generator;
+ return $x->$proxyMethod($d->_database, $table);
}
- // check input...= 0 or ' ' == error!
- if (!trim($order)) {
- return $this->raiseError("orderBy: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
+
+ if (!$rclass || !class_exists($rclass)) {
+ $dor = new DB_DataObject();
+ return $dor->raiseError(
+ "factory could not find class " .
+ (is_array($class) ? implode(PATH_SEPARATOR, $class) : $class) .
+ "from $table",
+ DB_DATAOBJECT_ERROR_INVALIDCONFIG
+ );
}
-
- if (!$this->_query['order_by']) {
- $this->_query['order_by'] = " ORDER BY {$order} ";
- return;
+
+ $ret = new $rclass();
+
+ if (!empty($database)) {
+ (new DB_DataObject)->debug("Setting database to $database", "FACTORY", 1);
+ $ret->database($database);
}
- $this->_query['order_by'] .= " , {$order}";
+ return $ret;
}
/**
- * Adds a group by condition
- *
- * $object->groupBy(); //reset the grouping
- * $object->groupBy("ID DESC");
- * $object->groupBy("ID,age");
+ * Default error handling is to create a pear error, but never return it.
+ * if you need to handle errors you should look at setting the PEAR_Error callback
+ * this is due to the fact it would wreck havoc on the internal methods!
*
- * @param string $group Grouping
+ * @param int $message message
+ * @param int $type type
+ * @param int $behaviour behaviour (die or continue!);
* @access public
- * @return none|PEAR::Error - invalid args only
+ * @return error|int|object
*/
- public function groupBy($group = false)
+ public function raiseError($message, $type = null, $behaviour = null)
{
- if ($this->_query === false) {
- $this->raiseError(
- "You cannot do two queries on the same object (copy it before finding)",
- DB_DATAOBJECT_ERROR_INVALIDARGS
- );
- return false;
- }
- if ($group === false) {
- $this->_query['group_by'] = '';
- return;
+ global $_DB_DATAOBJECT;
+
+ if ($behaviour == PEAR_ERROR_DIE && !empty($_DB_DATAOBJECT['CONFIG']['dont_die'])) {
+ $behaviour = null;
}
- // check input...= 0 or ' ' == error!
- if (!trim($group)) {
- return $this->raiseError("groupBy: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
+
+ $error = &(new PEAR)->getStaticProperty('DB_DataObject', 'lastError');
+
+
+ // no checks for production here?....... - we log errors before we throw them.
+ DB_DataObject::debug($message, 'ERROR', 1);
+
+
+ if ((new PEAR)->isError($message)) {
+ $error = $message;
+ } else {
+ //require_once 'DB/DataObject/Error.php';
+ require_once 'Error.php';
+ $dor = new PEAR();
+ $error = $dor->raiseError(
+ $message,
+ $type,
+ $behaviour,
+ $opts = null,
+ $userinfo = null,
+ 'DB_DataObject_Error'
+ );
}
-
-
- if (!$this->_query['group_by']) {
- $this->_query['group_by'] = " GROUP BY {$group} ";
- return;
+ // this will never work totally with PHP's object model.
+ // as this is passed on static calls (like staticGet in our case)
+
+ $_DB_DATAOBJECT['LASTERROR'] = $error;
+
+ if (isset($this) && is_object($this) && is_subclass_of($this, 'db_dataobject')) {
+ $this->_lastError = $error;
}
- $this->_query['group_by'] .= " , {$group}";
+
+ return $error;
}
/**
- * Adds a having clause
- *
- * $object->having(); //reset the grouping
- * $object->having("sum(value) > 0 ");
+ * autoload Class
*
- * @param string $having condition
- * @access public
- * @return none|PEAR::Error - invalid args only
+ * @param string|array $class Class
+ * @param bool $table Table trying to load.
+ * @return string classname on Success
+ * @access private
*/
- public function having($having = false)
+ public function _autoloadClass($class, $table = false)
{
- if ($this->_query === false) {
- $this->raiseError(
- "You cannot do two queries on the same object (copy it before finding)",
- DB_DATAOBJECT_ERROR_INVALIDARGS
- );
+ global $_DB_DATAOBJECT;
+
+ if (empty($_DB_DATAOBJECT['CONFIG'])) {
+ DB_DataObject::_loadConfig();
+ }
+ $class_prefix = empty($_DB_DATAOBJECT['CONFIG']['class_prefix']) ?
+ '' : $_DB_DATAOBJECT['CONFIG']['class_prefix'];
+
+ $table = $table ? $table : substr($class, strlen($class_prefix));
+
+ // only include the file if it exists - and barf badly if it has parse errors :)
+ if (!empty($_DB_DATAOBJECT['CONFIG']['proxy']) || empty($_DB_DATAOBJECT['CONFIG']['class_location'])) {
return false;
}
- if ($having === false) {
- $this->_query['having'] = '';
- return;
+ // support for:
+ // class_location = mydir/ => maps to mydir/Tablename.php
+ // class_location = mydir/myfile_%s.php => maps to mydir/myfile_Tablename
+ // with directory sepr
+ // class_location = mydir/:mydir2/: => tries all of thes locations.
+ $cl = $_DB_DATAOBJECT['CONFIG']['class_location'];
+
+
+ switch (true) {
+ case (strpos($cl, '%s') !== false):
+ $file = sprintf($cl, preg_replace('/[^A-Z0-9]/i', '_', ucfirst($table)));
+ break;
+
+ case (strpos($cl, PATH_SEPARATOR) !== false):
+ $file = array();
+ foreach (explode(PATH_SEPARATOR, $cl) as $p) {
+ $file[] = $p . '/' . preg_replace('/[^A-Z0-9]/i', '_', ucfirst($table)) . ".php";
+ }
+ break;
+ default:
+ $file = $cl . '/' . preg_replace('/[^A-Z0-9]/i', '_', ucfirst($table)) . ".php";
+ break;
}
- // check input...= 0 or ' ' == error!
- if (!trim($having)) {
- return $this->raiseError("Having: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
+
+ $cls = is_array($class) ? $class : array($class);
+
+ if (is_array($file) || !file_exists($file)) {
+ $found = false;
+
+ $file = is_array($file) ? $file : array($file);
+ $search = implode(PATH_SEPARATOR, $file);
+ foreach ($file as $f) {
+ foreach (explode(PATH_SEPARATOR, '' . PATH_SEPARATOR . ini_get('include_path')) as $p) {
+ $ff = empty($p) ? $f : "$p/$f";
+
+ if (file_exists($ff)) {
+ $file = $ff;
+ $found = true;
+ break;
+ }
+ }
+ if ($found) {
+ break;
+ }
+ }
+ if (!$found) {
+ $dor = new DB_DataObject();
+ $dor->raiseError(
+ "autoload:Could not find class " . implode(',', $cls) .
+ " using class_location value :" . $search .
+ " using include_path value :" . ini_get('include_path'),
+ DB_DATAOBJECT_ERROR_INVALIDCONFIG
+ );
+ return false;
+ }
}
-
-
- if (!$this->_query['having']) {
- $this->_query['having'] = " HAVING {$having} ";
- return;
+
+ include_once $file;
+
+
+ $ce = false;
+ foreach ($cls as $c) {
+ $ce = substr(phpversion(), 0, 1) > 4 ? class_exists($c, false) : class_exists($c);
+ if ($ce) {
+ $class = $c;
+ break;
+ }
}
- $this->_query['having'] .= " AND {$having}";
+ if (!$ce) {
+ $dor = new DB_DataObject();
+ $dor->raiseError(
+ "autoload:Could not autoload " . implode(',', $cls),
+ DB_DATAOBJECT_ERROR_INVALIDCONFIG
+ );
+ return false;
+ }
+ return $class;
}
/**
- * Adds a using Index
+ * connects to the database
*
- * $object->useIndex(); //reset the use Index
- * $object->useIndex("some_index");
*
- * Note do not put unfiltered user input into theis method.
- * This is mysql specific at present? - might need altering to support other databases.
+ * TODO: tidy this up - This has grown to support a number of connection options like
+ * a) dynamic changing of ini file to change which database to connect to
+ * b) multi data via the table_{$table} = dsn ini option
+ * c) session based storage.
*
- * @param string|array $index index or indexes to use.
- * @access public
- * @return none|PEAR::Error - invalid args only
+ * @access private
+ * @return error|PEAR|true
*/
- public function useIndex($index = false)
+ public function _connect()
{
- if ($this->_query === false) {
- $this->raiseError(
- "You cannot do two queries on the same object (copy it before finding)",
- DB_DATAOBJECT_ERROR_INVALIDARGS
- );
- return false;
+ global $_DB_DATAOBJECT;
+ if (empty($_DB_DATAOBJECT['CONFIG'])) {
+ $this->_loadConfig();
}
- if ($index=== false) {
- $this->_query['useindex'] = '';
- return;
+ // Set database driver for reference
+ $db_driver = empty($_DB_DATAOBJECT['CONFIG']['db_driver']) ?
+ 'DB' : $_DB_DATAOBJECT['CONFIG']['db_driver'];
+
+ // is it already connected ?
+ if ($this->_database_dsn_md5 && !empty($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) {
+
+ // connection is an error...
+ if ((new PEAR)->isError($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) {
+ return $this->raiseError(
+ $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->message,
+ $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->code,
+ PEAR_ERROR_DIE
+ );
+ }
+
+ if (empty($this->_database)) {
+ $this->_database = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['database'];
+ $hasGetDatabase = method_exists($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5], 'getDatabase');
+
+ $this->_database = ($db_driver != 'DB' && $hasGetDatabase)
+ ? $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->getDatabase()
+ : $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['database'];
+
+
+ if (($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['phptype'] == 'sqlite')
+ && is_file($this->_database)) {
+ $this->_database = basename($this->_database);
+ }
+ if ($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['phptype'] == 'ibase') {
+ $this->_database = substr(basename($this->_database), 0, -4);
+ }
+ }
+ // theoretically we have a md5, it's listed in connections and it's not an error.
+ // so everything is ok!
+ return true;
}
- // check input...= 0 or ' ' == error!
- if ((is_string($index) && !trim($index)) || (is_array($index) && !count($index))) {
- return $this->raiseError("Having: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
+
+ // it's not currently connected!
+ // try and work out what to use for the dsn !
+
+ $options = $_DB_DATAOBJECT['CONFIG'];
+ // if the databse dsn dis defined in the object..
+ $dsn = isset($this->_database_dsn) ? $this->_database_dsn : null;
+
+ if (!$dsn) {
+ if (!$this->_database && !strlen($this->tableName())) {
+ $this->_database = isset($options["table_{$this->tableName()}"]) ? $options["table_{$this->tableName()}"] : null;
+ }
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug("Checking for database specific ini ('{$this->_database}') : database_{$this->_database} in options", "CONNECT");
+ }
+
+ if ($this->_database && !empty($options["database_{$this->_database}"])) {
+ $dsn = $options["database_{$this->_database}"];
+ } elseif (!empty($options['database'])) {
+ $dsn = $options['database'];
+ }
}
- $index = is_array($index) ? implode(', ', $index) : $index;
-
- if (!$this->_query['useindex']) {
- $this->_query['useindex'] = " USE INDEX ({$index}) ";
- return;
+
+ // if still no database...
+ if (!$dsn) {
+ return $this->raiseError(
+ "No database name / dsn found anywhere",
+ DB_DATAOBJECT_ERROR_INVALIDCONFIG,
+ PEAR_ERROR_DIE
+ );
+ }
+
+
+ if (is_string($dsn)) {
+ $this->_database_dsn_md5 = md5($dsn);
+ } else {
+ /// support array based dsn's
+ $this->_database_dsn_md5 = md5(serialize($dsn));
+ }
+
+ if (!empty($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) {
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug("USING CACHED CONNECTION", "CONNECT", 3);
+ }
+
+
+ if (!$this->_database) {
+ $hasGetDatabase = method_exists($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5], 'getDatabase');
+ $this->_database = ($db_driver != 'DB' && $hasGetDatabase)
+ ? $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->getDatabase()
+ : $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['database'];
+
+ if (($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['phptype'] == 'sqlite')
+ && is_file($this->_database)) {
+ $this->_database = basename($this->_database);
+ }
+ }
+ return true;
+ }
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug("NEW CONNECTION TP DATABASE :" . $this->_database, "CONNECT", 3);
+ /* actualy make a connection */
+ $this->debug(print_r($dsn, true) . " {$this->_database_dsn_md5}", "CONNECT", 3);
+ }
+
+ // Note this is verbose deliberatly!
+
+ if ($db_driver == 'DB') {
+
+ /* PEAR DB connect */
+
+ // this allows the setings of compatibility on DB
+ $db_options = (new PEAR)->getStaticProperty('DB', 'options');
+ require_once 'DB.php';
+ if ($db_options) {
+ $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5] = DB::connect($dsn, $db_options);
+ } else {
+ $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5] = DB::connect($dsn);
+ }
+ } else {
+ /* assumption is MDB2 */
+ require_once 'MDB2.php';
+ // this allows the setings of compatibility on MDB2
+ $db_options = (new PEAR)->getStaticProperty('MDB2', 'options');
+ $db_options = is_array($db_options) ? $db_options : array();
+ $db_options['portability'] = isset($db_options['portability'])
+ ? $db_options['portability'] : MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_FIX_CASE;
+ $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5] = MDB2::connect($dsn, $db_options);
+ }
+
+
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug(print_r($_DB_DATAOBJECT['CONNECTIONS'], true), "CONNECT", 5);
}
- $this->_query['useindex'] = substr($this->_query['useindex'], 0, -2) . ", {$index}) ";
+ if ((new PEAR)->isError($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) {
+ $this->debug($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->toString(), "CONNECT FAILED", 5);
+ return $this->raiseError(
+ "Connect failed, turn on debugging to 5 see why",
+ $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->code,
+ PEAR_ERROR_DIE
+ );
+ }
+
+ if (empty($this->_database)) {
+ $hasGetDatabase = method_exists($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5], 'getDatabase');
+
+ $this->_database = ($db_driver != 'DB' && $hasGetDatabase)
+ ? $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->getDatabase()
+ : $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['database'];
+
+
+ if (($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['phptype'] == 'sqlite')
+ && is_file($this->_database)) {
+ $this->_database = basename($this->_database);
+ }
+ }
+
+ // Oracle need to optimize for portibility - not sure exactly what this does though :)
+
+ return true;
}
+
/**
- * Sets the Limit
- *
- * $boject->limit(); // clear limit
- * $object->limit(12);
- * $object->limit(12,10);
+ * Return or assign the name of the current table
*
- * Note this will emit an error on databases other than mysql/postgress
- * as there is no 'clean way' to implement it. - you should consider refering to
- * your database manual to decide how you want to implement it.
*
- * @param string $a limit start (or number), or blank to reset
- * @param string $b number
+ * @param string optinal table name to set
* @access public
- * @return none|PEAR::Error - invalid args only
+ * @return string The name of the current table
*/
- public function limit($a = null, $b = null)
+ public function tableName()
{
- if ($this->_query === false) {
- $this->raiseError(
- "You cannot do two queries on the same object (copy it before finding)",
- DB_DATAOBJECT_ERROR_INVALIDARGS
- );
- return false;
+ global $_DB_DATAOBJECT;
+ $args = func_get_args();
+ if (count($args)) {
+ $this->__table = $args[0];
}
-
- if ($a === null) {
- $this->_query['limit_start'] = '';
- $this->_query['limit_count'] = '';
- return;
+ if (empty($this->__table)) {
+ return '';
}
- // check input...= 0 or ' ' == error!
- if ((!is_int($a) && ((string)((int)$a) !== (string)$a))
- || (($b !== null) && (!is_int($b) && ((string)((int)$b) !== (string)$b)))) {
- return $this->raiseError("limit: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
+ if (!empty($_DB_DATAOBJECT['CONFIG']['portability']) && $_DB_DATAOBJECT['CONFIG']['portability'] & 1) {
+ return strtolower($this->__table);
}
- global $_DB_DATAOBJECT;
- $this->_connect();
- $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
-
- $this->_query['limit_start'] = ($b == null) ? 0 : (int)$a;
- $this->_query['limit_count'] = ($b == null) ? (int)$a : (int)$b;
+ return $this->__table;
}
/**
- * Adds a select columns
+ * Get a result using key, value.
*
- * $object->selectAdd(); // resets select to nothing!
- * $object->selectAdd("*"); // default select
- * $object->selectAdd("unixtime(DATE) as udate");
- * $object->selectAdd("DATE");
+ * for example
+ * $object->get("ID",1234);
+ * Returns Number of rows located (usually 1) for success,
+ * and puts all the table columns into this classes variables
*
- * to prepend distict:
- * $object->selectAdd('distinct ' . $object->selectAdd());
+ * see the fetch example on how to extend this.
*
- * @param string $k
- * @access public
- * @return mixed null or old string if you reset it.
+ * if no value is entered, it is assumed that $key is a value
+ * and get will then use the first key in keys()
+ * to obtain the key.
+ *
+ * @param string $k column
+ * @param string $v value
+ * @access public
+ * @return int No. of rows
*/
- public function selectAdd($k = null)
+ public function get($k = null, $v = null)
{
- if ($this->_query === false) {
- $this->raiseError(
- "You cannot do two queries on the same object (copy it before finding)",
- DB_DATAOBJECT_ERROR_INVALIDARGS
- );
- return false;
+ global $_DB_DATAOBJECT;
+ if (empty($_DB_DATAOBJECT['CONFIG'])) {
+ DB_DataObject::_loadConfig();
}
- if ($k === null) {
- $old = $this->_query['data_select'];
- $this->_query['data_select'] = '';
- return $old;
+ $keys = array();
+
+ if ($v === null) {
+ $v = $k;
+ $keys = $this->keys();
+ if (!$keys) {
+ $this->raiseError("No Keys available for {$this->tableName()}", DB_DATAOBJECT_ERROR_INVALIDCONFIG);
+ return false;
+ }
+ $k = $keys[0];
}
-
- // check input...= 0 or ' ' == error!
- if (!trim($k)) {
- return $this->raiseError("selectAdd: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug("$k $v " . print_r($keys, true), "GET");
}
-
- if ($this->_query['data_select']) {
- $this->_query['data_select'] .= ', ';
+
+ if ($v === null) {
+ $this->raiseError("No Value specified for get", DB_DATAOBJECT_ERROR_INVALIDARGS);
+ return false;
}
- $this->_query['data_select'] .= " $k ";
+ $this->$k = $v;
+ return $this->find(1);
}
+
/**
- * Adds multiple Columns or objects to select with formating.
+ * get/set an array of table primary keys
*
- * $object->selectAs(null); // adds "table.colnameA as colnameA,table.colnameB as colnameB,......"
- * // note with null it will also clear the '*' default select
- * $object->selectAs(array('a','b'),'%s_x'); // adds "a as a_x, b as b_x"
- * $object->selectAs(array('a','b'),'ddd_%s','ccc'); // adds "ccc.a as ddd_a, ccc.b as ddd_b"
- * $object->selectAdd($object,'prefix_%s'); // calls $object->get_table and adds it all as
- * objectTableName.colnameA as prefix_colnameA
+ * set usage: $do->keys('id','code');
*
- * @param array|object|null the array or object to take column names from.
- * @param string format in sprintf format (use %s for the colname)
- * @param string table name eg. if you have joinAdd'd or send $from as an array.
+ * This is defined in the table definition if it gets it wrong,
+ * or you do not want to use ini tables, you can override this.
+ * @param string optional set the key
+ * @param * optional set more keys
* @access public
- * @return void
+ * @return array
*/
- public function selectAs($from = null, $format = '%s', $tableName=false)
+ public function keys()
{
- global $_DB_DATAOBJECT;
-
- if ($this->_query === false) {
- $this->raiseError(
- "You cannot do two queries on the same object (copy it before finding)",
- DB_DATAOBJECT_ERROR_INVALIDARGS
- );
- return false;
- }
-
- if ($from === null) {
- // blank the '*'
- $this->selectAdd();
- $from = $this;
- }
-
-
- $table = $this->tableName();
- if (is_object($from)) {
- $table = $from->tableName();
- $from = array_keys($from->table());
+ // for temporary storage of database fields..
+ // note this is not declared as we dont want to bloat the print_r output
+ $args = func_get_args();
+ if (count($args)) {
+ $this->_database_keys = $args;
}
-
- if ($tableName !== false) {
- $table = $tableName;
+ if (isset($this->_database_keys)) {
+ return $this->_database_keys;
}
- $s = '%s';
- if (!empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers'])) {
+
+ global $_DB_DATAOBJECT;
+ if (!isset($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) {
$this->_connect();
- $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
- $s = $DB->quoteIdentifier($s);
- $format = $DB->quoteIdentifier($format);
}
- foreach ($from as $k) {
- $this->selectAdd(sprintf("{$s}.{$s} as {$format}", $table, $k, $k));
+ if (isset($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName() . "__keys"])) {
+ return array_keys($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName() . "__keys"]);
}
- $this->_query['data_select'] .= "\n";
+ $this->databaseStructure();
+
+ if (isset($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName() . "__keys"])) {
+ return array_keys($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName() . "__keys"]);
+ }
+ return array();
}
+
/**
- * Insert the current objects variables into the database
+ * Autoload or manually load the table definitions
*
- * Returns the ID of the inserted element (if auto increment or sequences are used.)
*
- * for example
+ * usage :
+ * DB_DataObject::databaseStructure( 'databasename',
+ * parse_ini_file('mydb.ini',true),
+ * parse_ini_file('mydb.link.ini',true));
*
- * Designed to be extended
+ * obviously you dont have to use ini files.. (just return array similar to ini files..)
*
- * $object = new mytable();
- * $object->name = "fred";
- * echo $object->insert();
+ * It should append to the table structure array
+ *
+ *
+ * @param optional string name of database to assign / read
+ * @param optional array structure of database, and keys
+ * @param optional array table links
*
* @access public
- * @return mixed false on failure, int when auto increment or sequence used, otherwise true on success
+ * @return true or PEAR:error on wrong paramenters.. or false if no file exists..
+ * or the array(tablename => array(column_name=>type)) if called with 1 argument.. (databasename)
*/
- public function insert()
+ public function databaseStructure()
{
global $_DB_DATAOBJECT;
-
- // we need to write to the connection (For nextid) - so us the real
- // one not, a copyied on (as ret-by-ref fails with overload!)
-
- if (!isset($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) {
- $this->_connect();
- }
-
- $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
-
- $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
-
- $items = $this->table();
-
- if (!$items) {
- $this->raiseError(
- "insert:No table definition for {$this->tableName()}",
- DB_DATAOBJECT_ERROR_INVALIDCONFIG
- );
- return false;
- }
- $options = $_DB_DATAOBJECT['CONFIG'];
+ // Assignment code
- $datasaved = 1;
- $leftq = '';
- $rightq = '';
-
- $seqKeys = isset($_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()]) ?
- $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] :
- $this->sequenceKey();
-
- $key = isset($seqKeys[0]) ? $seqKeys[0] : false;
- $useNative = isset($seqKeys[1]) ? $seqKeys[1] : false;
- $seq = isset($seqKeys[2]) ? $seqKeys[2] : false;
-
- $dbtype = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn["phptype"];
-
-
- // nativeSequences or Sequences..
+ if ($args = func_get_args()) {
+ if (count($args) == 1) {
- // big check for using sequences
-
- if (($key !== false) && !$useNative) {
- if (!$seq) {
- $keyvalue = $DB->nextId($this->tableName());
+ // this returns all the tables and their structure..
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug("Loading Generator as databaseStructure called with args", 1);
+ }
+
+ $x = new DB_DataObject;
+ $x->_database = $args[0];
+ $this->_connect();
+ $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+
+ $tables = $DB->getListOf('tables');
+ class_exists('DB_DataObject_Generator') ? '' :
+ //require_once 'DB/DataObject/Generator.php';
+ require_once 'Generator.php';
+
+ foreach ($tables as $table) {
+ $y = new DB_DataObject_Generator;
+ $y->fillTableSchema($x->_database, $table);
+ }
+ return $_DB_DATAOBJECT['INI'][$x->_database];
} else {
- $f = $DB->getOption('seqname_format');
- $DB->setOption('seqname_format', '%s');
- $keyvalue = $DB->nextId($seq);
- $DB->setOption('seqname_format', $f);
- }
- if (PEAR::isError($keyvalue)) {
- $this->raiseError($keyvalue->toString(), DB_DATAOBJECT_ERROR_INVALIDCONFIG);
- return false;
- }
- $this->$key = $keyvalue;
- }
-
- // if we haven't set disable_null_strings to "full"
- $ignore_null = !isset($options['disable_null_strings'])
- || !is_string($options['disable_null_strings'])
- || strtolower($options['disable_null_strings']) !== 'full' ;
-
-
- foreach ($items as $k => $v) {
-
- // if we are using autoincrement - skip the column...
- if ($key && ($k == $key) && $useNative) {
- continue;
- }
-
-
- // Ignore INTEGERS which aren't set to a value - or empty string..
- if ((!isset($this->$k) || ($v == 1 && $this->$k === ''))
- && $ignore_null
- ) {
- continue;
- }
- // dont insert data into mysql timestamps
- // use query() if you really want to do this!!!!
- if ($v & DB_DATAOBJECT_MYSQLTIMESTAMP) {
- continue;
- }
-
- if ($leftq) {
- $leftq .= ', ';
- $rightq .= ', ';
- }
-
- $leftq .= ($quoteIdentifiers ? ($DB->quoteIdentifier($k) . ' ') : "$k ");
-
- if (is_object($this->$k) && is_a($this->$k, 'DB_DataObject_Cast')) {
- $value = $this->$k->toString($v, $DB);
- if (PEAR::isError($value)) {
- $this->raiseError($value->toString(), DB_DATAOBJECT_ERROR_INVALIDARGS);
- return false;
+ $_DB_DATAOBJECT['INI'][$args[0]] = isset($_DB_DATAOBJECT['INI'][$args[0]]) ?
+ $_DB_DATAOBJECT['INI'][$args[0]] + $args[1] : $args[1];
+
+ if (isset($args[1])) {
+ $_DB_DATAOBJECT['LINKS'][$args[0]] = isset($_DB_DATAOBJECT['LINKS'][$args[0]]) ?
+ $_DB_DATAOBJECT['LINKS'][$args[0]] + $args[2] : $args[2];
}
- $rightq .= $value;
- continue;
- }
-
-
- if (!($v & DB_DATAOBJECT_NOTNULL) && DB_DataObject::_is_null($this, $k)) {
- $rightq .= " NULL ";
- continue;
- }
- // DATE is empty... on a col. that can be null..
- // note: this may be usefull for time as well..
- if (!$this->$k &&
- (($v & DB_DATAOBJECT_DATE) || ($v & DB_DATAOBJECT_TIME)) &&
- !($v & DB_DATAOBJECT_NOTNULL)) {
- $rightq .= " NULL ";
- continue;
- }
-
-
- if ($v & DB_DATAOBJECT_STR) {
- $rightq .= $this->_quote((string) (
- ($v & DB_DATAOBJECT_BOOL) ?
- // this is thanks to the braindead idea of postgres to
- // use t/f for boolean.
- (($this->$k === 'f') ? 0 : (int)(bool) $this->$k) :
- $this->$k
- )) . " ";
- continue;
- }
- if (is_numeric($this->$k)) {
- $rightq .=" {$this->$k} ";
- continue;
- }
- /* flag up string values - only at debug level... !!!??? */
- if (is_object($this->$k) || is_array($this->$k)) {
- $this->debug('ODD DATA: ' .$k . ' ' . print_r($this->$k, true), 'ERROR');
+ return true;
}
-
- // at present we only cast to integers
- // - V2 may store additional data about float/int
- $rightq .= ' ' . intval($this->$k) . ' ';
}
-
- // not sure why we let empty insert here.. - I guess to generate a blank row..
-
-
- if ($leftq || $useNative) {
- $table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->tableName()) : $this->tableName());
-
-
- if (($dbtype == 'pgsql') && empty($leftq)) {
- $r = $this->_query("INSERT INTO {$table} DEFAULT VALUES");
- } else {
- $r = $this->_query("INSERT INTO {$table} ($leftq) VALUES ($rightq) ");
- }
-
-
-
-
- if (PEAR::isError($r)) {
- $this->raiseError($r);
- return false;
- }
-
- if ($r < 1) {
- return 0;
- }
-
-
- // now do we have an integer key!
-
- if ($key && $useNative) {
- switch ($dbtype) {
- case 'mysql':
- case 'mysqli':
- $method = "{$dbtype}_insert_id";
- $this->$key = $method(
- $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->connection
- );
- break;
-
- case 'mssql':
- // note this is not really thread safe - you should wrapp it with
- // transactions = eg.
- // $db->query('BEGIN');
- // $db->insert();
- // $db->query('COMMIT');
- $db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
- $method = ($db_driver == 'DB') ? 'getOne' : 'queryOne';
- $mssql_key = $DB->$method("SELECT @@IDENTITY");
- if (PEAR::isError($mssql_key)) {
- $this->raiseError($mssql_key);
- return false;
- }
- $this->$key = $mssql_key;
- break;
-
- case 'pgsql':
- if (!$seq) {
- $seq = $DB->getSequenceName(strtolower($this->tableName()));
- }
- $db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
- $method = ($db_driver == 'DB') ? 'getOne' : 'queryOne';
- $pgsql_key = $DB->$method("SELECT currval('".$seq . "')");
- if (PEAR::isError($pgsql_key)) {
- $this->raiseError($pgsql_key);
- return false;
- }
- $this->$key = $pgsql_key;
- break;
-
- case 'ifx':
- $this->$key = array_shift(
- ifx_fetch_row(
- ifx_query(
- "select DBINFO('sqlca.sqlerrd1') FROM systables where tabid=1",
- $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->connection,
- IFX_SCROLL
- ),
- "FIRST"
- )
- );
- break;
-
- }
- }
+ if (!$this->_database) {
+ $this->_connect();
+ }
- if (isset($_DB_DATAOBJECT['CACHE'][strtolower(get_class($this))])) {
- $this->_clear_cache();
- }
- if ($key) {
- return $this->$key;
- }
+
+ // if this table is already loaded this table..
+ if (!empty($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()])) {
return true;
}
- $this->raiseError("insert: No Data specifed for query", DB_DATAOBJECT_ERROR_NODATA);
- return false;
- }
- /**
- * Updates current objects variables into the database
- * uses the keys() to decide how to update
- * Returns the true on success
- *
- * for example
- *
- * $object = DB_DataObject::factory('mytable');
- * $object->get("ID",234);
- * $object->email="testing@test.com";
- * if(!$object->update())
- * echo "UPDATE FAILED";
- *
- * to only update changed items :
- * $dataobject->get(132);
- * $original = $dataobject; // clone/copy it..
- * $dataobject->setFrom($_POST);
- * if ($dataobject->validate()) {
- * $dataobject->update($original);
- * } // otherwise an error...
- *
- * performing global updates:
- * $object = DB_DataObject::factory('mytable');
- * $object->status = "dead";
- * $object->whereAdd('age > 150');
- * $object->update(DB_DATAOBJECT_WHEREADD_ONLY);
- *
- * @param object dataobject (optional) | DB_DATAOBJECT_WHEREADD_ONLY - used to only update changed items.
- * @access public
- * @return int rows affected or false on failure
- */
- public function update($dataObject = false)
- {
- global $_DB_DATAOBJECT;
- // connect will load the config!
- $this->_connect();
-
-
- $original_query = $this->_query;
-
- $items = $this->table();
-
- // only apply update against sequence key if it is set?????
-
- $seq = $this->sequenceKey();
- if ($seq[0] !== false) {
- $keys = array($seq[0]);
- if (!isset($this->{$keys[0]}) && $dataObject !== true) {
- $this->raiseError("update: trying to perform an update without
- the key set, and argument to update is not
- DB_DATAOBJECT_WHEREADD_ONLY
- ". print_r(array('seq' => $seq , 'keys'=>$keys), true), DB_DATAOBJECT_ERROR_INVALIDARGS);
- return false;
- }
- } else {
- $keys = $this->keys();
+ // initialize the ini data.. if empt..
+ if (empty($_DB_DATAOBJECT['INI'][$this->_database])) {
+ $_DB_DATAOBJECT['INI'][$this->_database] = array();
}
-
-
- if (!$items) {
- $this->raiseError("update:No table definition for {$this->tableName()}", DB_DATAOBJECT_ERROR_INVALIDCONFIG);
- return false;
+
+ if (empty($_DB_DATAOBJECT['CONFIG'])) {
+ DB_DataObject::_loadConfig();
}
- $datasaved = 1;
- $settings = '';
- $this->_connect();
-
- $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
- $dbtype = $DB->dsn["phptype"];
- $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
- $options = $_DB_DATAOBJECT['CONFIG'];
-
-
- $ignore_null = !isset($options['disable_null_strings'])
- || !is_string($options['disable_null_strings'])
- || strtolower($options['disable_null_strings']) !== 'full' ;
-
-
- foreach ($items as $k => $v) {
-
- // I think this is ignoring empty vlalues
- if ((!isset($this->$k) || ($v == 1 && $this->$k === ''))
- && $ignore_null
- ) {
- continue;
- }
- // ignore stuff thats
-
- // dont write things that havent changed..
- if (($dataObject !== false) && isset($dataObject->$k) && ($dataObject->$k === $this->$k)) {
- continue;
- }
-
- // - dont write keys to left.!!!
- if (in_array($k, $keys)) {
- continue;
- }
-
- // dont insert data into mysql timestamps
- // use query() if you really want to do this!!!!
- if ($v & DB_DATAOBJECT_MYSQLTIMESTAMP) {
- continue;
- }
-
-
- if ($settings) {
- $settings .= ', ';
- }
-
- $kSql = ($quoteIdentifiers ? $DB->quoteIdentifier($k) : $k);
-
- if (is_object($this->$k) && is_a($this->$k, 'DB_DataObject_Cast')) {
- $value = $this->$k->toString($v, $DB);
- if (PEAR::isError($value)) {
- $this->raiseError($value->getMessage(), DB_DATAOBJECT_ERROR_INVALIDARG);
- return false;
- }
- $settings .= "$kSql = $value ";
- continue;
- }
-
- // special values ... at least null is handled...
- if (!($v & DB_DATAOBJECT_NOTNULL) && DB_DataObject::_is_null($this, $k)) {
- $settings .= "$kSql = NULL ";
- continue;
- }
- // DATE is empty... on a col. that can be null..
- // note: this may be usefull for time as well..
- if (!$this->$k &&
- (($v & DB_DATAOBJECT_DATE) || ($v & DB_DATAOBJECT_TIME)) &&
- !($v & DB_DATAOBJECT_NOTNULL)) {
- $settings .= "$kSql = NULL ";
- continue;
- }
-
- if ($v & DB_DATAOBJECT_STR) {
- $settings .= "$kSql = ". $this->_quote((string) (
- ($v & DB_DATAOBJECT_BOOL) ?
- // this is thanks to the braindead idea of postgres to
- // use t/f for boolean.
- (($this->$k === 'f') ? 0 : (int)(bool) $this->$k) :
- $this->$k
- )) . ' ';
- continue;
- }
- if (is_numeric($this->$k)) {
- $settings .= "$kSql = {$this->$k} ";
- continue;
+ // we do not have the data for this table yet...
+
+ // if we are configured to use the proxy..
+
+ if (!empty($_DB_DATAOBJECT['CONFIG']['proxy'])) {
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug("Loading Generator to fetch Schema", 1);
}
- // at present we only cast to integers
- // - V2 may store additional data about float/int
- $settings .= "$kSql = " . intval($this->$k) . ' ';
+ class_exists('DB_DataObject_Generator') ? '' :
+ //require_once 'DB/DataObject/Generator.php';
+ require_once 'Generator.php';
+
+
+ $x = new DB_DataObject_Generator;
+ $x->fillTableSchema($this->_database, $this->tableName());
+ return true;
}
-
-
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug("got keys as ".serialize($keys), 3);
+
+
+ // if you supply this with arguments, then it will take those
+ // as the database and links array...
+
+ $schemas = isset($_DB_DATAOBJECT['CONFIG']['schema_location']) ?
+ array("{$_DB_DATAOBJECT['CONFIG']['schema_location']}/{$this->_database}.ini") :
+ array();
+
+ if (isset($_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"])) {
+ $schemas = is_array($_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"]) ?
+ $_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"] :
+ explode(PATH_SEPARATOR, $_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"]);
}
- if ($dataObject !== true) {
- $this->_build_condition($items, $keys);
- } else {
- // prevent wiping out of data!
- if (empty($this->_query['condition'])) {
- $this->raiseError("update: global table update not available
- do \$do->whereAdd('1=1'); if you really want to do that.
- ", DB_DATAOBJECT_ERROR_INVALIDARGS);
- return false;
+
+
+ $_DB_DATAOBJECT['INI'][$this->_database] = array();
+ foreach ($schemas as $ini) {
+ if (file_exists($ini) && is_file($ini)) {
+ $_DB_DATAOBJECT['INI'][$this->_database] = array_merge(
+ $_DB_DATAOBJECT['INI'][$this->_database],
+ parse_ini_file($ini, true)
+ );
+
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ if (!is_readable($ini)) {
+ $this->debug("ini file is not readable: $ini", "databaseStructure", 1);
+ } else {
+ $this->debug("Loaded ini file: $ini", "databaseStructure", 1);
+ }
+ }
+ } else {
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug("Missing ini file: $ini", "databaseStructure", 1);
+ }
}
}
-
-
-
- // echo " $settings, $this->condition ";
- if ($settings && isset($this->_query) && $this->_query['condition']) {
- $table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->tableName()) : $this->tableName());
-
- $r = $this->_query("UPDATE {$table} SET {$settings} {$this->_query['condition']} ");
-
- // restore original query conditions.
- $this->_query = $original_query;
-
- if (PEAR::isError($r)) {
- $this->raiseError($r);
- return false;
- }
- if ($r < 1) {
- return 0;
+ // are table name lowecased..
+ if (!empty($_DB_DATAOBJECT['CONFIG']['portability']) && $_DB_DATAOBJECT['CONFIG']['portability'] & 1) {
+ foreach ($_DB_DATAOBJECT['INI'][$this->_database] as $k => $v) {
+ // results in duplicate cols.. but not a big issue..
+ $_DB_DATAOBJECT['INI'][$this->_database][strtolower($k)] = $v;
}
+ }
- $this->_clear_cache();
- return $r;
+
+ // now have we loaded the structure..
+
+ if (!empty($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()])) {
+ return true;
}
- // restore original query conditions.
- $this->_query = $original_query;
-
- // if you manually specified a dataobject, and there where no changes - then it's ok..
- if ($dataObject !== false) {
+ // - if not try building it..
+ if (!empty($_DB_DATAOBJECT['CONFIG']['proxy'])) {
+ class_exists('DB_DataObject_Generator') ? '' :
+ //require_once 'DB/DataObject/Generator.php';
+ require_once 'Generator.php';
+
+ $x = new DB_DataObject_Generator;
+ $x->fillTableSchema($this->_database, $this->tableName());
+ // should this fail!!!???
return true;
}
-
- $this->raiseError(
- "update: No Data specifed for query $settings , {$this->_query['condition']}",
- DB_DATAOBJECT_ERROR_NODATA
- );
+ $this->debug("Cant find database schema: {$this->_database}/{$this->tableName()} \n" .
+ "in links file data: " . print_r($_DB_DATAOBJECT['INI'], true), "databaseStructure", 5);
+ // we have to die here!! - it causes chaos if we dont (including looping forever!)
+ $this->raiseError("Unable to load schema for database and table (turn debugging up to 5 for full error message)", DB_DATAOBJECT_ERROR_INVALIDARGS, PEAR_ERROR_DIE);
return false;
}
/**
- * Deletes items from table which match current objects variables
- *
- * Returns the true on success
+ * find results, either normal or crosstable
*
* for example
*
- * Designed to be extended
- *
* $object = new mytable();
- * $object->ID=123;
- * echo $object->delete(); // builds a conditon
+ * $object->ID = 1;
+ * $object->find();
*
- * $object = new mytable();
- * $object->whereAdd('age > 12');
- * $object->limit(1);
- * $object->orderBy('age DESC');
- * $object->delete(true); // dont use object vars, use the conditions, limit and order.
*
- * @param bool $useWhere (optional) If DB_DATAOBJECT_WHEREADD_ONLY is passed in then
- * we will build the condition only using the whereAdd's. Default is to
- * build the condition only using the object parameters.
+ * will set $object->N to number of rows, and expects next command to fetch rows
+ * will return $object->N
*
- * @access public
- * @return mixed Int (No. of rows affected) on success, false on failure, 0 on no data affected
+ * if an error occurs $object->N will be set to false and return value will also be false;
+ * if numRows is not supported it will
+ *
+ *
+ * @param boolean $n Fetch first result
+ * @access public
+ * @return mixed (number of rows returned, or true if numRows fetching is not supported)
*/
- public function delete($useWhere = false)
+ public function find($n = false)
{
global $_DB_DATAOBJECT;
- // connect will load the config!
- $this->_connect();
- $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
- $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
-
- $extra_cond = ' ' . (isset($this->_query['order_by']) ? $this->_query['order_by'] : '');
-
- if (!$useWhere) {
- $keys = $this->keys();
- $this->_query = array(); // as it's probably unset!
- $this->_query['condition'] = ''; // default behaviour not to use where condition
- $this->_build_condition($this->table(), $keys);
- // if primary keys are not set then use data from rest of object.
- if (!$this->_query['condition']) {
- $this->_build_condition($this->table(), array(), $keys);
- }
- $extra_cond = '';
- }
-
-
- // don't delete without a condition
- if (($this->_query !== false) && $this->_query['condition']) {
- $table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->tableName()) : $this->tableName());
- $sql = "DELETE ";
- // using a joined delete. - with useWhere..
- $sql .= (!empty($this->_join) && $useWhere) ?
- "{$table} FROM {$table} {$this->_join} " :
- "FROM {$table} ";
-
- $sql .= $this->_query['condition']. $extra_cond;
-
- // add limit..
-
- if (isset($this->_query['limit_start']) && strlen($this->_query['limit_start'] . $this->_query['limit_count'])) {
- if (!isset($_DB_DATAOBJECT['CONFIG']['db_driver']) ||
- ($_DB_DATAOBJECT['CONFIG']['db_driver'] == 'DB')) {
- // pear DB
- $sql = $DB->modifyLimitQuery($sql, $this->_query['limit_start'], $this->_query['limit_count']);
- } else {
- // MDB2
- $DB->setLimit($this->_query['limit_count'], $this->_query['limit_start']);
- }
- }
-
-
- $r = $this->_query($sql);
-
-
- if (PEAR::isError($r)) {
- $this->raiseError($r);
- return false;
- }
- if ($r < 1) {
- return 0;
- }
- $this->_clear_cache();
- return $r;
- } else {
- $this->raiseError("delete: No condition specifed for query", DB_DATAOBJECT_ERROR_NODATA);
+ if ($this->_query === false) {
+ $this->raiseError(
+ "You cannot do two queries on the same object (copy it before finding)",
+ DB_DATAOBJECT_ERROR_INVALIDARGS
+ );
return false;
}
- }
- /**
- * fetches a specific row into this object variables
- *
- * Not recommended - better to use fetch()
- *
- * Returens true on success
- *
- * @param int $row row
- * @access public
- * @return boolean true on success
- */
- public function fetchRow($row = null)
- {
- global $_DB_DATAOBJECT;
if (empty($_DB_DATAOBJECT['CONFIG'])) {
- $this->_loadConfig();
- }
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug("{$this->tableName()} $row of {$this->N}", "fetchrow", 3);
- }
- if (!$this->tableName()) {
- $this->raiseError("fetchrow: No table", DB_DATAOBJECT_ERROR_INVALIDCONFIG);
- return false;
- }
- if ($row === null) {
- $this->raiseError("fetchrow: No row specified", DB_DATAOBJECT_ERROR_INVALIDARGS);
- return false;
- }
- if (!$this->N) {
- $this->raiseError("fetchrow: No results avaiable", DB_DATAOBJECT_ERROR_NODATA);
- return false;
- }
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug("{$this->tableName()} $row of {$this->N}", "fetchrow", 3);
+ DB_DataObject::_loadConfig();
}
-
- $result = $_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid];
- $array = $result->fetchrow(DB_DATAOBJECT_FETCHMODE_ASSOC, $row);
- if (!is_array($array)) {
- $this->raiseError("fetchrow: No results available", DB_DATAOBJECT_ERROR_NODATA);
- return false;
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug($n, "find", 1);
}
- $replace = array('.', ' ');
- foreach ($array as $k => $v) {
- // use strpos as str_replace is slow.
- $kk = (strpos($k, '.') === false && strpos($k, ' ') === false) ?
- $k : str_replace($replace, '_', $k);
-
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug("$kk = ". $array[$k], "fetchrow LINE", 3);
- }
- $this->$kk = $array[$k];
+ if (!strlen($this->tableName())) {
+ // xdebug can backtrace this!
+ trigger_error("NO \$__table SPECIFIED in class definition", E_USER_ERROR);
}
+ $this->N = 0;
+ $query_before = $this->_query;
+ $this->_build_condition($this->table());
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug("{$this->tableName()} DONE", "fetchrow", 3);
- }
- return true;
- }
- /**
- * Find the number of results from a simple query
- *
- * for example
- *
- * $object = new mytable();
- * $object->name = "fred";
- * echo $object->count();
- * echo $object->count(true); // dont use object vars.
- * echo $object->count('distinct mycol'); count distinct mycol.
- * echo $object->count('distinct mycol',true); // dont use object vars.
- * echo $object->count('distinct'); // count distinct id (eg. the primary key)
- *
- *
- * @param bool|string (optional)
- * (true|false => see below not on whereAddonly)
- * (string)
- * "DISTINCT" => does a distinct count on the tables 'key' column
- * otherwise => normally it counts primary keys - you can use
- * this to do things like $do->count('distinct mycol');
- *
- * @param bool $whereAddOnly (optional) If DB_DATAOBJECT_WHEREADD_ONLY is passed in then
- * we will build the condition only using the whereAdd's. Default is to
- * build the condition using the object parameters as well.
- *
- * @access public
- * @return int
- */
- public function count($countWhat = false, $whereAddOnly = false)
- {
- global $_DB_DATAOBJECT;
-
- if (is_bool($countWhat)) {
- $whereAddOnly = $countWhat;
- }
-
- $t = clone($this);
- $items = $t->table();
-
- $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
-
-
- if (!isset($t->_query)) {
- $this->raiseError(
- "You cannot do run count after you have run fetch()",
- DB_DATAOBJECT_ERROR_INVALIDARGS
- );
- return false;
- }
$this->_connect();
$DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
-
- if (!$whereAddOnly && $items) {
- $t->_build_condition($items);
+
+ $sql = $this->_build_select();
+
+ foreach ($this->_query['unions'] as $union_ar) {
+ $sql .= $union_ar[1] . $union_ar[0]->_build_select() . " \n";
}
- $keys = $this->keys();
- if (empty($keys[0]) && (!is_string($countWhat) || (strtoupper($countWhat) == 'DISTINCT'))) {
- $this->raiseError(
- "You cannot do run count without keys - use \$do->count('id'), or use \$do->count('distinct id')';",
- DB_DATAOBJECT_ERROR_INVALIDARGS,
- PEAR_ERROR_DIE
- );
- return false;
+ $sql .= $this->_query['order_by'] . " \n";
+
+
+ /* We are checking for method modifyLimitQuery as it is PEAR DB specific */
+ if ((!isset($_DB_DATAOBJECT['CONFIG']['db_driver'])) ||
+ ($_DB_DATAOBJECT['CONFIG']['db_driver'] == 'DB')) {
+ /* PEAR DB specific */
+
+ if (isset($this->_query['limit_start']) && strlen($this->_query['limit_start'] . $this->_query['limit_count'])) {
+ $sql = $DB->modifyLimitQuery($sql, $this->_query['limit_start'], $this->_query['limit_count']);
+ }
+ } else {
+ /* theoretically MDB2! */
+ if (isset($this->_query['limit_start']) && strlen($this->_query['limit_start'] . $this->_query['limit_count'])) {
+ $DB->setLimit($this->_query['limit_count'], $this->_query['limit_start']);
+ }
}
- $table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->tableName()) : $this->tableName());
- $key_col = empty($keys[0]) ? '' : (($quoteIdentifiers ? $DB->quoteIdentifier($keys[0]) : $keys[0]));
- $as = ($quoteIdentifiers ? $DB->quoteIdentifier('DATAOBJECT_NUM') : 'DATAOBJECT_NUM');
-
- // support distinct on default keys.
- $countWhat = (strtoupper($countWhat) == 'DISTINCT') ?
- "DISTINCT {$table}.{$key_col}" : $countWhat;
-
- $countWhat = is_string($countWhat) ? $countWhat : "{$table}.{$key_col}";
-
- $r = $t->_query(
- "SELECT count({$countWhat}) as $as
- FROM $table {$t->_join} {$t->_query['condition']}"
- );
- if (PEAR::isError($r)) {
+
+
+ $err = $this->_query($sql);
+ if (is_a($err, 'PEAR_Error')) {
return false;
}
-
- $result = $_DB_DATAOBJECT['RESULTS'][$t->_DB_resultid];
- $l = $result->fetchRow(DB_DATAOBJECT_FETCHMODE_ORDERED);
- // free the results - essential on oracle.
- $t->free();
+
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug('Count returned '. $l[0], 1);
+ $this->debug("CHECK autofetchd $n", "find", 1);
}
- return (int) $l[0];
- }
- /**
- * sends raw query to database
- *
- * Since _query has to be a private 'non overwriteable method', this is a relay
- *
- * @param string $string SQL Query
- * @access public
- * @return void or DB_Error
- */
- public function query($string)
- {
- return $this->_query($string);
- }
+ // find(true)
+ $ret = $this->N;
+ if (!$ret && !empty($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid])) {
+ // clear up memory if nothing found!?
+ unset($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]);
+ }
- /**
- * an escape wrapper around DB->escapeSimple()
- * can be used when adding manual queries or clauses
- * eg.
- * $object->query("select * from xyz where abc like '". $object->escape($_GET['name']) . "'");
- *
- * @param string $string value to be escaped
- * @param bool $likeEscape escapes % and _ as well. - so like queries can be protected.
- * @access public
- * @return string
- */
- public function escape($string, $likeEscape=false)
- {
- global $_DB_DATAOBJECT;
- $this->_connect();
- $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
- // mdb2 uses escape...
- $dd = empty($_DB_DATAOBJECT['CONFIG']['db_driver']) ? 'DB' : $_DB_DATAOBJECT['CONFIG']['db_driver'];
- $ret = ($dd == 'DB') ? $DB->escapeSimple($string) : $DB->escape($string);
- if ($likeEscape) {
- $ret = str_replace(array('_','%'), array('\_','\%'), $ret);
+ if ($n && $this->N > 0) {
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug("ABOUT TO AUTOFETCH", "find", 1);
+ }
+ $fs = $this->fetch();
+ // if fetch returns false (eg. failed), then the backend doesnt support numRows (eg. ret=true)
+ // - hence find() also returns false..
+ $ret = ($ret === true) ? $fs : $ret;
}
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug("DONE", "find", 1);
+ }
+ $this->_query = $query_before;
return $ret;
}
/* ==================================================== */
/**
- * The Database connection dsn (as described in the PEAR DB)
- * only used really if you are writing a very simple application/test..
- * try not to use this - it is better stored in configuration files..
+ * Builds the WHERE based on the values of of this object
*
+ * @param mixed $keys
+ * @param array $filter (used by update to only uses keys in this filter list).
+ * @param array $negative_filter (used by delete to prevent deleting using the keys mentioned..)
* @access private
- * @var string
+ * @return string
*/
- public $_database_dsn = '';
+ public function _build_condition($keys, $filter = array(), $negative_filter = array())
+ {
+ global $_DB_DATAOBJECT;
+ $this->_connect();
+ $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
- /**
- * The Database connection id (md5 sum of databasedsn)
- *
- * @access private
- * @var string
- */
- public $_database_dsn_md5 = '';
+ $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
+ $options = $_DB_DATAOBJECT['CONFIG'];
+
+ // if we dont have query vars.. - reset them.
+ if ($this->_query === false) {
+ $x = new DB_DataObject;
+ $this->_query = $x->_query;
+ }
+
+
+ foreach ($keys as $k => $v) {
+ // index keys is an indexed array
+ /* these filter checks are a bit suspicious..
+ - need to check that update really wants to work this way */
+
+ if ($filter) {
+ if (!in_array($k, $filter)) {
+ continue;
+ }
+ }
+ if ($negative_filter) {
+ if (in_array($k, $negative_filter)) {
+ continue;
+ }
+ }
+ if (!isset($this->$k)) {
+ continue;
+ }
+
+ $kSql = $quoteIdentifiers
+ ? ($DB->quoteIdentifier($this->tableName()) . '.' . $DB->quoteIdentifier($k))
+ : "{$this->tableName()}.{$k}";
+
+
+ if (is_object($this->$k) && is_a($this->$k, 'DB_DataObject_Cast')) {
+ $dbtype = $DB->dsn["phptype"];
+ $value = $this->$k->toString($v, $DB);
+ if ((new PEAR)->isError($value)) {
+ $this->raiseError($value->getMessage(), DB_DATAOBJECT_ERROR_INVALIDARG);
+ return false;
+ }
+ if ((strtolower($value) === 'null') && !($v & DB_DATAOBJECT_NOTNULL)) {
+ $this->whereAdd(" $kSql IS NULL");
+ continue;
+ }
+ $this->whereAdd(" $kSql = $value");
+ continue;
+ }
+
+ if (!($v & DB_DATAOBJECT_NOTNULL) && DB_DataObject::_is_null($this, $k)) {
+ $this->whereAdd(" $kSql IS NULL");
+ continue;
+ }
+
+
+ if ($v & DB_DATAOBJECT_STR) {
+ $this->whereAdd(" $kSql = " . $this->_quote((string)(
+ ($v & DB_DATAOBJECT_BOOL) ?
+ // this is thanks to the braindead idea of postgres to
+ // use t/f for boolean.
+ (($this->$k === 'f') ? 0 : (int)(bool)$this->$k) :
+ $this->$k
+ )));
+ continue;
+ }
+ if (is_numeric($this->$k)) {
+ $this->whereAdd(" $kSql = {$this->$k}");
+ continue;
+ }
+ /* this is probably an error condition! */
+ $this->whereAdd(" $kSql = " . intval($this->$k));
+ }
+ return "";
+ }
/**
- * The Database name
- * created in __connection
+ * Adds a condition to the WHERE statement, defaults to AND
*
- * @access private
- * @var string
+ * $object->whereAdd(); //reset or cleaer ewhwer
+ * $object->whereAdd("ID > 20");
+ * $object->whereAdd("age > 20","OR");
+ *
+ * @param bool $cond condition
+ * @param string $logic optional logic "OR" (defaults to "AND")
+ * @return string|PEAR::Error - previous condition or Error when invalid args found
+ * @access public
*/
- public $_database = '';
+ public function whereAdd($cond = false, $logic = 'AND')
+ {
+ // for PHP5.2.3 - there is a bug with setting array properties of an object.
+ $_query = $this->_query;
+
+ if (!isset($this->_query) || ($_query === false)) {
+ return $this->raiseError(
+ "You cannot do two queries on the same object (clone it before finding)",
+ DB_DATAOBJECT_ERROR_INVALIDARGS
+ );
+ }
+
+ if ($cond === false) {
+ $r = $this->_query['condition'];
+ $_query['condition'] = '';
+ $this->_query = $_query;
+ return preg_replace('/^\s+WHERE\s+/', '', $r);
+ }
+ // check input...= 0 or ' ' == error!
+ if (!trim($cond)) {
+ return $this->raiseError("WhereAdd: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
+ }
+ $r = $_query['condition'];
+ if ($_query['condition']) {
+ $_query['condition'] .= " {$logic} ( {$cond} )";
+ $this->_query = $_query;
+ return $r;
+ }
+ $_query['condition'] = " WHERE ( {$cond} ) ";
+ $this->_query = $_query;
+ return $r;
+ }
-
-
/**
- * The QUERY rules
- * This replaces alot of the private variables
- * used to build a query, it is unset after find() is run.
+ * Evaluate whether or not a value is set to null, taking the 'disable_null_strings' option into account.
+ * If the value is a string set to "null" and the "disable_null_strings" option is not set to
+ * true, then the value is considered to be null.
+ * If the value is actually a PHP NULL value, and "disable_null_strings" has been set to
+ * the value "full", then it will also be considered null. - this can not differenticate between not set
*
*
- *
- * @access private
- * @var array
+ * @param object|array $obj_or_ar
+ * @param string|false $prop prperty
+ * @access private
+ * @return bool object
*/
- public $_query = array(
- 'condition' => '', // the WHERE condition
- 'group_by' => '', // the GROUP BY condition
- 'order_by' => '', // the ORDER BY condition
- 'having' => '', // the HAVING condition
- 'useindex' => '', // the USE INDEX condition
- 'limit_start' => '', // the LIMIT condition
- 'limit_count' => '', // the LIMIT condition
- 'data_select' => '*', // the columns to be SELECTed
- 'unions' => array(), // the added unions,
- 'derive_table' => '', // derived table name (BETA)
- 'derive_select' => '', // derived table select (BETA)
- );
-
-
-
+ public function _is_null($obj_or_ar, $prop)
+ {
+ global $_DB_DATAOBJECT;
+
+
+ $isset = $prop === false ? isset($obj_or_ar) :
+ (is_array($obj_or_ar) ? isset($obj_or_ar[$prop]) : isset($obj_or_ar->$prop));
+
+ $value = $isset ?
+ ($prop === false ? $obj_or_ar :
+ (is_array($obj_or_ar) ? $obj_or_ar[$prop] : $obj_or_ar->$prop))
+ : null;
+
+
+ $options = $_DB_DATAOBJECT['CONFIG'];
+
+ $null_strings = !isset($options['disable_null_strings'])
+ || $options['disable_null_strings'] === false;
+
+ $crazy_null = isset($options['disable_null_strings'])
+ && is_string($options['disable_null_strings'])
+ && strtolower($options['disable_null_strings'] === 'full');
+
+ if ($null_strings && $isset && is_string($value) && (strtolower($value) === 'null')) {
+ return true;
+ }
+
+ if ($crazy_null && !$isset) {
+ return true;
+ }
+
+ return false;
+ }
/**
- * Database result id (references global $_DB_DataObject[results]
+ * backend wrapper for quoting, as MDB2 and DB do it differently...
*
- * @access private
- * @var integer
+ * @access private
+ * @param $str
+ * @return string quoted
*/
- public $_DB_resultid;
-
- /**
- * ResultFields - on the last call to fetch(), resultfields is sent here,
- * so we can clean up the memory.
- *
- * @access public
- * @var array
- */
- public $_resultFields = false;
-
- /* ============================================================== */
- /* Table definition layer (started of very private but 'came out'*/
- /* ============================================================== */
+ public function _quote($str)
+ {
+ global $_DB_DATAOBJECT;
+ return (empty($_DB_DATAOBJECT['CONFIG']['db_driver']) ||
+ ($_DB_DATAOBJECT['CONFIG']['db_driver'] == 'DB'))
+ ? $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->quoteSmart($str)
+ : $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->quote($str);
+ }
/**
- * Autoload or manually load the table definitions
- *
- *
- * usage :
- * DB_DataObject::databaseStructure( 'databasename',
- * parse_ini_file('mydb.ini',true),
- * parse_ini_file('mydb.link.ini',true));
- *
- * obviously you dont have to use ini files.. (just return array similar to ini files..)
- *
- * It should append to the table structure array
- *
- *
- * @param optional string name of database to assign / read
- * @param optional array structure of database, and keys
- * @param optional array table links
+ * get/set an associative array of table columns
*
* @access public
- * @return true or PEAR:error on wrong paramenters.. or false if no file exists..
- * or the array(tablename => array(column_name=>type)) if called with 1 argument.. (databasename)
+ * @param array key=>type array
+ * @return array (associative)
*/
- public function databaseStructure()
+ public function table()
{
- global $_DB_DATAOBJECT;
-
- // Assignment code
-
- if ($args = func_get_args()) {
- if (count($args) == 1) {
-
- // this returns all the tables and their structure..
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug("Loading Generator as databaseStructure called with args", 1);
- }
-
- $x = new DB_DataObject;
- $x->_database = $args[0];
- $this->_connect();
- $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
-
- $tables = $DB->getListOf('tables');
- class_exists('DB_DataObject_Generator') ? '' :
- require_once 'DB/DataObject/Generator.php';
-
- foreach ($tables as $table) {
- $y = new DB_DataObject_Generator;
- $y->fillTableSchema($x->_database, $table);
- }
- return $_DB_DATAOBJECT['INI'][$x->_database];
- } else {
- $_DB_DATAOBJECT['INI'][$args[0]] = isset($_DB_DATAOBJECT['INI'][$args[0]]) ?
- $_DB_DATAOBJECT['INI'][$args[0]] + $args[1] : $args[1];
-
- if (isset($args[1])) {
- $_DB_DATAOBJECT['LINKS'][$args[0]] = isset($_DB_DATAOBJECT['LINKS'][$args[0]]) ?
- $_DB_DATAOBJECT['LINKS'][$args[0]] + $args[2] : $args[2];
- }
- return true;
- }
+
+ // for temporary storage of database fields..
+ // note this is not declared as we dont want to bloat the print_r output
+ $args = func_get_args();
+ if (count($args)) {
+ $this->_database_fields = $args[0];
}
-
-
-
- if (!$this->_database) {
- $this->_connect();
+ if (isset($this->_database_fields)) {
+ return $this->_database_fields;
}
-
-
- // if this table is already loaded this table..
- if (!empty($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()])) {
- return true;
+
+
+ global $_DB_DATAOBJECT;
+ if (!isset($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) {
+ $this->_connect();
}
-
- // initialize the ini data.. if empt..
- if (empty($_DB_DATAOBJECT['INI'][$this->_database])) {
- $_DB_DATAOBJECT['INI'][$this->_database] = array();
+
+ if (isset($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()])) {
+ return $_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()];
}
-
- if (empty($_DB_DATAOBJECT['CONFIG'])) {
- DB_DataObject::_loadConfig();
+
+ $this->databaseStructure();
+
+
+ $ret = array();
+ if (isset($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()])) {
+ $ret = $_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()];
}
-
- // we do not have the data for this table yet...
-
- // if we are configured to use the proxy..
-
- if (!empty($_DB_DATAOBJECT['CONFIG']['proxy'])) {
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug("Loading Generator to fetch Schema", 1);
- }
- class_exists('DB_DataObject_Generator') ? '' :
- require_once 'DB/DataObject/Generator.php';
-
-
- $x = new DB_DataObject_Generator;
- $x->fillTableSchema($this->_database, $this->tableName());
- return true;
- }
-
-
-
-
- // if you supply this with arguments, then it will take those
- // as the database and links array...
-
- $schemas = isset($_DB_DATAOBJECT['CONFIG']['schema_location']) ?
- array("{$_DB_DATAOBJECT['CONFIG']['schema_location']}/{$this->_database}.ini") :
- array() ;
-
- if (isset($_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"])) {
- $schemas = is_array($_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"]) ?
- $_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"] :
- explode(PATH_SEPARATOR, $_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"]);
- }
-
-
- $_DB_DATAOBJECT['INI'][$this->_database] = array();
- foreach ($schemas as $ini) {
- if (file_exists($ini) && is_file($ini)) {
- $_DB_DATAOBJECT['INI'][$this->_database] = array_merge(
- $_DB_DATAOBJECT['INI'][$this->_database],
- parse_ini_file($ini, true)
- );
-
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- if (!is_readable($ini)) {
- $this->debug("ini file is not readable: $ini", "databaseStructure", 1);
- } else {
- $this->debug("Loaded ini file: $ini", "databaseStructure", 1);
- }
- }
- } else {
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug("Missing ini file: $ini", "databaseStructure", 1);
- }
- }
- }
- // are table name lowecased..
- if (!empty($_DB_DATAOBJECT['CONFIG']['portability']) && $_DB_DATAOBJECT['CONFIG']['portability'] & 1) {
- foreach ($_DB_DATAOBJECT['INI'][$this->_database] as $k=>$v) {
- // results in duplicate cols.. but not a big issue..
- $_DB_DATAOBJECT['INI'][$this->_database][strtolower($k)] = $v;
- }
- }
-
-
- // now have we loaded the structure..
-
- if (!empty($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()])) {
- return true;
- }
- // - if not try building it..
- if (!empty($_DB_DATAOBJECT['CONFIG']['proxy'])) {
- class_exists('DB_DataObject_Generator') ? '' :
- require_once 'DB/DataObject/Generator.php';
-
- $x = new DB_DataObject_Generator;
- $x->fillTableSchema($this->_database, $this->tableName());
- // should this fail!!!???
- return true;
- }
- $this->debug("Cant find database schema: {$this->_database}/{$this->tableName()} \n".
- "in links file data: " . print_r($_DB_DATAOBJECT['INI'], true), "databaseStructure", 5);
- // we have to die here!! - it causes chaos if we dont (including looping forever!)
- $this->raiseError("Unable to load schema for database and table (turn debugging up to 5 for full error message)", DB_DATAOBJECT_ERROR_INVALIDARGS, PEAR_ERROR_DIE);
- return false;
- }
-
-
-
- /**
- * Return or assign the name of the current table
- *
- *
- * @param string optinal table name to set
- * @access public
- * @return string The name of the current table
- */
- public function tableName()
- {
- global $_DB_DATAOBJECT;
- $args = func_get_args();
- if (count($args)) {
- $this->__table = $args[0];
- }
- if (empty($this->__table)) {
- return '';
- }
- if (!empty($_DB_DATAOBJECT['CONFIG']['portability']) && $_DB_DATAOBJECT['CONFIG']['portability'] & 1) {
- return strtolower($this->__table);
- }
- return $this->__table;
- }
-
- /**
- * Return or assign the name of the current database
- *
- * @param string optional database name to set
- * @access public
- * @return string The name of the current database
- */
- public function database()
- {
- $args = func_get_args();
- if (count($args)) {
- $this->_database = $args[0];
- } else {
- $this->_connect();
- }
-
- return $this->_database;
- }
-
- /**
- * get/set an associative array of table columns
- *
- * @access public
- * @param array key=>type array
- * @return array (associative)
- */
- public function table()
- {
-
- // for temporary storage of database fields..
- // note this is not declared as we dont want to bloat the print_r output
- $args = func_get_args();
- if (count($args)) {
- $this->_database_fields = $args[0];
- }
- if (isset($this->_database_fields)) {
- return $this->_database_fields;
- }
-
-
- global $_DB_DATAOBJECT;
- if (!isset($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) {
- $this->_connect();
- }
-
- if (isset($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()])) {
- return $_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()];
- }
-
- $this->databaseStructure();
-
-
- $ret = array();
- if (isset($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()])) {
- $ret = $_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()];
- }
-
return $ret;
}
/**
- * get/set an array of table primary keys
- *
- * set usage: $do->keys('id','code');
+ * build the basic select query.
*
- * This is defined in the table definition if it gets it wrong,
- * or you do not want to use ini tables, you can override this.
- * @param string optional set the key
- * @param * optional set more keys
- * @access public
- * @return array
+ * @access private
*/
- public function keys()
+
+ public function _build_select()
{
- // for temporary storage of database fields..
- // note this is not declared as we dont want to bloat the print_r output
- $args = func_get_args();
- if (count($args)) {
- $this->_database_keys = $args;
- }
- if (isset($this->_database_keys)) {
- return $this->_database_keys;
- }
-
global $_DB_DATAOBJECT;
- if (!isset($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) {
+ $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
+ if ($quoteIdentifiers) {
$this->_connect();
+ $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
}
- if (isset($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()."__keys"])) {
- return array_keys($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()."__keys"]);
- }
- $this->databaseStructure();
-
- if (isset($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()."__keys"])) {
- return array_keys($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()."__keys"]);
+ $tn = ($quoteIdentifiers ? $DB->quoteIdentifier($this->tableName()) : $this->tableName());
+ if (!empty($this->_query['derive_table']) && !empty($this->_query['derive_select'])) {
+
+ // this is a derived select..
+ // not much support in the api yet..
+
+ $sql = 'SELECT ' .
+ $this->_query['derive_select']
+ . ' FROM ( SELECT' .
+ $this->_query['data_select'] . " \n" .
+ " FROM $tn " . $this->_query['useindex'] . " \n" .
+ $this->_join . " \n" .
+ $this->_query['condition'] . " \n" .
+ $this->_query['group_by'] . " \n" .
+ $this->_query['having'] . " \n" .
+ ') ' . $this->_query['derive_table'];
+
+ return $sql;
}
- return array();
+
+
+ $sql = 'SELECT ' .
+ $this->_query['data_select'] . " \n" .
+ " FROM $tn " . $this->_query['useindex'] . " \n" .
+ $this->_join . " \n" .
+ $this->_query['condition'] . " \n" .
+ $this->_query['group_by'] . " \n" .
+ $this->_query['having'] . " \n";
+
+ return $sql;
}
+
+
+ /* ============================================================== */
+ /* Table definition layer (started of very private but 'came out'*/
+ /* ============================================================== */
+
/**
- * get/set an sequence key
- *
- * by default it returns the first key from keys()
- * set usage: $do->sequenceKey('id',true);
- *
- * override this to return array(false,false) if table has no real sequence key.
+ * sends query to database - this is the private one that must work
+ * - internal functions use this rather than $this->query()
*
- * @param string optional the key sequence/autoinc. key
- * @param boolean optional use native increment. default false
- * @param false|string optional native sequence name
- * @access public
- * @return array (column,use_native,sequence_name)
+ * @param string $string
+ * @access private
+ * @return mixed none or PEAR_Error
*/
- public function sequenceKey()
+ public function _query($string)
{
global $_DB_DATAOBJECT;
-
- // call setting
- if (!$this->_database) {
- $this->_connect();
- }
-
- if (!isset($_DB_DATAOBJECT['SEQUENCE'][$this->_database])) {
- $_DB_DATAOBJECT['SEQUENCE'][$this->_database] = array();
- }
+ $this->_connect();
-
- $args = func_get_args();
- if (count($args)) {
- $args[1] = isset($args[1]) ? $args[1] : false;
- $args[2] = isset($args[2]) ? $args[2] : false;
- $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = $args;
- }
- if (isset($_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()])) {
- return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()];
- }
- // end call setting (eg. $do->sequenceKeys(a,b,c); )
-
-
-
-
- $keys = $this->keys();
- if (!$keys) {
- return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()]
- = array(false,false,false);
+
+ $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+
+ $options = $_DB_DATAOBJECT['CONFIG'];
+
+ $_DB_driver = empty($_DB_DATAOBJECT['CONFIG']['db_driver']) ?
+ 'DB' : $_DB_DATAOBJECT['CONFIG']['db_driver'];
+
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug($string, $log = "QUERY");
}
-
- $table = $this->table();
-
- $dbtype = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['phptype'];
-
- $usekey = $keys[0];
-
-
-
- $seqname = false;
-
- if (!empty($_DB_DATAOBJECT['CONFIG']['sequence_'.$this->tableName()])) {
- $seqname = $_DB_DATAOBJECT['CONFIG']['sequence_'.$this->tableName()];
- if (strpos($seqname, ':') !== false) {
- list($usekey, $seqname) = explode(':', $seqname);
+ if (
+ strtoupper($string) == 'BEGIN' ||
+ strtoupper($string) == 'START TRANSACTION'
+ ) {
+ if ($_DB_driver == 'DB') {
+ $DB->autoCommit(false);
+ $DB->simpleQuery('BEGIN');
+ } else {
+ $DB->beginTransaction();
}
+ return true;
}
-
-
- // if the key is not an integer - then it's not a sequence or native
- if (empty($table[$usekey]) || !($table[$usekey] & DB_DATAOBJECT_INT)) {
- return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = array(false,false,false);
- }
-
-
- if (!empty($_DB_DATAOBJECT['CONFIG']['ignore_sequence_keys'])) {
- $ignore = $_DB_DATAOBJECT['CONFIG']['ignore_sequence_keys'];
- if (is_string($ignore) && (strtoupper($ignore) == 'ALL')) {
- return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = array(false,false,$seqname);
- }
- if (is_string($ignore)) {
- $ignore = $_DB_DATAOBJECT['CONFIG']['ignore_sequence_keys'] = explode(',', $ignore);
- }
- if (in_array($this->tableName(), $ignore)) {
- return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = array(false,false,$seqname);
+
+ if (strtoupper($string) == 'COMMIT') {
+ $res = $DB->commit();
+ if ($_DB_driver == 'DB') {
+ $DB->autoCommit(true);
}
+ return $res;
}
-
-
- $realkeys = $_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()."__keys"];
-
- // if you are using an old ini file - go back to old behaviour...
- if (is_numeric($realkeys[$usekey])) {
- $realkeys[$usekey] = 'N';
- }
-
- // multiple unique primary keys without a native sequence...
- if (($realkeys[$usekey] == 'K') && (count($keys) > 1)) {
- return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = array(false,false,$seqname);
- }
- // use native sequence keys...
- // technically postgres native here...
- // we need to get the new improved tabledata sorted out first.
-
- // support named sequence keys.. - currently postgres only..
-
- if (in_array($dbtype, array('pgsql')) &&
- ($table[$usekey] & DB_DATAOBJECT_INT) &&
- isset($realkeys[$usekey]) && strlen($realkeys[$usekey]) > 1) {
- return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = array($usekey,true, $realkeys[$usekey]);
- }
-
- if (in_array($dbtype, array('pgsql', 'mysql', 'mysqli', 'mssql', 'ifx')) &&
- ($table[$usekey] & DB_DATAOBJECT_INT) &&
- isset($realkeys[$usekey]) && ($realkeys[$usekey] == 'N')
- ) {
- return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = array($usekey,true,$seqname);
- }
-
-
- // if not a native autoinc, and we have not assumed all primary keys are sequence
- if (($realkeys[$usekey] != 'N') &&
- !empty($_DB_DATAOBJECT['CONFIG']['dont_use_pear_sequences'])) {
- return array(false,false,false);
- }
-
-
-
- // I assume it's going to try and be a nextval DB sequence.. (not native)
- return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = array($usekey,false,$seqname);
- }
-
-
-
- /* =========================================================== */
- /* Major Private Methods - the core part! */
- /* =========================================================== */
-
-
-
- /**
- * clear the cache values for this class - normally done on insert/update etc.
- *
- * @access private
- * @return void
- */
- public function _clear_cache()
- {
- global $_DB_DATAOBJECT;
-
- $class = strtolower(get_class($this));
-
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug("Clearing Cache for ".$class, 1);
- }
-
- if (!empty($_DB_DATAOBJECT['CACHE'][$class])) {
- unset($_DB_DATAOBJECT['CACHE'][$class]);
- }
- }
-
-
- /**
- * backend wrapper for quoting, as MDB2 and DB do it differently...
- *
- * @access private
- * @return string quoted
- */
-
- public function _quote($str)
- {
- global $_DB_DATAOBJECT;
- return (empty($_DB_DATAOBJECT['CONFIG']['db_driver']) ||
- ($_DB_DATAOBJECT['CONFIG']['db_driver'] == 'DB'))
- ? $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->quoteSmart($str)
- : $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->quote($str);
- }
-
-
- /**
- * connects to the database
- *
- *
- * TODO: tidy this up - This has grown to support a number of connection options like
- * a) dynamic changing of ini file to change which database to connect to
- * b) multi data via the table_{$table} = dsn ini option
- * c) session based storage.
- *
- * @access private
- * @return true | PEAR::error
- */
- public function _connect()
- {
- global $_DB_DATAOBJECT;
- if (empty($_DB_DATAOBJECT['CONFIG'])) {
- $this->_loadConfig();
- }
- // Set database driver for reference
- $db_driver = empty($_DB_DATAOBJECT['CONFIG']['db_driver']) ?
- 'DB' : $_DB_DATAOBJECT['CONFIG']['db_driver'];
-
- // is it already connected ?
- if ($this->_database_dsn_md5 && !empty($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) {
-
- // connection is an error...
- if (PEAR::isError($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) {
- return $this->raiseError(
- $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->message,
- $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->code,
- PEAR_ERROR_DIE
- );
- }
-
- if (empty($this->_database)) {
- $this->_database = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['database'];
- $hasGetDatabase = method_exists($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5], 'getDatabase');
-
- $this->_database = ($db_driver != 'DB' && $hasGetDatabase)
- ? $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->getDatabase()
- : $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['database'];
-
-
-
- if (($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['phptype'] == 'sqlite')
- && is_file($this->_database)) {
- $this->_database = basename($this->_database);
- }
- if ($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['phptype'] == 'ibase') {
- $this->_database = substr(basename($this->_database), 0, -4);
- }
- }
- // theoretically we have a md5, it's listed in connections and it's not an error.
- // so everything is ok!
- return true;
- }
-
- // it's not currently connected!
- // try and work out what to use for the dsn !
-
- $options= $_DB_DATAOBJECT['CONFIG'];
- // if the databse dsn dis defined in the object..
- $dsn = isset($this->_database_dsn) ? $this->_database_dsn : null;
-
- if (!$dsn) {
- if (!$this->_database && !strlen($this->tableName())) {
- $this->_database = isset($options["table_{$this->tableName()}"]) ? $options["table_{$this->tableName()}"] : null;
- }
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug("Checking for database specific ini ('{$this->_database}') : database_{$this->_database} in options", "CONNECT");
- }
-
- if ($this->_database && !empty($options["database_{$this->_database}"])) {
- $dsn = $options["database_{$this->_database}"];
- } elseif (!empty($options['database'])) {
- $dsn = $options['database'];
- }
- }
-
- // if still no database...
- if (!$dsn) {
- return $this->raiseError(
- "No database name / dsn found anywhere",
- DB_DATAOBJECT_ERROR_INVALIDCONFIG,
- PEAR_ERROR_DIE
- );
- }
-
-
- if (is_string($dsn)) {
- $this->_database_dsn_md5 = md5($dsn);
- } else {
- /// support array based dsn's
- $this->_database_dsn_md5 = md5(serialize($dsn));
- }
-
- if (!empty($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) {
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug("USING CACHED CONNECTION", "CONNECT", 3);
- }
-
-
-
- if (!$this->_database) {
- $hasGetDatabase = method_exists($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5], 'getDatabase');
- $this->_database = ($db_driver != 'DB' && $hasGetDatabase)
- ? $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->getDatabase()
- : $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['database'];
-
- if (($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['phptype'] == 'sqlite')
- && is_file($this->_database)) {
- $this->_database = basename($this->_database);
- }
- }
- return true;
- }
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug("NEW CONNECTION TP DATABASE :" .$this->_database, "CONNECT", 3);
- /* actualy make a connection */
- $this->debug(print_r($dsn, true) ." {$this->_database_dsn_md5}", "CONNECT", 3);
- }
-
- // Note this is verbose deliberatly!
-
- if ($db_driver == 'DB') {
-
- /* PEAR DB connect */
-
- // this allows the setings of compatibility on DB
- $db_options = PEAR::getStaticProperty('DB', 'options');
- require_once 'DB.php';
- if ($db_options) {
- $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5] = DB::connect($dsn, $db_options);
- } else {
- $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5] = DB::connect($dsn);
- }
- } else {
- /* assumption is MDB2 */
- require_once 'MDB2.php';
- // this allows the setings of compatibility on MDB2
- $db_options = PEAR::getStaticProperty('MDB2', 'options');
- $db_options = is_array($db_options) ? $db_options : array();
- $db_options['portability'] = isset($db_options['portability'])
- ? $db_options['portability'] : MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_FIX_CASE;
- $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5] = MDB2::connect($dsn, $db_options);
- }
-
-
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug(print_r($_DB_DATAOBJECT['CONNECTIONS'], true), "CONNECT", 5);
- }
- if (PEAR::isError($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) {
- $this->debug($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->toString(), "CONNECT FAILED", 5);
- return $this->raiseError(
- "Connect failed, turn on debugging to 5 see why",
- $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->code,
- PEAR_ERROR_DIE
- );
- }
-
- if (empty($this->_database)) {
- $hasGetDatabase = method_exists($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5], 'getDatabase');
-
- $this->_database = ($db_driver != 'DB' && $hasGetDatabase)
- ? $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->getDatabase()
- : $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['database'];
-
-
- if (($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['phptype'] == 'sqlite')
- && is_file($this->_database)) {
- $this->_database = basename($this->_database);
- }
- }
-
- // Oracle need to optimize for portibility - not sure exactly what this does though :)
-
- return true;
- }
-
- /**
- * sends query to database - this is the private one that must work
- * - internal functions use this rather than $this->query()
- *
- * @param string $string
- * @access private
- * @return mixed none or PEAR_Error
- */
- public function _query($string)
- {
- global $_DB_DATAOBJECT;
- $this->_connect();
-
-
- $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
- $options = $_DB_DATAOBJECT['CONFIG'];
-
- $_DB_driver = empty($_DB_DATAOBJECT['CONFIG']['db_driver']) ?
- 'DB': $_DB_DATAOBJECT['CONFIG']['db_driver'];
-
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $this->debug($string, $log="QUERY");
- }
-
- if (
- strtoupper($string) == 'BEGIN' ||
- strtoupper($string) == 'START TRANSACTION'
- ) {
- if ($_DB_driver == 'DB') {
- $DB->autoCommit(false);
- $DB->simpleQuery('BEGIN');
- } else {
- $DB->beginTransaction();
- }
- return true;
- }
-
- if (strtoupper($string) == 'COMMIT') {
- $res = $DB->commit();
- if ($_DB_driver == 'DB') {
- $DB->autoCommit(true);
- }
- return $res;
- }
-
if (strtoupper($string) == 'ROLLBACK') {
$DB->rollback();
if ($_DB_driver == 'DB') {
}
return true;
}
-
+
if (!empty($options['debug_ignore_updates']) &&
(strtolower(substr(trim($string), 0, 6)) != 'select') &&
(strtolower(substr(trim($string), 0, 4)) != 'show') &&
(strtolower(substr(trim($string), 0, 8)) != 'describe')) {
$this->debug('Disabling Update as you are in debug mode');
- return $this->raiseError("Disabling Update as you are in debug mode", null) ;
+ return $this->raiseError("Disabling Update as you are in debug mode", null);
}
//if (@$_DB_DATAOBJECT['CONFIG']['debug'] > 1) {
// this will only work when PEAR:DB supports it.
//$this->debug($DB->getAll('explain ' .$string,DB_DATAOBJECT_FETCHMODE_ASSOC), $log="sql",2);
//}
-
+
// some sim
- $t= explode(' ', microtime());
- $_DB_DATAOBJECT['QUERYENDTIME'] = $time = $t[0]+$t[1];
-
-
- for ($tries = 0;$tries < 3;$tries++) {
+ $t = explode(' ', microtime());
+ $_DB_DATAOBJECT['QUERYENDTIME'] = $time = $t[0] + $t[1];
+
+
+ for ($tries = 0; $tries < 3; $tries++) {
if ($_DB_driver == 'DB') {
$result = $DB->query($string);
} else {
switch (strtolower(substr(trim($string), 0, 6))) {
-
+
case 'insert':
case 'update':
case 'delete':
$result = $DB->exec($string);
break;
-
+
default:
$result = $DB->query($string);
break;
}
}
-
+
// see if we got a failure.. - try again a few times..
if (!is_object($result) || !is_a($result, 'PEAR_Error')) {
break;
sleep(1); // wait before retyring..
$DB->connect($DB->dsn);
}
-
+
if (is_object($result) && is_a($result, 'PEAR_Error')) {
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
return $this->raiseError($result);
}
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- $t= explode(' ', microtime());
- $_DB_DATAOBJECT['QUERYENDTIME'] = $t[0]+$t[1];
- $this->debug('QUERY DONE IN '.($t[0]+$t[1]-$time)." seconds", 'query', 1);
+ $t = explode(' ', microtime());
+ $_DB_DATAOBJECT['QUERYENDTIME'] = $t[0] + $t[1];
+ $this->debug('QUERY DONE IN ' . ($t[0] + $t[1] - $time) . " seconds", 'query', 1);
}
switch (strtolower(substr(trim($string), 0, 6))) {
case 'insert':
}
if (is_object($result)) {
// lets hope that copying the result object is OK!
-
- $_DB_resultid = $GLOBALS['_DB_DATAOBJECT']['RESULTSEQ']++;
+
+ $_DB_resultid = $GLOBALS['_DB_DATAOBJECT']['RESULTSEQ']++;
$_DB_DATAOBJECT['RESULTS'][$_DB_resultid] = $result;
$this->_DB_resultid = $_DB_resultid;
}
} else {
$DB->expectError(MDB2_ERROR_UNSUPPORTED);
}
-
+
$this->N = $result->numRows();
//var_dump($this->N);
-
+
if (is_object($this->N) && is_a($this->N, 'PEAR_Error')) {
$this->N = true;
}
$DB->popExpect();
}
+ return null;
}
/**
- * Builds the WHERE based on the values of of this object
+ * fetches next row into this objects var's
*
- * @param mixed $keys
- * @param array $filter (used by update to only uses keys in this filter list).
- * @param array $negative_filter (used by delete to prevent deleting using the keys mentioned..)
- * @access private
- * @return string
- */
- public function _build_condition($keys, $filter = array(), $negative_filter=array())
- {
- global $_DB_DATAOBJECT;
- $this->_connect();
- $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
-
- $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
- $options = $_DB_DATAOBJECT['CONFIG'];
-
- // if we dont have query vars.. - reset them.
- if ($this->_query === false) {
- $x = new DB_DataObject;
- $this->_query= $x->_query;
+ * returns 1 on success 0 on failure
+ *
+ *
+ *
+ * Example
+ * $object = new mytable();
+ * $object->name = "fred";
+ * $object->find();
+ * $store = array();
+ * while ($object->fetch()) {
+ * echo $this->ID;
+ * $store[] = $object; // builds an array of object lines.
+ * }
+ *
+ * to add features to a fetch
+ * function fetch () {
+ * $ret = parent::fetch();
+ * $this->date_formated = date('dmY',$this->date);
+ * return $ret;
+ * }
+ *
+ * @access public
+ * @return boolean on success
+ */
+ public function fetch()
+ {
+ global $_DB_DATAOBJECT;
+ if (empty($_DB_DATAOBJECT['CONFIG'])) {
+ DB_DataObject::_loadConfig();
}
-
-
- foreach ($keys as $k => $v) {
- // index keys is an indexed array
- /* these filter checks are a bit suspicious..
- - need to check that update really wants to work this way */
-
- if ($filter) {
- if (!in_array($k, $filter)) {
- continue;
- }
+ if (empty($this->N)) {
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug("No data returned from FIND (eg. N is 0)", "FETCH", 3);
}
- if ($negative_filter) {
- if (in_array($k, $negative_filter)) {
- continue;
- }
+ return false;
+ }
+
+ if (empty($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]) ||
+ !is_object($result = $_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid])) {
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug('fetched on object after fetch completed (no results found)');
}
- if (!isset($this->$k)) {
- continue;
+ return false;
+ }
+
+
+ $array = $result->fetchRow(DB_DATAOBJECT_FETCHMODE_ASSOC);
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug(serialize($array), "FETCH");
+ }
+
+ // fetched after last row..
+ if ($array === null) {
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $t = explode(' ', microtime());
+
+ $this->debug(
+ "Last Data Fetch'ed after " .
+ ($t[0] + $t[1] - $_DB_DATAOBJECT['QUERYENDTIME']) .
+ " seconds",
+ "FETCH",
+ 1
+ );
}
-
- $kSql = $quoteIdentifiers
- ? ($DB->quoteIdentifier($this->tableName()) . '.' . $DB->quoteIdentifier($k))
- : "{$this->tableName()}.{$k}";
-
-
-
- if (is_object($this->$k) && is_a($this->$k, 'DB_DataObject_Cast')) {
- $dbtype = $DB->dsn["phptype"];
- $value = $this->$k->toString($v, $DB);
- if (PEAR::isError($value)) {
- $this->raiseError($value->getMessage(), DB_DATAOBJECT_ERROR_INVALIDARG);
- return false;
- }
- if ((strtolower($value) === 'null') && !($v & DB_DATAOBJECT_NOTNULL)) {
- $this->whereAdd(" $kSql IS NULL");
- continue;
- }
- $this->whereAdd(" $kSql = $value");
- continue;
+ // reduce the memory usage a bit... (but leave the id in, so count() works ok on it)
+ unset($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]);
+
+ // we need to keep a copy of resultfields locally so toArray() still works
+ // however we dont want to keep it in the global cache..
+
+ if (!empty($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid])) {
+ $this->_resultFields = $_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid];
+ unset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid]);
}
-
- if (!($v & DB_DATAOBJECT_NOTNULL) && DB_DataObject::_is_null($this, $k)) {
- $this->whereAdd(" $kSql IS NULL");
- continue;
+ // this is probably end of data!!
+ //DB_DataObject::raiseError("fetch: no data returned", DB_DATAOBJECT_ERROR_NODATA);
+ return false;
+ }
+ // make sure resultFields is always empty..
+ $this->_resultFields = false;
+
+ if (!isset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid])) {
+ // note: we dont declare this to keep the print_r size down.
+ $_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid] = array_flip(array_keys($array));
+ }
+ $replace = array('.', ' ');
+ foreach ($array as $k => $v) {
+ // use strpos as str_replace is slow.
+ $kk = (strpos($k, '.') === false && strpos($k, ' ') === false) ?
+ $k : str_replace($replace, '_', $k);
+
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug("$kk = " . $array[$k], "fetchrow LINE", 3);
}
-
+ $this->$kk = $array[$k];
+ }
- if ($v & DB_DATAOBJECT_STR) {
- $this->whereAdd(" $kSql = " . $this->_quote((string) (
- ($v & DB_DATAOBJECT_BOOL) ?
- // this is thanks to the braindead idea of postgres to
- // use t/f for boolean.
- (($this->$k === 'f') ? 0 : (int)(bool) $this->$k) :
- $this->$k
- )));
- continue;
+ // set link flag
+ $this->_link_loaded = false;
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug("{$this->tableName()} DONE", "fetchrow", 2);
+ }
+ if (($this->_query !== false) && empty($_DB_DATAOBJECT['CONFIG']['keep_query_after_fetch'])) {
+ $this->_query = false;
+ }
+ return true;
+ }
+
+ /**
+ * Get the value of the primary id
+ *
+ * While I normally use 'id' as the PRIMARY KEY value, some database use
+ * {table}_id as the column name.
+ *
+ * To save a bit of typing,
+ *
+ * $id = $do->pid();
+ *
+ * @return bool|the
+ */
+ public function pid()
+ {
+ $keys = $this->keys();
+ if (!$keys) {
+ $this->raiseError(
+ "No Keys available for {$this->tableName()}",
+ DB_DATAOBJECT_ERROR_INVALIDCONFIG
+ );
+ return false;
+ }
+ $k = $keys[0];
+ if (empty($this->$k)) { // we do not
+ $this->raiseError(
+ "pid() called on Object where primary key value not available",
+ DB_DATAOBJECT_ERROR_NODATA
+ );
+ return false;
+ }
+ return $this->$k;
+ }
+
+ /**
+ * fetches all results as an array,
+ *
+ * return format is dependant on args.
+ * if selectAdd() has not been called on the object, then it will add the correct columns to the query.
+ *
+ * A) Array of values (eg. a list of 'id')
+ *
+ * $x = DB_DataObject::factory('mytable');
+ * $x->whereAdd('something = 1')
+ * $ar = $x->fetchAll('id');
+ * -- returns array(1,2,3,4,5)
+ *
+ * B) Array of values (not from table)
+ *
+ * $x = DB_DataObject::factory('mytable');
+ * $x->whereAdd('something = 1');
+ * $x->selectAdd();
+ * $x->selectAdd('distinct(group_id) as group_id');
+ * $ar = $x->fetchAll('group_id');
+ * -- returns array(1,2,3,4,5)
+ * *
+ * C) A key=>value associative array
+ *
+ * $x = DB_DataObject::factory('mytable');
+ * $x->whereAdd('something = 1')
+ * $ar = $x->fetchAll('id','name');
+ * -- returns array(1=>'fred',2=>'blogs',3=> .......
+ *
+ * D) array of objects
+ * $x = DB_DataObject::factory('mytable');
+ * $x->whereAdd('something = 1');
+ * $ar = $x->fetchAll();
+ *
+ * E) array of arrays (for example)
+ * $x = DB_DataObject::factory('mytable');
+ * $x->whereAdd('something = 1');
+ * $ar = $x->fetchAll(false,false,'toArray');
+ *
+ *
+ * @param string|false $k key
+ * @param string|false $v value
+ * @param string|false $method method to call on each result to get array value (eg. 'toArray')
+ * @access public
+ * @return array format dependant on arguments, may be empty
+ */
+ public function fetchAll($k = false, $v = false, $method = false)
+ {
+ // should it even do this!!!?!?
+ if ($k !== false &&
+ ( // only do this is we have not been explicit..
+ empty($this->_query['data_select']) ||
+ ($this->_query['data_select'] == '*')
+ )
+ ) {
+ $this->selectAdd();
+ $this->selectAdd($k);
+ if ($v !== false) {
+ $this->selectAdd($v);
}
- if (is_numeric($this->$k)) {
- $this->whereAdd(" $kSql = {$this->$k}");
+ }
+
+ $this->find();
+ $ret = array();
+ while ($this->fetch()) {
+ if ($v !== false) {
+ $ret[$this->$k] = $this->$v;
continue;
}
- /* this is probably an error condition! */
- $this->whereAdd(" $kSql = ".intval($this->$k));
+ $ret[] = $k === false ?
+ ($method == false ? clone($this) : $this->$method())
+ : $this->$k;
}
+ return $ret;
}
-
-
/**
- * classic factory method for loading a table class
- * usage: $do = DB_DataObject::factory('person')
- * WARNING - this may emit a include error if the file does not exist..
- * use @ to silence it (if you are sure it is acceptable)
- * eg. $do = @DB_DataObject::factory('person')
- *
- * table name can bedatabasename/table
- * - and allow modular dataobjects to be written..
- * (this also helps proxy creation)
- *
- * Experimental Support for Multi-Database factory eg. mydatabase.mytable
- *
- *
- * @param string $table tablename (use blank to create a new instance of the same class.)
- * @access private
- * @return DataObject|PEAR_Error
- */
-
-
-
- public static function factory($table = '')
+ * Adds a select columns
+ *
+ * $object->selectAdd(); // resets select to nothing!
+ * $object->selectAdd("*"); // default select
+ * $object->selectAdd("unixtime(DATE) as udate");
+ * $object->selectAdd("DATE");
+ *
+ * to prepend distict:
+ * $object->selectAdd('distinct ' . $object->selectAdd());
+ *
+ * @param string $k
+ * @access public
+ * @return mixed null or old string if you reset it.
+ */
+ public function selectAdd($k = null)
{
- global $_DB_DATAOBJECT;
-
-
- // multi-database support.. - experimental.
- $database = '';
-
- if (strpos($table, '/') !== false) {
- list($database, $table) = explode('.', $table, 2);
+ if ($this->_query === false) {
+ $this->raiseError(
+ "You cannot do two queries on the same object (copy it before finding)",
+ DB_DATAOBJECT_ERROR_INVALIDARGS
+ );
+ return false;
}
-
- if (empty($_DB_DATAOBJECT['CONFIG'])) {
- DB_DataObject::_loadConfig();
+ if ($k === null) {
+ $old = $this->_query['data_select'];
+ $this->_query['data_select'] = '';
+ return $old;
}
- // no configuration available for database
- if (!empty($database) && empty($_DB_DATAOBJECT['CONFIG']['database_'.$database])) {
- $do = new DB_DataObject();
- $do->raiseError(
- "unable to find database_{$database} in Configuration, It is required for factory with database",
- 0,
- PEAR_ERROR_DIE
- );
+
+ // check input...= 0 or ' ' == error!
+ if (!trim($k)) {
+ return $this->raiseError("selectAdd: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
}
-
-
- /*
- if ($table === '') {
- if (is_a($this,'DB_DataObject') && strlen($this->tableName())) {
- $table = $this->tableName();
- } else {
- return DB_DataObject::raiseError(
- "factory did not recieve a table name",
- DB_DATAOBJECT_ERROR_INVALIDARGS);
+
+ if ($this->_query['data_select']) {
+ $this->_query['data_select'] .= ', ';
+ }
+ $this->_query['data_select'] .= " $k ";
+ return null;
+ }
+
+ /**
+ * Adds a 'IN' condition to the WHERE statement
+ *
+ * $object->whereAddIn('id', $array, 'int'); //minimal usage
+ * $object->whereAddIn('price', $array, 'float', 'OR'); // cast to float, and call whereAdd with 'OR'
+ * $object->whereAddIn('name', $array, 'string'); // quote strings
+ *
+ * @param string $key key column to match
+ * @param array $list list of values to match
+ * @param string $type string|int|integer|float|bool cast to type.
+ * @param string $logic optional logic to call whereAdd with eg. "OR" (defaults to "AND")
+ * @access public
+ * @return string|PEAR::Error - previous condition or Error when invalid args found
+ */
+ public function whereAddIn($key, $list, $type, $logic = 'AND')
+ {
+ $not = '';
+ if ($key[0] == '!') {
+ $not = 'NOT ';
+ $key = substr($key, 1);
+ }
+ // fix type for short entry.
+ $type = $type == 'int' ? 'integer' : $type;
+
+ if ($type == 'string') {
+ $this->_connect();
+ }
+
+ $ar = array();
+ foreach ($list as $k) {
+ settype($k, $type);
+ $ar[] = $type == 'string' ? $this->_quote($k) : $k;
+ }
+
+ if (!$ar) {
+ return $not ? $this->_query['condition'] : $this->whereAdd("1=0");
+ }
+ return $this->whereAdd("$key $not IN (" . implode(',', $ar) . ')', $logic);
+ }
+
+
+
+ /* =========================================================== */
+ /* Major Private Methods - the core part! */
+ /* =========================================================== */
+
+ /**
+ * Adds a order by condition
+ *
+ * $object->orderBy(); //clears order by
+ * $object->orderBy("ID");
+ * $object->orderBy("ID,age");
+ *
+ * @param bool $order Order
+ * @return bool|error|none|PEAR
+ * @access public
+ */
+ public function orderBy($order = false)
+ {
+ if ($this->_query === false) {
+ $this->raiseError(
+ "You cannot do two queries on the same object (copy it before finding)",
+ DB_DATAOBJECT_ERROR_INVALIDARGS
+ );
+ return false;
+ }
+ if ($order === false) {
+ $this->_query['order_by'] = '';
+ return null;
+ }
+ // check input...= 0 or ' ' == error!
+ if (!trim($order)) {
+ return $this->raiseError("orderBy: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
+ }
+
+ if (!$this->_query['order_by']) {
+ $this->_query['order_by'] = " ORDER BY {$order} ";
+ return null;
+ }
+ $this->_query['order_by'] .= " , {$order}";
+ return null;
+ }
+
+ /**
+ * Adds a group by condition
+ *
+ * $object->groupBy(); //reset the grouping
+ * $object->groupBy("ID DESC");
+ * $object->groupBy("ID,age");
+ *
+ * @param bool $group Grouping
+ * @return bool|none|PEAR
+ * @access public
+ */
+ public function groupBy($group = false)
+ {
+ if ($this->_query === false) {
+ $this->raiseError(
+ "You cannot do two queries on the same object (copy it before finding)",
+ DB_DATAOBJECT_ERROR_INVALIDARGS
+ );
+ return false;
+ }
+ if ($group === false) {
+ $this->_query['group_by'] = '';
+ return null;
+ }
+ // check input...= 0 or ' ' == error!
+ if (!trim($group)) {
+ return $this->raiseError("groupBy: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
+ }
+
+
+ if (!$this->_query['group_by']) {
+ $this->_query['group_by'] = " GROUP BY {$group} ";
+ return null;
+ }
+ $this->_query['group_by'] .= " , {$group}";
+ return null;
+ }
+
+ /**
+ * Adds a having clause
+ *
+ * $object->having(); //reset the grouping
+ * $object->having("sum(value) > 0 ");
+ *
+ * @param bool $having condition
+ * @return bool|none|PEAR
+ * @access public
+ */
+ public function having($having = false)
+ {
+ if ($this->_query === false) {
+ $this->raiseError(
+ "You cannot do two queries on the same object (copy it before finding)",
+ DB_DATAOBJECT_ERROR_INVALIDARGS
+ );
+ return false;
+ }
+ if ($having === false) {
+ $this->_query['having'] = '';
+ return null;
+ }
+ // check input...= 0 or ' ' == error!
+ if (!trim($having)) {
+ return $this->raiseError("Having: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
+ }
+
+
+ if (!$this->_query['having']) {
+ $this->_query['having'] = " HAVING {$having} ";
+ return null;
+ }
+ $this->_query['having'] .= " AND {$having}";
+ return null;
+ }
+
+ /**
+ * Adds a using Index
+ *
+ * $object->useIndex(); //reset the use Index
+ * $object->useIndex("some_index");
+ *
+ * Note do not put unfiltered user input into theis method.
+ * This is mysql specific at present? - might need altering to support other databases.
+ *
+ * @param bool $index index or indexes to use.
+ * @return bool|none|PEAR
+ * @access public
+ */
+ public function useIndex($index = false)
+ {
+ if ($this->_query === false) {
+ $this->raiseError(
+ "You cannot do two queries on the same object (copy it before finding)",
+ DB_DATAOBJECT_ERROR_INVALIDARGS
+ );
+ return false;
+ }
+ if ($index === false) {
+ $this->_query['useindex'] = '';
+ return null;
+ }
+ // check input...= 0 or ' ' == error!
+ if ((is_string($index) && !trim($index)) || (is_array($index) && !count($index))) {
+ return $this->raiseError("Having: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
+ }
+ $index = is_array($index) ? implode(', ', $index) : $index;
+
+ if (!$this->_query['useindex']) {
+ $this->_query['useindex'] = " USE INDEX ({$index}) ";
+ return null;
+ }
+ $this->_query['useindex'] = substr($this->_query['useindex'], 0, -2) . ", {$index}) ";
+ return null;
+ }
+
+ /**
+ * Sets the Limit
+ *
+ * $boject->limit(); // clear limit
+ * $object->limit(12);
+ * $object->limit(12,10);
+ *
+ * Note this will emit an error on databases other than mysql/postgress
+ * as there is no 'clean way' to implement it. - you should consider refering to
+ * your database manual to decide how you want to implement it.
+ *
+ * @param string $a limit start (or number), or blank to reset
+ * @param string $b number
+ * @return bool|none|PEAR
+ * @access public
+ */
+ public function limit($a = null, $b = null)
+ {
+ if ($this->_query === false) {
+ $this->raiseError(
+ "You cannot do two queries on the same object (copy it before finding)",
+ DB_DATAOBJECT_ERROR_INVALIDARGS
+ );
+ return false;
+ }
+
+ if ($a === null) {
+ $this->_query['limit_start'] = '';
+ $this->_query['limit_count'] = '';
+ return null;
+ }
+ // check input...= 0 or ' ' == error!
+ if ((!is_int($a) && ((string)((int)$a) !== (string)$a))
+ || (($b !== null) && (!is_int($b) && ((string)((int)$b) !== (string)$b)))) {
+ return $this->raiseError("limit: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
+ }
+ global $_DB_DATAOBJECT;
+ $this->_connect();
+ $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+
+ $this->_query['limit_start'] = ($b == null) ? 0 : (int)$a;
+ $this->_query['limit_count'] = ($b == null) ? (int)$a : (int)$b;
+ return null;
+ }
+
+ /**
+ * Insert the current objects variables into the database
+ *
+ * Returns the ID of the inserted element (if auto increment or sequences are used.)
+ *
+ * for example
+ *
+ * Designed to be extended
+ *
+ * $object = new mytable();
+ * $object->name = "fred";
+ * echo $object->insert();
+ *
+ * @access public
+ * @return mixed false on failure, int when auto increment or sequence used, otherwise true on success
+ */
+ public function insert()
+ {
+ global $_DB_DATAOBJECT;
+
+ // we need to write to the connection (For nextid) - so us the real
+ // one not, a copyied on (as ret-by-ref fails with overload!)
+
+ if (!isset($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) {
+ $this->_connect();
+ }
+
+ $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
+
+ $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+
+ $items = $this->table();
+
+ if (!$items) {
+ $this->raiseError(
+ "insert:No table definition for {$this->tableName()}",
+ DB_DATAOBJECT_ERROR_INVALIDCONFIG
+ );
+ return false;
+ }
+ $options = $_DB_DATAOBJECT['CONFIG'];
+
+
+ $datasaved = 1;
+ $leftq = '';
+ $rightq = '';
+
+ $seqKeys = isset($_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()]) ?
+ $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] :
+ $this->sequenceKey();
+
+ $key = isset($seqKeys[0]) ? $seqKeys[0] : false;
+ $useNative = isset($seqKeys[1]) ? $seqKeys[1] : false;
+ $seq = isset($seqKeys[2]) ? $seqKeys[2] : false;
+
+ $dbtype = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn["phptype"];
+
+
+ // nativeSequences or Sequences..
+
+ // big check for using sequences
+
+ if (($key !== false) && !$useNative) {
+ if (!$seq) {
+ $keyvalue = $DB->nextId($this->tableName());
+ } else {
+ $f = $DB->getOption('seqname_format');
+ $DB->setOption('seqname_format', '%s');
+ $keyvalue = $DB->nextId($seq);
+ $DB->setOption('seqname_format', $f);
+ }
+ if ((new PEAR)->isError($keyvalue)) {
+ $this->raiseError($keyvalue->toString(), DB_DATAOBJECT_ERROR_INVALIDCONFIG);
+ return false;
+ }
+ $this->$key = $keyvalue;
+ }
+
+ // if we haven't set disable_null_strings to "full"
+ $ignore_null = !isset($options['disable_null_strings'])
+ || !is_string($options['disable_null_strings'])
+ || strtolower($options['disable_null_strings']) !== 'full';
+
+
+ foreach ($items as $k => $v) {
+
+ // if we are using autoincrement - skip the column...
+ if ($key && ($k == $key) && $useNative) {
+ continue;
+ }
+
+
+ // Ignore INTEGERS which aren't set to a value - or empty string..
+ if ((!isset($this->$k) || ($v == 1 && $this->$k === ''))
+ && $ignore_null
+ ) {
+ continue;
+ }
+ // dont insert data into mysql timestamps
+ // use query() if you really want to do this!!!!
+ if ($v & DB_DATAOBJECT_MYSQLTIMESTAMP) {
+ continue;
+ }
+
+ if ($leftq) {
+ $leftq .= ', ';
+ $rightq .= ', ';
+ }
+
+ $leftq .= ($quoteIdentifiers ? ($DB->quoteIdentifier($k) . ' ') : "$k ");
+
+ if (is_object($this->$k) && is_a($this->$k, 'DB_DataObject_Cast')) {
+ $value = $this->$k->toString($v, $DB);
+ if ((new PEAR)->isError($value)) {
+ $this->raiseError($value->toString(), DB_DATAOBJECT_ERROR_INVALIDARGS);
+ return false;
+ }
+ $rightq .= $value;
+ continue;
+ }
+
+
+ if (!($v & DB_DATAOBJECT_NOTNULL) && DB_DataObject::_is_null($this, $k)) {
+ $rightq .= " NULL ";
+ continue;
+ }
+ // DATE is empty... on a col. that can be null..
+ // note: this may be usefull for time as well..
+ if (!$this->$k &&
+ (($v & DB_DATAOBJECT_DATE) || ($v & DB_DATAOBJECT_TIME)) &&
+ !($v & DB_DATAOBJECT_NOTNULL)) {
+ $rightq .= " NULL ";
+ continue;
+ }
+
+
+ if ($v & DB_DATAOBJECT_STR) {
+ $rightq .= $this->_quote((string)(
+ ($v & DB_DATAOBJECT_BOOL) ?
+ // this is thanks to the braindead idea of postgres to
+ // use t/f for boolean.
+ (($this->$k === 'f') ? 0 : (int)(bool)$this->$k) :
+ $this->$k
+ )) . " ";
+ continue;
+ }
+ if (is_numeric($this->$k)) {
+ $rightq .= " {$this->$k} ";
+ continue;
+ }
+ /* flag up string values - only at debug level... !!!??? */
+ if (is_object($this->$k) || is_array($this->$k)) {
+ $this->debug('ODD DATA: ' . $k . ' ' . print_r($this->$k, true), 'ERROR');
+ }
+
+ // at present we only cast to integers
+ // - V2 may store additional data about float/int
+ $rightq .= ' ' . intval($this->$k) . ' ';
+ }
+
+ // not sure why we let empty insert here.. - I guess to generate a blank row..
+
+
+ if ($leftq || $useNative) {
+ $table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->tableName()) : $this->tableName());
+
+
+ if (($dbtype == 'pgsql') && empty($leftq)) {
+ $r = $this->_query("INSERT INTO {$table} DEFAULT VALUES");
+ } else {
+ $r = $this->_query("INSERT INTO {$table} ($leftq) VALUES ($rightq) ");
+ }
+
+
+ if ((new PEAR)->isError($r)) {
+ $this->raiseError($r);
+ return false;
+ }
+
+ if ($r < 1) {
+ return 0;
+ }
+
+
+ // now do we have an integer key!
+
+ if ($key && $useNative) {
+ switch ($dbtype) {
+ case 'mysql':
+ case 'mysqli':
+ $method = "{$dbtype}_insert_id";
+ $this->$key = $method(
+ $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->connection
+ );
+ break;
+
+ case 'mssql':
+ // note this is not really thread safe - you should wrapp it with
+ // transactions = eg.
+ // $db->query('BEGIN');
+ // $db->insert();
+ // $db->query('COMMIT');
+ $db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
+ $method = ($db_driver == 'DB') ? 'getOne' : 'queryOne';
+ $mssql_key = $DB->$method("SELECT @@IDENTITY");
+ if ((new PEAR)->isError($mssql_key)) {
+ $this->raiseError($mssql_key);
+ return false;
+ }
+ $this->$key = $mssql_key;
+ break;
+
+ case 'pgsql':
+ if (!$seq) {
+ $seq = $DB->getSequenceName(strtolower($this->tableName()));
+ }
+ $db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
+ $method = ($db_driver == 'DB') ? 'getOne' : 'queryOne';
+ $pgsql_key = $DB->$method("SELECT currval('" . $seq . "')");
+
+
+ if ((new PEAR)->isError($pgsql_key)) {
+ $this->raiseError($pgsql_key);
+ return false;
+ }
+ $this->$key = $pgsql_key;
+ break;
+
+ case 'ifx':
+ $this->$key = array_shift(
+ ifx_fetch_row(
+ ifx_query(
+ "select DBINFO('sqlca.sqlerrd1') FROM systables where tabid=1",
+ $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->connection,
+ IFX_SCROLL
+ ),
+ "FIRST"
+ )
+ );
+ break;
+
+ }
+ }
+
+ if (isset($_DB_DATAOBJECT['CACHE'][strtolower(get_class($this))])) {
+ $this->_clear_cache();
+ }
+ if ($key) {
+ return $this->$key;
+ }
+ return true;
+ }
+ $this->raiseError("insert: No Data specifed for query", DB_DATAOBJECT_ERROR_NODATA);
+ return false;
+ }
+
+ /**
+ * get/set an sequence key
+ *
+ * by default it returns the first key from keys()
+ * set usage: $do->sequenceKey('id',true);
+ *
+ * override this to return array(false,false) if table has no real sequence key.
+ *
+ * @param string optional the key sequence/autoinc. key
+ * @param boolean optional use native increment. default false
+ * @param false|string optional native sequence name
+ * @access public
+ * @return array (column,use_native,sequence_name)
+ */
+ public function sequenceKey()
+ {
+ global $_DB_DATAOBJECT;
+
+ // call setting
+ if (!$this->_database) {
+ $this->_connect();
+ }
+
+ if (!isset($_DB_DATAOBJECT['SEQUENCE'][$this->_database])) {
+ $_DB_DATAOBJECT['SEQUENCE'][$this->_database] = array();
+ }
+
+
+ $args = func_get_args();
+ if (count($args)) {
+ $args[1] = isset($args[1]) ? $args[1] : false;
+ $args[2] = isset($args[2]) ? $args[2] : false;
+ $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = $args;
+ }
+ if (isset($_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()])) {
+ return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()];
+ }
+ // end call setting (eg. $do->sequenceKeys(a,b,c); )
+
+
+ $keys = $this->keys();
+ if (!$keys) {
+ return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()]
+ = array(false, false, false);
+ }
+
+
+ $table = $this->table();
+
+ $dbtype = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['phptype'];
+
+ $usekey = $keys[0];
+
+
+ $seqname = false;
+
+ if (!empty($_DB_DATAOBJECT['CONFIG']['sequence_' . $this->tableName()])) {
+ $seqname = $_DB_DATAOBJECT['CONFIG']['sequence_' . $this->tableName()];
+ if (strpos($seqname, ':') !== false) {
+ list($usekey, $seqname) = explode(':', $seqname);
+ }
+ }
+
+
+ // if the key is not an integer - then it's not a sequence or native
+ if (empty($table[$usekey]) || !($table[$usekey] & DB_DATAOBJECT_INT)) {
+ return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = array(false, false, false);
+ }
+
+
+ if (!empty($_DB_DATAOBJECT['CONFIG']['ignore_sequence_keys'])) {
+ $ignore = $_DB_DATAOBJECT['CONFIG']['ignore_sequence_keys'];
+ if (is_string($ignore) && (strtoupper($ignore) == 'ALL')) {
+ return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = array(false, false, $seqname);
+ }
+ if (is_string($ignore)) {
+ $ignore = $_DB_DATAOBJECT['CONFIG']['ignore_sequence_keys'] = explode(',', $ignore);
+ }
+ if (in_array($this->tableName(), $ignore)) {
+ return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = array(false, false, $seqname);
+ }
+ }
+
+
+ $realkeys = $_DB_DATAOBJECT['INI'][$this->_database][$this->tableName() . "__keys"];
+
+ // if you are using an old ini file - go back to old behaviour...
+ if (is_numeric($realkeys[$usekey])) {
+ $realkeys[$usekey] = 'N';
+ }
+
+ // multiple unique primary keys without a native sequence...
+ if (($realkeys[$usekey] == 'K') && (count($keys) > 1)) {
+ return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = array(false, false, $seqname);
+ }
+ // use native sequence keys...
+ // technically postgres native here...
+ // we need to get the new improved tabledata sorted out first.
+
+ // support named sequence keys.. - currently postgres only..
+
+ if (in_array($dbtype, array('pgsql')) &&
+ ($table[$usekey] & DB_DATAOBJECT_INT) &&
+ isset($realkeys[$usekey]) && strlen($realkeys[$usekey]) > 1) {
+ return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = array($usekey, true, $realkeys[$usekey]);
+ }
+
+ if (in_array($dbtype, array('pgsql', 'mysql', 'mysqli', 'mssql', 'ifx')) &&
+ ($table[$usekey] & DB_DATAOBJECT_INT) &&
+ isset($realkeys[$usekey]) && ($realkeys[$usekey] == 'N')
+ ) {
+ return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = array($usekey, true, $seqname);
+ }
+
+
+ // if not a native autoinc, and we have not assumed all primary keys are sequence
+ if (($realkeys[$usekey] != 'N') &&
+ !empty($_DB_DATAOBJECT['CONFIG']['dont_use_pear_sequences'])) {
+ return array(false, false, false);
+ }
+
+
+ // I assume it's going to try and be a nextval DB sequence.. (not native)
+ return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = array($usekey, false, $seqname);
+ }
+
+ /**
+ * clear the cache values for this class - normally done on insert/update etc.
+ *
+ * @access private
+ * @return void
+ */
+ public function _clear_cache()
+ {
+ global $_DB_DATAOBJECT;
+
+ $class = strtolower(get_class($this));
+
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug("Clearing Cache for " . $class, 1);
+ }
+
+ if (!empty($_DB_DATAOBJECT['CACHE'][$class])) {
+ unset($_DB_DATAOBJECT['CACHE'][$class]);
+ }
+ }
+
+ /**
+ * Updates current objects variables into the database
+ * uses the keys() to decide how to update
+ * Returns the true on success
+ *
+ * for example
+ *
+ * $object = DB_DataObject::factory('mytable');
+ * $object->get("ID",234);
+ * $object->email="testing@test.com";
+ * if(!$object->update())
+ * echo "UPDATE FAILED";
+ *
+ * to only update changed items :
+ * $dataobject->get(132);
+ * $original = $dataobject; // clone/copy it..
+ * $dataobject->setFrom($_POST);
+ * if ($dataobject->validate()) {
+ * $dataobject->update($original);
+ * } // otherwise an error...
+ *
+ * performing global updates:
+ * $object = DB_DataObject::factory('mytable');
+ * $object->status = "dead";
+ * $object->whereAdd('age > 150');
+ * $object->update(DB_DATAOBJECT_WHEREADD_ONLY);
+ *
+ * @param bool $dataObject
+ * @return int rows affected or false on failure
+ * @access public
+ */
+ public function update($dataObject = false)
+ {
+ global $_DB_DATAOBJECT;
+ // connect will load the config!
+ $this->_connect();
+
+
+ $original_query = $this->_query;
+
+ $items = $this->table();
+
+ // only apply update against sequence key if it is set?????
+
+ $seq = $this->sequenceKey();
+ if ($seq[0] !== false) {
+ $keys = array($seq[0]);
+ if (!isset($this->{$keys[0]}) && $dataObject !== true) {
+ $this->raiseError("update: trying to perform an update without
+ the key set, and argument to update is not
+ DB_DATAOBJECT_WHEREADD_ONLY
+ " . print_r(array('seq' => $seq, 'keys' => $keys), true), DB_DATAOBJECT_ERROR_INVALIDARGS);
+ return false;
+ }
+ } else {
+ $keys = $this->keys();
+ }
+
+
+ if (!$items) {
+ $this->raiseError("update:No table definition for {$this->tableName()}", DB_DATAOBJECT_ERROR_INVALIDCONFIG);
+ return false;
+ }
+ $datasaved = 1;
+ $settings = '';
+ $this->_connect();
+
+ $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+ $dbtype = $DB->dsn["phptype"];
+ $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
+ $options = $_DB_DATAOBJECT['CONFIG'];
+
+
+ $ignore_null = !isset($options['disable_null_strings'])
+ || !is_string($options['disable_null_strings'])
+ || strtolower($options['disable_null_strings']) !== 'full';
+
+
+ foreach ($items as $k => $v) {
+
+ // I think this is ignoring empty vlalues
+ if ((!isset($this->$k) || ($v == 1 && $this->$k === ''))
+ && $ignore_null
+ ) {
+ continue;
+ }
+ // ignore stuff thats
+
+ // dont write things that havent changed..
+ if (($dataObject !== false) && isset($dataObject->$k) && ($dataObject->$k === $this->$k)) {
+ continue;
+ }
+
+ // - dont write keys to left.!!!
+ if (in_array($k, $keys)) {
+ continue;
+ }
+
+ // dont insert data into mysql timestamps
+ // use query() if you really want to do this!!!!
+ if ($v & DB_DATAOBJECT_MYSQLTIMESTAMP) {
+ continue;
+ }
+
+
+ if ($settings) {
+ $settings .= ', ';
+ }
+
+ $kSql = ($quoteIdentifiers ? $DB->quoteIdentifier($k) : $k);
+
+ if (is_object($this->$k) && is_a($this->$k, 'DB_DataObject_Cast')) {
+ $value = $this->$k->toString($v, $DB);
+ if ((new PEAR)->isError($value)) {
+ $this->raiseError($value->getMessage(), DB_DATAOBJECT_ERROR_INVALIDARG);
+ return false;
+ }
+ $settings .= "$kSql = $value ";
+ continue;
+ }
+
+ // special values ... at least null is handled...
+ if (!($v & DB_DATAOBJECT_NOTNULL) && DB_DataObject::_is_null($this, $k)) {
+ $settings .= "$kSql = NULL ";
+ continue;
+ }
+ // DATE is empty... on a col. that can be null..
+ // note: this may be usefull for time as well..
+ if (!$this->$k &&
+ (($v & DB_DATAOBJECT_DATE) || ($v & DB_DATAOBJECT_TIME)) &&
+ !($v & DB_DATAOBJECT_NOTNULL)) {
+ $settings .= "$kSql = NULL ";
+ continue;
+ }
+
+
+ if ($v & DB_DATAOBJECT_STR) {
+ $settings .= "$kSql = " . $this->_quote((string)(
+ ($v & DB_DATAOBJECT_BOOL) ?
+ // this is thanks to the braindead idea of postgres to
+ // use t/f for boolean.
+ (($this->$k === 'f') ? 0 : (int)(bool)$this->$k) :
+ $this->$k
+ )) . ' ';
+ continue;
+ }
+ if (is_numeric($this->$k)) {
+ $settings .= "$kSql = {$this->$k} ";
+ continue;
+ }
+ // at present we only cast to integers
+ // - V2 may store additional data about float/int
+ $settings .= "$kSql = " . intval($this->$k) . ' ';
+ }
+
+
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug("got keys as " . serialize($keys), 3);
+ }
+ if ($dataObject !== true) {
+ $this->_build_condition($items, $keys);
+ } else {
+ // prevent wiping out of data!
+ if (empty($this->_query['condition'])) {
+ $this->raiseError("update: global table update not available
+ do \$do->whereAdd('1=1'); if you really want to do that.
+ ", DB_DATAOBJECT_ERROR_INVALIDARGS);
+ return false;
+ }
+ }
+
+
+ // echo " $settings, $this->condition ";
+ if ($settings && isset($this->_query) && $this->_query['condition']) {
+ $table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->tableName()) : $this->tableName());
+
+ $r = $this->_query("UPDATE {$table} SET {$settings} {$this->_query['condition']} ");
+
+ // restore original query conditions.
+ $this->_query = $original_query;
+
+ if ((new PEAR)->isError($r)) {
+ $this->raiseError($r);
+ return false;
+ }
+ if ($r < 1) {
+ return 0;
+ }
+
+ $this->_clear_cache();
+ return $r;
+ }
+ // restore original query conditions.
+ $this->_query = $original_query;
+
+ // if you manually specified a dataobject, and there where no changes - then it's ok..
+ if ($dataObject !== false) {
+ return true;
+ }
+
+ $this->raiseError(
+ "update: No Data specifed for query $settings , {$this->_query['condition']}",
+ DB_DATAOBJECT_ERROR_NODATA
+ );
+ return false;
+ }
+
+ /**
+ * Deletes items from table which match current objects variables
+ *
+ * Returns the true on success
+ *
+ * for example
+ *
+ * Designed to be extended
+ *
+ * $object = new mytable();
+ * $object->ID=123;
+ * echo $object->delete(); // builds a conditon
+ *
+ * $object = new mytable();
+ * $object->whereAdd('age > 12');
+ * $object->limit(1);
+ * $object->orderBy('age DESC');
+ * $object->delete(true); // dont use object vars, use the conditions, limit and order.
+ *
+ * @param bool $useWhere (optional) If DB_DATAOBJECT_WHEREADD_ONLY is passed in then
+ * we will build the condition only using the whereAdd's. Default is to
+ * build the condition only using the object parameters.
+ *
+ * @access public
+ * @return mixed Int (No. of rows affected) on success, false on failure, 0 on no data affected
+ */
+ public function delete($useWhere = false)
+ {
+ global $_DB_DATAOBJECT;
+ // connect will load the config!
+ $this->_connect();
+ $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+ $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
+
+ $extra_cond = ' ' . (isset($this->_query['order_by']) ? $this->_query['order_by'] : '');
+
+ if (!$useWhere) {
+ $keys = $this->keys();
+ $this->_query = array(); // as it's probably unset!
+ $this->_query['condition'] = ''; // default behaviour not to use where condition
+ $this->_build_condition($this->table(), $keys);
+ // if primary keys are not set then use data from rest of object.
+ if (!$this->_query['condition']) {
+ $this->_build_condition($this->table(), array(), $keys);
+ }
+ $extra_cond = '';
+ }
+
+
+ // don't delete without a condition
+ if (($this->_query !== false) && $this->_query['condition']) {
+ $table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->tableName()) : $this->tableName());
+ $sql = "DELETE ";
+ // using a joined delete. - with useWhere..
+ $sql .= (!empty($this->_join) && $useWhere) ?
+ "{$table} FROM {$table} {$this->_join} " :
+ "FROM {$table} ";
+
+ $sql .= $this->_query['condition'] . $extra_cond;
+
+ // add limit..
+
+ if (isset($this->_query['limit_start']) && strlen($this->_query['limit_start'] . $this->_query['limit_count'])) {
+ if (!isset($_DB_DATAOBJECT['CONFIG']['db_driver']) ||
+ ($_DB_DATAOBJECT['CONFIG']['db_driver'] == 'DB')) {
+ // pear DB
+ $sql = $DB->modifyLimitQuery($sql, $this->_query['limit_start'], $this->_query['limit_count']);
+ } else {
+ // MDB2
+ $DB->setLimit($this->_query['limit_count'], $this->_query['limit_start']);
+ }
+ }
+
+
+ $r = $this->_query($sql);
+
+
+ if ((new PEAR)->isError($r)) {
+ $this->raiseError($r);
+ return false;
+ }
+ if ($r < 1) {
+ return 0;
+ }
+ $this->_clear_cache();
+ return $r;
+ } else {
+ $this->raiseError("delete: No condition specifed for query", DB_DATAOBJECT_ERROR_NODATA);
+ return false;
+ }
+ }
+
+ /**
+ * fetches a specific row into this object variables
+ *
+ * Not recommended - better to use fetch()
+ *
+ * Returens true on success
+ *
+ * @param int $row row
+ * @access public
+ * @return boolean true on success
+ */
+ public function fetchRow($row = null)
+ {
+ global $_DB_DATAOBJECT;
+ if (empty($_DB_DATAOBJECT['CONFIG'])) {
+ $this->_loadConfig();
+ }
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug("{$this->tableName()} $row of {$this->N}", "fetchrow", 3);
+ }
+ if (!$this->tableName()) {
+ $this->raiseError("fetchrow: No table", DB_DATAOBJECT_ERROR_INVALIDCONFIG);
+ return false;
+ }
+ if ($row === null) {
+ $this->raiseError("fetchrow: No row specified", DB_DATAOBJECT_ERROR_INVALIDARGS);
+ return false;
+ }
+ if (!$this->N) {
+ $this->raiseError("fetchrow: No results avaiable", DB_DATAOBJECT_ERROR_NODATA);
+ return false;
+ }
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug("{$this->tableName()} $row of {$this->N}", "fetchrow", 3);
+ }
+
+
+ $result = $_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid];
+ $array = $result->fetchrow(DB_DATAOBJECT_FETCHMODE_ASSOC, $row);
+ if (!is_array($array)) {
+ $this->raiseError("fetchrow: No results available", DB_DATAOBJECT_ERROR_NODATA);
+ return false;
+ }
+ $replace = array('.', ' ');
+ foreach ($array as $k => $v) {
+ // use strpos as str_replace is slow.
+ $kk = (strpos($k, '.') === false && strpos($k, ' ') === false) ?
+ $k : str_replace($replace, '_', $k);
+
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug("$kk = " . $array[$k], "fetchrow LINE", 3);
+ }
+ $this->$kk = $array[$k];
+ }
+
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug("{$this->tableName()} DONE", "fetchrow", 3);
+ }
+ return true;
+ }
+
+ /**
+ * Find the number of results from a simple query
+ *
+ * for example
+ *
+ * $object = new mytable();
+ * $object->name = "fred";
+ * echo $object->count();
+ * echo $object->count(true); // dont use object vars.
+ * echo $object->count('distinct mycol'); count distinct mycol.
+ * echo $object->count('distinct mycol',true); // dont use object vars.
+ * echo $object->count('distinct'); // count distinct id (eg. the primary key)
+ *
+ *
+ * @param bool|string (optional)
+ * (true|false => see below not on whereAddonly)
+ * (string)
+ * "DISTINCT" => does a distinct count on the tables 'key' column
+ * otherwise => normally it counts primary keys - you can use
+ * this to do things like $do->count('distinct mycol');
+ *
+ * @param bool $whereAddOnly (optional) If DB_DATAOBJECT_WHEREADD_ONLY is passed in then
+ * we will build the condition only using the whereAdd's. Default is to
+ * build the condition using the object parameters as well.
+ *
+ * @access public
+ * @return int
+ */
+ public function count($countWhat = false, $whereAddOnly = false)
+ {
+ global $_DB_DATAOBJECT;
+
+ if (is_bool($countWhat)) {
+ $whereAddOnly = $countWhat;
+ }
+
+ $t = clone($this);
+ $items = $t->table();
+
+ $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
+
+
+ if (!isset($t->_query)) {
+ $this->raiseError(
+ "You cannot do run count after you have run fetch()",
+ DB_DATAOBJECT_ERROR_INVALIDARGS
+ );
+ return false;
+ }
+ $this->_connect();
+ $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+
+
+ if (!$whereAddOnly && $items) {
+ $t->_build_condition($items);
+ }
+ $keys = $this->keys();
+
+ if (empty($keys[0]) && (!is_string($countWhat) || (strtoupper($countWhat) == 'DISTINCT'))) {
+ $this->raiseError(
+ "You cannot do run count without keys - use \$do->count('id'), or use \$do->count('distinct id')';",
+ DB_DATAOBJECT_ERROR_INVALIDARGS,
+ PEAR_ERROR_DIE
+ );
+ return false;
+ }
+ $table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->tableName()) : $this->tableName());
+ $key_col = empty($keys[0]) ? '' : (($quoteIdentifiers ? $DB->quoteIdentifier($keys[0]) : $keys[0]));
+ $as = ($quoteIdentifiers ? $DB->quoteIdentifier('DATAOBJECT_NUM') : 'DATAOBJECT_NUM');
+
+ // support distinct on default keys.
+ $countWhat = (strtoupper($countWhat) == 'DISTINCT') ?
+ "DISTINCT {$table}.{$key_col}" : $countWhat;
+
+ $countWhat = is_string($countWhat) ? $countWhat : "{$table}.{$key_col}";
+
+ $r = $t->_query(
+ "SELECT count({$countWhat}) as $as
+ FROM $table {$t->_join} {$t->_query['condition']}"
+ );
+ if ((new PEAR)->isError($r)) {
+ return false;
+ }
+
+ $result = $_DB_DATAOBJECT['RESULTS'][$t->_DB_resultid];
+ $l = $result->fetchRow(DB_DATAOBJECT_FETCHMODE_ORDERED);
+ // free the results - essential on oracle.
+ $t->free();
+ if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+ $this->debug('Count returned ' . $l[0], 1);
+ }
+ return (int)$l[0];
+ }
+
+ /**
+ * Free global arrays associated with this object.
+ *
+ *
+ * @access public
+ * @return none
+ */
+ public function free()
+ {
+ global $_DB_DATAOBJECT;
+
+ if (isset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid])) {
+ unset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid]);
+ }
+ if (isset($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid])) {
+ unset($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]);
+ }
+ // clear the staticGet cache as well.
+ $this->_clear_cache();
+ // this is a huge bug in DB!
+ if (isset($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) {
+ $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->num_rows = array();
+ }
+
+ if (is_array($this->_link_loaded)) {
+ foreach ($this->_link_loaded as $do) {
+ if (
+ !empty($this->{$do}) &&
+ is_object($this->{$do}) &&
+ method_exists($this->{$do}, 'free')
+ ) {
+ $this->{$do}->free();
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * sends raw query to database
+ *
+ * Since _query has to be a private 'non overwriteable method', this is a relay
+ *
+ * @param string $string SQL Query
+ * @access public
+ * @return void or DB_Error
+ */
+ public function query($string)
+ {
+ return $this->_query($string);
+ }
+
+ /**
+ * an escape wrapper around DB->escapeSimple()
+ * can be used when adding manual queries or clauses
+ * eg.
+ * $object->query("select * from xyz where abc like '". $object->escape($_GET['name']) . "'");
+ *
+ * @param string $string value to be escaped
+ * @param bool $likeEscape escapes % and _ as well. - so like queries can be protected.
+ * @access public
+ * @return string
+ */
+ public function escape($string, $likeEscape = false)
+ {
+ global $_DB_DATAOBJECT;
+ $this->_connect();
+ $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+ // mdb2 uses escape...
+ $dd = empty($_DB_DATAOBJECT['CONFIG']['db_driver']) ? 'DB' : $_DB_DATAOBJECT['CONFIG']['db_driver'];
+ $ret = ($dd == 'DB') ? $DB->escapeSimple($string) : $DB->escape($string);
+ if ($likeEscape) {
+ $ret = str_replace(array('_', '%'), array('\_', '\%'), $ret);
+ }
+ return $ret;
+ }
+
+ /**
+ * Return or assign the name of the current database
+ *
+ * @param string optional database name to set
+ * @access public
+ * @return string The name of the current database
+ */
+ public function database()
+ {
+ $args = func_get_args();
+ if (count($args)) {
+ $this->_database = $args[0];
+ } else {
+ $this->_connect();
+ }
+
+ return $this->_database;
+ }
+
+ /**
+ * generic getter/setter for links
+ *
+ * This is the new 'recommended' way to get get/set linked objects.
+ * must be used with links.ini
+ *
+ * usage:
+ * get:
+ * $obj = $do->link('company_id');
+ * $obj = $do->link(array('local_col', 'linktable:linked_col'));
+ *
+ * set:
+ * $do->link('company_id',0);
+ * $do->link('company_id',$obj);
+ * $do->link('company_id', array($obj));
+ *
+ * example function
+ *
+ * function company() {
+ * $this->link(array('company_id','company:id'), func_get_args());
+ * }
+ *
+ *
+ *
+ * @param $field
+ * @param array $set_args
+ * @return mixed true or false on setting, object on getting
+ * @author Alan Knowles
+ * @access public
+ */
+ public function link($field, $set_args = array())
+ {
+ //require_once 'DB/DataObject/Links.php';
+ require_once 'Links.php';
+ $l = new DB_DataObject_Links($this);
+ return $l->link($field, $set_args);
+ }
+
+ /**
+ * load related objects
+ *
+ * Generally not recommended to use this.
+ * The generator should support creating getter_setter methods which are better suited.
+ *
+ * Relies on <dbname>.links.ini
+ *
+ * Sets properties on the calling dataobject you can change what
+ * object vars the links are stored in by changeing the format parameter
+ *
+ *
+ * @param string format (default _%s) where %s is the table name.
+ * @return boolean , true on success
+ * @author Tim White <tim@cyface.com>
+ * @access public
+ */
+ public function getLinks($format = '_%s')
+ {
+ //require_once 'DB/DataObject/Links.php';
+ require_once 'Links.php';
+ $l = new DB_DataObject_Links($this);
+ return $l->applyLinks($format);
+ }
+
+ /**
+ * deprecited : @use link()
+ * @param $row
+ * @param null $table
+ * @param bool $link
+ * @return mixed
+ */
+ public function getLink($row, $table = null, $link = false)
+ {
+ //require_once 'DB/DataObject/Links.php';
+ require_once 'Links.php';
+ $l = new DB_DataObject_Links($this);
+ return $l->getLink($row, $table === null ? false : $table, $link);
+ }
+
+ /**
+ * getLinkArray
+ * Fetch an array of related objects. This should be used in conjunction with a <dbname>.links.ini file configuration (see the introduction on linking for details on this).
+ * You may also use this with all parameters to specify, the column and related table.
+ * This is highly dependant on naming columns 'correctly' :)
+ * using colname = xxxxx_yyyyyy
+ * xxxxxx = related table; (yyyyy = user defined..)
+ * looks up table xxxxx, for value id=$this->xxxxx
+ * stores it in $this->_xxxxx_yyyyy
+ *
+ * @access public
+ * @param $row
+ * @param string $table - name of table to look up value in
+ * @return array - array of results (empty array on failure)
+ *
+ * Example - Getting the related objects
+ *
+ * $person = new DataObjects_Person;
+ * $person->get(12);
+ * $children = $person->getLinkArray('children');
+ *
+ * echo 'There are ', count($children), ' descendant(s):<br />';
+ * foreach ($children as $child) {
+ * echo $child->name, '<br />';
+ * }
+ */
+ public function getLinkArray($row, $table = null)
+ {
+ //require_once 'DB/DataObject/Links.php';
+ require_once 'Links.php';
+ $l = new DB_DataObject_Links($this);
+ return $l->getLinkArray($row, $table === null ? false : $table);
+ }
+
+ /**
+ * unionAdd - adds another dataobject to this, building a unioned query.
+ *
+ * usage:
+ * $doTable1 = DB_DataObject::factory("table1");
+ * $doTable2 = DB_DataObject::factory("table2");
+ *
+ * $doTable1->selectAdd();
+ * $doTable1->selectAdd("col1,col2");
+ * $doTable1->whereAdd("col1 > 100");
+ * $doTable1->orderBy("col1");
+ *
+ * $doTable2->selectAdd();
+ * $doTable2->selectAdd("col1, col2");
+ * $doTable2->whereAdd("col2 = 'v'");
+ *
+ * $doTable1->unionAdd($doTable2);
+ * $doTable1->find();
+ *
+ * Note: this model may be a better way to implement joinAdd?, eg. do the building in find?
+ *
+ *
+ * @param $obj object|false the union object or false to reset
+ * @param string $is_all string 'ALL' to do all.
+ * @return false|mixed|object
+ */
+
+ public function unionAdd($obj, $is_all = '')
+ {
+ if ($obj === false) {
+ $ret = $this->_query['unions'];
+ $this->_query['unions'] = array();
+ return $ret;
+ }
+ $this->_query['unions'][] = array($obj, 'UNION ' . $is_all . ' ');
+ return $obj;
+ }
+
+ /**
+ * autoJoin - using the links.ini file, it builds a query with all the joins
+ * usage:
+ * $x = DB_DataObject::factory('mytable');
+ * $x->autoJoin();
+ * $x->get(123);
+ * will result in all of the joined data being added to the fetched object..
+ *
+ * $x = DB_DataObject::factory('mytable');
+ * $x->autoJoin();
+ * $ar = $x->fetchAll();
+ * will result in an array containing all the data from the table, and any joined tables..
+ *
+ * $x = DB_DataObject::factory('mytable');
+ * $jdata = $x->autoJoin();
+ * $x->selectAdd(); //reset..
+ * foreach($_REQUEST['requested_cols'] as $c) {
+ * if (!isset($jdata[$c])) continue; // ignore columns not available..
+ * $x->selectAdd( $jdata[$c] . ' as ' . $c);
+ * }
+ * $ar = $x->fetchAll();
+ * will result in only the columns requested being fetched...
+ *
+ *
+ *
+ * @param array Configuration
+ * exclude Array of columns to exclude from results (eg. modified_by_id)
+ * links The equivilant links.ini data for this table eg.
+ * array( 'person_id' => 'person:id', .... )
+ * include Array of columns to include
+ * distinct Array of distinct columns.
+ *
+ * @return array info about joins
+ * cols => map of resulting {joined_tablename}.{joined_table_column_name}
+ * join_names => map of resulting {join_name_as}.{joined_table_column_name}
+ * count => the column to count on.
+ * @access public
+ */
+ public function autoJoin($cfg = array())
+ {
+ global $_DB_DATAOBJECT;
+ //var_Dump($cfg);exit;
+ $pre_links = $this->links();
+ if (!empty($cfg['links'])) {
+ $this->links(array_merge($pre_links, $cfg['links']));
+ }
+ $map = $this->links();
+
+ $this->databaseStructure();
+ $dbstructure = $_DB_DATAOBJECT['INI'][$this->_database];
+ //print_r($map);
+ $tabdef = $this->table();
+
+ // we need this as normally it's only cleared by an empty selectAs call.
+
+
+ $keys = array_keys($tabdef);
+ if (!empty($cfg['exclude'])) {
+ $keys = array_intersect($keys, array_diff($keys, $cfg['exclude']));
+ }
+ if (!empty($cfg['include'])) {
+ $keys = array_intersect($keys, $cfg['include']);
+ }
+
+ $selectAs = array();
+
+ if (!empty($keys)) {
+ $selectAs = array(array($keys, '%s', false));
+ }
+
+ $ret = array(
+ 'cols' => array(),
+ 'join_names' => array(),
+ 'count' => false,
+ );
+
+
+ $has_distinct = false;
+ if (!empty($cfg['distinct']) && $keys) {
+
+ // reset the columsn?
+ $cols = array();
+
+ //echo '<PRE>' ;print_r($xx);exit;
+ foreach ($keys as $c) {
+ //var_dump($c);
+
+ if ($cfg['distinct'] == $c) {
+ $has_distinct = 'DISTINCT( ' . $this->tableName() . '.' . $c . ') as ' . $c;
+ $ret['count'] = 'DISTINCT ' . $this->tableName() . '.' . $c . '';
+ continue;
+ }
+ // cols is in our filtered keys...
+ $cols = $c;
}
+ // apply our filtered version, which excludes the distinct column.
+
+ $selectAs = empty($cols) ? array() : array(array(array($cols), '%s', false));
+ }
+
+ foreach ($keys as $k) {
+ $ret['cols'][$k] = $this->tableName() . '.' . $k;
}
- */
- // does this need multi db support??
- $cp = isset($_DB_DATAOBJECT['CONFIG']['class_prefix']) ?
- explode(PATH_SEPARATOR, $_DB_DATAOBJECT['CONFIG']['class_prefix']) : '';
-
- //print_r($cp);
-
- // multiprefix support.
- $tbl = preg_replace('/[^A-Z0-9]/i', '_', ucfirst($table));
- if (is_array($cp)) {
- $class = array();
- foreach ($cp as $cpr) {
- $ce = substr(phpversion(), 0, 1) > 4 ? class_exists($cpr . $tbl, false) : class_exists($cpr . $tbl);
- if ($ce) {
- $class = $cpr . $tbl;
- break;
+
+ foreach ($map as $ocl => $info) {
+ list($tab, $col) = explode(':', $info);
+ // what about multiple joins on the same table!!!
+
+ // if links point to a table that does not exist - ignore.
+ if (!isset($dbstructure[$tab])) {
+ continue;
+ }
+
+ $xx = DB_DataObject::factory($tab);
+ if (!is_object($xx) || !is_a($xx, 'DB_DataObject')) {
+ continue;
+ }
+ // skip columns that are excluded.
+
+ // we ignore include here... - as
+
+ // this is borked ... for multiple jions..
+ $this->joinAdd($xx, 'LEFT', 'join_' . $ocl . '_' . $col, $ocl);
+
+ if (!empty($cfg['exclude']) && in_array($ocl, $cfg['exclude'])) {
+ continue;
+ }
+
+ $tabdef = $xx->table();
+ $table = $xx->tableName();
+
+ $keys = array_keys($tabdef);
+
+
+ if (!empty($cfg['exclude'])) {
+ $keys = array_intersect($keys, array_diff($keys, $cfg['exclude']));
+
+ foreach ($keys as $k) {
+ if (in_array($ocl . '_' . $k, $cfg['exclude'])) {
+ $keys = array_diff($keys, $k); // removes the k..
+ }
}
- $class[] = $cpr . $tbl;
- }
- } else {
- $class = $tbl;
- $ce = substr(phpversion(), 0, 1) > 4 ? class_exists($class, false) : class_exists($class);
- }
-
-
- $rclass = $ce ? $class : DB_DataObject::_autoloadClass($class, $table);
- // proxy = full|light
- if (!$rclass && isset($_DB_DATAOBJECT['CONFIG']['proxy'])) {
- DB_DataObject::debug("FAILED TO Autoload $database.$table - using proxy.", "FACTORY", 1);
-
-
- $proxyMethod = 'getProxy'.$_DB_DATAOBJECT['CONFIG']['proxy'];
- // if you have loaded (some other way) - dont try and load it again..
- class_exists('DB_DataObject_Generator') ? '' :
- require_once 'DB/DataObject/Generator.php';
-
- $d = new DB_DataObject;
-
- $d->__table = $table;
-
- $ret = $d->_connect();
- if (is_object($ret) && is_a($ret, 'PEAR_Error')) {
- return $ret;
}
-
- $x = new DB_DataObject_Generator;
- return $x->$proxyMethod($d->_database, $table);
- }
-
- if (!$rclass || !class_exists($rclass)) {
- $dor = new DB_DataObject();
- return $dor->raiseError(
- "factory could not find class " .
- (is_array($class) ? implode(PATH_SEPARATOR, $class) : $class).
- "from $table",
- DB_DATAOBJECT_ERROR_INVALIDCONFIG
- );
- }
-
- $ret = new $rclass();
-
- if (!empty($database)) {
- DB_DataObject::debug("Setting database to $database", "FACTORY", 1);
- $ret->database($database);
- }
- return $ret;
- }
- /**
- * autoload Class
- *
- * @param string|array $class Class
- * @param string $table Table trying to load.
- * @access private
- * @return string classname on Success
- */
- public function _autoloadClass($class, $table=false)
- {
- global $_DB_DATAOBJECT;
-
- if (empty($_DB_DATAOBJECT['CONFIG'])) {
- DB_DataObject::_loadConfig();
- }
- $class_prefix = empty($_DB_DATAOBJECT['CONFIG']['class_prefix']) ?
- '' : $_DB_DATAOBJECT['CONFIG']['class_prefix'];
-
- $table = $table ? $table : substr($class, strlen($class_prefix));
- // only include the file if it exists - and barf badly if it has parse errors :)
- if (!empty($_DB_DATAOBJECT['CONFIG']['proxy']) || empty($_DB_DATAOBJECT['CONFIG']['class_location'])) {
- return false;
- }
- // support for:
- // class_location = mydir/ => maps to mydir/Tablename.php
- // class_location = mydir/myfile_%s.php => maps to mydir/myfile_Tablename
- // with directory sepr
- // class_location = mydir/:mydir2/: => tries all of thes locations.
- $cl = $_DB_DATAOBJECT['CONFIG']['class_location'];
-
-
- switch (true) {
- case (strpos($cl, '%s') !== false):
- $file = sprintf($cl, preg_replace('/[^A-Z0-9]/i', '_', ucfirst($table)));
- break;
-
- case (strpos($cl, PATH_SEPARATOR) !== false):
- $file = array();
- foreach (explode(PATH_SEPARATOR, $cl) as $p) {
- $file[] = $p .'/'.preg_replace('/[^A-Z0-9]/i', '_', ucfirst($table)).".php";
+ if (!empty($cfg['include'])) {
+ // include will basically be BASECOLNAME_joinedcolname
+ $nkeys = array();
+ foreach ($keys as $k) {
+ if (in_array(sprintf($ocl . '_%s', $k), $cfg['include'])) {
+ $nkeys[] = $k;
+ }
}
- break;
- default:
- $file = $cl .'/'.preg_replace('/[^A-Z0-9]/i', '_', ucfirst($table)).".php";
- break;
- }
-
- $cls = is_array($class) ? $class : array($class);
-
- if (is_array($file) || !file_exists($file)) {
- $found = false;
-
- $file = is_array($file) ? $file : array($file);
- $search = implode(PATH_SEPARATOR, $file);
- foreach ($file as $f) {
- foreach (explode(PATH_SEPARATOR, '' . PATH_SEPARATOR . ini_get('include_path')) as $p) {
- $ff = empty($p) ? $f : "$p/$f";
+ $keys = $nkeys;
+ }
- if (file_exists($ff)) {
- $file = $ff;
- $found = true;
- break;
+ if (empty($keys)) {
+ continue;
+ }
+ // got distinct, and not yet found it..
+ if (!$has_distinct && !empty($cfg['distinct'])) {
+ $cols = array();
+ foreach ($keys as $c) {
+ $tn = sprintf($ocl . '_%s', $c);
+
+ if ($tn == $cfg['distinct']) {
+ $has_distinct = 'DISTINCT( ' . 'join_' . $ocl . '_' . $col . '.' . $c . ') as ' . $tn;
+ $ret['count'] = 'DISTINCT join_' . $ocl . '_' . $col . '.' . $c;
+ // var_dump($this->countWhat );
+ continue;
}
+ $cols[] = $c;
}
- if ($found) {
- break;
+
+ if (!empty($cols)) {
+ $selectAs[] = array($cols, $ocl . '_%s', 'join_' . $ocl . '_' . $col);
}
+ } else {
+ $selectAs[] = array($keys, $ocl . '_%s', 'join_' . $ocl . '_' . $col);
}
- if (!$found) {
- $dor = new DB_DataObject();
- $dor->raiseError(
- "autoload:Could not find class " . implode(',', $cls) .
- " using class_location value :" . $search .
- " using include_path value :" . ini_get('include_path'),
- DB_DATAOBJECT_ERROR_INVALIDCONFIG
- );
- return false;
+
+ foreach ($keys as $k) {
+ $ret['cols'][sprintf('%s_%s', $ocl, $k)] = $tab . '.' . $k;
+ $ret['join_names'][sprintf('%s_%s', $ocl, $k)] = sprintf('join_%s_%s.%s', $ocl, $col, $k);
}
}
-
- include_once $file;
-
-
- $ce = false;
- foreach ($cls as $c) {
- $ce = substr(phpversion(), 0, 1) > 4 ? class_exists($c, false) : class_exists($c);
- if ($ce) {
- $class = $c;
- break;
- }
+
+ // fill in the select details..
+ $this->selectAdd();
+
+ if ($has_distinct) {
+ $this->selectAdd($has_distinct);
}
- if (!$ce) {
- $dor = new DB_DataObject();
- $dor->raiseError(
- "autoload:Could not autoload " . implode(',', $cls),
- DB_DATAOBJECT_ERROR_INVALIDCONFIG
- );
- return false;
+
+ foreach ($selectAs as $ar) {
+ $this->selectAs($ar[0], $ar[1], $ar[2]);
}
- return $class;
+ // restore links..
+ $this->links($pre_links);
+
+ return $ret;
}
-
-
-
+
/**
- * Have the links been loaded?
- * if they have it contains a array of those variables.
+ * Get the links associate array as defined by the links.ini file.
*
- * @access private
- * @var boolean | array
+ *
+ * Experimental... -
+ * Should look a bit like
+ * [local_col_name] => "related_tablename:related_col_name"
+ *
+ * @return array|null
+ * array = if there are links defined for this table.
+ * empty array - if there is a links.ini file, but no links on this table
+ * false - if no links.ini exists for this database (hence try auto_links).
+ * @access public
+ * @see DB_DataObject::getLinks(), DB_DataObject::getLink()
*/
- public $_link_loaded = false;
-
- /**
- * Get the links associate array as defined by the links.ini file.
- *
- *
- * Experimental... -
- * Should look a bit like
- * [local_col_name] => "related_tablename:related_col_name"
- *
- * @param array $new_links optional - force update of the links for this table
- * You probably want to restore it to it's original state after,
- * as modifying here does it for the whole PHP request.
- *
- * @return array|null
- * array = if there are links defined for this table.
- * empty array - if there is a links.ini file, but no links on this table
- * false - if no links.ini exists for this database (hence try auto_links).
- * @access public
- * @see DB_DataObject::getLinks(), DB_DataObject::getLink()
- */
-
+
public function links()
{
global $_DB_DATAOBJECT;
}
// have to connect.. -> otherwise things break later.
$this->_connect();
-
+
// alias for shorter code..
- $lcfg = &$_DB_DATAOBJECT['LINKS'];
- $cfg = $_DB_DATAOBJECT['CONFIG'];
+ $lcfg = &$_DB_DATAOBJECT['LINKS'];
+ $cfg = $_DB_DATAOBJECT['CONFIG'];
if ($args = func_get_args()) {
// an associative array was specified, that updates the current
// either no file, or empty..
return $lcfg[$this->_database] === false ? null : array();
}
-
+
// links are same place as schema by default.
$schemas = isset($cfg['schema_location']) ?
array("{$cfg['schema_location']}/{$this->_database}.ini") :
- array() ;
+ array();
// if ini_* is set look there instead.
// and support multiple locations.
$cfg["ini_{$this->_database}"] :
explode(PATH_SEPARATOR, $cfg["ini_{$this->_database}"]);
}
-
+
// default to not available.
$lcfg[$this->_database] = false;
foreach ($schemas as $ini) {
$links = isset($cfg["links_{$this->_database}"]) ?
- $cfg["links_{$this->_database}"] :
- str_replace('.ini', '.links.ini', $ini);
-
+ $cfg["links_{$this->_database}"] :
+ str_replace('.ini', '.links.ini', $ini);
+
// file really exists..
if (!file_exists($links) || !is_file($links)) {
if (!empty($cfg['debug'])) {
parse_ini_file($links, true)
);
-
+
if (!empty($cfg['debug'])) {
$this->debug("Loaded links.ini file: $links", "links", 1);
}
}
-
+
if (!empty($_DB_DATAOBJECT['CONFIG']['portability']) && $_DB_DATAOBJECT['CONFIG']['portability'] & 1) {
- foreach ($lcfg[$this->_database] as $k=>$v) {
+ foreach ($lcfg[$this->_database] as $k => $v) {
$nk = strtolower($k);
// results in duplicate cols.. but not a big issue..
$lcfg[$this->_database][$nk] = isset($lcfg[$this->_database][$nk])
- ? $lcfg[$this->_database][$nk] : array();
-
- foreach ($v as $kk =>$vv) {
- //var_Dump($vv);exit;
- $vv =explode(':', $vv);
- $vv[0] = strtolower($vv[0]);
- $lcfg[$this->_database][$nk][$kk] = implode(':', $vv);
- }
- }
- }
- //echo '<PRE>';print_r($lcfg);exit;
-
- // if there is no link data at all on the file!
- // we return null.
- if ($lcfg[$this->_database] === false) {
- return null;
- }
-
- if (isset($lcfg[$this->_database][$this->tableName()])) {
- return $lcfg[$this->_database][$this->tableName()];
- }
-
- return array();
- }
-
-
- /**
- * generic getter/setter for links
- *
- * This is the new 'recommended' way to get get/set linked objects.
- * must be used with links.ini
- *
- * usage:
- * get:
- * $obj = $do->link('company_id');
- * $obj = $do->link(array('local_col', 'linktable:linked_col'));
- *
- * set:
- * $do->link('company_id',0);
- * $do->link('company_id',$obj);
- * $do->link('company_id', array($obj));
- *
- * example function
- *
- * function company() {
- * $this->link(array('company_id','company:id'), func_get_args());
- * }
- *
- *
- *
- * @param mixed $link_spec link specification (normally a string)
- * uses similar rules to joinAdd() array argument.
- * @param mixed $set_value (optional) int, DataObject, or array('set')
- * @author Alan Knowles
- * @access public
- * @return mixed true or false on setting, object on getting
- */
- public function link($field, $set_args = array())
- {
- require_once 'DB/DataObject/Links.php';
- $l = new DB_DataObject_Links($this);
- return $l->link($field, $set_args) ;
- }
-
- /**
- * load related objects
- *
- * Generally not recommended to use this.
- * The generator should support creating getter_setter methods which are better suited.
- *
- * Relies on <dbname>.links.ini
- *
- * Sets properties on the calling dataobject you can change what
- * object vars the links are stored in by changeing the format parameter
- *
- *
- * @param string format (default _%s) where %s is the table name.
- * @author Tim White <tim@cyface.com>
- * @access public
- * @return boolean , true on success
- */
- public function getLinks($format = '_%s')
- {
- require_once 'DB/DataObject/Links.php';
- $l = new DB_DataObject_Links($this);
- return $l->applyLinks($format);
- }
+ ? $lcfg[$this->_database][$nk] : array();
- /**
- * deprecited : @use link()
- */
- public function getLink($row, $table = null, $link = false)
- {
- require_once 'DB/DataObject/Links.php';
- $l = new DB_DataObject_Links($this);
- return $l->getLink($row, $table === null ? false: $table, $link);
- }
+ foreach ($v as $kk => $vv) {
+ //var_Dump($vv);exit;
+ $vv = explode(':', $vv);
+ $vv[0] = strtolower($vv[0]);
+ $lcfg[$this->_database][$nk][$kk] = implode(':', $vv);
+ }
+ }
+ }
+ //echo '<PRE>';print_r($lcfg);exit;
- /**
- * getLinkArray
- * Fetch an array of related objects. This should be used in conjunction with a <dbname>.links.ini file configuration (see the introduction on linking for details on this).
- * You may also use this with all parameters to specify, the column and related table.
- * This is highly dependant on naming columns 'correctly' :)
- * using colname = xxxxx_yyyyyy
- * xxxxxx = related table; (yyyyy = user defined..)
- * looks up table xxxxx, for value id=$this->xxxxx
- * stores it in $this->_xxxxx_yyyyy
- *
- * @access public
- * @param string $column - either column or column.xxxxx
- * @param string $table - name of table to look up value in
- * @return array - array of results (empty array on failure)
- *
- * Example - Getting the related objects
- *
- * $person = new DataObjects_Person;
- * $person->get(12);
- * $children = $person->getLinkArray('children');
- *
- * echo 'There are ', count($children), ' descendant(s):<br />';
- * foreach ($children as $child) {
- * echo $child->name, '<br />';
- * }
- *
- */
- public function getLinkArray($row, $table = null)
- {
- require_once 'DB/DataObject/Links.php';
- $l = new DB_DataObject_Links($this);
- return $l->getLinkArray($row, $table === null ? false: $table);
- }
+ // if there is no link data at all on the file!
+ // we return null.
+ if ($lcfg[$this->_database] === false) {
+ return null;
+ }
- /**
- * unionAdd - adds another dataobject to this, building a unioned query.
- *
- * usage:
- * $doTable1 = DB_DataObject::factory("table1");
- * $doTable2 = DB_DataObject::factory("table2");
- *
- * $doTable1->selectAdd();
- * $doTable1->selectAdd("col1,col2");
- * $doTable1->whereAdd("col1 > 100");
- * $doTable1->orderBy("col1");
- *
- * $doTable2->selectAdd();
- * $doTable2->selectAdd("col1, col2");
- * $doTable2->whereAdd("col2 = 'v'");
- *
- * $doTable1->unionAdd($doTable2);
- * $doTable1->find();
- *
- * Note: this model may be a better way to implement joinAdd?, eg. do the building in find?
- *
- *
- * @param $obj object|false the union object or false to reset
- * @param optional $is_all string 'ALL' to do all.
- * @returns $obj object|array the added object, or old list if reset.
- */
-
- public function unionAdd($obj, $is_all= '')
- {
- if ($obj === false) {
- $ret = $this->_query['unions'];
- $this->_query['unions'] = array();
- return $ret;
+ if (isset($lcfg[$this->_database][$this->tableName()])) {
+ return $lcfg[$this->_database][$this->tableName()];
}
- $this->_query['unions'][] = array($obj, 'UNION ' . $is_all . ' ') ;
- return $obj;
- }
-
-
- /**
- * The JOIN condition
- *
- * @access private
- * @var string
- */
- public $_join = '';
+ return array();
+ }
/**
* joinAdd - adds another dataobject to this, building a joined query.
* }
*
*
- * @param optional $obj object |array the joining object (no value resets the join)
+ * @param bool $obj object |array the joining object (no value resets the join)
* If you use an array here it should be in the format:
* array('local_column','remotetable:remote_column');
* if remotetable does not have a definition, you should
* array('local_column', $dataobject , 'remote_column');
* if array has 3 args, then second is assumed to be the linked dataobject.
*
- * @param optional $joinType string | array
+ * @param string $joinType string | array
* 'LEFT'|'INNER'|'RIGHT'|'' Inner is default, '' indicates
* just select ... from a,b,c with no join and
* links are added as where items.
* 'joinCol' => ....
* 'useWhereAsOn' => false,
*
- * @param optional $joinAs string if you want to select the table as anther name
+ * @param bool $joinAs string if you want to select the table as anther name
* useful when you want to select multiple columsn
* from a secondary table.
-
- * @param optional $joinCol string The column on This objects table to match (needed
+ * @param bool $joinCol string The column on This objects table to match (needed
* if this table links to the child object in
* multiple places eg.
* user->friend (is a link to another user)
* into ON arguments.
*
*
- * @return none
+ * @return error|none
* @access public
* @author Stijn de Reede <sjr@gmx.co.uk>
*/
- public function joinAdd($obj = false, $joinType='INNER', $joinAs=false, $joinCol=false)
+ public function joinAdd($obj = false, $joinType = 'INNER', $joinAs = false, $joinCol = false)
{
global $_DB_DATAOBJECT;
if ($obj === false) {
$this->_join = '';
- return;
+ return null;
}
-
+
//echo '<PRE>'; print_r(func_get_args());
$useWhereAsOn = false;
// support for 2nd argument as an array of options
if (is_array($joinType)) {
// new options can now go in here... (dont forget to document them)
$useWhereAsOn = !empty($joinType['useWhereAsOn']);
- $joinCol = isset($joinType['joinCol']) ? $joinType['joinCol'] : $joinCol;
- $joinAs = isset($joinType['joinAs']) ? $joinType['joinAs'] : $joinAs;
- $joinType = isset($joinType['joinType']) ? $joinType['joinType'] : 'INNER';
+ $joinCol = isset($joinType['joinCol']) ? $joinType['joinCol'] : $joinCol;
+ $joinAs = isset($joinType['joinAs']) ? $joinType['joinAs'] : $joinAs;
+ $joinType = isset($joinType['joinType']) ? $joinType['joinType'] : 'INNER';
}
// support for array as first argument
// this assumes that you dont have a links.ini for the specified table.
// and it doesnt exist as am extended dataobject!! - experimental.
-
+
$ofield = false; // object field
$tfield = false; // this field
$toTable = false;
if (is_array($obj)) {
$tfield = $obj[0];
-
+
if (count($obj) == 3) {
$ofield = $obj[2];
$obj = $obj[1];
} else {
list($toTable, $ofield) = explode(':', $obj[1]);
-
+
$obj = is_string($toTable) ? DB_DataObject::factory($toTable) : $toTable;
-
+
if (!$obj || !is_object($obj) || is_a($obj, 'PEAR_Error')) {
$obj = new DB_DataObject;
$obj->__table = $toTable;
// things in the child table...???
$items = array();
}
-
+
if (!is_object($obj) || !is_a($obj, 'DB_DataObject')) {
return $this->raiseError("joinAdd: called without an object", DB_DATAOBJECT_ERROR_NODATA, PEAR_ERROR_DIE);
}
/* make sure $this->_database is set. */
$this->_connect();
$DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
-
+
/// CHANGED 26 JUN 2009 - we prefer links from our local table over the remote one.
-
+
/* otherwise see if there are any links from this table to the obj. */
//print_r($this->links());
if (($ofield === false) && ($links = $this->links())) {
// link contains this_column = linked_table:linked_column
foreach ($links as $k => $linkVar) {
if (!is_array($linkVar)) {
- $linkVar = array($linkVar);
+ $linkVar = array($linkVar);
}
foreach ($linkVar as $v) {
-
-
+
/* link contains {this column} = {linked table}:{linked column} */
$ar = explode(':', $v);
// Feature Request #4266 - Allow joins with multiple keys
foreach ($olinks as $k => $linkVar) {
/* link contains {this column} = array ( {linked table}:{linked column} )*/
if (!is_array($linkVar)) {
- $linkVar = array($linkVar);
+ $linkVar = array($linkVar);
}
foreach ($linkVar as $v) {
-
+
/* link contains {this column} = {linked table}:{linked column} */
$ar = explode(':', $v);
-
+
// Feature Request #4266 - Allow joins with multiple keys
$links_key_array = strpos($k, ',');
if ($links_key_array !== false) {
$k = explode(',', $k);
}
-
+
$ar_array = strpos($ar[1], ',');
if ($ar_array !== false) {
$ar[1] = explode(',', $ar[1]);
}
-
+
if ($ar[0] != $this->tableName()) {
continue;
}
-
+
// you have explictly specified the column
// and the col is listed here..
// not sure if 1:1 table could cause probs here..
-
+
if ($joinCol !== false) {
$this->raiseError(
"joinAdd: You cannot target a join column in the " .
"'link from' table ({$obj->tableName()}). " .
- "Either remove the fourth argument to joinAdd() ".
+ "Either remove the fourth argument to joinAdd() " .
"({$joinCol}), or alter your links.ini file.",
DB_DATAOBJECT_ERROR_NODATA
);
return false;
}
-
+
$ofield = $k;
$tfield = $ar[1];
break;
return false;
}
$joinType = strtoupper($joinType);
-
+
// we default to joining as the same name (this is remvoed later..)
-
+
if ($joinAs === false) {
$joinAs = $obj->tableName();
}
-
+
$quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
$options = $_DB_DATAOBJECT['CONFIG'];
-
+
// not sure how portable adding database prefixes is..
$objTable = $quoteIdentifiers ?
- $DB->quoteIdentifier($obj->tableName()) :
- $obj->tableName() ;
-
- $dbPrefix = '';
- if (strlen($obj->_database) && in_array($DB->dsn['phptype'], array('mysql','mysqli'))) {
+ $DB->quoteIdentifier($obj->tableName()) :
+ $obj->tableName();
+
+ $dbPrefix = '';
+ if (strlen($obj->_database) && in_array($DB->dsn['phptype'], array('mysql', 'mysqli'))) {
$dbPrefix = ($quoteIdentifiers
- ? $DB->quoteIdentifier($obj->_database)
- : $obj->_database) . '.';
+ ? $DB->quoteIdentifier($obj->_database)
+ : $obj->_database) . '.';
}
-
+
// if they are the same, then dont add a prefix...
if ($obj->_database == $this->_database) {
$dbPrefix = '';
// as far as we know only mysql supports database prefixes..
// prefixing the database name is now the default behaviour,
// as it enables joining mutiple columns from multiple databases...
-
+
// prefix database (quoted if neccessary..)
$objTable = $dbPrefix . $objTable;
-
+
$cond = '';
// if obj only a dataobject - eg. no extended class has been defined..
// until we get on the fly querying of tables..
// note: we have already checked that it is_a(db_dataobject earlier)
if (strtolower(get_class($obj)) != 'db_dataobject') {
-
+
// now add where conditions for anything that is set in the object
-
-
-
+
+
$items = $obj->table();
// will return an array if no items..
-
+
// only fail if we where expecting it to work (eg. not joined on a array)
-
+
if (!$items) {
$this->raiseError(
"joinAdd: No table definition for {$obj->tableName()}",
);
return false;
}
-
+
$ignore_null = !isset($options['disable_null_strings'])
- || !is_string($options['disable_null_strings'])
- || strtolower($options['disable_null_strings']) !== 'full' ;
-
+ || !is_string($options['disable_null_strings'])
+ || strtolower($options['disable_null_strings']) !== 'full';
+
foreach ($items as $k => $v) {
if (!isset($obj->$k) && $ignore_null) {
continue;
}
-
+
$kSql = ($quoteIdentifiers ? $DB->quoteIdentifier($k) : $k);
-
+
if (DB_DataObject::_is_null($obj, $k)) {
$obj->whereAdd("{$joinAs}.{$kSql} IS NULL");
continue;
}
-
+
if ($v & DB_DATAOBJECT_STR) {
- $obj->whereAdd("{$joinAs}.{$kSql} = " . $this->_quote((string) (
+ $obj->whereAdd("{$joinAs}.{$kSql} = " . $this->_quote((string)(
($v & DB_DATAOBJECT_BOOL) ?
- // this is thanks to the braindead idea of postgres to
- // use t/f for boolean.
- (($obj->$k === 'f') ? 0 : (int)(bool) $obj->$k) :
- $obj->$k
+ // this is thanks to the braindead idea of postgres to
+ // use t/f for boolean.
+ (($obj->$k === 'f') ? 0 : (int)(bool)$obj->$k) :
+ $obj->$k
)));
continue;
}
$obj->whereAdd("{$joinAs}.{$kSql} = {$obj->$k}");
continue;
}
-
+
if (is_object($obj->$k) && is_a($obj->$k, 'DB_DataObject_Cast')) {
$value = $obj->$k->toString($v, $DB);
- if (PEAR::isError($value)) {
+ if ((new PEAR)->isError($value)) {
$this->raiseError($value->getMessage(), DB_DATAOBJECT_ERROR_INVALIDARG);
return false;
}
$obj->whereAdd("{$joinAs}.{$kSql} = $value");
continue;
}
-
-
+
+
/* this is probably an error condition! */
$obj->whereAdd("{$joinAs}.{$kSql} = 0");
}
$this->whereAdd($cond);
}
}
-
-
-
-
+
+
// nested (join of joined objects..)
$appendJoin = '';
if ($obj->_join) {
$appendJoin = $obj->_join;
}
}
-
-
+
+
// fix for #2216
// add the joinee object's conditions to the ON clause instead of the WHERE clause
if ($useWhereAsOn && strlen($cond)) {
$appendJoin = ' AND ' . $cond . ' ' . $appendJoin;
}
-
-
-
+
+
$table = $this->tableName();
-
+
if ($quoteIdentifiers) {
- $joinAs = $DB->quoteIdentifier($joinAs);
- $table = $DB->quoteIdentifier($table);
- $ofield = (is_array($ofield)) ? array_map(array($DB, 'quoteIdentifier'), $ofield) : $DB->quoteIdentifier($ofield);
- $tfield = (is_array($tfield)) ? array_map(array($DB, 'quoteIdentifier'), $tfield) : $DB->quoteIdentifier($tfield);
+ $joinAs = $DB->quoteIdentifier($joinAs);
+ $table = $DB->quoteIdentifier($table);
+ $ofield = (is_array($ofield)) ? array_map(array($DB, 'quoteIdentifier'), $ofield) : $DB->quoteIdentifier($ofield);
+ $tfield = (is_array($tfield)) ? array_map(array($DB, 'quoteIdentifier'), $tfield) : $DB->quoteIdentifier($tfield);
}
// add database prefix if they are different databases
-
-
+
+
$fullJoinAs = '';
- $addJoinAs = ($quoteIdentifiers ? $DB->quoteIdentifier($obj->tableName()) : $obj->tableName()) != $joinAs;
+ $addJoinAs = ($quoteIdentifiers ? $DB->quoteIdentifier($obj->tableName()) : $obj->tableName()) != $joinAs;
if ($addJoinAs) {
// join table a AS b - is only supported by a few databases and is probably not needed
// , however since it makes the whole Statement alot clearer we are leaving it in
// for those databases.
- $fullJoinAs = in_array($DB->dsn["phptype"], array('mysql','mysqli','pgsql')) ? "AS {$joinAs}" : $joinAs;
+ $fullJoinAs = in_array($DB->dsn["phptype"], array('mysql', 'mysqli', 'pgsql')) ? "AS {$joinAs}" : $joinAs;
} else {
// if
$joinAs = $dbPrefix . $joinAs;
}
-
-
+
+
switch ($joinType) {
case 'INNER':
case 'LEFT':
case 'RIGHT': // others??? .. cross, left outer, right outer, natural..?
-
+
// Feature Request #4266 - Allow joins with multiple keys
$jadd = "\n {$joinType} JOIN {$objTable} {$fullJoinAs}";
//$this->_join .= "\n {$joinType} JOIN {$objTable} {$fullJoinAs}";
//echo $jadd ."\n";
$this->_join .= $jadd;
break;
-
+
case '': // this is just a standard multitable select..
$this->_join .= "\n , {$objTable} {$fullJoinAs} {$appendJoin}";
$this->whereAdd("{$joinAs}.{$ofield}={$table}.{$tfield}");
}
-
-
+
+
return true;
}
/**
- * autoJoin - using the links.ini file, it builds a query with all the joins
- * usage:
- * $x = DB_DataObject::factory('mytable');
- * $x->autoJoin();
- * $x->get(123);
- * will result in all of the joined data being added to the fetched object..
- *
- * $x = DB_DataObject::factory('mytable');
- * $x->autoJoin();
- * $ar = $x->fetchAll();
- * will result in an array containing all the data from the table, and any joined tables..
- *
- * $x = DB_DataObject::factory('mytable');
- * $jdata = $x->autoJoin();
- * $x->selectAdd(); //reset..
- * foreach($_REQUEST['requested_cols'] as $c) {
- * if (!isset($jdata[$c])) continue; // ignore columns not available..
- * $x->selectAdd( $jdata[$c] . ' as ' . $c);
- * }
- * $ar = $x->fetchAll();
- * will result in only the columns requested being fetched...
- *
- *
+ * Adds multiple Columns or objects to select with formating.
*
- * @param array Configuration
- * exclude Array of columns to exclude from results (eg. modified_by_id)
- * links The equivilant links.ini data for this table eg.
- * array( 'person_id' => 'person:id', .... )
- * include Array of columns to include
- * distinct Array of distinct columns.
+ * $object->selectAs(null); // adds "table.colnameA as colnameA,table.colnameB as colnameB,......"
+ * // note with null it will also clear the '*' default select
+ * $object->selectAs(array('a','b'),'%s_x'); // adds "a as a_x, b as b_x"
+ * $object->selectAs(array('a','b'),'ddd_%s','ccc'); // adds "ccc.a as ddd_a, ccc.b as ddd_b"
+ * $object->selectAdd($object,'prefix_%s'); // calls $object->get_table and adds it all as
+ * objectTableName.colnameA as prefix_colnameA
*
- * @return array info about joins
- * cols => map of resulting {joined_tablename}.{joined_table_column_name}
- * join_names => map of resulting {join_name_as}.{joined_table_column_name}
- * count => the column to count on.
- * @access public
+ * @param array|object|null the array or object to take column names from.
+ * @param string $format
+ * @param bool $tableName
+ * @return bool|void
+ * @access public
*/
- public function autoJoin($cfg = array())
+ public function selectAs($from = null, $format = '%s', $tableName = false)
{
global $_DB_DATAOBJECT;
- //var_Dump($cfg);exit;
- $pre_links = $this->links();
- if (!empty($cfg['links'])) {
- $this->links(array_merge($pre_links, $cfg['links']));
- }
- $map = $this->links();
-
- $this->databaseStructure();
- $dbstructure = $_DB_DATAOBJECT['INI'][$this->_database];
- //print_r($map);
- $tabdef = $this->table();
-
- // we need this as normally it's only cleared by an empty selectAs call.
-
-
- $keys = array_keys($tabdef);
- if (!empty($cfg['exclude'])) {
- $keys = array_intersect($keys, array_diff($keys, $cfg['exclude']));
- }
- if (!empty($cfg['include'])) {
- $keys = array_intersect($keys, $cfg['include']);
- }
-
- $selectAs = array();
-
- if (!empty($keys)) {
- $selectAs = array(array( $keys , '%s', false));
- }
-
- $ret = array(
- 'cols' => array(),
- 'join_names' => array(),
- 'count' => false,
- );
-
-
-
- $has_distinct = false;
- if (!empty($cfg['distinct']) && $keys) {
-
- // reset the columsn?
- $cols = array();
-
- //echo '<PRE>' ;print_r($xx);exit;
- foreach ($keys as $c) {
- //var_dump($c);
-
- if ($cfg['distinct'] == $c) {
- $has_distinct = 'DISTINCT( ' . $this->tableName() .'.'. $c .') as ' . $c;
- $ret['count'] = 'DISTINCT ' . $this->tableName() .'.'. $c .'';
- continue;
- }
- // cols is in our filtered keys...
- $cols = $c;
- }
- // apply our filtered version, which excludes the distinct column.
-
- $selectAs = empty($cols) ? array() : array(array(array( $cols) , '%s', false)) ;
- }
-
- foreach ($keys as $k) {
- $ret['cols'][$k] = $this->tableName(). '.' . $k;
- }
-
-
-
- foreach ($map as $ocl=>$info) {
- list($tab, $col) = explode(':', $info);
- // what about multiple joins on the same table!!!
-
- // if links point to a table that does not exist - ignore.
- if (!isset($dbstructure[$tab])) {
- continue;
- }
-
- $xx = DB_DataObject::factory($tab);
- if (!is_object($xx) || !is_a($xx, 'DB_DataObject')) {
- continue;
- }
- // skip columns that are excluded.
-
- // we ignore include here... - as
-
- // this is borked ... for multiple jions..
- $this->joinAdd($xx, 'LEFT', 'join_'.$ocl.'_'. $col, $ocl);
-
- if (!empty($cfg['exclude']) && in_array($ocl, $cfg['exclude'])) {
- continue;
- }
-
- $tabdef = $xx->table();
- $table = $xx->tableName();
-
- $keys = array_keys($tabdef);
-
-
- if (!empty($cfg['exclude'])) {
- $keys = array_intersect($keys, array_diff($keys, $cfg['exclude']));
-
- foreach ($keys as $k) {
- if (in_array($ocl.'_'.$k, $cfg['exclude'])) {
- $keys = array_diff($keys, $k); // removes the k..
- }
- }
- }
-
- if (!empty($cfg['include'])) {
- // include will basically be BASECOLNAME_joinedcolname
- $nkeys = array();
- foreach ($keys as $k) {
- if (in_array(sprintf($ocl.'_%s', $k), $cfg['include'])) {
- $nkeys[] = $k;
- }
- }
- $keys = $nkeys;
- }
-
- if (empty($keys)) {
- continue;
- }
- // got distinct, and not yet found it..
- if (!$has_distinct && !empty($cfg['distinct'])) {
- $cols = array();
- foreach ($keys as $c) {
- $tn = sprintf($ocl.'_%s', $c);
-
- if ($tn == $cfg['distinct']) {
- $has_distinct = 'DISTINCT( ' . 'join_'.$ocl.'_'.$col.'.'.$c .') as ' . $tn ;
- $ret['count'] = 'DISTINCT join_'.$ocl.'_'.$col.'.'.$c;
- // var_dump($this->countWhat );
- continue;
- }
- $cols[] = $c;
- }
-
- if (!empty($cols)) {
- $selectAs[] = array($cols, $ocl.'_%s', 'join_'.$ocl.'_'. $col);
- }
- } else {
- $selectAs[] = array($keys, $ocl.'_%s', 'join_'.$ocl.'_'. $col);
- }
-
- foreach ($keys as $k) {
- $ret['cols'][sprintf('%s_%s', $ocl, $k)] = $tab.'.'.$k;
- $ret['join_names'][sprintf('%s_%s', $ocl, $k)] = sprintf('join_%s_%s.%s', $ocl, $col, $k);
- }
+
+ if ($this->_query === false) {
+ $this->raiseError(
+ "You cannot do two queries on the same object (copy it before finding)",
+ DB_DATAOBJECT_ERROR_INVALIDARGS
+ );
+ return false;
}
-
- // fill in the select details..
- $this->selectAdd();
-
- if ($has_distinct) {
- $this->selectAdd($has_distinct);
+
+ if ($from === null) {
+ // blank the '*'
+ $this->selectAdd();
+ $from = $this;
}
-
- foreach ($selectAs as $ar) {
- $this->selectAs($ar[0], $ar[1], $ar[2]);
+
+
+ $table = $this->tableName();
+ if (is_object($from)) {
+ $table = $from->tableName();
+ $from = array_keys($from->table());
}
- // restore links..
- $this->links($pre_links);
-
- return $ret;
+
+ if ($tableName !== false) {
+ $table = $tableName;
+ }
+ $s = '%s';
+ if (!empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers'])) {
+ $this->_connect();
+ $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+ $s = $DB->quoteIdentifier($s);
+ $format = $DB->quoteIdentifier($format);
+ }
+ foreach ($from as $k) {
+ $this->selectAdd(sprintf("{$s}.{$s} as {$format}", $table, $k, $k));
+ }
+ $this->_query['data_select'] .= "\n";
}
-
+
/**
* Factory method for calling DB_DataObject_Cast
*
*
*
* @param string $value (or type if used with 2 arguments)
- * @param string $callvalue (optional) used with date/null etc..
+ * @return mixed
*/
-
+
public function sqlValue($value)
{
$method = 'sql';
$method = $value;
$value = func_get_arg(1);
}
- require_once 'DB/DataObject/Cast.php';
+ //require_once 'DB/DataObject/Cast.php';
+ require_once 'Cast.php';
return call_user_func(array('DB_DataObject_Cast', $method), $value);
}
-
-
+
+
+ /* ----------------------- Debugger ------------------ */
+
/**
* Copies items that are in the table definitions from an
* array or object into the current object
* will not override key values.
*
*
- * @param array | object $from
- * @param string $format eg. map xxxx_name to $object->name using 'xxxx_%s' (defaults to %s - eg. name -> $object->name
- * @param boolean $skipEmpty (dont assign empty values if a column is empty (eg. '' / 0 etc...)
+ * @param array | object $from
+ * @param string $format eg. map xxxx_name to $object->name using 'xxxx_%s' (defaults to %s - eg. name -> $object->name
+ * @param boolean $skipEmpty (dont assign empty values if a column is empty (eg. '' / 0 etc...)
* @access public
- * @return true on success or array of key=>setValue error message
+ * @return array|true
*/
- public function setFrom($from, $format = '%s', $skipEmpty=false)
+ public function setFrom($from, $format = '%s', $skipEmpty = false)
{
global $_DB_DATAOBJECT;
- $keys = $this->keys();
+ $keys = $this->keys();
$items = $this->table();
-
+
if (!$items) {
$this->raiseError(
"setFrom:Could not find table definition for {$this->tableName()}",
DB_DATAOBJECT_ERROR_INVALIDCONFIG
);
- return;
+ return null;
}
$overload_return = array();
foreach (array_keys($items) as $k) {
if (!$k) {
continue; // ignore empty keys!!! what
}
-
+
$chk = is_object($from) &&
(
- version_compare(phpversion(), "5.1.0", ">=") ?
+ version_compare(phpversion(), "5.1.0", ">=") ?
property_exists($from, sprintf($format, $k)) : // php5.1
array_key_exists(sprintf($format, $k), get_class_vars($from)) //older
);
// if from has property ($format($k)
if ($chk) {
$kk = (strtolower($k) == 'from') ? '_from' : $k;
- if (method_exists($this, 'set'.$kk)) {
- $ret = $this->{'set'.$kk}($from->{sprintf($format, $k)});
+ if (method_exists($this, 'set' . $kk)) {
+ $ret = $this->{'set' . $kk}($from->{sprintf($format, $k)});
if (is_string($ret)) {
$overload_return[$k] = $ret;
}
$this->$k = $from->{sprintf($format, $k)};
continue;
}
-
+
if (is_object($from)) {
continue;
}
-
+
if (empty($from[sprintf($format, $k)]) && $skipEmpty) {
continue;
}
-
+
if (!isset($from[sprintf($format, $k)]) && !DB_DataObject::_is_null($from, sprintf($format, $k))) {
continue;
}
-
+
$kk = (strtolower($k) == 'from') ? '_from' : $k;
- if (method_exists($this, 'set'. $kk)) {
- $ret = $this->{'set'.$kk}($from[sprintf($format, $k)]);
+ if (method_exists($this, 'set' . $kk)) {
+ $ret = $this->{'set' . $kk}($from[sprintf($format, $k)]);
if (is_string($ret)) {
$overload_return[$k] = $ret;
}
return true;
}
+ /**
+ * standard set* implementation.
+ *
+ * takes data and uses it to set dates/strings etc.
+ * normally called from __call..
+ *
+ * Current supports
+ * date = using (standard time format, or unixtimestamp).... so you could create a method :
+ * function setLastread($string) { $this->fromValue('lastread',strtotime($string)); }
+ *
+ * time = using strtotime
+ * datetime = using same as date - accepts iso standard or unixtimestamp.
+ * string = typecast only..
+ *
+ * TODO: add formater:: eg. d/m/Y for date! ???
+ *
+ * @param string column of database
+ * @param mixed value to assign
+ *
+ * @return true| false (False on error)
+ * @access public
+ * @see DB_DataObject::_call
+ */
+
+
+ public function fromValue($col, $value)
+ {
+ global $_DB_DATAOBJECT;
+ $options = $_DB_DATAOBJECT['CONFIG'];
+ $cols = $this->table();
+ // dont know anything about this col..
+ if (!isset($cols[$col]) || is_a($value, 'DB_DataObject_Cast')) {
+ $this->$col = $value;
+ return true;
+ }
+ //echo "FROM VALUE $col, {$cols[$col]}, $value\n";
+ switch (true) {
+ // set to null and column is can be null...
+ case ((!($cols[$col] & DB_DATAOBJECT_NOTNULL)) && DB_DataObject::_is_null($value, false)):
+ case (is_object($value) && is_a($value, 'DB_DataObject_Cast')):
+ $this->$col = $value;
+ return true;
+
+ // fail on setting null on a not null field..
+ case (($cols[$col] & DB_DATAOBJECT_NOTNULL) && DB_DataObject::_is_null($value, false)):
+
+ return false;
+
+ case (($cols[$col] & DB_DATAOBJECT_DATE) && ($cols[$col] & DB_DATAOBJECT_TIME)):
+ // empty values get set to '' (which is inserted/updated as NULl
+ if (!$value) {
+ $this->$col = '';
+ }
+
+ if (is_numeric($value)) {
+ $this->$col = date('Y-m-d H:i:s', $value);
+ return true;
+ }
+
+ // eak... - no way to validate date time otherwise...
+ $this->$col = (string)$value;
+ return true;
+
+ case ($cols[$col] & DB_DATAOBJECT_DATE):
+ // empty values get set to '' (which is inserted/updated as NULl
+
+ if (!$value) {
+ $this->$col = '';
+ return true;
+ }
+
+ if (is_numeric($value)) {
+ $this->$col = date('Y-m-d', $value);
+ return true;
+ }
+
+ // try date!!!!
+ require_once 'Date.php';
+ $x = new Date($value);
+ $this->$col = $x->format("%Y-%m-%d");
+ return true;
+
+ case ($cols[$col] & DB_DATAOBJECT_TIME):
+ // empty values get set to '' (which is inserted/updated as NULl
+ if (!$value) {
+ $this->$col = '';
+ }
+
+ $guess = strtotime($value);
+ if ($guess != -1) {
+ $this->$col = date('H:i:s', $guess);
+ return $return = true;
+ }
+ // otherwise an error in type...
+ return false;
+
+ case ($cols[$col] & DB_DATAOBJECT_STR):
+
+ $this->$col = (string)$value;
+ return true;
+
+ // todo : floats numerics and ints...
+ default:
+ $this->$col = $value;
+ return true;
+ }
+ }
+
/**
* Returns an associative array from the current data
* (kind of oblivates the idea behind DataObjects, but
*
* will also return links converted to arrays.
*
- * @param string sprintf format for array
- * @param bool||number [true = elemnts that have a value set],
+ * @param string sprintf format for array
+ * @param bool||number [true = elemnts that have a value set],
* [false = table + returned colums] ,
* [0 = returned columsn only]
*
public function toArray($format = '%s', $hideEmpty = false)
{
global $_DB_DATAOBJECT;
-
+
// we use false to ignore sprintf.. (speed up..)
$format = $format == '%s' ? false : $format;
-
+
$ret = array();
$rf = ($this->_resultFields !== false) ? $this->_resultFields :
- (isset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid]) ?
- $_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid] : false);
-
+ (isset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid]) ?
+ $_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid] : false);
+
$ar = ($rf !== false) ?
(($hideEmpty === 0) ? $rf : array_merge($rf, $this->table())) :
$this->table();
- foreach ($ar as $k=>$v) {
+ foreach ($ar as $k => $v) {
if (!isset($this->$k)) {
if (!$hideEmpty) {
$ret[$format === false ? $k : sprintf($format, $k)] = '';
continue;
}
// call the overloaded getXXXX() method. - except getLink and getLinks
- if (method_exists($this, 'get'.$k) && !in_array(strtolower($k), array('links','link'))) {
- $ret[$format === false ? $k : sprintf($format, $k)] = $this->{'get'.$k}();
+ if (method_exists($this, 'get' . $k) && !in_array(strtolower($k), array('links', 'link'))) {
+ $ret[$format === false ? $k : sprintf($format, $k)] = $this->{'get' . $k}();
continue;
}
// should this call toValue() ???
foreach ($this->_link_loaded as $k) {
$ret[$format === false ? $k : sprintf($format, $k)] = $this->$k->toArray();
}
-
+
return $ret;
}
*
*
* @access public
- * @return array of validation results (where key=>value, value=false|object if it failed) or true (if they all succeeded)
+ * @return array|bool
*/
public function validate()
{
global $_DB_DATAOBJECT;
require_once 'Validate.php';
$table = $this->table();
- $ret = array();
- $seq = $this->sequenceKey();
+ $ret = array();
+ $seq = $this->sequenceKey();
$options = $_DB_DATAOBJECT['CONFIG'];
foreach ($table as $key => $val) {
-
-
+
+
// call user defined validation always...
$method = "Validate" . ucfirst($key);
if (method_exists($this, $method)) {
$ret[$key] = $this->$method();
continue;
}
-
+
// if not null - and it's not set.......
-
+
if ($val & DB_DATAOBJECT_NOTNULL && DB_DataObject::_is_null($this, $key)) {
// dont check empty sequence key values..
if (($key == $seq[0]) && ($seq[1] == true)) {
$ret[$key] = false;
continue;
}
-
-
+
+
if (DB_DataObject::_is_null($this, $key)) {
if ($val & DB_DATAOBJECT_NOTNULL) {
$this->debug("'null' field used for '$key', but it is defined as NOT NULL", 'VALIDATION', 4);
}
// ignore things that are not set. ?
-
+
if (!isset($this->$key)) {
continue;
}
-
+
// if the string is empty.. assume it is ok..
- if (!is_object($this->$key) && !is_array($this->$key) && !strlen((string) $this->$key)) {
+ if (!is_object($this->$key) && !is_array($this->$key) && !strlen((string)$this->$key)) {
continue;
}
-
+
// dont try and validate cast objects - assume they are problably ok..
if (is_object($this->$key) && is_a($this->$key, 'DB_DataObject_Cast')) {
continue;
// at this point if you have set something to an object, and it's not expected
// the Validate will probably break!!... - rightly so! (your design is broken,
// so issuing a runtime error like PEAR_Error is probably not appropriate..
-
+
switch (true) {
// todo: date time.....
case ($val & DB_DATAOBJECT_STR):
- $ret[$key] = Validate::string($this->$key, VALIDATE_PUNCTUATION . VALIDATE_NAME);
+ $ret[$key] = (new Validate)->string($this->$key, VALIDATE_PUNCTUATION . VALIDATE_NAME);
break;
case ($val & DB_DATAOBJECT_INT):
- $ret[$key] = Validate::number($this->$key, array('decimal'=>'.'));
+ $ret[$key] = (new Validate)->number($this->$key, array('decimal' => '.'));
break;
}
}
* Gets the DB object related to an object - so you can use funky peardb stuf with it :)
*
* @access public
- * @return object The DB connection
+ * @return bool|object
*/
public function getDatabaseConnection()
{
}
return $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
}
-
-
+
/**
* Gets the DB result object related to the objects active query
* - so you can use funky pear stuff with it - like pager for example.. :)
*
* @access public
- * @return object The DB result object
+ * @return bool|object
*/
-
+
public function getDatabaseResult()
{
global $_DB_DATAOBJECT;
* has problems with 4.3.2RC2 here
*
* @access public
+ * @param $method
+ * @param $params
+ * @param $return
* @return true?
+ * @throws ReflectionException
* @see overload
*/
-
+
public function _call($method, $params, &$return)
{
-
+
//$this->debug("ATTEMPTING OVERLOAD? $method");
// ignore constructors : - mm
if (strtolower($method) == strtolower(get_class($this))) {
if (($type != 'set') && ($type != 'get')) {
return false;
}
-
-
-
+
+
// deal with naming conflick of setFrom = this is messy ATM!
-
+
if (strtolower($method) == 'set_from') {
$return = $this->toValue('from', isset($params[0]) ? $params[0] : null);
- return true;
+ return true;
}
-
+
$element = substr($method, 3);
-
+
// dont you just love php's case insensitivity!!!!
-
- $array = array_keys(get_class_vars($class));
+
+ $array = array_keys(get_class_vars($class));
/* php5 version which segfaults on 5.0.3 */
if (class_exists('ReflectionClass')) {
- $reflection = new ReflectionClass($class);
- $array = array_keys($reflection->getdefaultProperties());
- }
-
- if (!in_array($element, $array)) {
- // munge case
- foreach ($array as $k) {
- $case[strtolower($k)] = $k;
- }
- if ((substr(phpversion(), 0, 1) == 5) && isset($case[strtolower($element)])) {
- trigger_error("PHP5 set/get calls should match the case of the variable", E_USER_WARNING);
- $element = strtolower($element);
- }
-
- // does it really exist?
- if (!isset($case[$element])) {
- return false;
- }
- // use the mundged case
- $element = $case[$element]; // real case !
- }
-
-
- if ($type == 'get') {
- $return = $this->toValue($element, isset($params[0]) ? $params[0] : null);
- return true;
- }
-
-
- $return = $this->fromValue($element, $params[0]);
-
- return true;
- }
-
-
- /**
- * standard set* implementation.
- *
- * takes data and uses it to set dates/strings etc.
- * normally called from __call..
- *
- * Current supports
- * date = using (standard time format, or unixtimestamp).... so you could create a method :
- * function setLastread($string) { $this->fromValue('lastread',strtotime($string)); }
- *
- * time = using strtotime
- * datetime = using same as date - accepts iso standard or unixtimestamp.
- * string = typecast only..
- *
- * TODO: add formater:: eg. d/m/Y for date! ???
- *
- * @param string column of database
- * @param mixed value to assign
- *
- * @return true| false (False on error)
- * @access public
- * @see DB_DataObject::_call
- */
-
-
- public function fromValue($col, $value)
- {
- global $_DB_DATAOBJECT;
- $options = $_DB_DATAOBJECT['CONFIG'];
- $cols = $this->table();
- // dont know anything about this col..
- if (!isset($cols[$col]) || is_a($value, 'DB_DataObject_Cast')) {
- $this->$col = $value;
- return true;
- }
- //echo "FROM VALUE $col, {$cols[$col]}, $value\n";
- switch (true) {
- // set to null and column is can be null...
- case ((!($cols[$col] & DB_DATAOBJECT_NOTNULL)) && DB_DataObject::_is_null($value, false)):
- case (is_object($value) && is_a($value, 'DB_DataObject_Cast')):
- $this->$col = $value;
- return true;
-
- // fail on setting null on a not null field..
- case (($cols[$col] & DB_DATAOBJECT_NOTNULL) && DB_DataObject::_is_null($value, false)):
-
- return false;
-
- case (($cols[$col] & DB_DATAOBJECT_DATE) && ($cols[$col] & DB_DATAOBJECT_TIME)):
- // empty values get set to '' (which is inserted/updated as NULl
- if (!$value) {
- $this->$col = '';
- }
-
- if (is_numeric($value)) {
- $this->$col = date('Y-m-d H:i:s', $value);
- return true;
- }
-
- // eak... - no way to validate date time otherwise...
- $this->$col = (string) $value;
- return true;
-
- case ($cols[$col] & DB_DATAOBJECT_DATE):
- // empty values get set to '' (which is inserted/updated as NULl
-
- if (!$value) {
- $this->$col = '';
- return true;
- }
-
- if (is_numeric($value)) {
- $this->$col = date('Y-m-d', $value);
- return true;
- }
-
- // try date!!!!
- require_once 'Date.php';
- $x = new Date($value);
- $this->$col = $x->format("%Y-%m-%d");
- return true;
-
- case ($cols[$col] & DB_DATAOBJECT_TIME):
- // empty values get set to '' (which is inserted/updated as NULl
- if (!$value) {
- $this->$col = '';
- }
-
- $guess = strtotime($value);
- if ($guess != -1) {
- $this->$col = date('H:i:s', $guess);
- return $return = true;
- }
- // otherwise an error in type...
+ $reflection = new ReflectionClass($class);
+ $array = array_keys($reflection->getdefaultProperties());
+ }
+
+ if (!in_array($element, $array)) {
+ // munge case
+ foreach ($array as $k) {
+ $case[strtolower($k)] = $k;
+ }
+ if ((substr(phpversion(), 0, 1) == 5) && isset($case[strtolower($element)])) {
+ trigger_error("PHP5 set/get calls should match the case of the variable", E_USER_WARNING);
+ $element = strtolower($element);
+ }
+
+ // does it really exist?
+ if (!isset($case[$element])) {
return false;
-
- case ($cols[$col] & DB_DATAOBJECT_STR):
-
- $this->$col = (string) $value;
- return true;
-
- // todo : floats numerics and ints...
- default:
- $this->$col = $value;
- return true;
+ }
+ // use the mundged case
+ $element = $case[$element]; // real case !
+ }
+
+
+ if ($type == 'get') {
+ $return = $this->toValue($element, isset($params[0]) ? $params[0] : null);
+ return true;
}
+
+
+ $return = $this->fromValue($element, $params[0]);
+
+ return true;
}
+
/**
- * standard get* implementation.
- *
- * with formaters..
- * supported formaters:
- * date/time : %d/%m/%Y (eg. php strftime) or pear::Date
- * numbers : %02d (eg. sprintf)
- * NOTE you will get unexpected results with times like 0000-00-00 !!!
- *
- *
- *
- * @param string column of database
- * @param format foramt
- *
- * @return true Description
- * @access public
- * @see DB_DataObject::_call(),strftime(),Date::format()
- */
+ * standard get* implementation.
+ *
+ * with formaters..
+ * supported formaters:
+ * date/time : %d/%m/%Y (eg. php strftime) or pear::Date
+ * numbers : %02d (eg. sprintf)
+ * NOTE you will get unexpected results with times like 0000-00-00 !!!
+ *
+ *
+ *
+ * @param string column of database
+ * @param format foramt
+ *
+ * @return string|true
+ * @access public
+ * @see DB_DataObject::_call(),strftime(),Date::format()
+ */
public function toValue($col, $format = null)
{
if (is_null($format)) {
}
$cols = $this->table();
switch (true) {
- case (($cols[$col] & DB_DATAOBJECT_DATE) && ($cols[$col] & DB_DATAOBJECT_TIME)):
+ case (($cols[$col] & DB_DATAOBJECT_DATE) && ($cols[$col] & DB_DATAOBJECT_TIME)):
if (!$this->$col) {
return '';
}
require_once 'Date.php';
$x = new Date($this->$col);
return $x->format($format);
-
+
case ($cols[$col] & DB_DATAOBJECT_TIME):
if (!$this->$col) {
return '';
}
// otherwise an error in type...
return $this->$col;
-
- case ($cols[$col] & DB_DATAOBJECT_MYSQLTIMESTAMP):
+
+ case ($cols[$col] & DB_DATAOBJECT_MYSQLTIMESTAMP):
if (!$this->$col) {
return '';
}
require_once 'Date.php';
-
- $x = new Date($this->$col);
-
- return $x->format($format);
-
-
- case ($cols[$col] & DB_DATAOBJECT_BOOL):
-
- if ($cols[$col] & DB_DATAOBJECT_STR) {
- // it's a 't'/'f' !
- return ($this->$col === 't');
- }
- return (bool) $this->$col;
-
-
- default:
- return sprintf($format, $this->col);
- }
- }
-
-
- /* ----------------------- Debugger ------------------ */
-
- /**
- * Debugger. - use this in your extended classes to output debugging information.
- *
- * Uses DB_DataObject::DebugLevel(x) to turn it on
- *
- * @param string $message - message to output
- * @param string $logtype - bold at start
- * @param string $level - output level
- * @access public
- * @return none
- */
- public function debug($message, $logtype = 0, $level = 1)
- {
- global $_DB_DATAOBJECT;
-
- if (empty($_DB_DATAOBJECT['CONFIG']['debug']) ||
- (is_numeric($_DB_DATAOBJECT['CONFIG']['debug']) && $_DB_DATAOBJECT['CONFIG']['debug'] < $level)) {
- return;
- }
- // this is a bit flaky due to php's wonderfull class passing around crap..
- // but it's about as good as it gets..
- $class = (isset($this) && is_a($this, 'DB_DataObject')) ? get_class($this) : 'DB_DataObject';
-
- if (!is_string($message)) {
- $message = print_r($message, true);
- }
- if (!is_numeric($_DB_DATAOBJECT['CONFIG']['debug']) && is_callable($_DB_DATAOBJECT['CONFIG']['debug'])) {
- return call_user_func($_DB_DATAOBJECT['CONFIG']['debug'], $class, $message, $logtype, $level);
- }
-
- if (!ini_get('html_errors')) {
- echo "$class : $logtype : $message\n";
- flush();
- return;
- }
- if (!is_string($message)) {
- $message = print_r($message, true);
- }
- $colorize = ($logtype == 'ERROR') ? '<font color="red">' : '<font>';
- echo "<code>{$colorize}<B>$class: $logtype:</B> ". nl2br(htmlspecialchars($message)) . "</font></code><BR>\n";
- }
-
- /**
- * sets and returns debug level
- * eg. DB_DataObject::debugLevel(4);
- *
- * @param int $v level
- * @access public
- * @return none
- */
- public static function debugLevel($v = null)
- {
- global $_DB_DATAOBJECT;
- if (empty($_DB_DATAOBJECT['CONFIG'])) {
- DB_DataObject::_loadConfig();
- }
- if ($v !== null) {
- $r = isset($_DB_DATAOBJECT['CONFIG']['debug']) ? $_DB_DATAOBJECT['CONFIG']['debug'] : 0;
- $_DB_DATAOBJECT['CONFIG']['debug'] = $v;
- return $r;
- }
- return isset($_DB_DATAOBJECT['CONFIG']['debug']) ? $_DB_DATAOBJECT['CONFIG']['debug'] : 0;
- }
- /**
- * Last Error that has occured
- * - use $this->_lastError or
- * $last_error = PEAR::getStaticProperty('DB_DataObject','lastError');
- *
- * @access public
- * @var object PEAR_Error (or false)
- */
- public $_lastError = false;
+ $x = new Date($this->$col);
- /**
- * Default error handling is to create a pear error, but never return it.
- * if you need to handle errors you should look at setting the PEAR_Error callback
- * this is due to the fact it would wreck havoc on the internal methods!
- *
- * @param int $message message
- * @param int $type type
- * @param int $behaviour behaviour (die or continue!);
- * @access public
- * @return error object
- */
- public function raiseError($message, $type = null, $behaviour = null)
- {
- global $_DB_DATAOBJECT;
-
- if ($behaviour == PEAR_ERROR_DIE && !empty($_DB_DATAOBJECT['CONFIG']['dont_die'])) {
- $behaviour = null;
- }
-
- $error = &PEAR::getStaticProperty('DB_DataObject', 'lastError');
-
-
- // no checks for production here?....... - we log errors before we throw them.
- DB_DataObject::debug($message, 'ERROR', 1);
-
-
- if (PEAR::isError($message)) {
- $error = $message;
- } else {
- require_once 'DB/DataObject/Error.php';
- $dor = new PEAR();
- $error = $dor->raiseError(
- $message,
- $type,
- $behaviour,
- $opts=null,
- $userinfo=null,
- 'DB_DataObject_Error'
- );
- }
- // this will never work totally with PHP's object model.
- // as this is passed on static calls (like staticGet in our case)
-
- $_DB_DATAOBJECT['LASTERROR'] = $error;
-
- if (isset($this) && is_object($this) && is_subclass_of($this, 'db_dataobject')) {
- $this->_lastError = $error;
- }
-
- return $error;
- }
+ return $x->format($format);
- /**
- * Define the global $_DB_DATAOBJECT['CONFIG'] as an alias to PEAR::getStaticProperty('DB_DataObject','options');
- *
- * After Profiling DB_DataObject, I discoved that the debug calls where taking
- * considerable time (well 0.1 ms), so this should stop those calls happening. as
- * all calls to debug are wrapped with direct variable queries rather than actually calling the funciton
- * THIS STILL NEEDS FURTHER INVESTIGATION
- *
- * @access public
- * @return object an error object
- */
- public function _loadConfig()
- {
- global $_DB_DATAOBJECT;
- $_DB_DATAOBJECT['CONFIG'] = &PEAR::getStaticProperty('DB_DataObject', 'options');
- }
- /**
- * Free global arrays associated with this object.
- *
- *
- * @access public
- * @return none
- */
- public function free()
- {
- global $_DB_DATAOBJECT;
-
- if (isset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid])) {
- unset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid]);
- }
- if (isset($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid])) {
- unset($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]);
- }
- // clear the staticGet cache as well.
- $this->_clear_cache();
- // this is a huge bug in DB!
- if (isset($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) {
- $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->num_rows = array();
- }
+ case ($cols[$col] & DB_DATAOBJECT_BOOL):
- if (is_array($this->_link_loaded)) {
- foreach ($this->_link_loaded as $do) {
- if (
- !empty($this->{$do}) &&
- is_object($this->{$do}) &&
- method_exists($this->{$do}, 'free')
- ) {
- $this->{$do}->free();
+ if ($cols[$col] & DB_DATAOBJECT_STR) {
+ // it's a 't'/'f' !
+ return ($this->$col === 't');
}
- }
- }
- }
- /**
- * Evaluate whether or not a value is set to null, taking the 'disable_null_strings' option into account.
- * If the value is a string set to "null" and the "disable_null_strings" option is not set to
- * true, then the value is considered to be null.
- * If the value is actually a PHP NULL value, and "disable_null_strings" has been set to
- * the value "full", then it will also be considered null. - this can not differenticate between not set
- *
- *
- * @param object|array $obj_or_ar
- * @param string|false $prop prperty
-
- * @access private
- * @return bool object
- */
- public function _is_null($obj_or_ar, $prop)
- {
- global $_DB_DATAOBJECT;
-
-
- $isset = $prop === false ? isset($obj_or_ar) :
- (is_array($obj_or_ar) ? isset($obj_or_ar[$prop]) : isset($obj_or_ar->$prop));
-
- $value = $isset ?
- ($prop === false ? $obj_or_ar :
- (is_array($obj_or_ar) ? $obj_or_ar[$prop] : $obj_or_ar->$prop))
- : null;
-
-
-
- $options = $_DB_DATAOBJECT['CONFIG'];
-
- $null_strings = !isset($options['disable_null_strings'])
- || $options['disable_null_strings'] === false;
-
- $crazy_null = isset($options['disable_null_strings'])
- && is_string($options['disable_null_strings'])
- && strtolower($options['disable_null_strings'] === 'full');
-
- if ($null_strings && $isset && is_string($value) && (strtolower($value) === 'null')) {
- return true;
- }
-
- if ($crazy_null && !$isset) {
- return true;
- }
-
- return false;
- }
-
- /**
- * (deprecated - use ::get / and your own caching method)
- */
- public static function staticGet($class, $k, $v = null)
- {
- $lclass = strtolower($class);
- global $_DB_DATAOBJECT;
- if (empty($_DB_DATAOBJECT['CONFIG'])) {
- DB_DataObject::_loadConfig();
- }
+ return (bool)$this->$col;
-
-
- $key = "$k:$v";
- if ($v === null) {
- $key = $k;
- }
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- DB_DataObject::debug("$class $key", "STATIC GET - TRY CACHE");
- }
- if (!empty($_DB_DATAOBJECT['CACHE'][$lclass][$key])) {
- return $_DB_DATAOBJECT['CACHE'][$lclass][$key];
- }
- if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
- DB_DataObject::debug("$class $key", "STATIC GET - NOT IN CACHE");
- }
- $obj = DB_DataObject::factory(substr($class, strlen($_DB_DATAOBJECT['CONFIG']['class_prefix'])));
- if (PEAR::isError($obj)) {
- $dor = new DB_DataObject();
- $dor->raiseError("could not autoload $class", DB_DATAOBJECT_ERROR_NOCLASS);
- $r = false;
- return $r;
- }
-
- if (!isset($_DB_DATAOBJECT['CACHE'][$lclass])) {
- $_DB_DATAOBJECT['CACHE'][$lclass] = array();
- }
- if (!$obj->get($k, $v)) {
- $dor = new DB_DataObject();
- $dor->raiseError("No Data return from get $k $v", DB_DATAOBJECT_ERROR_NODATA);
-
- $r = false;
- return $r;
+ default:
+ return sprintf($format, $this->col);
}
- $_DB_DATAOBJECT['CACHE'][$lclass][$key] = $obj;
- return $_DB_DATAOBJECT['CACHE'][$lclass][$key];
}
-
+
/**
* autoload Class relating to a table
* (deprecited - use ::factory)
*
- * @param string $table table
+ * @param string $table table
* @access private
* @return string classname on Success
*/
$p = isset($_DB_DATAOBJECT['CONFIG']['class_prefix']) ?
$_DB_DATAOBJECT['CONFIG']['class_prefix'] : '';
$class = $p . preg_replace('/[^A-Z0-9]/i', '_', ucfirst($table));
-
+
$ce = substr(phpversion(), 0, 1) > 4 ? class_exists($class, false) : class_exists($class);
- $class = $ce ? $class : DB_DataObject::_autoloadClass($class);
+ $class = $ce ? $class : DB_DataObject::_autoloadClass($class);
return $class;
}
-
+
/* ---- LEGACY BC METHODS - NOT DOCUMENTED - See Documentation on New Methods. ---*/
-
+
public function _get_table()
{
return $this->table();
}
+
public function _get_keys()
{
return $this->keys();
}
}
+
// technially 4.3.2RC1 was broken!!
// looks like 4.3.3 may have problems too....
if (!defined('DB_DATAOBJECT_NO_OVERLOAD')) {
* @version CVS: $Id: Cast.php 287158 2009-08-12 13:58:31Z alan_k $
* @link http://pear.php.net/package/DB_DataObject
*/
-
+
/**
-*
-* Common usages:
-* // blobs
-* $data = DB_DataObject_Cast::blob($somefile);
-* $data = DB_DataObject_Cast::string($somefile);
-* $dataObject->someblobfield = $data
-*
-* // dates?
-* $d1 = new DB_DataObject_Cast::date('12/12/2000');
-* $d2 = new DB_DataObject_Cast::date(2000,12,30);
-* $d3 = new DB_DataObject_Cast::date($d1->year, $d1->month+30, $d1->day+30);
-*
-* // time, datetime.. ?????????
-*
-* // raw sql????
-* $data = DB_DataObject_Cast::sql('cast("123123",datetime)');
-* $data = DB_DataObject_Cast::sql('NULL');
-*
-* // int's/string etc. are proably pretty pointless..!!!!
-*
-*
-* inside DB_DataObject,
-* if (is_a($v,'db_dataobject_class')) {
-* $value .= $v->toString(DB_DATAOBJECT_INT,'mysql');
-* }
-*
-*
-*
-*
-
-*/
+ *
+ * Common usages:
+ * // blobs
+ * $data = DB_DataObject_Cast::blob($somefile);
+ * $data = DB_DataObject_Cast::string($somefile);
+ * $dataObject->someblobfield = $data
+ *
+ * // dates?
+ * $d1 = new DB_DataObject_Cast::date('12/12/2000');
+ * $d2 = new DB_DataObject_Cast::date(2000,12,30);
+ * $d3 = new DB_DataObject_Cast::date($d1->year, $d1->month+30, $d1->day+30);
+ *
+ * // time, datetime.. ?????????
+ *
+ * // raw sql????
+ * $data = DB_DataObject_Cast::sql('cast("123123",datetime)');
+ * $data = DB_DataObject_Cast::sql('NULL');
+ *
+ * // int's/string etc. are proably pretty pointless..!!!!
+ *
+ *
+ * inside DB_DataObject,
+ * if (is_a($v,'db_dataobject_class')) {
+ * $value .= $v->toString(DB_DATAOBJECT_INT,'mysql');
+ * }
+ *
+ *
+ *
+ *
+
+ */
class DB_DataObject_Cast
{
-
+
/**
- * Type of data Stored in the object..
- *
- * @var string (date|blob|.....?)
- * @access public
- */
+ * Type of data Stored in the object..
+ *
+ * @var string (date|blob|.....?)
+ * @access public
+ */
public $type;
-
+
/**
- * Data For date representation
- *
- * @var int day/month/year
- * @access public
- */
+ * Data For date representation
+ *
+ * @var int day/month/year
+ * @access public
+ */
public $day;
public $month;
public $year;
-
+
/**
- * Generic Data..
- *
- * @var string
- * @access public
- */
+ * Generic Data..
+ *
+ * @var string
+ * @access public
+ */
public $value;
-
-
+ /**
+ * Data For time representation ** does not handle timezones!!
+ *
+ * @var int hour/minute/second
+ * @access public
+ */
+ public $hour;
+ public $minute;
+ public $second;
/**
- * Blob consructor
- *
- * create a Cast object from some raw data.. (binary)
- *
- *
- * @param string (with binary data!)
- *
- * @return object DB_DataObject_Cast
- * @access public
- */
-
+ * Blob consructor
+ *
+ * create a Cast object from some raw data.. (binary)
+ *
+ *
+ * @param string (with binary data!)
+ *
+ * @return object DB_DataObject_Cast
+ * @access public
+ */
+
public function blob($value)
{
$r = new DB_DataObject_Cast;
return $r;
}
-
/**
- * String consructor (actually use if for ints and everything else!!!
- *
- * create a Cast object from some string (not binary)
- *
- *
- * @param string (with binary data!)
- *
- * @return object DB_DataObject_Cast
- * @access public
- */
-
+ * String consructor (actually use if for ints and everything else!!!
+ *
+ * create a Cast object from some string (not binary)
+ *
+ *
+ * @param string (with binary data!)
+ *
+ * @return object DB_DataObject_Cast
+ * @access public
+ */
+
public function string($value)
{
$r = new DB_DataObject_Cast;
$r->value = $value;
return $r;
}
-
+
/**
- * SQL constructor (for raw SQL insert)
- *
- * create a Cast object from some sql
- *
- * @param string (with binary data!)
- *
- * @return object DB_DataObject_Cast
- * @access public
- */
-
+ * SQL constructor (for raw SQL insert)
+ *
+ * create a Cast object from some sql
+ *
+ * @param string (with binary data!)
+ *
+ * @return object DB_DataObject_Cast
+ * @access public
+ */
+
public function sql($value)
{
$r = new DB_DataObject_Cast;
return $r;
}
+ /**
+ * DateTime Constructor
+ *
+ * create a Cast object from a Date/Time
+ * Maybe should accept a Date object.!
+ * NO VALIDATION DONE, although some crappy re-calcing done!
+ *
+ * @param vargs... accepts
+ * noargs (now)
+ * yyyy-mm-dd HH:MM:SS (Iso)
+ * array(yyyy,mm,dd,HH,MM,SS)
+ *
+ *
+ * @return bool|object
+ * @access public
+ * @author therion 5 at hotmail
+ */
+
+ public function dateTime()
+ {
+ $args = func_get_args();
+ switch (count($args)) {
+ case 0: // no args = now!
+ $datetime = date('Y-m-d G:i:s', mktime());
+
+ // no break
+ case 1:
+ // continue on from 0 args.
+ if (!isset($datetime)) {
+ $datetime = $args[0];
+ }
+
+ $parts = explode(' ', $datetime);
+ $bits = explode('-', $parts[0]);
+ $bits = array_merge($bits, explode(':', $parts[1]));
+ break;
+
+ default: // 2 or more..
+ $bits = $args;
+
+ }
+
+ if (count($bits) != 6) {
+ // PEAR ERROR?
+ return false;
+ }
+
+ $r = DB_DataObject_Cast::date($bits[0], $bits[1], $bits[2]);
+ if (!$r) {
+ return $r; // pass thru error (False) - doesnt happen at present!
+ }
+ // change the type!
+ $r->type = 'datetime';
+
+ // should we mathematically sort this out..
+ // (or just assume that no-one's dumb enough to enter 26:90:90 as a time!
+ $r->hour = $bits[3];
+ $r->minute = $bits[4];
+ $r->second = $bits[5];
+ return $r;
+ }
/**
- * Date Constructor
- *
- * create a Cast object from some string (not binary)
- * NO VALIDATION DONE, although some crappy re-calcing done!
- *
- * @param vargs... accepts
- * dd/mm
- * dd/mm/yyyy
- * yyyy-mm
- * yyyy-mm-dd
- * array(yyyy,dd)
- * array(yyyy,dd,mm)
- *
- *
- *
- * @return object DB_DataObject_Cast
- * @access public
- */
-
+ * Date Constructor
+ *
+ * create a Cast object from some string (not binary)
+ * NO VALIDATION DONE, although some crappy re-calcing done!
+ *
+ * @param vargs... accepts
+ * dd/mm
+ * dd/mm/yyyy
+ * yyyy-mm
+ * yyyy-mm-dd
+ * array(yyyy,dd)
+ * array(yyyy,dd,mm)
+ *
+ *
+ *
+ * @return object DB_DataObject_Cast
+ * @access public
+ */
+
public function date()
{
$args = func_get_args();
switch (count($args)) {
case 0: // no args = today!
- $bits = explode('-', date('Y-m-d'));
+ $bits = explode('-', date('Y-m-d'));
break;
case 1: // one arg = a string
-
+
if (strpos($args[0], '/') !== false) {
$bits = array_reverse(explode('/', $args[0]));
} else {
if (count($bits) == 1) { // if YYYY set day = 1st..
$bits[] = 1;
}
-
+
if (count($bits) == 2) { // if YYYY-DD set day = 1st..
$bits[] = 1;
}
-
+
// if year < 1970 we cant use system tools to check it...
// so we make a few best gueses....
// basically do date calculations for the year 2000!!!
list($r->year, $r->month, $r->day) = $bits;
return $r;
}
-
-
/**
- * Data For time representation ** does not handle timezones!!
- *
- * @var int hour/minute/second
- * @access public
- */
- public $hour;
- public $minute;
- public $second;
-
-
- /**
- * DateTime Constructor
- *
- * create a Cast object from a Date/Time
- * Maybe should accept a Date object.!
- * NO VALIDATION DONE, although some crappy re-calcing done!
- *
- * @param vargs... accepts
- * noargs (now)
- * yyyy-mm-dd HH:MM:SS (Iso)
- * array(yyyy,mm,dd,HH,MM,SS)
- *
- *
- * @return object DB_DataObject_Cast
- * @access public
- * @author therion 5 at hotmail
- */
-
- public function dateTime()
- {
- $args = func_get_args();
- switch (count($args)) {
- case 0: // no args = now!
- $datetime = date('Y-m-d G:i:s', mktime());
-
- // no break
- case 1:
- // continue on from 0 args.
- if (!isset($datetime)) {
- $datetime = $args[0];
- }
-
- $parts = explode(' ', $datetime);
- $bits = explode('-', $parts[0]);
- $bits = array_merge($bits, explode(':', $parts[1]));
- break;
-
- default: // 2 or more..
- $bits = $args;
-
- }
-
- if (count($bits) != 6) {
- // PEAR ERROR?
- return false;
- }
-
- $r = DB_DataObject_Cast::date($bits[0], $bits[1], $bits[2]);
- if (!$r) {
- return $r; // pass thru error (False) - doesnt happen at present!
- }
- // change the type!
- $r->type = 'datetime';
-
- // should we mathematically sort this out..
- // (or just assume that no-one's dumb enough to enter 26:90:90 as a time!
- $r->hour = $bits[3];
- $r->minute = $bits[4];
- $r->second = $bits[5];
- return $r;
- }
-
-
-
- /**
- * time Constructor
- *
- * create a Cast object from a Date/Time
- * Maybe should accept a Date object.!
- * NO VALIDATION DONE, and no-recalcing done!
- *
- * @param vargs... accepts
- * noargs (now)
- * HH:MM:SS (Iso)
- * array(HH,MM,SS)
- *
- *
- * @return object DB_DataObject_Cast
- * @access public
- * @author therion 5 at hotmail
- */
+ * time Constructor
+ *
+ * create a Cast object from a Date/Time
+ * Maybe should accept a Date object.!
+ * NO VALIDATION DONE, and no-recalcing done!
+ *
+ * @param vargs... accepts
+ * noargs (now)
+ * HH:MM:SS (Iso)
+ * array(HH,MM,SS)
+ *
+ *
+ * @return bool|object
+ * @access public
+ * @author therion 5 at hotmail
+ */
public function time()
{
$args = func_get_args();
switch (count($args)) {
case 0: // no args = now!
$time = date('G:i:s', mktime());
-
- // no break
+
+ // no break
case 1:
// continue on from 0 args.
if (!isset($time)) {
$time = $args[0];
}
- $bits = explode(':', $time);
+ $bits = explode(':', $time);
break;
-
+
default: // 2 or more..
$bits = $args;
-
+
}
-
+
if (count($bits) != 3) {
return false;
}
-
+
// now take data from bits into object fields
$r = new DB_DataObject_Cast;
$r->type = 'time';
return $r;
}
-
-
+
/**
- * get the string to use in the SQL statement for this...
- *
- *
- * @param int $to Type (DB_DATAOBJECT_*
- * @param object $db DB Connection Object
- *
- *
- * @return string
- * @access public
- */
-
- public function toString($to=false, $db)
+ * get the string to use in the SQL statement for this...
+ *
+ *
+ * @param bool $to Type (DB_DATAOBJECT_*
+ * @param object $db DB Connection Object
+ *
+ *
+ * @return string
+ * @access public
+ */
+
+ public function toString($to = false, $db)
{
// if $this->type is not set, we are in serious trouble!!!!
// values for to:
- $method = 'toStringFrom'.$this->type;
+ $method = 'toStringFrom' . $this->type;
return $this->$method($to, $db);
}
-
+
/**
- * get the string to use in the SQL statement from a blob of binary data
- * ** Suppots only blob->postgres::bytea
- *
- * @param int $to Type (DB_DATAOBJECT_*
- * @param object $db DB Connection Object
- *
- *
- * @return string
- * @access public
- */
+ * get the string to use in the SQL statement from a blob of binary data
+ * ** Suppots only blob->postgres::bytea
+ *
+ * @param int $to Type (DB_DATAOBJECT_*
+ * @param object $db DB Connection Object
+ *
+ *
+ * @return string
+ * @access public
+ */
public function toStringFromBlob($to, $db)
{
// first weed out invalid casts..
// in blobs can only be cast to blobs.!
-
+
// perhaps we should support TEXT fields???
-
+
if (!($to & DB_DATAOBJECT_BLOB)) {
- return PEAR::raiseError('Invalid Cast from a DB_DataObject_Cast::blob to something other than a blob!');
+ return (new PEAR)->raiseError('Invalid Cast from a DB_DataObject_Cast::blob to something other than a blob!');
}
-
+
switch ($db->dsn["phptype"]) {
case 'pgsql':
- return "'".pg_escape_bytea($this->value)."'::bytea";
-
+ return "'" . pg_escape_bytea($this->value) . "'::bytea";
+
case 'mysql':
- return "'".mysql_real_escape_string($this->value, $db->connection)."'";
-
+ return "'" . mysql_real_escape_string($this->value, $db->connection) . "'";
+
case 'mysqli':
// this is funny - the parameter order is reversed ;)
- return "'".mysqli_real_escape_string($db->connection, $this->value)."'";
-
+ return "'" . mysqli_real_escape_string($db->connection, $this->value) . "'";
+
case 'sqlite':
// this is funny - the parameter order is reversed ;)
- return "'".sqlite_escape_string($this->value)."'";
-
+ return "'" . sqlite_escape_string($this->value) . "'";
+
case 'mssql':
-
+
if (is_numeric($this->value)) {
return $this->value;
}
$unpacked = unpack('H*hex', $this->value);
return '0x' . $unpacked['hex'];
-
-
-
+
+
default:
- return PEAR::raiseError("DB_DataObject_Cast cant handle blobs for Database:{$db->dsn['phptype']} Yet");
+ return (new PEAR)->raiseError("DB_DataObject_Cast cant handle blobs for Database:{$db->dsn['phptype']} Yet");
}
}
-
+
/**
- * get the string to use in the SQL statement for a blob from a string!
- * ** Suppots only string->postgres::bytea
- *
- *
- * @param int $to Type (DB_DATAOBJECT_*
- * @param object $db DB Connection Object
- *
- *
- * @return string
- * @access public
- */
+ * get the string to use in the SQL statement for a blob from a string!
+ * ** Suppots only string->postgres::bytea
+ *
+ *
+ * @param int $to Type (DB_DATAOBJECT_*
+ * @param object $db DB Connection Object
+ *
+ *
+ * @return string
+ * @access public
+ */
public function toStringFromString($to, $db)
{
// first weed out invalid casts..
// in blobs can only be cast to blobs.!
-
+
// perhaps we should support TEXT fields???
//
-
+
// $to == a string field which is the default type (0)
// so we do not test it here. - we assume that number fields
// will accept a string?? - which is stretching it a bit ...
// should probaly add that test as some point.
-
+
switch ($db->dsn['phptype']) {
case 'pgsql':
- return "'".pg_escape_string($this->value)."'::bytea";
-
+ return "'" . pg_escape_string($this->value) . "'::bytea";
+
case 'mysql':
- return "'".mysql_real_escape_string($this->value, $db->connection)."'";
-
-
+ return "'" . mysql_real_escape_string($this->value, $db->connection) . "'";
+
+
case 'mysqli':
- return "'".mysqli_real_escape_string($db->connection, $this->value)."'";
+ return "'" . mysqli_real_escape_string($db->connection, $this->value) . "'";
case 'mssql':
// copied from the old DB mssql code...?? not sure how safe this is.
return "'" . str_replace(
- array("'", "\\\r\n", "\\\n"),
- array("''", "\\\\\r\n\r\n", "\\\\\n\n"),
- $this->value
+ array("'", "\\\r\n", "\\\n"),
+ array("''", "\\\\\r\n\r\n", "\\\\\n\n"),
+ $this->value
) . "'";
-
+
default:
- return PEAR::raiseError("DB_DataObject_Cast cant handle blobs for Database:{$db->dsn['phptype']} Yet");
+ return (new PEAR)->raiseError("DB_DataObject_Cast cant handle blobs for Database:{$db->dsn['phptype']} Yet");
}
}
-
-
+
+
/**
- * get the string to use in the SQL statement for a date
- *
- *
- *
- * @param int $to Type (DB_DATAOBJECT_*
- * @param object $db DB Connection Object
- *
- *
- * @return string
- * @access public
- */
+ * get the string to use in the SQL statement for a date
+ *
+ *
+ *
+ * @param int $to Type (DB_DATAOBJECT_*
+ * @param object $db DB Connection Object
+ *
+ *
+ * @return string
+ * @access public
+ */
public function toStringFromDate($to, $db)
{
// first weed out invalid casts..
// in blobs can only be cast to blobs.!
// perhaps we should support TEXT fields???
//
-
+
if (($to !== false) && !($to & DB_DATAOBJECT_DATE)) {
- return PEAR::raiseError('Invalid Cast from a DB_DataObject_Cast::string to something other than a date!'.
+ return (new PEAR)->raiseError('Invalid Cast from a DB_DataObject_Cast::string to something other than a date!' .
' (why not just use native features)');
}
return "'{$this->year}-{$this->month}-{$this->day}'";
}
-
+
/**
- * get the string to use in the SQL statement for a datetime
- *
- *
- *
- * @param int $to Type (DB_DATAOBJECT_*
- * @param object $db DB Connection Object
- *
- *
- * @return string
- * @access public
- * @author therion 5 at hotmail
- */
-
+ * get the string to use in the SQL statement for a datetime
+ *
+ *
+ *
+ * @param int $to Type (DB_DATAOBJECT_*
+ * @param object $db DB Connection Object
+ *
+ *
+ * @return string
+ * @access public
+ * @author therion 5 at hotmail
+ */
+
public function toStringFromDateTime($to, $db)
{
// first weed out invalid casts..
// perhaps we should support TEXT fields???
if (($to !== false) &&
!($to & (DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME))) {
- return PEAR::raiseError('Invalid Cast from a ' .
+ return (new PEAR)->raiseError('Invalid Cast from a ' .
' DB_DataObject_Cast::dateTime to something other than a datetime!' .
' (try using native features)');
}
}
/**
- * get the string to use in the SQL statement for a time
- *
- *
- *
- * @param int $to Type (DB_DATAOBJECT_*
- * @param object $db DB Connection Object
- *
- *
- * @return string
- * @access public
- * @author therion 5 at hotmail
- */
+ * get the string to use in the SQL statement for a time
+ *
+ *
+ *
+ * @param int $to Type (DB_DATAOBJECT_*
+ * @param object $db DB Connection Object
+ *
+ *
+ * @return string
+ * @access public
+ * @author therion 5 at hotmail
+ */
public function toStringFromTime($to, $db)
{
// in blobs can only be cast to blobs.!
// perhaps we should support TEXT fields???
if (($to !== false) && !($to & DB_DATAOBJECT_TIME)) {
- return PEAR::raiseError('Invalid Cast from a' .
- ' DB_DataObject_Cast::time to something other than a time!'.
+ return (new PEAR)->raiseError('Invalid Cast from a' .
+ ' DB_DataObject_Cast::time to something other than a time!' .
' (try using native features)');
}
return "'{$this->hour}:{$this->minute}:{$this->second}'";
}
-
+
/**
- * get the string to use in the SQL statement for a raw sql statement.
- *
- * @param int $to Type (DB_DATAOBJECT_*
- * @param object $db DB Connection Object
- *
- *
- * @return string
- * @access public
- */
+ * get the string to use in the SQL statement for a raw sql statement.
+ *
+ * @param int $to Type (DB_DATAOBJECT_*
+ * @param object $db DB Connection Object
+ *
+ *
+ * @return string
+ * @access public
+ */
public function toStringFromSql($to, $db)
{
return $this->value;
* @version CVS: $Id: Error.php 287158 2009-08-12 13:58:31Z alan_k $
* @link http://pear.php.net/package/DB_DataObject
*/
-
-
+
+
class DB_DataObject_Error extends PEAR_Error
{
-
+
/**
* DB_DataObject_Error constructor.
*
- * @param mixed $code DB error code, or string with error message.
- * @param integer $mode what "error mode" to operate in
- * @param integer $level what error level to use for $mode & PEAR_ERROR_TRIGGER
- * @param mixed $debuginfo additional debug info, such as the last query
- *
+ * @param string $message
+ * @param mixed $code DB error code, or string with error message.
+ * @param integer $mode what "error mode" to operate in
+ * @param integer $level what error level to use for $mode & PEAR_ERROR_TRIGGER
* @access public
*
* @see PEAR_Error
*/
- public function DB_DataObject_Error(
+ public function __construct(
$message = '',
$code = DB_ERROR,
$mode = PEAR_ERROR_RETURN,
$level = E_USER_NOTICE
- ) {
+ )
+ {
$this->PEAR_Error('DB_DataObject Error: ' . $message, $code, $mode, $level);
}
-
-
+
+
// todo : - support code -> message handling, and translated error messages...
}
* @version CVS: $Id: Generator.php 336719 2015-05-05 10:37:33Z alan_k $
* @link http://pear.php.net/package/DB_DataObject
*/
-
- /*
- * Security Notes:
- * This class uses eval to create classes on the fly.
- * The table name and database name are used to check the database before writing the
- * class definitions, we now check for quotes and semi-colon's in both variables
- * so I cant see how it would be possible to generate code even if
- * for some crazy reason you took the classname and table name from User Input.
- *
- * If you consider that wrong, or can prove it.. let me know!
- */
-
- /**
+
+/*
+* Security Notes:
+* This class uses eval to create classes on the fly.
+* The table name and database name are used to check the database before writing the
+* class definitions, we now check for quotes and semi-colon's in both variables
+* so I cant see how it would be possible to generate code even if
+* for some crazy reason you took the classname and table name from User Input.
+*
+* If you consider that wrong, or can prove it.. let me know!
+*/
+
+/**
*
* Config _$ptions
* [DB_DataObject]
* We lazy load here, due to problems with the tests not setting up include path correctly.
* FIXME!
*/
-class_exists('DB_DataObject') ? '' : require_once 'DB/DataObject.php';
+class_exists('DB_DataObject') ? '' : /*require_once 'DB/DataObject.php'*/ require_once '../DataObject.php';
//require_once('Config.php');
/**
* @access private
*/
public $_fkeys; // active tablename
+ /**
+ * Output File was config object, now just string
+ * Used to generate the Tables
+ *
+ * @var string outputbuffer for table definitions
+ * @access private
+ */
+ public $_newConfig;
+ /**
+ * class being extended (can be overridden by [DB_DataObject] extends=xxxx
+ *
+ * @var string
+ * @access private
+ */
+ public $_extends = 'DB_DataObject';
+ /**
+ * line to use for require('DB/DataObject.php');
+ *
+ * @var string
+ * @access private
+ */
+ public $_extendsFile = "DB/DataObject.php";
+ /**
+ * class being generated
+ *
+ * @var string
+ * @access private
+ */
+ public $_className;
/**
* The 'starter' = call this to start the process
*/
public function start()
{
- $options = &PEAR::getStaticProperty('DB_DataObject', 'options');
+ $options = &(new PEAR)->getStaticProperty('DB_DataObject', 'options');
$db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
$databases = array();
- foreach ($options as $k=>$v) {
+ foreach ($options as $k => $v) {
if (substr($k, 0, 9) == 'database_') {
$databases[substr($k, 9)] = $v;
}
}
}
$this->debug("DONE\n\n");
+ return null;
}
- /**
- * Output File was config object, now just string
- * Used to generate the Tables
- *
- * @var string outputbuffer for table definitions
- * @access private
- */
- public $_newConfig;
-
/**
* Build a list of tables;
* and store it in $this->tables and $this->_definitions[tablename];
*
* @access private
- * @return none
+ * @return none|object
*/
public function _createTableList()
{
$this->_connect();
-
- $options = &PEAR::getStaticProperty('DB_DataObject', 'options');
-
+ $options = &(new PEAR)->getStaticProperty('DB_DataObject', 'options');
- $__DB= &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5];
+
+ $__DB = &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5];
$db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
$is_MDB2 = ($db_driver != 'DB') ? true : false;
if (is_object($__DB) && is_a($__DB, 'PEAR_Error')) {
- return PEAR::raiseError($__DB->toString(), null, PEAR_ERROR_DIE);
+ return (new PEAR)->raiseError($__DB->toString(), null, PEAR_ERROR_DIE);
}
-
+
if (!$is_MDB2) {
// try getting a list of schema tables first. (postgres)
$__DB->expectError(DB_ERROR_UNSUPPORTED);
/**
* set portability and some modules to fetch the informations
*/
- $db_options = PEAR::getStaticProperty('MDB2', 'options');
+ $db_options = (new PEAR)->getStaticProperty('MDB2', 'options');
if (empty($db_options)) {
$__DB->setOption('portability', MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_FIX_CASE);
}
-
+
$__DB->loadModule('Manager');
$__DB->loadModule('Reverse');
}
}
if (is_object($this->tables) && is_a($this->tables, 'PEAR_Error')) {
- return PEAR::raiseError($this->tables->toString(), null, PEAR_ERROR_DIE);
+ return (new PEAR)->raiseError($this->tables->toString(), null, PEAR_ERROR_DIE);
}
// build views as well if asked to.
if (!empty($options['build_views'])) {
if (!$is_MDB2) {
$views = $__DB->getListOf(is_string($options['build_views']) ?
- $options['build_views'] : 'views');
+ $options['build_views'] : 'views');
} else {
$views = $__DB->manager->listViews();
}
if (is_object($views) && is_a($views, 'PEAR_Error')) {
- return PEAR::raiseError(
+ return (new PEAR)->raiseError(
'Error getting Views (check the PEAR bug database for the fix to DB), ' .
- $views->toString(),
+ $views->toString(),
null,
PEAR_ERROR_DIE
);
foreach ($this->tables as $table) {
if (isset($options['generator_include_regex']) &&
- !preg_match($options['generator_include_regex'], $table)) {
+ !preg_match($options['generator_include_regex'], $table)) {
$this->debug("SKIPPING (generator_include_regex) : $table");
continue;
}
-
+
if (isset($options['generator_exclude_regex']) &&
- preg_match($options['generator_exclude_regex'], $table)) {
+ preg_match($options['generator_exclude_regex'], $table)) {
continue;
}
-
+
$strip = empty($options['generator_strip_schema']) ? false : $options['generator_strip_schema'];
- $strip = is_numeric($strip) ? (bool) $strip : $strip;
+ $strip = is_numeric($strip) ? (bool)$strip : $strip;
$strip = (is_string($strip) && strtolower($strip) == 'true') ? true : $strip;
-
+
// postgres strip the schema bit from the
if (!empty($strip)) {
if (!is_string($strip) || preg_match($strip, $table)) {
}
}
$this->debug("EXTRACTING : $table");
-
+
$quotedTable = !empty($options['quote_identifiers_tableinfo']) ?
$__DB->quoteIdentifier($table) : $table;
-
+
if (!$is_MDB2) {
- $defs = $__DB->tableInfo($quotedTable);
+ $defs = $__DB->tableInfo($quotedTable);
} else {
- $defs = $__DB->reverse->tableInfo($quotedTable);
+ $defs = $__DB->reverse->tableInfo($quotedTable);
// rename the length value, so it matches db's return.
}
if (is_object($defs) && is_a($defs, 'PEAR_Error')) {
// running in debug mode should pick this up as a big warning..
$this->debug("Error reading tableInfo: $table");
- $this->raiseError('Error reading tableInfo, '. $defs->toString());
+ $this->raiseError('Error reading tableInfo, ' . $defs->toString());
continue;
}
// cast all definitions to objects - as we deal with that better.
-
foreach ($defs as $def) {
if (!is_array($def)) {
continue;
if (isset($def['length']) && !isset($def['len'])) {
$def['len'] = $def['length'];
}
- $this->_definitions[$table][] = (object) $def;
+ $this->_definitions[$table][] = (object)$def;
}
// we find a matching table, just store it into a temporary array
$tmp_table[] = $table;
// the temporary table array is now the right one (tables names matching
// with regex expressions have been removed)
$this->tables = $tmp_table;
-
+
//print_r($this->_definitions);
+ return null;
}
-
+
/**
* Auto generation of table data.
*
* it will output to db_oo_{database} the table definitions
*
* @access private
- * @return none
+ * @return none|void
*/
public function generateDefinitions()
{
$this->debug("Generating Definitions file: ");
if (!$this->tables) {
$this->debug("-- NO TABLES -- \n");
- return;
+ return null;
}
- $options = &PEAR::getStaticProperty('DB_DataObject', 'options');
+ $options = &(new PEAR)->getStaticProperty('DB_DataObject', 'options');
//$this->_newConfig = new Config('IniFile');
// dont generate a schema if location is not set
// it's created on the fly!
if (empty($options['schema_location']) && empty($options["ini_{$this->_database}"])) {
- return;
+ return null;
}
if (!empty($options['generator_no_ini'])) { // built in ini files..
- return;
+ return null;
}
- $base = @$options['schema_location'];
+ $base = @$options['schema_location'];
if (isset($options["ini_{$this->_database}"])) {
$file = $options["ini_{$this->_database}"];
} else {
$file = "{$base}/{$this->_database}.ini";
}
-
+
if (!file_exists(dirname($file))) {
require_once 'System.php';
- System::mkdir(array('-p','-m',0755,dirname($file)));
+ (new System)->mkdir(array('-p', '-m', 0755, dirname($file)));
}
$this->debug("Writing ini as {$file}\n");
//touch($file);
//print_r($this->_newConfig);
$fh = fopen($tmpname, 'w');
if (!$fh) {
- return PEAR::raiseError(
- "Failed to create temporary file: $tmpname\n".
+ return (new PEAR)->raiseError(
+ "Failed to create temporary file: $tmpname\n" .
"make sure session.save_path is set and is writable\n",
null,
PEAR_ERROR_DIE
fclose($fh);
$perms = file_exists($file) ? fileperms($file) : 0755;
// windows can fail doing this. - not a perfect solution but otherwise it's getting really kludgy..
-
+
if (!@rename($tmpname, $file)) {
unlink($file);
rename($tmpname, $file);
chmod($file, $perms);
//$ret = $this->_newConfig->writeInput($file,false);
- //if (PEAR::isError($ret) ) {
+ //if ((new PEAR)->isError($ret) ) {
// return PEAR::raiseError($ret->message,null,PEAR_ERROR_DIE);
// }
- }
- /**
- * create the data for Foreign Keys (for links.ini)
- * Currenly only works with mysql / mysqli / posgtreas
- * to use, you must set option: generate_links=true
- *
- * @author Pascal Sch�ni
- */
-
- public function _createForiegnKeys()
- {
- $options = PEAR::getStaticProperty('DB_DataObject', 'options');
- if (empty($options['generate_links'])) {
- return false;
- }
- $__DB = &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5];
- if (!in_array($__DB->phptype, array('mysql', 'mysqli', 'pgsql'))) {
- echo "WARNING: cant handle non-mysql and pgsql introspection for defaults.";
- return; // cant handle non-mysql introspection for defaults.
- }
- $this->debug("generateForeignKeys: Start");
- $DB = $this->getDatabaseConnection();
-
- $fk = array();
-
-
- switch ($DB->phptype) {
-
-
- case 'pgsql':
- foreach ($this->tables as $this->table) {
- $quotedTable = !empty($options['quote_identifiers_tableinfo']) ? $DB->quoteIdentifier($table) : $this->table;
- $res =& $DB->query("SELECT
- pg_catalog.pg_get_constraintdef(r.oid, true) AS condef
- FROM pg_catalog.pg_constraint r,
- pg_catalog.pg_class c
- WHERE c.oid=r.conrelid
- AND r.contype = 'f'
- AND c.relname = '" . $quotedTable . "'");
- if (PEAR::isError($res)) {
- die($res->getMessage());
- }
-
- while ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) {
- $treffer = array();
- // this only picks up one of these.. see this for why: http://pear.php.net/bugs/bug.php?id=17049
- preg_match(
- "/FOREIGN KEY \((\w*)\) REFERENCES (\w*)\((\w*)\)/i",
- $row['condef'],
- $treffer
- );
- if (!count($treffer)) {
- continue;
- }
- $fk[$this->table][$treffer[1]] = $treffer[2] . ":" . $treffer[3];
- }
- }
- break;
-
-
- case 'mysql':
- case 'mysqli':
- default:
-
- foreach ($this->tables as $this->table) {
- $quotedTable = !empty($options['quote_identifiers_tableinfo']) ? $DB->quoteIdentifier($table) : $this->table;
-
- $res =& $DB->query('SHOW CREATE TABLE ' . $quotedTable);
-
- if (PEAR::isError($res)) {
- die($res->getMessage());
- }
-
- $text = $res->fetchRow(DB_FETCHMODE_DEFAULT, 0);
- $treffer = array();
- // Extract FOREIGN KEYS
- preg_match_all(
- "/FOREIGN KEY \(`(\w*)`\) REFERENCES `(\w*)` \(`(\w*)`\)/i",
- $text[1],
- $treffer,
- PREG_SET_ORDER
- );
-
- if (!count($treffer)) {
- continue;
- }
- foreach ($treffer as $i=> $tref) {
- $fk[$this->table][$tref[1]] = $tref[2] . ":" . $tref[3];
- }
- }
-
- }
-
-
- $this->_fkeys = $fk;
- }
-
-
- /**
- * generate Foreign Keys (for links.ini)
- * Currenly only works with mysql / mysqli
- * to use, you must set option: generate_links=true
- *
- * @author Pascal Sch�ni
- */
- public function generateForeignKeys()
- {
- $options = PEAR::getStaticProperty('DB_DataObject', 'options');
- if (empty($options['generate_links'])) {
- return false;
- }
- $__DB = &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5];
- if (!in_array($__DB->phptype, array('mysql', 'mysqli', 'pgsql'))) {
- echo "WARNING: cant handle non-mysql and pgsql introspection for defaults.";
- return; // cant handle non-mysql introspection for defaults.
- }
- $this->debug("generateForeignKeys: Start");
-
- $fk = $this->_fkeys;
- $links_ini = "";
-
- foreach ($fk as $table => $details) {
- $links_ini .= "[$table]\n";
- foreach ($details as $col => $ref) {
- $links_ini .= "$col = $ref\n";
- }
- $links_ini .= "\n";
- }
-
- // dont generate a schema if location is not set
- // it's created on the fly!
- $options = PEAR::getStaticProperty('DB_DataObject', 'options');
-
- if (!empty($options['schema_location'])) {
- $file = "{$options['schema_location']}/{$this->_database}.links.ini";
- } elseif (isset($options["ini_{$this->_database}"])) {
- $file = preg_replace('/\.ini/', '.links.ini', $options["ini_{$this->_database}"]);
- } else {
- $this->debug("generateForeignKeys: SKIP - schema_location or ini_{database} was not set");
- return;
- }
-
-
- if (!file_exists(dirname($file))) {
- mkdir(dirname($file), 0755, true);
- }
-
- $this->debug("Writing ini as {$file}\n");
-
- //touch($file); // not sure why this is needed?
- $tmpname = tempnam(session_save_path(), 'DataObject_');
-
- $fh = fopen($tmpname, 'w');
- if (!$fh) {
- return PEAR::raiseError(
- "Failed to create temporary file: $tmpname\n".
- "make sure session.save_path is set and is writable\n",
- null,
- PEAR_ERROR_DIE
- );
- }
- fwrite($fh, $links_ini);
- fclose($fh);
- $perms = file_exists($file) ? fileperms($file) : 0755;
- // windows can fail doing this. - not a perfect solution but otherwise it's getting really kludgy..
- if (!@rename($tmpname, $file)) {
- unlink($file);
- rename($tmpname, $file);
- }
- chmod($file, $perms);
+ return null;
}
-
/**
* The table geneation part
*
* @access private
- * @return tabledef and keys array.
+ * @return array|tabledef
*/
public function _generateDefinitionsTable()
{
global $_DB_DATAOBJECT;
- $options = PEAR::getStaticProperty('DB_DataObject', 'options');
+ $options = (new PEAR)->getStaticProperty('DB_DataObject', 'options');
$defs = $this->_definitions[$this->table];
$this->_newConfig .= "\n[{$this->table}]\n";
- $keys_out = "\n[{$this->table}__keys]\n";
+ $keys_out = "\n[{$this->table}__keys]\n";
$keys_out_primary = '';
$keys_out_secondary = '';
if (@$_DB_DATAOBJECT['CONFIG']['debug'] > 2) {
}
$DB = $this->getDatabaseConnection();
$dbtype = $DB->phptype;
-
+
$ret = array(
- 'table' => array(),
- 'keys' => array(),
- );
-
+ 'table' => array(),
+ 'keys' => array(),
+ );
+
$ret_keys_primary = array();
$ret_keys_secondary = array();
-
-
-
+
+
foreach ($defs as $t) {
- $n=0;
+ $n = 0;
$write_ini = true;
-
-
+
+
switch (strtoupper($t->type)) {
case 'INT':
case 'BIGINT':
$type = DB_DATAOBJECT_INT;
if ($t->len == 1) {
- $type += DB_DATAOBJECT_BOOL;
+ $type += DB_DATAOBJECT_BOOL;
}
break;
-
+
case 'REAL':
case 'DOUBLE':
case 'DOUBLE PRECISION': // double precision (firebird)
case 'NUMBER': // oci8
$type = DB_DATAOBJECT_INT; // should really by FLOAT!!! / MONEY...
break;
-
+
case 'YEAR':
$type = DB_DATAOBJECT_INT;
break;
-
+
case 'BIT':
case 'BOOL':
case 'BOOLEAN':
-
+
$type = DB_DATAOBJECT_BOOL;
// postgres needs to quote '0'
if ($dbtype == 'pgsql') {
- $type += DB_DATAOBJECT_STR;
+ $type += DB_DATAOBJECT_STR;
}
break;
-
+
case 'STRING':
case 'CHAR':
case 'VARCHAR':
case 'VARCHAR2':
case 'TINYTEXT':
-
+
case 'ENUM':
case 'SET': // not really but oh well
-
+
case 'POINT': // mysql geometry stuff - not really string - but will do..
-
+
case 'TIMESTAMPTZ': // postgres
case 'BPCHAR': // postgres
case 'INTERVAL': // postgres (eg. '12 days')
-
+
case 'CIDR': // postgres IP net spec
case 'INET': // postgres IP
case 'MACADDR': // postgress network Mac address.
-
+
case 'INTEGER[]': // postgres type
case 'BOOLEAN[]': // postgres type
-
+
$type = DB_DATAOBJECT_STR;
break;
-
+
case 'TEXT':
case 'MEDIUMTEXT':
case 'LONGTEXT':
case '_TEXT': //postgres (?? view ??)
-
+
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_TXT;
break;
-
-
+
+
case 'DATE':
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE;
break;
-
+
case 'TIME':
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_TIME;
break;
-
-
+
+
case 'DATETIME':
-
+
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME;
break;
-
+
case 'TIMESTAMP': // do other databases use this???
-
+
$type = ($dbtype == 'mysql') ?
DB_DATAOBJECT_MYSQLTIMESTAMP :
DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME;
break;
-
-
+
+
case 'BLOB': /// these should really be ignored!!!???
case 'TINYBLOB':
case 'MEDIUMBLOB':
case 'LONGBLOB':
-
+
case 'CLOB': // oracle character lob support
-
+
case 'BYTEA': // postgres blob support..
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_BLOB;
break;
-
+
default:
- echo "*****************************************************************\n".
- "** WARNING UNKNOWN TYPE **\n".
- "** Found column '{$t->name}', of type '{$t->type}' **\n".
- "** Please submit a bug, describe what type you expect this **\n".
- "** column to be **\n".
- "** ---------POSSIBLE FIX / WORKAROUND -------------------------**\n".
- "** Try using MDB2 as the backend - eg set the config option **\n".
- "** db_driver = MDB2 **\n".
- "*****************************************************************\n";
+ echo "*****************************************************************\n" .
+ "** WARNING UNKNOWN TYPE **\n" .
+ "** Found column '{$t->name}', of type '{$t->type}' **\n" .
+ "** Please submit a bug, describe what type you expect this **\n" .
+ "** column to be **\n" .
+ "** ---------POSSIBLE FIX / WORKAROUND -------------------------**\n" .
+ "** Try using MDB2 as the backend - eg set the config option **\n" .
+ "** db_driver = MDB2 **\n" .
+ "*****************************************************************\n";
$write_ini = false;
break;
}
-
+
if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $t->name)) {
- echo "*****************************************************************\n".
- "** WARNING COLUMN NAME UNUSABLE **\n".
- "** Found column '{$t->name}', of type '{$t->type}' **\n".
- "** Since this column name can't be converted to a php variable **\n".
- "** name, and the whole idea of mapping would result in a mess **\n".
- "** This column has been ignored... **\n".
- "*****************************************************************\n";
+ echo "*****************************************************************\n" .
+ "** WARNING COLUMN NAME UNUSABLE **\n" .
+ "** Found column '{$t->name}', of type '{$t->type}' **\n" .
+ "** Since this column name can't be converted to a php variable **\n" .
+ "** name, and the whole idea of mapping would result in a mess **\n" .
+ "** This column has been ignored... **\n" .
+ "*****************************************************************\n";
continue;
}
-
+
if (!strlen(trim($t->name))) {
continue; // is this a bug?
}
-
+
if (preg_match('/not[ _]null/i', $t->flags)) {
$type += DB_DATAOBJECT_NOTNULL;
}
-
-
- if (in_array($t->name, array('null','yes','no','true','false'))) {
- echo "*****************************************************************\n".
- "** WARNING **\n".
- "** Found column '{$t->name}', which is invalid in an .ini file **\n".
- "** This line will not be writen to the file - you will have **\n".
- "** define the keys()/method manually. **\n".
- "*****************************************************************\n";
+
+
+ if (in_array($t->name, array('null', 'yes', 'no', 'true', 'false'))) {
+ echo "*****************************************************************\n" .
+ "** WARNING **\n" .
+ "** Found column '{$t->name}', which is invalid in an .ini file **\n" .
+ "** This line will not be writen to the file - you will have **\n" .
+ "** define the keys()/method manually. **\n" .
+ "*****************************************************************\n";
$write_ini = false;
} else {
$this->_newConfig .= "{$t->name} = $type\n";
}
-
+
$ret['table'][$t->name] = $type;
// i've no idea if this will work well on other databases?
// only use primary key or nextval(), cause the setFrom blocks you setting all key items...
// if no keys exist fall back to using unique
//echo "\n{$t->name} => {$t->flags}\n";
$secondary_key_match = isset($options['generator_secondary_key_match']) ? $options['generator_secondary_key_match'] : 'primary|unique';
-
+
$m = array();
if (preg_match('/(auto_increment|nextval\(([^)]*))/i', rawurldecode($t->flags), $m)
|| (isset($t->autoincrement) && ($t->autoincrement === true))) {
$keys_out_primary .= "{$t->name} = $sn\n";
}
$ret_keys_primary[$t->name] = $sn;
- } elseif ($secondary_key_match && preg_match('/('.$secondary_key_match.')/i', $t->flags)) {
+ } elseif ($secondary_key_match && preg_match('/(' . $secondary_key_match . ')/i', $t->flags)) {
// keys.. = 1
$key_type = 'K';
if (!preg_match("/(primary)/i", $t->flags)) {
$key_type = 'U';
}
-
+
if ($write_ini) {
$keys_out_secondary .= "{$t->name} = {$key_type}\n";
}
$ret_keys_secondary[$t->name] = $key_type;
}
}
-
+
$this->_newConfig .= $keys_out . (empty($keys_out_primary) ? $keys_out_secondary : $keys_out_primary);
$ret['keys'] = empty($keys_out_primary) ? $ret_keys_secondary : $ret_keys_primary;
-
+
if (@$_DB_DATAOBJECT['CONFIG']['debug'] > 2) {
print_r(array("dump for {$this->table}", $ret));
}
-
+
return $ret;
}
/**
- * Convert a table name into a class name -> override this if you want a different mapping
- *
- * @access public
- * @return string class name;
- */
-
-
- public function getClassNameFromTableName($table)
- {
- $options = &PEAR::getStaticProperty('DB_DataObject', 'options');
- $class_prefix = empty($options['class_prefix']) ? '' : $options['class_prefix'];
- return $class_prefix.preg_replace('/[^A-Z0-9]/i', '_', ucfirst(trim($this->table)));
- }
-
-
- /**
- * Convert a table name into a file name -> override this if you want a different mapping
- *
- * @access public
- * @return string file name;
- */
-
-
- public function getFileNameFromTableName($table)
+ * create the data for Foreign Keys (for links.ini)
+ * Currenly only works with mysql / mysqli / posgtreas
+ * to use, you must set option: generate_links=true
+ *
+ * @author Pascal Sch�ni
+ */
+
+ public function _createForiegnKeys()
{
- $options = &PEAR::getStaticProperty('DB_DataObject', 'options');
- $base = $options['class_location'];
- if (strpos($base, '%s') !== false) {
- $base = dirname($base);
+ $options = (new PEAR)->getStaticProperty('DB_DataObject', 'options');
+ if (empty($options['generate_links'])) {
+ return false;
}
- if (!file_exists($base)) {
- require_once 'System.php';
- System::mkdir(array('-p',$base));
+ $__DB = &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5];
+ if (!in_array($__DB->phptype, array('mysql', 'mysqli', 'pgsql'))) {
+ echo "WARNING: cant handle non-mysql and pgsql introspection for defaults.";
+ return null; // cant handle non-mysql introspection for defaults.
}
- if (strpos($options['class_location'], '%s') !== false) {
- $outfilename = sprintf(
- $options['class_location'],
- preg_replace('/[^A-Z0-9]/i', '_', ucfirst($this->table))
- );
- } else {
- $outfilename = "{$base}/".preg_replace('/[^A-Z0-9]/i', '_', ucfirst($this->table)).".php";
+ $this->debug("generateForeignKeys: Start");
+ $DB = $this->getDatabaseConnection();
+
+ $fk = array();
+
+
+ switch ($DB->phptype) {
+
+
+ case 'pgsql':
+ foreach ($this->tables as $this->table) {
+ $quotedTable = !empty($options['quote_identifiers_tableinfo']) ? $DB->quoteIdentifier($this->table) : $this->table;
+ $res =& $DB->query("SELECT
+ pg_catalog.pg_get_constraintdef(r.oid, true) AS condef
+ FROM pg_catalog.pg_constraint r,
+ pg_catalog.pg_class c
+ WHERE c.oid=r.conrelid
+ AND r.contype = 'f'
+ AND c.relname = '" . $quotedTable . "'");
+ if ((new PEAR)->isError($res)) {
+ die($res->getMessage());
+ }
+
+ while ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) {
+ $treffer = array();
+ // this only picks up one of these.. see this for why: http://pear.php.net/bugs/bug.php?id=17049
+ preg_match(
+ "/FOREIGN KEY \((\w*)\) REFERENCES (\w*)\((\w*)\)/i",
+ $row['condef'],
+ $treffer
+ );
+ if (!count($treffer)) {
+ continue;
+ }
+ $fk[$this->table][$treffer[1]] = $treffer[2] . ":" . $treffer[3];
+ }
+ }
+ break;
+
+
+ case 'mysql':
+ case 'mysqli':
+ default:
+
+ foreach ($this->tables as $this->table) {
+ $quotedTable = !empty($options['quote_identifiers_tableinfo']) ? $DB->quoteIdentifier($this->table) : $this->table;
+
+ $res =& $DB->query('SHOW CREATE TABLE ' . $quotedTable);
+
+ if ((new PEAR)->isError($res)) {
+ die($res->getMessage());
+ }
+
+ $text = $res->fetchRow(DB_FETCHMODE_DEFAULT, 0);
+ $treffer = array();
+ // Extract FOREIGN KEYS
+ preg_match_all(
+ "/FOREIGN KEY \(`(\w*)`\) REFERENCES `(\w*)` \(`(\w*)`\)/i",
+ $text[1],
+ $treffer,
+ PREG_SET_ORDER
+ );
+
+ if (!count($treffer)) {
+ continue;
+ }
+ foreach ($treffer as $i => $tref) {
+ $fk[$this->table][$tref[1]] = $tref[2] . ":" . $tref[3];
+ }
+ }
+
}
- return $outfilename;
+
+
+ $this->_fkeys = $fk;
+ return null;
}
-
-
+
/**
- * Convert a column name into a method name (usually prefixed by get/set/validateXXXXX)
- *
- * @access public
- * @return string method name;
- */
-
-
- public function getMethodNameFromColumnName($col)
+ * generate Foreign Keys (for links.ini)
+ * Currenly only works with mysql / mysqli
+ * to use, you must set option: generate_links=true
+ *
+ * @author Pascal Sch�ni
+ */
+ public function generateForeignKeys()
{
- return ucfirst($col);
+ $options = (new PEAR)->getStaticProperty('DB_DataObject', 'options');
+ if (empty($options['generate_links'])) {
+ return false;
+ }
+ $__DB = &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5];
+ if (!in_array($__DB->phptype, array('mysql', 'mysqli', 'pgsql'))) {
+ echo "WARNING: cant handle non-mysql and pgsql introspection for defaults.";
+ return null; // cant handle non-mysql introspection for defaults.
+ }
+ $this->debug("generateForeignKeys: Start");
+
+ $fk = $this->_fkeys;
+ $links_ini = "";
+
+ foreach ($fk as $table => $details) {
+ $links_ini .= "[$table]\n";
+ foreach ($details as $col => $ref) {
+ $links_ini .= "$col = $ref\n";
+ }
+ $links_ini .= "\n";
+ }
+
+ // dont generate a schema if location is not set
+ // it's created on the fly!
+ $options = (new PEAR)->getStaticProperty('DB_DataObject', 'options');
+
+ if (!empty($options['schema_location'])) {
+ $file = "{$options['schema_location']}/{$this->_database}.links.ini";
+ } elseif (isset($options["ini_{$this->_database}"])) {
+ $file = preg_replace('/\.ini/', '.links.ini', $options["ini_{$this->_database}"]);
+ } else {
+ $this->debug("generateForeignKeys: SKIP - schema_location or ini_{database} was not set");
+ return null;
+ }
+
+
+ if (!file_exists(dirname($file))) {
+ mkdir(dirname($file), 0755, true);
+ }
+
+ $this->debug("Writing ini as {$file}\n");
+
+ //touch($file); // not sure why this is needed?
+ $tmpname = tempnam(session_save_path(), 'DataObject_');
+
+ $fh = fopen($tmpname, 'w');
+ if (!$fh) {
+ return (new PEAR)->raiseError(
+ "Failed to create temporary file: $tmpname\n" .
+ "make sure session.save_path is set and is writable\n",
+ null,
+ PEAR_ERROR_DIE
+ );
+ }
+ fwrite($fh, $links_ini);
+ fclose($fh);
+ $perms = file_exists($file) ? fileperms($file) : 0755;
+ // windows can fail doing this. - not a perfect solution but otherwise it's getting really kludgy..
+ if (!@rename($tmpname, $file)) {
+ unlink($file);
+ rename($tmpname, $file);
+ }
+ chmod($file, $perms);
+ return null;
}
-
-
-
-
+
+
/*
* building the class files
* for each of the tables output a file!
*/
+
public function generateClasses()
{
//echo "Generating Class files: \n";
- $options = &PEAR::getStaticProperty('DB_DataObject', 'options');
-
+ $options = &(new PEAR)->getStaticProperty('DB_DataObject', 'options');
+
$this->_extends = empty($options['extends']) ? $this->_extends : $options['extends'];
$this->_extendsFile = !isset($options['extends_location']) ? $this->_extendsFile : $options['extends_location'];
-
+
foreach ($this->tables as $this->table) {
- $this->table = trim($this->table);
- $this->classname = $this->getClassNameFromTableName($this->table);
+ $this->table = trim($this->table);
+ $this->classname = $this->getClassNameFromTableName($this->table);
$i = '';
- $outfilename = $this->getFileNameFromTableName($this->table);
-
+ $outfilename = $this->getFileNameFromTableName($this->table);
+
$oldcontents = '';
if (file_exists($outfilename)) {
// file_get_contents???
$oldcontents = implode('', file($outfilename));
}
-
+
$out = $this->_generateClassTable($oldcontents);
$this->debug("writing $this->classname\n");
$tmpname = tempnam(session_save_path(), 'DataObject_');
-
+
$fh = fopen($tmpname, "w");
if (!$fh) {
- return PEAR::raiseError(
- "Failed to create temporary file: $tmpname\n".
+ return (new PEAR)->raiseError(
+ "Failed to create temporary file: $tmpname\n" .
"make sure session.save_path is set and is writable\n",
null,
PEAR_ERROR_DIE
fputs($fh, $out);
fclose($fh);
$perms = file_exists($outfilename) ? fileperms($outfilename) : 0755;
-
+
// windows can fail doing this. - not a perfect solution but otherwise it's getting really kludgy..
if (!@rename($tmpname, $outfilename)) {
unlink($outfilename);
rename($tmpname, $outfilename);
}
-
+
chmod($outfilename, $perms);
}
//echo $out;
+ return null;
}
/**
- * class being extended (can be overridden by [DB_DataObject] extends=xxxx
+ * Convert a table name into a class name -> override this if you want a different mapping
*
- * @var string
- * @access private
+ * @access public
+ * @param $table
+ * @return string class name;
*/
- public $_extends = 'DB_DataObject';
- /**
- * line to use for require('DB/DataObject.php');
- *
- * @var string
- * @access private
- */
- public $_extendsFile = "DB/DataObject.php";
+
+ public function getClassNameFromTableName($table)
+ {
+ $options = &(new PEAR)->getStaticProperty('DB_DataObject', 'options');
+ $class_prefix = empty($options['class_prefix']) ? '' : $options['class_prefix'];
+ return $class_prefix . preg_replace('/[^A-Z0-9]/i', '_', ucfirst(trim($this->table)));
+ }
/**
- * class being generated
+ * Convert a table name into a file name -> override this if you want a different mapping
*
- * @var string
- * @access private
+ * @access public
+ * @param $table
+ * @return string file name;
*/
- public $_className;
+
+
+ public function getFileNameFromTableName($table)
+ {
+ $options = &(new PEAR)->getStaticProperty('DB_DataObject', 'options');
+ $base = $options['class_location'];
+ if (strpos($base, '%s') !== false) {
+ $base = dirname($base);
+ }
+ if (!file_exists($base)) {
+ require_once 'System.php';
+ (new System)->mkdir(array('-p', $base));
+ }
+ if (strpos($options['class_location'], '%s') !== false) {
+ $outfilename = sprintf(
+ $options['class_location'],
+ preg_replace('/[^A-Z0-9]/i', '_', ucfirst($this->table))
+ );
+ } else {
+ $outfilename = "{$base}/" . preg_replace('/[^A-Z0-9]/i', '_', ucfirst($this->table)) . ".php";
+ }
+ return $outfilename;
+ }
/**
* The table class geneation part - single file.
*
* @access private
- * @return none
+ * @param string $input
+ * @return none|string
*/
public function _generateClassTable($input = '')
{
$head .= " */\n";
$head .= $this->derivedHookExtendsDocBlock();
-
+
// requires - if you set extends_location = (blank) then no require line will be set
// this can be used if you have an autoloader
-
+
if (!empty($this->_extendsFile)) {
$head .= "require_once '{$this->_extendsFile}';\n\n";
}
$head .= $this->derivedHookClassDocBlock();
$head .= "class {$this->classname} extends {$this->_extends} \n{";
- $body = "\n ###START_AUTOCODE\n";
+ $body = "\n ###START_AUTOCODE\n";
$body .= " /* the code below is auto generated do not remove the above tag */\n\n";
// table
- $p = str_repeat(' ', max(2, (18 - strlen($this->table)))) ;
-
- $options = &PEAR::getStaticProperty('DB_DataObject', 'options');
-
-
+ $p = str_repeat(' ', max(2, (18 - strlen($this->table))));
+
+ $options = &(new PEAR)->getStaticProperty('DB_DataObject', 'options');
+
+
$var = (substr(phpversion(), 0, 1) > 4) ? 'public' : 'var';
$var = !empty($options['generator_var_keyword']) ? $options['generator_var_keyword'] : $var;
-
-
+
+
$body .= " {$var} \$__table = '{$this->table}'; {$p}// table name\n";
-
+
// if we are using the option database_{databasename} = dsn
// then we should add var $_database = here
// as database names may not always match..
-
+
if (empty($GLOBALS['_DB_DATAOBJECT']['CONFIG'])) {
DB_DataObject::_loadConfig();
}
// Only include the $_database property if the omit_database_var is unset or false
-
+
if (isset($options["database_{$this->_database}"]) && empty($GLOBALS['_DB_DATAOBJECT']['CONFIG']['generator_omit_database_var'])) {
$p = str_repeat(' ', max(2, (16 - strlen($this->_database))));
$body .= " {$var} \$_database = '{$this->_database}'; {$p}// database name (used with database_{*} config)\n";
}
-
-
+
+
if (!empty($options['generator_novars'])) {
- $var = '//'.$var;
+ $var = '//' . $var;
}
-
+
$defs = $this->_definitions[$this->table];
// show nice information!
continue;
}
if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $t->name)) {
- echo "*****************************************************************\n".
- "** WARNING COLUMN NAME UNUSABLE **\n".
- "** Found column '{$t->name}', of type '{$t->type}' **\n".
- "** Since this column name can't be converted to a php variable **\n".
- "** name, and the whole idea of mapping would result in a mess **\n".
- "** This column has been ignored... **\n".
- "*****************************************************************\n";
+ echo "*****************************************************************\n" .
+ "** WARNING COLUMN NAME UNUSABLE **\n" .
+ "** Found column '{$t->name}', of type '{$t->type}' **\n" .
+ "** Since this column name can't be converted to a php variable **\n" .
+ "** name, and the whole idea of mapping would result in a mess **\n" .
+ "** This column has been ignored... **\n" .
+ "*****************************************************************\n";
continue;
}
-
+
$pad = str_repeat(' ', max(2, (30 - strlen($t->name))));
- $length = empty($t->len) ? '' : '('.$t->len.')';
- $flags = strlen($t->flags) ? (' '. trim($t->flags)) : '';
- $body .=" {$var} \${$t->name}; {$pad}// {$t->type}{$length}{$flags}\n";
-
+ $length = empty($t->len) ? '' : '(' . $t->len . ')';
+ $flags = strlen($t->flags) ? (' ' . trim($t->flags)) : '';
+ $body .= " {$var} \${$t->name}; {$pad}// {$t->type}{$length}{$flags}\n";
+
// can not do set as PEAR::DB table info doesnt support it.
//if (substr($t->Type,0,3) == "set")
// $sets[$t->Field] = "array".substr($t->Type,3);
$body .= $this->derivedHookVar($t, strlen($p));
}
-
+
$body .= $this->derivedHookPostVar($defs);
// THIS IS TOTALLY BORKED old FC creation
$body .= " /* ZE2 compatibility trick*/\n";
$body .= " function __clone() { return \$this;}\n";
}
-
-
+
+
// depricated - in here for BC...
if (!empty($options['static_get'])) {
-
+
// simple creation tools ! (static stuff!)
$body .= "\n";
$body .= " /* Static get */\n";
$body .= " $static function staticGet(\$k,\$v=NULL) { " .
- "return DB_DataObject::staticGet('{$this->classname}',\$k,\$v = null); }\n";
+ "return DB_DataObject::staticGet('{$this->classname}',\$k,\$v = null); }\n";
}
// generate getter and setter methods
$body .= $this->_generateGetters($input);
// $kk = strtoupper($k);
// $body .=" function getSets{$k}() { return {$v}; }\n";
//}
-
+
if (!empty($options['generator_no_ini'])) {
$def = $this->_generateDefinitionsTable(); // simplify this!?
$body .= $this->_generateTableFunction($def['table']);
// stubs..
-
+
if (!empty($options['generator_add_validate_stubs'])) {
foreach ($defs as $t) {
if (!strlen(trim($t->name))) {
}
-
-
$foot .= "}\n";
$full = $head . $body . $foot;
unless use set generator_class_rewrite to ANY or a name*/
$class_rewrite = 'DB_DataObject';
- $options = &PEAR::getStaticProperty('DB_DataObject', 'options');
+ $options = &(new PEAR)->getStaticProperty('DB_DataObject', 'options');
if (empty($options['generator_class_rewrite']) || !($class_rewrite = $options['generator_class_rewrite'])) {
$class_rewrite = 'DB_DataObject';
}
}
$input = preg_replace(
- '/(\n|\r\n)class\s*[a-z0-9_]+\s*extends\s*' .$class_rewrite . '\s*(\n|\r\n)\{(\n|\r\n)/si',
+ '/(\n|\r\n)class\s*[a-z0-9_]+\s*extends\s*' . $class_rewrite . '\s*(\n|\r\n)\{(\n|\r\n)/si',
"\nclass {$this->classname} extends {$this->_extends} \n{\n",
$input
);
- $ret = preg_replace(
+ $ret = preg_replace(
'/(\n|\r\n)\s*###START_AUTOCODE(\n|\r\n).*(\n|\r\n)\s*###END_AUTOCODE(\n|\r\n)/s',
$body,
$input
);
-
+
if (!strlen($ret)) {
- return PEAR::raiseError(
- "PREG_REPLACE failed to replace body, - you probably need to set these in your php.ini\n".
- "pcre.backtrack_limit=1000000\n".
+ return (new PEAR)->raiseError(
+ "PREG_REPLACE failed to replace body, - you probably need to set these in your php.ini\n" .
+ "pcre.backtrack_limit=1000000\n" .
"pcre.recursion_limit=1000000\n",
null,
PEAR_ERROR_DIE
);
}
-
+
return $ret;
}
/**
- * hook to add extra methods to all classes
- *
- * called once for each class, use with $this->table and
- * $this->_definitions[$this->table], to get data out of the current table,
- * use it to add extra methods to the default classes.
+ * hook to add extra page-level (in terms of phpDocumentor) DocBlock
*
- * @access public
- * @return string added to class eg. functions.
+ * called once for each class, use it add extra page-level docs
+ * @access public
+ * @return string added to class eg. functions.
*/
- public function derivedHookFunctions($input = "")
+ public function derivedHookPageLevelDocBlock()
{
- // This is so derived generator classes can generate functions
- // It MUST NOT be changed here!!!
- return "";
+ return '';
}
/**
- * hook for var lines
- * called each time a var line is generated, override to add extra var
- * lines
+ * hook to add extra doc block (in terms of phpDocumentor) to extend string
*
- * @param object t containing type,len,flags etc. from tableInfo call
- * @param int padding number of spaces
- * @access public
- * @return string added to class eg. functions.
- */
- public function derivedHookVar(&$t, $padding)
- {
- // This is so derived generator classes can generate variabels
- // It MUST NOT be changed here!!!
- return "";
- }
- /**
- * hook for after var lines (
- * called at the end of the output of var line have generated, override to add extra var
- * lines
- *
- * @param array cols containing array of objects with type,len,flags etc. from tableInfo call
- * @access public
- * @return string added to class eg. functions.
- */
- public function derivedHookPostVar($t)
- {
- // This is so derived generator classes can generate variabels
- // It MUST NOT be changed here!!!
- return "";
- }
- /**
- * hook to add extra page-level (in terms of phpDocumentor) DocBlock
- *
- * called once for each class, use it add extra page-level docs
- * @access public
- * @return string added to class eg. functions.
- */
- public function derivedHookPageLevelDocBlock()
- {
- return '';
- }
-
- /**
- * hook to add extra doc block (in terms of phpDocumentor) to extend string
- *
- * called once for each class, use it add extra comments to extends
- * string (require_once...)
- * @access public
- * @return string added to class eg. functions.
+ * called once for each class, use it add extra comments to extends
+ * string (require_once...)
+ * @access public
+ * @return string added to class eg. functions.
*/
public function derivedHookExtendsDocBlock()
{
}
/**
-
- /**
- * getProxyFull - create a class definition on the fly and instantate it..
- *
- * similar to generated files - but also evals the class definitoin code.
- *
- *
- * @param string database name
- * @param string table name of table to create proxy for.
- *
- *
- * @return object Instance of class. or PEAR Error
- * @access public
- */
- public function getProxyFull($database, $table)
+ * hook for var lines
+ * called each time a var line is generated, override to add extra var
+ * lines
+ *
+ * @param object t containing type,len,flags etc. from tableInfo call
+ * @param int padding number of spaces
+ * @access public
+ * @return string added to class eg. functions.
+ */
+ public function derivedHookVar(&$t, $padding)
{
- if ($err = $this->fillTableSchema($database, $table)) {
- return $err;
- }
-
-
- $options = &PEAR::getStaticProperty('DB_DataObject', 'options');
- $class_prefix = empty($options['class_prefix']) ? '' : $options['class_prefix'];
-
- $this->_extends = empty($options['extends']) ? $this->_extends : $options['extends'];
- $this->_extendsFile = !isset($options['extends_location']) ? $this->_extendsFile : $options['extends_location'];
-
- $classname = $this->classname = $this->getClassNameFromTableName($this->table);
-
- $out = $this->_generateClassTable();
- //echo $out;
- eval('?>'.$out);
- return new $classname;
+ // This is so derived generator classes can generate variabels
+ // It MUST NOT be changed here!!!
+ return "";
}
-
+
/**
- * fillTableSchema - set the database schema on the fly
- *
- *
- *
- * @param string database name
- * @param string table name of table to create schema info for
- *
- * @return none | PEAR::error()
- * @access public
- */
- public function fillTableSchema($database, $table)
+ * hook for after var lines (
+ * called at the end of the output of var line have generated, override to add extra var
+ * lines
+ *
+ * @param array cols containing array of objects with type,len,flags etc. from tableInfo call
+ * @access public
+ * @return string added to class eg. functions.
+ */
+ public function derivedHookPostVar($t)
{
- global $_DB_DATAOBJECT;
- // a little bit of sanity testing.
- if ((false !== strpos($database, "'")) || (false !== strpos($database, ";"))) {
- return PEAR::raiseError("Error: Database name contains a quote or semi-colon", null, PEAR_ERROR_DIE);
- }
-
- $this->_database = $database;
-
- $this->_connect();
- $table = trim($table);
-
- // a little bit of sanity testing.
- if ((false !== strpos($table, "'")) || (false !== strpos($table, ";"))) {
- return PEAR::raiseError("Error: Table contains a quote or semi-colon", null, PEAR_ERROR_DIE);
- }
- $__DB= &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5];
-
-
- $options = PEAR::getStaticProperty('DB_DataObject', 'options');
- $db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
- $is_MDB2 = ($db_driver != 'DB') ? true : false;
-
- if (!$is_MDB2) {
- // try getting a list of schema tables first. (postgres)
- $__DB->expectError(DB_ERROR_UNSUPPORTED);
- $this->tables = $__DB->getListOf('schema.tables');
- $__DB->popExpect();
- } else {
- /**
- * set portability and some modules to fetch the informations
- */
- $__DB->setOption('portability', MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_FIX_CASE);
- $__DB->loadModule('Manager');
- $__DB->loadModule('Reverse');
- }
- $quotedTable = !empty($options['quote_identifiers_tableinfo']) ?
- $__DB->quoteIdentifier($table) : $table;
-
- if (!$is_MDB2) {
- $defs = $__DB->tableInfo($quotedTable);
- } else {
- $defs = $__DB->reverse->tableInfo($quotedTable);
- if (PEAR::isError($defs)) {
- return $defs;
- }
- foreach ($defs as $k => $v) {
- if (!isset($defs[$k]['length'])) {
- continue;
- }
- $defs[$k]['len'] = $defs[$k]['length'];
- }
- }
-
- if (PEAR::isError($defs)) {
- return $defs;
- }
-
-
-
- if (@$_DB_DATAOBJECT['CONFIG']['debug'] > 2) {
- $this->debug("getting def for $database/$table", 'fillTable');
- $this->debug(print_r($defs, true), 'defs');
- }
- // cast all definitions to objects - as we deal with that better.
-
-
- foreach ($defs as $def) {
- if (is_array($def)) {
- $this->_definitions[$table][] = (object) $def;
- }
- }
-
- $this->table = trim($table);
- $ret = $this->_generateDefinitionsTable();
-
- $_DB_DATAOBJECT['INI'][$database][$table] = $ret['table'];
- $_DB_DATAOBJECT['INI'][$database][$table.'__keys'] = $ret['keys'];
- return false;
+ // This is so derived generator classes can generate variabels
+ // It MUST NOT be changed here!!!
+ return "";
}
-
+
/**
- * Generate getter methods for class definition
- *
- * @param string $input Existing class contents
- * @return string
- * @access public
- */
+ * Generate getter methods for class definition
+ *
+ * @param string $input Existing class contents
+ * @return string
+ * @access public
+ */
public function _generateGetters($input)
{
- $options = &PEAR::getStaticProperty('DB_DataObject', 'options');
+ $options = &(new PEAR)->getStaticProperty('DB_DataObject', 'options');
$getters = '';
// only generate if option is set to true
$input = preg_replace('/(\n|\r\n)\s*###START_AUTOCODE(\n|\r\n).*(\n|\r\n)\s*###END_AUTOCODE(\n|\r\n)/s', '', $input);
$getters .= "\n\n";
- $defs = $this->_definitions[$this->table];
+ $defs = $this->_definitions[$this->table];
// loop through properties and create getter methods
- foreach ($defs = $defs as $t) {
+ foreach ($defs as $t) {
// build mehtod name
$methodName = 'get' . $this->getMethodNameFromColumnName($t->name);
$getters .= " * Getter for \${$t->name}\n";
$getters .= " *\n";
$getters .= (stristr($t->flags, 'multiple_key')) ? " * @return object\n"
- : " * @return {$t->type}\n";
+ : " * @return {$t->type}\n";
$getters .= " * @access public\n";
$getters .= " */\n";
$getters .= (substr(phpversion(), 0, 1) > 4) ? ' public '
- : ' ';
+ : ' ';
$getters .= "function $methodName() {\n";
$getters .= " return \$this->{$t->name};\n";
$getters .= " }\n\n";
}
-
+
return $getters;
}
+
/**
- * Generate link setter/getter methods for class definition
- *
- * @param string Existing class contents
- * @return string
- * @access public
- */
- public function _generateLinkMethods($input)
+ * Convert a column name into a method name (usually prefixed by get/set/validateXXXXX)
+ *
+ * @access public
+ * @param $col
+ * @return string method name;
+ */
+
+
+ public function getMethodNameFromColumnName($col)
{
- $options = &PEAR::getStaticProperty('DB_DataObject', 'options');
+ return ucfirst($col);
+ }
+
+ /**
+ * Generate setter methods for class definition
+ *
+ * @param string Existing class contents
+ * @return string
+ * @access public
+ */
+ public function _generateSetters($input)
+ {
+ $options = &(new PEAR)->getStaticProperty('DB_DataObject', 'options');
$setters = '';
// only generate if option is set to true
-
- // generate_link_methods true::
-
-
- if (empty($options['generate_link_methods'])) {
- //echo "skip lm? - not set";
- return '';
- }
-
- if (empty($this->_fkeys)) {
- // echo "skip lm? - fkyes empty";
- return '';
- }
- if (empty($this->_fkeys[$this->table])) {
- //echo "skip lm? - no fkeys for {$this->table}";
+ if (empty($options['generate_setters'])) {
return '';
}
-
+
// remove auto-generated code from input to be able to check if the method exists outside of the auto-code
$input = preg_replace('/(\n|\r\n)\s*###START_AUTOCODE(\n|\r\n).*(\n|\r\n)\s*###END_AUTOCODE(\n|\r\n)/s', '', $input);
$setters .= "\n";
- $defs = $this->_fkeys[$this->table];
-
-
- // $fk[$this->table][$tref[1]] = $tref[2] . ":" . $tref[3];
+ $defs = $this->_definitions[$this->table];
// loop through properties and create setter methods
- foreach ($defs as $k => $info) {
+ foreach ($defs as $t) {
// build mehtod name
- $methodName = is_callable($options['generate_link_methods']) ?
- $options['generate_link_methods']($k) : $k;
+ $methodName = 'set' . $this->getMethodNameFromColumnName($t->name);
- if (!strlen(trim($k)) || preg_match("/function[\s]+[&]?$methodName\(/i", $input)) {
+ if (!strlen(trim($t->name)) || preg_match("/function[\s]+[&]?$methodName\(/i", $input)) {
continue;
}
$setters .= " /**\n";
- $setters .= " * Getter / Setter for \${$k}\n";
+ $setters .= " * Setter for \${$t->name}\n";
$setters .= " *\n";
- $setters .= " * @param mixed (optional) value to assign\n";
+ $setters .= " * @param mixed input value\n";
$setters .= " * @access public\n";
-
$setters .= " */\n";
$setters .= (substr(phpversion(), 0, 1) > 4) ? ' public '
- : ' ';
- $setters .= "function $methodName() {\n";
- $setters .= " return \$this->link('$k', func_get_args());\n";
+ : ' ';
+ $setters .= "function $methodName(\$value) {\n";
+ $setters .= " \$this->{$t->name} = \$value;\n";
$setters .= " }\n\n";
}
-
+
+
return $setters;
}
/**
- * Generate setter methods for class definition
+ * Generate link setter/getter methods for class definition
*
- * @param string Existing class contents
+ * @param string Existing class contents
* @return string
* @access public
*/
- public function _generateSetters($input)
+ public function _generateLinkMethods($input)
{
- $options = &PEAR::getStaticProperty('DB_DataObject', 'options');
+ $options = &(new PEAR)->getStaticProperty('DB_DataObject', 'options');
$setters = '';
// only generate if option is set to true
- if (empty($options['generate_setters'])) {
+
+ // generate_link_methods true::
+
+
+ if (empty($options['generate_link_methods'])) {
+ //echo "skip lm? - not set";
+ return '';
+ }
+
+ if (empty($this->_fkeys)) {
+ // echo "skip lm? - fkyes empty";
+ return '';
+ }
+ if (empty($this->_fkeys[$this->table])) {
+ //echo "skip lm? - no fkeys for {$this->table}";
return '';
}
$input = preg_replace('/(\n|\r\n)\s*###START_AUTOCODE(\n|\r\n).*(\n|\r\n)\s*###END_AUTOCODE(\n|\r\n)/s', '', $input);
$setters .= "\n";
- $defs = $this->_definitions[$this->table];
+ $defs = $this->_fkeys[$this->table];
+
+
+ // $fk[$this->table][$tref[1]] = $tref[2] . ":" . $tref[3];
// loop through properties and create setter methods
- foreach ($defs = $defs as $t) {
+ foreach ($defs as $k => $info) {
// build mehtod name
- $methodName = 'set' . $this->getMethodNameFromColumnName($t->name);
+ $methodName = is_callable($options['generate_link_methods']) ?
+ $options['generate_link_methods']($k) : $k;
- if (!strlen(trim($t->name)) || preg_match("/function[\s]+[&]?$methodName\(/i", $input)) {
+ if (!strlen(trim($k)) || preg_match("/function[\s]+[&]?$methodName\(/i", $input)) {
continue;
}
$setters .= " /**\n";
- $setters .= " * Setter for \${$t->name}\n";
+ $setters .= " * Getter / Setter for \${$k}\n";
$setters .= " *\n";
- $setters .= " * @param mixed input value\n";
+ $setters .= " * @param mixed (optional) value to assign\n";
$setters .= " * @access public\n";
+
$setters .= " */\n";
$setters .= (substr(phpversion(), 0, 1) > 4) ? ' public '
- : ' ';
- $setters .= "function $methodName(\$value) {\n";
- $setters .= " \$this->{$t->name} = \$value;\n";
+ : ' ';
+ $setters .= "function $methodName() {\n";
+ $setters .= " return \$this->link('$k', func_get_args());\n";
$setters .= " }\n\n";
}
-
return $setters;
}
+
/**
- * Generate table Function - used when generator_no_ini is set.
- *
- * @param array table array.
- * @return string
- * @access public
- */
+ * Generate table Function - used when generator_no_ini is set.
+ *
+ * @param array table array.
+ * @return string
+ * @access public
+ */
public function _generateTableFunction($def)
{
$defines = explode(',', 'INT,STR,DATE,TIME,BOOL,TXT,BLOB,NOTNULL,MYSQLTIMESTAMP');
-
+
$ret = "\n" .
- " function table()\n" .
- " {\n" .
- " return array(\n";
-
- foreach ($def as $k=>$v) {
+ " function table()\n" .
+ " {\n" .
+ " return array(\n";
+
+ foreach ($def as $k => $v) {
$str = '0';
foreach ($defines as $dn) {
if ($v & constant('DB_DATAOBJECT_' . $dn)) {
$str = substr($str, 3); // strip the 0 +
}
// hopefully addslashes is good enough here!!!
- $ret .= ' \''.addslashes($k).'\' => ' . $str . ",\n";
+ $ret .= ' \'' . addslashes($k) . '\' => ' . $str . ",\n";
}
return $ret . " );\n" .
- " }\n";
+ " }\n";
}
+
/**
- * Generate keys Function - used generator_no_ini is set.
- *
- * @param array keys array.
- * @return string
- * @access public
- */
+ * Generate keys Function - used generator_no_ini is set.
+ *
+ * @param array keys array.
+ * @return string
+ * @access public
+ */
public function _generateKeysFunction($def)
{
$ret = "\n" .
- " function keys()\n" .
- " {\n" .
- " return array(";
-
- foreach ($def as $k=>$type) {
+ " function keys()\n" .
+ " {\n" .
+ " return array(";
+
+ foreach ($def as $k => $type) {
// hopefully addslashes is good enough here!!!
- $ret .= '\''.addslashes($k).'\', ';
+ $ret .= '\'' . addslashes($k) . '\', ';
}
$ret = preg_replace('#, $#', '', $ret);
return $ret . ");\n" .
- " }\n";
+ " }\n";
}
+
/**
- * Generate sequenceKey Function - used generator_no_ini is set.
- *
- * @param array table and key definition.
- * @return string
- * @access public
- */
+ * Generate sequenceKey Function - used generator_no_ini is set.
+ *
+ * @param array table and key definition.
+ * @return string
+ * @access public
+ */
public function _generateSequenceKeyFunction($def)
{
-
+
//print_r($def);
// DB_DataObject::debugLevel(5);
global $_DB_DATAOBJECT;
// print_r($def);
-
-
- $dbtype = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['phptype'];
- $realkeys = $def['keys'];
- $keys = array_keys($realkeys);
- $usekey = isset($keys[0]) ? $keys[0] : false;
- $table = $def['table'];
-
-
+
+
+ $dbtype = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['phptype'];
+ $realkeys = $def['keys'];
+ $keys = array_keys($realkeys);
+ $usekey = isset($keys[0]) ? $keys[0] : false;
+ $table = $def['table'];
+
+
$seqname = false;
-
-
-
-
- $ar = array(false,false,false);
+
+
+ $ar = array(false, false, false);
if ($usekey !== false) {
- if (!empty($_DB_DATAOBJECT['CONFIG']['sequence_'.$this->__table])) {
- $usekey = $_DB_DATAOBJECT['CONFIG']['sequence_'.$this->__table];
+ if (!empty($_DB_DATAOBJECT['CONFIG']['sequence_' . $this->__table])) {
+ $usekey = $_DB_DATAOBJECT['CONFIG']['sequence_' . $this->__table];
if (strpos($usekey, ':') !== false) {
list($usekey, $seqname) = explode(':', $usekey);
}
}
-
- if (in_array($dbtype, array( 'mysql', 'mysqli', 'mssql', 'ifx')) &&
+
+ if (in_array($dbtype, array('mysql', 'mysqli', 'mssql', 'ifx')) &&
($table[$usekey] & DB_DATAOBJECT_INT) &&
isset($realkeys[$usekey]) && ($realkeys[$usekey] == 'N')
- ) {
+ ) {
// use native sequence keys.
- $ar = array($usekey,true,$seqname);
+ $ar = array($usekey, true, $seqname);
} else {
// use generated sequence keys..
if ($table[$usekey] & DB_DATAOBJECT_INT) {
- $ar = array($usekey,false,$seqname);
+ $ar = array($usekey, false, $seqname);
}
}
}
-
-
-
-
+
+
$ret = "\n" .
- " function sequenceKey() // keyname, use native, native name\n" .
- " {\n" .
- " return array(";
+ " function sequenceKey() // keyname, use native, native name\n" .
+ " {\n" .
+ " return array(";
foreach ($ar as $v) {
switch (gettype($v)) {
case 'boolean':
$ret .= ($v ? 'true' : 'false') . ', ';
break;
-
+
case 'string':
$ret .= "'" . $v . "', ";
break;
-
+
default: // eak
$ret .= "null, ";
-
+
}
}
$ret = preg_replace('#, $#', '', $ret);
return $ret . ");\n" .
- " }\n";
+ " }\n";
}
+
/**
- * Generate defaults Function - used generator_add_defaults or generator_no_ini is set.
- * Only supports mysql and mysqli ... welcome ideas for more..
- *
- *
- * @param array table and key definition.
- * @return string
- * @access public
- */
+ * Generate defaults Function - used generator_add_defaults or generator_no_ini is set.
+ * Only supports mysql and mysqli ... welcome ideas for more..
+ *
+ *
+ * @param $table
+ * @param $defs
+ * @return string
+ * @access public
+ */
public function _generateDefaultsFunction($table, $defs)
{
- $__DB= &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5];
- if (!in_array($__DB->phptype, array('mysql','mysqli'))) {
- return; // cant handle non-mysql introspection for defaults.
+ $__DB = &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5];
+ if (!in_array($__DB->phptype, array('mysql', 'mysqli'))) {
+ return null; // cant handle non-mysql introspection for defaults.
}
- $options = PEAR::getStaticProperty('DB_DataObject', 'options');
+ $options = (new PEAR)->getStaticProperty('DB_DataObject', 'options');
$db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
$method = $db_driver == 'DB' ? 'getAll' : 'queryAll';
$res = $__DB->$method('DESCRIBE ' . $table, DB_FETCHMODE_ASSOC);
foreach ($res as $ar) {
// this is initially very dumb... -> and it may mess up..
$type = $defs[$ar['Field']];
-
+
switch (true) {
-
+
case (is_null($ar['Default'])):
- $defaults[$ar['Field']] = 'null';
+ $defaults[$ar['Field']] = 'null';
break;
-
+
case ($type & DB_DATAOBJECT_DATE):
case ($type & DB_DATAOBJECT_TIME):
case ($type & DB_DATAOBJECT_MYSQLTIMESTAMP): // not supported yet..
break;
-
+
case ($type & DB_DATAOBJECT_BOOL):
- $defaults[$ar['Field']] = (int)(boolean) $ar['Default'];
+ $defaults[$ar['Field']] = (int)(boolean)$ar['Default'];
break;
-
-
+
+
case ($type & DB_DATAOBJECT_STR):
- $defaults[$ar['Field']] = "'" . addslashes($ar['Default']) . "'";
+ $defaults[$ar['Field']] = "'" . addslashes($ar['Default']) . "'";
break;
-
-
+
+
default: // hopefully eveything else... - numbers etc.
if (!strlen($ar['Default'])) {
continue;
}
if (is_numeric($ar['Default'])) {
- $defaults[$ar['Field']] = $ar['Default'];
+ $defaults[$ar['Field']] = $ar['Default'];
}
break;
-
+
}
//var_dump(array($ar['Field'], $ar['Default'], $defaults[$ar['Field']]));
}
if (empty($defaults)) {
- return;
+ return null;
}
-
+
$ret = "\n" .
- " function defaults() // column default values \n" .
- " {\n" .
- " return array(\n";
- foreach ($defaults as $k=>$v) {
- $ret .= ' \''.addslashes($k).'\' => ' . $v . ",\n";
+ " function defaults() // column default values \n" .
+ " {\n" .
+ " return array(\n";
+ foreach ($defaults as $k => $v) {
+ $ret .= ' \'' . addslashes($k) . '\' => ' . $v . ",\n";
}
return $ret . " );\n" .
- " }\n";
+ " }\n";
+ }
+
+ /**
+ * hook to add extra methods to all classes
+ *
+ * called once for each class, use with $this->table and
+ * $this->_definitions[$this->table], to get data out of the current table,
+ * use it to add extra methods to the default classes.
+ *
+ * @access public
+ * @param string $input
+ * @return string added to class eg. functions.
+ */
+ public function derivedHookFunctions($input = "")
+ {
+ // This is so derived generator classes can generate functions
+ // It MUST NOT be changed here!!!
+ return "";
+ }
+
+ /**
+ *
+ * /**
+ * getProxyFull - create a class definition on the fly and instantate it..
+ *
+ * similar to generated files - but also evals the class definitoin code.
+ *
+ *
+ * @param string database name
+ * @param string table name of table to create proxy for.
+ *
+ *
+ * @return object Instance of class. or PEAR Error
+ * @access public
+ */
+ public function getProxyFull($database, $table)
+ {
+ if ($err = $this->fillTableSchema($database, $table)) {
+ return $err;
+ }
+
+
+ $options = &(new PEAR)->getStaticProperty('DB_DataObject', 'options');
+ $class_prefix = empty($options['class_prefix']) ? '' : $options['class_prefix'];
+
+ $this->_extends = empty($options['extends']) ? $this->_extends : $options['extends'];
+ $this->_extendsFile = !isset($options['extends_location']) ? $this->_extendsFile : $options['extends_location'];
+
+ $classname = $this->classname = $this->getClassNameFromTableName($this->table);
+
+ $out = $this->_generateClassTable();
+ //echo $out;
+ eval('?>' . $out);
+ return new $classname;
+ }
+
+ /**
+ * fillTableSchema - set the database schema on the fly
+ *
+ *
+ *
+ * @param string database name
+ * @param string table name of table to create schema info for
+ *
+ * @return none|object|PEAR
+ * @access public
+ */
+ public function fillTableSchema($database, $table)
+ {
+ global $_DB_DATAOBJECT;
+ // a little bit of sanity testing.
+ if ((false !== strpos($database, "'")) || (false !== strpos($database, ";"))) {
+ return (new PEAR)->raiseError("Error: Database name contains a quote or semi-colon", null, PEAR_ERROR_DIE);
+ }
+
+ $this->_database = $database;
+
+ $this->_connect();
+ $table = trim($table);
+
+ // a little bit of sanity testing.
+ if ((false !== strpos($table, "'")) || (false !== strpos($table, ";"))) {
+ return (new PEAR)->raiseError("Error: Table contains a quote or semi-colon", null, PEAR_ERROR_DIE);
+ }
+ $__DB = &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5];
+
+
+ $options = (new PEAR)->getStaticProperty('DB_DataObject', 'options');
+ $db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
+ $is_MDB2 = ($db_driver != 'DB') ? true : false;
+
+ if (!$is_MDB2) {
+ // try getting a list of schema tables first. (postgres)
+ $__DB->expectError(DB_ERROR_UNSUPPORTED);
+ $this->tables = $__DB->getListOf('schema.tables');
+ $__DB->popExpect();
+ } else {
+ /**
+ * set portability and some modules to fetch the informations
+ */
+ $__DB->setOption('portability', MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_FIX_CASE);
+ $__DB->loadModule('Manager');
+ $__DB->loadModule('Reverse');
+ }
+ $quotedTable = !empty($options['quote_identifiers_tableinfo']) ?
+ $__DB->quoteIdentifier($table) : $table;
+
+ if (!$is_MDB2) {
+ $defs = $__DB->tableInfo($quotedTable);
+ } else {
+ $defs = $__DB->reverse->tableInfo($quotedTable);
+ if ((new PEAR)->isError($defs)) {
+ return $defs;
+ }
+ foreach ($defs as $k => $v) {
+ if (!isset($defs[$k]['length'])) {
+ continue;
+ }
+ $defs[$k]['len'] = $defs[$k]['length'];
+ }
+ }
+
+ if ((new PEAR)->isError($defs)) {
+ return $defs;
+ }
+
+
+ if (@$_DB_DATAOBJECT['CONFIG']['debug'] > 2) {
+ $this->debug("getting def for $database/$table", 'fillTable');
+ $this->debug(print_r($defs, true), 'defs');
+ }
+ // cast all definitions to objects - as we deal with that better.
+
+
+ foreach ($defs as $def) {
+ if (is_array($def)) {
+ $this->_definitions[$table][] = (object)$def;
+ }
+ }
+
+ $this->table = trim($table);
+ $ret = $this->_generateDefinitionsTable();
+
+ $_DB_DATAOBJECT['INI'][$database][$table] = $ret['table'];
+ $_DB_DATAOBJECT['INI'][$database][$table . '__keys'] = $ret['keys'];
+ return false;
}
}
* Currenly only supports existing methods, and new 'link()' method
*
*/
-
-
+
+
/**
* Links class
*
class DB_DataObject_Links
{
/**
- * @property {DB_DataObject} do DataObject to apply this to.
- */
+ * @property {DB_DataObject} do DataObject to apply this to.
+ */
public $do = false;
-
-
+
+
/**
* @property {Array|String} load What to load, 'all' or an array of properties. (default all)
*/
* @property {Boolean} apply apply the result to this object, (default true)
*/
public $apply = true;
-
-
+
+
//------------------------- RETURN ------------------------------------
/**
* @property {Array} links key value associative array of links.
*/
public $links;
-
-
+
+
/**
* Constructor
* -- good ole style..
- * @param {DB_DataObject} do DataObject to apply to.
- * @param {Array} cfg Configuration (basically properties of this object)
+ * @param {DB_DataObject} do DataObject to apply to.
+ * @param array $cfg
*/
-
- public function DB_DataObject_Links($do, $cfg= array())
+
+ public function __construct($do, $cfg = array())
{
// check if do is set!!!?
$this->do = $do;
-
- foreach ($cfg as $k=>$v) {
+
+ foreach ($cfg as $k => $v) {
$this->$k = $v;
}
}
-
+
/**
- * return name from related object
+ * a generic geter/setter provider..
*
- * The relies on a <dbname>.links.ini file, unless you specify the arguments.
+ * provides a generic getter setter for the referenced object
+ * eg.
+ * $link->link('company_id') returns getLink for the object
+ * if nothing is linked (it will return an empty dataObject)
+ * $link->link('company_id', array(1)) - just sets the
*
- * you can also use $this->getLink('thisColumnName','otherTable','otherTableColumnName')
+ * also array as the field speck supports
+ * $link->link(array('company_id', 'company:id'))
*
*
- * @param string $field|array either row or row.xxxxx or links spec.
- * @param string|DB_DataObject $table (optional) name of table to look up value in
- * @param string $link (optional) name of column in other table to match
- * @author Tim White <tim@cyface.com>
- * @access public
- * @return mixed object on success false on failure or '0' when not linked
+ * @param string|array $field the field to fetch or link spec.
+ * @param array $args
+ * @return mixed true of false on set, the object on getter.
+ * @params array $args the arguments sent to the getter setter
*/
- public function getLink($field, $table= false, $link='')
+ public function link($field, $args = array())
{
- static $cache = array();
-
- // GUESS THE LINKED TABLE.. (if found - recursevly call self)
-
- if ($table == false) {
- $info = $this->linkInfo($field);
-
- if ($info) {
- return $this->getLink($field, $info[0], $link === false ? $info[1] : $link);
- }
-
- // no links defined.. - use borked BC method...
- // use the old _ method - this shouldnt happen if called via getLinks()
- if (!($p = strpos($field, '_'))) {
- return false;
- }
- $table = substr($field, 0, $p);
- return $this->getLink($field, $table);
- }
-
- $tn = is_string($table) ? $table : $table->tableName();
-
-
-
- if (!isset($this->do->$field)) {
- $this->do->raiseError("getLink: row not set $field", DB_DATAOBJECT_ERROR_NODATA);
- return false;
- }
-
- // check to see if we know anything about this table..
-
-
- if (empty($this->do->$field) || $this->do->$field < 0) {
- return 0; // no record.
- }
-
- if ($this->cached && isset($cache[$tn.':'. $link .':'. $this->do->$field])) {
- return $cache[$tn.':'. $link .':'. $this->do->$field];
- }
-
- $obj = is_string($table) ? $this->do->factory($tn) : $table;
- ;
-
- if (!is_a($obj, 'DB_DataObject')) {
+ $info = $this->linkInfo($field);
+
+ if (!$info) {
$this->do->raiseError(
- "getLink:Could not find class for row $field, table $tn",
+ "getLink:Could not find link for row $field",
DB_DATAOBJECT_ERROR_INVALIDCONFIG
);
return false;
}
- // -1 or 0 -- no referenced record..
-
- $ret = false;
- if ($link) {
- if ($obj->get($link, $this->do->$field)) {
- $ret = $obj;
+ $field = $info[2];
+
+
+ if (empty($args)) { // either an empty array or really empty....
+
+ if (!isset($this->do->$field)) {
+ return $info[0]; // empty dataobject.
}
-
-
- // this really only happens when no link config is set (old BC stuff)
- } elseif ($obj->get($this->do->$field)) {
- $ret= $obj;
+
+ $ret = $this->getLink($field);
+ // nothing linked -- return new object..
+ return ($ret === 0) ? $info[0] : $ret;
}
- if ($this->cached) {
- $cache[$tn.':'. $link .':'. $this->do->$field] = $ret;
+ $assign = is_array($args) ? $args[0] : $args;
+
+ // otherwise it's a set call..
+ if (!is_a($assign, 'DB_DataObject')) {
+ if (is_numeric($assign) && is_integer($assign * 1)) {
+ if ($assign > 0) {
+ if (!$info) {
+ return false;
+ }
+ // check that record exists..
+ if (!$info[0]->get($info[1], $assign)) {
+ return false;
+ }
+ }
+
+ $this->do->$field = $assign;
+ return true;
+ }
+
+ return false;
}
- return $ret;
+
+ // otherwise we are assigning it ...
+
+ $this->do->$field = $assign->{$info[1]};
+ return true;
}
+
/**
* get link information for a field or field specification
*
* array(3) : 'field', $dataobject, 'remote_col' (handy for joinAdd to do nested joins.)
*
* @param string|array $field or link spec to use.
- * @return (false|array) array of dataobject and linked field or false.
- *
+ * @return array|bool (false|array) array of dataobject and linked field or false.
*
*/
-
+
public function linkInfo($field)
{
if (is_array($field)) {
);
}
list($table, $link) = explode(':', $field[1]);
-
+
return array(
$this->do->factory($table),
$link,
);
}
// work out the link.. (classic way)
-
+
$links = $this->do->links();
-
+
if (empty($links) || !is_array($links)) {
return false;
}
-
-
+
+
if (!isset($links[$field])) {
return false;
}
list($table, $link) = explode(':', $links[$field]);
-
-
+
+
//??? needed???
if ($p = strpos($field, ".")) {
$field = substr($field, 0, $p);
}
-
+
return array(
$this->do->factory($table),
$link,
$field
);
}
-
-
-
+
/**
- * a generic geter/setter provider..
- *
- * provides a generic getter setter for the referenced object
- * eg.
- * $link->link('company_id') returns getLink for the object
- * if nothing is linked (it will return an empty dataObject)
- * $link->link('company_id', array(1)) - just sets the
+ * return name from related object
*
- * also array as the field speck supports
- * $link->link(array('company_id', 'company:id'))
+ * The relies on a <dbname>.links.ini file, unless you specify the arguments.
*
+ * you can also use $this->getLink('thisColumnName','otherTable','otherTableColumnName')
*
- * @param string|array $field the field to fetch or link spec.
- * @params array $args the arguments sent to the getter setter
- * @return mixed true of false on set, the object on getter.
*
+ * @param string $field |array either row or row.xxxxx or links spec.
+ * @param bool $table (optional) name of table to look up value in
+ * @param string $link (optional) name of column in other table to match
+ * @return mixed object on success false on failure or '0' when not linked
+ * @author Tim White <tim@cyface.com>
+ * @access public
*/
- public function link($field, $args = array())
+ public function getLink($field, $table = false, $link = '')
{
- $info = $this->linkInfo($field);
-
- if (!$info) {
+ static $cache = array();
+
+ // GUESS THE LINKED TABLE.. (if found - recursevly call self)
+
+ if ($table == false) {
+ $info = $this->linkInfo($field);
+
+ if ($info) {
+ return $this->getLink($field, $info[0], $link === false ? $info[1] : $link);
+ }
+
+ // no links defined.. - use borked BC method...
+ // use the old _ method - this shouldnt happen if called via getLinks()
+ if (!($p = strpos($field, '_'))) {
+ return false;
+ }
+ $table = substr($field, 0, $p);
+ return $this->getLink($field, $table);
+ }
+
+ $tn = is_string($table) ? $table : $table->tableName();
+
+
+ if (!isset($this->do->$field)) {
+ $this->do->raiseError("getLink: row not set $field", DB_DATAOBJECT_ERROR_NODATA);
+ return false;
+ }
+
+ // check to see if we know anything about this table..
+
+
+ if (empty($this->do->$field) || $this->do->$field < 0) {
+ return 0; // no record.
+ }
+
+ if ($this->cached && isset($cache[$tn . ':' . $link . ':' . $this->do->$field])) {
+ return $cache[$tn . ':' . $link . ':' . $this->do->$field];
+ }
+
+ $obj = is_string($table) ? $this->do->factory($tn) : $table;;
+
+ if (!is_a($obj, 'DB_DataObject')) {
$this->do->raiseError(
- "getLink:Could not find link for row $field",
+ "getLink:Could not find class for row $field, table $tn",
DB_DATAOBJECT_ERROR_INVALIDCONFIG
);
return false;
}
- $field = $info[2];
-
-
- if (empty($args)) { // either an empty array or really empty....
-
- if (!isset($this->do->$field)) {
- return $info[0]; // empty dataobject.
+ // -1 or 0 -- no referenced record..
+
+ $ret = false;
+ if ($link) {
+ if ($obj->get($link, $this->do->$field)) {
+ $ret = $obj;
}
-
- $ret = $this->getLink($field);
- // nothing linked -- return new object..
- return ($ret === 0) ? $info[0] : $ret;
+
+
+ // this really only happens when no link config is set (old BC stuff)
+ } elseif ($obj->get($this->do->$field)) {
+ $ret = $obj;
}
- $assign = is_array($args) ? $args[0] : $args;
-
- // otherwise it's a set call..
- if (!is_a($assign, 'DB_DataObject')) {
- if (is_numeric($assign) && is_integer($assign * 1)) {
- if ($assign > 0) {
- if (!$info) {
- return false;
- }
- // check that record exists..
- if (!$info[0]->get($info[1], $assign)) {
- return false;
- }
- }
-
- $this->do->$field = $assign ;
- return true;
- }
-
- return false;
+ if ($this->cached) {
+ $cache[$tn . ':' . $link . ':' . $this->do->$field] = $ret;
}
-
- // otherwise we are assigning it ...
-
- $this->do->$field = $assign->{$info[1]};
- return true;
+ return $ret;
}
+
/**
* load related objects
*
* object vars the links are stored in by changeing the format parameter
*
*
- * @param string format (default _%s) where %s is the table name.
+ * @param string format (default _%s) where %s is the table name.
+ * @return boolean , true on success
* @author Tim White <tim@cyface.com>
* @access public
- * @return boolean , true on success
*/
-
+
public function applyLinks($format = '_%s')
{
-
+
// get table will load the options.
if ($this->do->_link_loaded) {
return true;
}
-
+
$this->do->_link_loaded = false;
- $cols = $this->do->table();
+ $cols = $this->do->table();
$links = $this->do->links();
-
+
$loaded = array();
-
+
if ($links) {
foreach ($links as $key => $match) {
list($table, $link) = explode(':', $match);
if ($p = strpos($key, '.')) {
$key = substr($key, 0, $p);
}
-
+
$this->do->$k = $this->getLink($key, $table, $link);
-
+
if (is_object($this->do->$k)) {
$loaded[] = $k;
}
if (!is_null($links)) {
return false;
}
-
-
+
+
foreach (array_keys($cols) as $key) {
if (!($p = strpos($key, '_'))) {
continue;
}
// does the table exist.
- $k =sprintf($format, $key);
+ $k = sprintf($format, $key);
$this->do->$k = $this->getLink($key);
if (is_object($this->do->$k)) {
$loaded[] = $k;
$this->do->_link_loaded = $loaded;
return true;
}
-
+
/**
* getLinkArray
* Fetch an array of related objects. This should be used in conjunction with a
* You may also use this with all parameters to specify, the column and related table.
*
* @access public
- * @param string $field- either column or column.xxxxx
+ * @param string $field - either column or column.xxxxx
* @param string $table (optional) name of table to look up value in
- * @param string $fkey (optional) fetchall key see DB_DataObject::fetchAll()
- * @param string $fval (optional)fetchall val DB_DataObject::fetchAll()
- * @param string $fval (optional) fetchall method DB_DataObject::fetchAll()
+ * @param bool $fkey (optional) fetchall key see DB_DataObject::fetchAll()
+ * @param bool $fval (optional) fetchall method DB_DataObject::fetchAll()
+ * @param bool $fmethod
* @return array - array of results (empty array on failure)
*
* Example - Getting the related objects
* foreach ($children as $child) {
* echo $child->name, '<br />';
* }
- *
*/
public function getLinkArray($field, $table = null, $fkey = false, $fval = false, $fmethod = false)
{
$ret = array();
if (!$table) {
$links = $this->do->links();
-
+
if (is_array($links)) {
if (!isset($links[$field])) {
// failed..
}
return $this->getLinkArray($field, substr($field, 0, $p));
}
-
- $c = $this->do->factory($table);
-
+
+ $c = $this->do->factory($table);
+
if (!is_object($c) || !is_a($c, 'DB_DataObject')) {
$this->do->raiseError(
"getLinkArray:Could not find class for row $field, table $table",
define('DB_DATAOBJECT_NO_OVERLOAD', 1);
//require_once 'DB/DataObject/Generator.php';
-require_once 'DB/DataObject/Generator.php';
+require_once 'Generator.php';
if (php_sapi_name() != 'cli') {
- PEAR::raiseError("\nERROR: You must turn use the cli sapi to run this", null, PEAR_ERROR_DIE);
+ (new PEAR)->raiseError("\nERROR: You must turn use the cli sapi to run this", null, PEAR_ERROR_DIE);
}
if (!ini_get('register_argc_argv')) {
- PEAR::raiseError("\nERROR: You must turn register_argc_argv On in you php.ini file for this to work\neg.\n\nregister_argc_argv = On\n\n", null, PEAR_ERROR_DIE);
+ (new PEAR)->raiseError("\nERROR: You must turn register_argc_argv On in you php.ini file for this to work\neg.\n\nregister_argc_argv = On\n\n", null, PEAR_ERROR_DIE);
exit;
}
if (!@$_SERVER['argv'][1]) {
- PEAR::raiseError("\nERROR: createTable.php usage:\n\n" .$_SERVER['argv'][0] . " example.ini\n\n", null, PEAR_ERROR_DIE);
+ (new PEAR)->raiseError("\nERROR: createTable.php usage:\n\n" . $_SERVER['argv'][0] . " example.ini\n\n", null, PEAR_ERROR_DIE);
exit;
}
$config = parse_ini_file($_SERVER['argv'][1], true);
-foreach ($config as $class=>$values) {
- $options = &PEAR::getStaticProperty($class, 'options');
+foreach ($config as $class => $values) {
+ $options = &(new PEAR)->getStaticProperty($class, 'options');
$options = $values;
}
-$options = &PEAR::getStaticProperty('DB_DataObject', 'options');
+$options = &(new PEAR)->getStaticProperty('DB_DataObject', 'options');
if (empty($options)) {
- PEAR::raiseError("\nERROR: could not read ini file\n\n", null, PEAR_ERROR_DIE);
+ (new PEAR)->raiseError("\nERROR: could not read ini file\n\n", null, PEAR_ERROR_DIE);
exit;
}
set_time_limit(0);
}
if (isset($this->autocommit)) {
return array('autocommit',
- 'dbsyntax',
- 'dsn',
- 'features',
- 'fetchmode',
- 'fetchmode_object_class',
- 'options',
- 'was_connected',
- );
+ 'dbsyntax',
+ 'dsn',
+ 'features',
+ 'fetchmode',
+ 'fetchmode_object_class',
+ 'options',
+ 'was_connected',
+ );
} else {
return array('dbsyntax',
- 'dsn',
- 'features',
- 'fetchmode',
- 'fetchmode_object_class',
- 'options',
- 'was_connected',
- );
+ 'dsn',
+ 'features',
+ 'fetchmode',
+ 'fetchmode_object_class',
+ 'options',
+ 'was_connected',
+ );
}
}
// {{{ __toString()
/**
- * Automatic string conversion for PHP 5
+ * DEPRECATED: String conversion method
*
* @return string a string describing the current PEAR DB object
*
- * @since Method available since Release 1.7.0
+ * @deprecated Method deprecated in Release 1.7.0
*/
- public function __toString()
+ public function toString()
{
- $info = strtolower(get_class($this));
- $info .= ': (phptype=' . $this->phptype .
- ', dbsyntax=' . $this->dbsyntax .
- ')';
- if ($this->connection) {
- $info .= ' [connected]';
- }
- return $info;
+ return $this->__toString();
}
// }}}
// {{{ toString()
/**
- * DEPRECATED: String conversion method
+ * Automatic string conversion for PHP 5
*
* @return string a string describing the current PEAR DB object
*
- * @deprecated Method deprecated in Release 1.7.0
+ * @since Method available since Release 1.7.0
*/
- public function toString()
+ public function __toString()
{
- return $this->__toString();
+ $info = strtolower(get_class($this));
+ $info .= ': (phptype=' . $this->phptype .
+ ', dbsyntax=' . $this->dbsyntax .
+ ')';
+ if ($this->connection) {
+ $info .= ' [connected]';
+ }
+ return $info;
}
// }}}
* DEPRECATED: Quotes a string so it can be safely used within string
* delimiters in a query
*
- * @param string $string the string to be quoted
+ * @param string $string the string to be quoted
*
* @return string the quoted string
*
// }}}
// {{{ quote()
- /**
- * DEPRECATED: Quotes a string so it can be safely used in a query
- *
- * @param string $string the string to quote
- *
- * @return string the quoted string or the string <samp>NULL</samp>
- * if the value submitted is <kbd>null</kbd>.
- *
- * @see DB_common::quoteSmart(), DB_common::escapeSimple()
- * @deprecated Deprecated in release 1.6.0
- */
- public function quote($string = null)
- {
- return $this->quoteSmart($string);
- }
-
- // }}}
- // {{{ quoteIdentifier()
-
- /**
- * Quotes a string so it can be safely used as a table or column name
- *
- * Delimiting style depends on which database driver is being used.
- *
- * NOTE: just because you CAN use delimited identifiers doesn't mean
- * you SHOULD use them. In general, they end up causing way more
- * problems than they solve.
- *
- * Portability is broken by using the following characters inside
- * delimited identifiers:
- * + backtick (<kbd>`</kbd>) -- due to MySQL
- * + double quote (<kbd>"</kbd>) -- due to Oracle
- * + brackets (<kbd>[</kbd> or <kbd>]</kbd>) -- due to Access
- *
- * Delimited identifiers are known to generally work correctly under
- * the following drivers:
- * + mssql
- * + mysql
- * + mysqli
- * + oci8
- * + odbc(access)
- * + odbc(db2)
- * + pgsql
- * + sqlite
- * + sybase (must execute <kbd>set quoted_identifier on</kbd> sometime
- * prior to use)
- *
- * InterBase doesn't seem to be able to use delimited identifiers
- * via PHP 4. They work fine under PHP 5.
- *
- * @param string $str the identifier name to be quoted
- *
- * @return string the quoted identifier
- *
- * @since Method available since Release 1.6.0
- */
- public function quoteIdentifier($str)
- {
- return '"' . str_replace('"', '""', $str) . '"';
- }
-
- // }}}
- // {{{ quoteSmart()
-
/**
* Formats input so it can be safely used in a query
*
* The output depends on the PHP data type of input and the database
* type being used.
*
- * @param mixed $in the data to be formatted
+ * @param mixed $in the data to be formatted
*
* @return mixed the formatted data. The format depends on the input's
* PHP type:
}
}
+ // }}}
+ // {{{ quoteIdentifier()
+
+ /**
+ * Formats a float value for use within a query in a locale-independent
+ * manner.
+ *
+ * @param float the float value to be quoted.
+ * @return string the quoted string.
+ * @see DB_common::quoteSmart()
+ * @since Method available since release 1.7.8.
+ */
+ public function quoteFloat($float)
+ {
+ return "'" . $this->escapeSimple(str_replace(',', '.', strval(floatval($float)))) . "'";
+ }
+
+ // }}}
+ // {{{ quoteSmart()
+
+ /**
+ * Escapes a string according to the current DBMS's standards
+ *
+ * In SQLite, this makes things safe for inserts/updates, but may
+ * cause problems when performing text comparisons against columns
+ * containing binary data. See the
+ * {@link http://php.net/sqlite_escape_string PHP manual} for more info.
+ *
+ * @param string $str the string to be escaped
+ *
+ * @return string the escaped string
+ *
+ * @see DB_common::quoteSmart()
+ * @since Method available since Release 1.6.0
+ */
+ public function escapeSimple($str)
+ {
+ return str_replace("'", "''", $str);
+ }
+
// }}}
// {{{ quoteBoolean()
{
return $boolean ? '1' : '0';
}
-
+
// }}}
// {{{ quoteFloat()
/**
- * Formats a float value for use within a query in a locale-independent
- * manner.
+ * DEPRECATED: Quotes a string so it can be safely used in a query
*
- * @param float the float value to be quoted.
- * @return string the quoted string.
- * @see DB_common::quoteSmart()
- * @since Method available since release 1.7.8.
+ * @param string $string the string to quote
+ *
+ * @return string the quoted string or the string <samp>NULL</samp>
+ * if the value submitted is <kbd>null</kbd>.
+ *
+ * @see DB_common::quoteSmart(), DB_common::escapeSimple()
+ * @deprecated Deprecated in release 1.6.0
*/
- public function quoteFloat($float)
+ public function quote($string = null)
{
- return "'".$this->escapeSimple(str_replace(',', '.', strval(floatval($float))))."'";
+ return $this->quoteSmart($string);
}
-
+
// }}}
// {{{ escapeSimple()
/**
- * Escapes a string according to the current DBMS's standards
+ * Quotes a string so it can be safely used as a table or column name
*
- * In SQLite, this makes things safe for inserts/updates, but may
- * cause problems when performing text comparisons against columns
- * containing binary data. See the
- * {@link http://php.net/sqlite_escape_string PHP manual} for more info.
+ * Delimiting style depends on which database driver is being used.
*
- * @param string $str the string to be escaped
+ * NOTE: just because you CAN use delimited identifiers doesn't mean
+ * you SHOULD use them. In general, they end up causing way more
+ * problems than they solve.
*
- * @return string the escaped string
+ * Portability is broken by using the following characters inside
+ * delimited identifiers:
+ * + backtick (<kbd>`</kbd>) -- due to MySQL
+ * + double quote (<kbd>"</kbd>) -- due to Oracle
+ * + brackets (<kbd>[</kbd> or <kbd>]</kbd>) -- due to Access
+ *
+ * Delimited identifiers are known to generally work correctly under
+ * the following drivers:
+ * + mssql
+ * + mysql
+ * + mysqli
+ * + oci8
+ * + odbc(access)
+ * + odbc(db2)
+ * + pgsql
+ * + sqlite
+ * + sybase (must execute <kbd>set quoted_identifier on</kbd> sometime
+ * prior to use)
+ *
+ * InterBase doesn't seem to be able to use delimited identifiers
+ * via PHP 4. They work fine under PHP 5.
+ *
+ * @param string $str the identifier name to be quoted
+ *
+ * @return string the quoted identifier
*
- * @see DB_common::quoteSmart()
* @since Method available since Release 1.6.0
*/
- public function escapeSimple($str)
+ public function quoteIdentifier($str)
{
- return str_replace("'", "''", $str);
+ return '"' . str_replace('"', '""', $str) . '"';
}
// }}}
/**
* Tells whether the present driver supports a given feature
*
- * @param string $feature the feature you're curious about
+ * @param string $feature the feature you're curious about
*
* @return bool whether this driver supports $feature
*/
/**
* Sets the fetch mode that should be used by default for query results
*
- * @param integer $fetchmode DB_FETCHMODE_ORDERED, DB_FETCHMODE_ASSOC
+ * @param integer $fetchmode DB_FETCHMODE_ORDERED, DB_FETCHMODE_ASSOC
* or DB_FETCHMODE_OBJECT
- * @param string $object_class the class name of the object to be returned
+ * @param string $object_class the class name of the object to be returned
* by the fetch methods when the
* DB_FETCHMODE_OBJECT mode is selected.
* If no class is specified by default a cast
* done. There is also the posibility to use
* and extend the 'DB_row' class.
*
+ * @return object
* @see DB_FETCHMODE_ORDERED, DB_FETCHMODE_ASSOC, DB_FETCHMODE_OBJECT
*/
public function setFetchMode($fetchmode, $object_class = 'stdClass')
switch ($fetchmode) {
case DB_FETCHMODE_OBJECT:
$this->fetchmode_object_class = $object_class;
- // no break
+ // no break
case DB_FETCHMODE_ORDERED:
case DB_FETCHMODE_ASSOC:
$this->fetchmode = $fetchmode;
default:
return $this->raiseError('invalid fetchmode mode');
}
+ return null;
}
// }}}
// {{{ setOption()
+ /**
+ * Communicates an error and invoke error callbacks, etc
+ *
+ * Basically a wrapper for PEAR::raiseError without the message string.
+ *
+ * @param mixed integer error code, or a PEAR error object (all
+ * other parameters are ignored if this parameter is
+ * an object
+ * @param int error mode, see PEAR_Error docs
+ * @param mixed if error mode is PEAR_ERROR_TRIGGER, this is the
+ * error level (E_USER_NOTICE etc). If error mode is
+ * PEAR_ERROR_CALLBACK, this is the callback function,
+ * either as a function name, or as an array of an
+ * object and method name. For other error modes this
+ * parameter is ignored.
+ * @param string extra debug information. Defaults to the last
+ * query and native error code.
+ * @param mixed native error code, integer or string depending the
+ * backend
+ * @param mixed dummy parameter for E_STRICT compatibility with
+ * PEAR::raiseError
+ * @param mixed dummy parameter for E_STRICT compatibility with
+ * PEAR::raiseError
+ *
+ * @return object the PEAR_Error object
+ *
+ * @see PEAR_Error
+ */
+ public function &raiseError(
+ $code = DB_ERROR,
+ $mode = null,
+ $options = null,
+ $userinfo = null,
+ $nativecode = null,
+ $dummy1 = null,
+ $dummy2 = null
+ )
+ {
+ // The error is yet a DB error object
+ if (is_object($code)) {
+ // because we the static PEAR::raiseError, our global
+ // handler should be used if it is set
+ if ($mode === null && !empty($this->_default_error_mode)) {
+ $mode = $this->_default_error_mode;
+ $options = $this->_default_error_options;
+ }
+ $tmp = PEAR::raiseError(
+ $code,
+ null,
+ $mode,
+ $options,
+ null,
+ null,
+ true
+ );
+ return $tmp;
+ }
+
+ if ($userinfo === null) {
+ $userinfo = $this->last_query;
+ }
+
+ if ($nativecode) {
+ $userinfo .= ' [nativecode=' . trim($nativecode) . ']';
+ } else {
+ $userinfo .= ' [DB Error: ' . DB::errorMessage($code) . ']';
+ }
+
+ $tmp = PEAR::raiseError(
+ null,
+ $code,
+ $mode,
+ $options,
+ $userinfo,
+ 'DB_Error',
+ true
+ );
+ return $tmp;
+ }
+
+ // }}}
+ // {{{ getOption()
+
/**
* Sets run-time configuration options for PEAR DB
*
* </code>
*
* @param string $option option name
- * @param mixed $value value for the option
+ * @param mixed $value value for the option
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_common::$options
*/
switch ($this->phptype) {
case 'oci8':
$this->options['portability'] =
- DB_PORTABILITY_LOWERCASE |
- DB_PORTABILITY_NUMROWS;
- break;
- case 'fbsql':
- case 'mysql':
- case 'mysqli':
- case 'sqlite':
- $this->options['portability'] =
- DB_PORTABILITY_DELETE_COUNT;
- break;
- }
- } else {
- $this->options['portability'] = DB_PORTABILITY_NONE;
- }
- }
-
- return DB_OK;
- }
- return $this->raiseError("unknown option $option");
- }
-
- // }}}
- // {{{ getOption()
-
- /**
- * Returns the value of an option
- *
- * @param string $option the option name you're curious about
- *
- * @return mixed the option's value
- */
- public function getOption($option)
- {
- if (isset($this->options[$option])) {
- return $this->options[$option];
- }
- return $this->raiseError("unknown option $option");
- }
-
- // }}}
- // {{{ prepare()
-
- /**
- * Prepares a query for multiple execution with execute()
- *
- * Creates a query that can be run multiple times. Each time it is run,
- * the placeholders, if any, will be replaced by the contents of
- * execute()'s $data argument.
- *
- * Three types of placeholders can be used:
- * + <kbd>?</kbd> scalar value (i.e. strings, integers). The system
- * will automatically quote and escape the data.
- * + <kbd>!</kbd> value is inserted 'as is'
- * + <kbd>&</kbd> requires a file name. The file's contents get
- * inserted into the query (i.e. saving binary
- * data in a db)
- *
- * Example 1.
- * <code>
- * $sth = $db->prepare('INSERT INTO tbl (a, b, c) VALUES (?, !, &)');
- * $data = array(
- * "John's text",
- * "'it''s good'",
- * 'filename.txt'
- * );
- * $res = $db->execute($sth, $data);
- * </code>
- *
- * Use backslashes to escape placeholder characters if you don't want
- * them to be interpreted as placeholders:
- * <pre>
- * "UPDATE foo SET col=? WHERE col='over \& under'"
- * </pre>
- *
- * With some database backends, this is emulated.
- *
- * {@internal ibase and oci8 have their own prepare() methods.}}
- *
- * @param string $query the query to be prepared
- *
- * @return mixed DB statement resource on success. A DB_Error object
- * on failure.
- *
- * @see DB_common::execute()
- */
- public function prepare($query)
- {
- $tokens = preg_split(
- '/((?<!\\\)[&?!])/',
- $query,
- -1,
- PREG_SPLIT_DELIM_CAPTURE
- );
- $token = 0;
- $types = array();
- $newtokens = array();
-
- foreach ($tokens as $val) {
- switch ($val) {
- case '?':
- $types[$token++] = DB_PARAM_SCALAR;
- break;
- case '&':
- $types[$token++] = DB_PARAM_OPAQUE;
- break;
- case '!':
- $types[$token++] = DB_PARAM_MISC;
- break;
- default:
- $newtokens[] = preg_replace('/\\\([&?!])/', "\\1", $val);
- }
- }
-
- $this->prepare_tokens[] = &$newtokens;
- end($this->prepare_tokens);
-
- $k = key($this->prepare_tokens);
- $this->prepare_types[$k] = $types;
- $this->prepared_queries[$k] = implode(' ', $newtokens);
-
- return $k;
- }
-
- // }}}
- // {{{ autoPrepare()
+ DB_PORTABILITY_LOWERCASE |
+ DB_PORTABILITY_NUMROWS;
+ break;
+ case 'fbsql':
+ case 'mysql':
+ case 'mysqli':
+ case 'sqlite':
+ $this->options['portability'] =
+ DB_PORTABILITY_DELETE_COUNT;
+ break;
+ }
+ } else {
+ $this->options['portability'] = DB_PORTABILITY_NONE;
+ }
+ }
- /**
- * Automaticaly generates an insert or update query and pass it to prepare()
- *
- * @param string $table the table name
- * @param array $table_fields the array of field names
- * @param int $mode a type of query to make:
- * DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE
- * @param string $where for update queries: the WHERE clause to
- * append to the SQL statement. Don't
- * include the "WHERE" keyword.
- *
- * @return resource the query handle
- *
- * @uses DB_common::prepare(), DB_common::buildManipSQL()
- */
- public function autoPrepare(
- $table,
- $table_fields,
- $mode = DB_AUTOQUERY_INSERT,
- $where = false
- ) {
- $query = $this->buildManipSQL($table, $table_fields, $mode, $where);
- if (DB::isError($query)) {
- return $query;
+ return DB_OK;
}
- return $this->prepare($query);
+ return $this->raiseError("unknown option $option");
}
// }}}
- // {{{ autoExecute()
+ // {{{ prepare()
/**
* Automaticaly generates an insert or update query and call prepare()
* and execute() with it
*
- * @param string $table the table name
- * @param array $fields_values the associative array where $key is a
+ * @param string $table the table name
+ * @param array $fields_values the associative array where $key is a
* field name and $value its value
- * @param int $mode a type of query to make:
+ * @param int $mode a type of query to make:
* DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE
- * @param string $where for update queries: the WHERE clause to
+ * @param bool $where for update queries: the WHERE clause to
* append to the SQL statement. Don't
* include the "WHERE" keyword.
*
$fields_values,
$mode = DB_AUTOQUERY_INSERT,
$where = false
- ) {
+ )
+ {
$sth = $this->autoPrepare(
$table,
array_keys($fields_values),
}
// }}}
- // {{{ buildManipSQL()
+ // {{{ autoPrepare()
+
+ /**
+ * Automaticaly generates an insert or update query and pass it to prepare()
+ *
+ * @param string $table the table name
+ * @param array $table_fields the array of field names
+ * @param int $mode a type of query to make:
+ * DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE
+ * @param bool $where for update queries: the WHERE clause to
+ * append to the SQL statement. Don't
+ * include the "WHERE" keyword.
+ *
+ * @return resource|string
+ *
+ * @uses DB_common::prepare(), DB_common::buildManipSQL()
+ */
+ public function autoPrepare(
+ $table,
+ $table_fields,
+ $mode = DB_AUTOQUERY_INSERT,
+ $where = false
+ )
+ {
+ $query = $this->buildManipSQL($table, $table_fields, $mode, $where);
+ if (DB::isError($query)) {
+ return $query;
+ }
+ return $this->prepare($query);
+ }
+
+ // }}}
+ // {{{ autoExecute()
/**
* Produces an SQL query string for autoPrepare()
* - Be carefull! If you don't give a $where param with an UPDATE
* query, all the records of the table will be updated!
*
- * @param string $table the table name
- * @param array $table_fields the array of field names
- * @param int $mode a type of query to make:
+ * @param string $table the table name
+ * @param array $table_fields the array of field names
+ * @param int $mode a type of query to make:
* DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE
- * @param string $where for update queries: the WHERE clause to
+ * @param bool $where for update queries: the WHERE clause to
* append to the SQL statement. Don't
* include the "WHERE" keyword.
*
}
}
+ // }}}
+ // {{{ buildManipSQL()
+
+ /**
+ * Prepares a query for multiple execution with execute()
+ *
+ * Creates a query that can be run multiple times. Each time it is run,
+ * the placeholders, if any, will be replaced by the contents of
+ * execute()'s $data argument.
+ *
+ * Three types of placeholders can be used:
+ * + <kbd>?</kbd> scalar value (i.e. strings, integers). The system
+ * will automatically quote and escape the data.
+ * + <kbd>!</kbd> value is inserted 'as is'
+ * + <kbd>&</kbd> requires a file name. The file's contents get
+ * inserted into the query (i.e. saving binary
+ * data in a db)
+ *
+ * Example 1.
+ * <code>
+ * $sth = $db->prepare('INSERT INTO tbl (a, b, c) VALUES (?, !, &)');
+ * $data = array(
+ * "John's text",
+ * "'it''s good'",
+ * 'filename.txt'
+ * );
+ * $res = $db->execute($sth, $data);
+ * </code>
+ *
+ * Use backslashes to escape placeholder characters if you don't want
+ * them to be interpreted as placeholders:
+ * <pre>
+ * "UPDATE foo SET col=? WHERE col='over \& under'"
+ * </pre>
+ *
+ * With some database backends, this is emulated.
+ *
+ * {@internal ibase and oci8 have their own prepare() methods.}}
+ *
+ * @param string $query the query to be prepared
+ *
+ * @return mixed DB statement resource on success. A DB_Error object
+ * on failure.
+ *
+ * @see DB_common::execute()
+ */
+ public function prepare($query)
+ {
+ $tokens = preg_split(
+ '/((?<!\\\)[&?!])/',
+ $query,
+ -1,
+ PREG_SPLIT_DELIM_CAPTURE
+ );
+ $token = 0;
+ $types = array();
+ $newtokens = array();
+
+ foreach ($tokens as $val) {
+ switch ($val) {
+ case '?':
+ $types[$token++] = DB_PARAM_SCALAR;
+ break;
+ case '&':
+ $types[$token++] = DB_PARAM_OPAQUE;
+ break;
+ case '!':
+ $types[$token++] = DB_PARAM_MISC;
+ break;
+ default:
+ $newtokens[] = preg_replace('/\\\([&?!])/', "\\1", $val);
+ }
+ }
+
+ $this->prepare_tokens[] = &$newtokens;
+ end($this->prepare_tokens);
+
+ $k = key($this->prepare_tokens);
+ $this->prepare_types[$k] = $types;
+ $this->prepared_queries[$k] = implode(' ', $newtokens);
+
+ return $k;
+ }
+
// }}}
// {{{ execute()
* $res = $db->execute($sth, $data);
* </code>
*
- * @param resource $stmt a DB statement resource returned from prepare()
- * @param mixed $data array, string or numeric data to be used in
+ * @param resource $stmt a DB statement resource returned from prepare()
+ * @param mixed $data array, string or numeric data to be used in
* execution of the statement. Quantity of items
* passed must match quantity of placeholders in
* query: meaning 1 placeholder for non-array
/**
* Emulates executing prepared statements if the DBMS not support them
*
- * @param resource $stmt a DB statement resource returned from execute()
- * @param mixed $data array, string or numeric data to be used in
+ * @param resource $stmt a DB statement resource returned from execute()
+ * @param mixed $data array, string or numeric data to be used in
* execution of the statement. Quantity of items
* passed must match quantity of placeholders in
* query: meaning 1 placeholder for non-array
// }}}
// {{{ executeMultiple()
+ /**
+ * Frees the internal resources associated with a prepared query
+ *
+ * @param resource $stmt the prepared statement's PHP resource
+ * @param bool $free_resource should the PHP resource be freed too?
+ * Use false if you need to get data
+ * from the result set later.
+ *
+ * @return bool TRUE on success, FALSE if $result is invalid
+ *
+ * @see DB_common::prepare()
+ */
+ public function freePrepared($stmt, $free_resource = true)
+ {
+ $stmt = (int)$stmt;
+ if (isset($this->prepare_tokens[$stmt])) {
+ unset($this->prepare_tokens[$stmt]);
+ unset($this->prepare_types[$stmt]);
+ unset($this->prepared_queries[$stmt]);
+ return true;
+ }
+ return false;
+ }
+
+ // }}}
+ // {{{ freePrepared()
+
/**
* Performs several execute() calls on the same statement handle
*
* If an error occurs during execute(), executeMultiple() does not
* execute the unfinished rows, but rather returns that error.
*
- * @param resource $stmt query handle from prepare()
- * @param array $data numeric array containing the
+ * @param resource $stmt query handle from prepare()
+ * @param array $data numeric array containing the
* data to insert into the query
*
* @return int DB_OK on success. A DB_Error object on failure.
return DB_OK;
}
- // }}}
- // {{{ freePrepared()
-
- /**
- * Frees the internal resources associated with a prepared query
- *
- * @param resource $stmt the prepared statement's PHP resource
- * @param bool $free_resource should the PHP resource be freed too?
- * Use false if you need to get data
- * from the result set later.
- *
- * @return bool TRUE on success, FALSE if $result is invalid
- *
- * @see DB_common::prepare()
- */
- public function freePrepared($stmt, $free_resource = true)
- {
- $stmt = (int)$stmt;
- if (isset($this->prepare_tokens[$stmt])) {
- unset($this->prepare_tokens[$stmt]);
- unset($this->prepare_types[$stmt]);
- unset($this->prepared_queries[$stmt]);
- return true;
- }
- return false;
- }
-
// }}}
// {{{ modifyQuery()
*
* It is defined here to ensure all drivers have this method available.
*
- * @param string $query the query string to modify
+ * @param string $query the query string to modify
*
* @return string the modified query string
*
// }}}
// {{{ modifyLimitQuery()
+ /**
+ * Generates and executes a LIMIT query
+ *
+ * @param string $query the query
+ * @param intr $from the row to start to fetching (0 = the first row)
+ * @param int $count the numbers of rows to fetch
+ * @param mixed $params array, string or numeric data to be used in
+ * execution of the statement. Quantity of items
+ * passed must match quantity of placeholders in
+ * query: meaning 1 placeholder for non-array
+ * parameters or 1 placeholder per array element.
+ *
+ * @return mixed a new DB_result object for successful SELECT queries
+ * or DB_OK for successul data manipulation queries.
+ * A DB_Error object on failure.
+ */
+ public function &limitQuery($query, $from, $count, $params = array())
+ {
+ $query = $this->modifyLimitQuery($query, $from, $count, $params);
+ if (DB::isError($query)) {
+ return $query;
+ }
+ $result = $this->query($query, $params);
+ if (is_object($result) && is_a($result, 'DB_result')) {
+ $result->setOption('limit_from', $from);
+ $result->setOption('limit_count', $count);
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ query()
+
/**
* Adds LIMIT clauses to a query string according to current DBMS standards
*
* It is defined here to assure that all implementations
* have this method defined.
*
- * @param string $query the query to modify
- * @param int $from the row to start to fetching (0 = the first row)
- * @param int $count the numbers of rows to fetch
- * @param mixed $params array, string or numeric data to be used in
+ * @param string $query the query to modify
+ * @param int $from the row to start to fetching (0 = the first row)
+ * @param int $count the numbers of rows to fetch
+ * @param mixed $params array, string or numeric data to be used in
* execution of the statement. Quantity of items
* passed must match quantity of placeholders in
* query: meaning 1 placeholder for non-array
}
// }}}
- // {{{ query()
+ // {{{ limitQuery()
/**
* Sends a query to the database server
* to the server OR if <var>$params</var> are passed the query can have
* placeholders and it will be passed through prepare() and execute().
*
- * @param string $query the SQL query or the statement to prepare
- * @param mixed $params array, string or numeric data to be used in
+ * @param string $query the SQL query or the statement to prepare
+ * @param mixed $params array, string or numeric data to be used in
* execution of the statement. Quantity of items
* passed must match quantity of placeholders in
* query: meaning 1 placeholder for non-array
if ($result === DB_OK || DB::isError($result)) {
return $result;
} else {
- $tmp = new DB_result($this, $result);
- return $tmp;
- }
- }
- }
-
- // }}}
- // {{{ limitQuery()
-
- /**
- * Generates and executes a LIMIT query
- *
- * @param string $query the query
- * @param intr $from the row to start to fetching (0 = the first row)
- * @param int $count the numbers of rows to fetch
- * @param mixed $params array, string or numeric data to be used in
- * execution of the statement. Quantity of items
- * passed must match quantity of placeholders in
- * query: meaning 1 placeholder for non-array
- * parameters or 1 placeholder per array element.
- *
- * @return mixed a new DB_result object for successful SELECT queries
- * or DB_OK for successul data manipulation queries.
- * A DB_Error object on failure.
- */
- public function &limitQuery($query, $from, $count, $params = array())
- {
- $query = $this->modifyLimitQuery($query, $from, $count, $params);
- if (DB::isError($query)) {
- return $query;
- }
- $result = $this->query($query, $params);
- if (is_object($result) && is_a($result, 'DB_result')) {
- $result->setOption('limit_from', $from);
- $result->setOption('limit_count', $count);
+ $tmp = new DB_result($this, $result);
+ return $tmp;
+ }
}
- return $result;
}
// }}}
*
* Takes care of doing the query and freeing the results when finished.
*
- * @param string $query the SQL query
- * @param mixed $params array, string or numeric data to be used in
+ * @param string $query the SQL query
+ * @param mixed $params array, string or numeric data to be used in
* execution of the statement. Quantity of items
* passed must match quantity of placeholders in
* query: meaning 1 placeholder for non-array
*
* Takes care of doing the query and freeing the results when finished.
*
- * @param string $query the SQL query
- * @param mixed $params array, string or numeric data to be used in
+ * @param string $query the SQL query
+ * @param mixed $params array, string or numeric data to be used in
* execution of the statement. Quantity of items
* passed must match quantity of placeholders in
* query: meaning 1 placeholder for non-array
* parameters or 1 placeholder per array element.
- * @param int $fetchmode the fetch mode to use
+ * @param int $fetchmode the fetch mode to use
*
* @return array the first row of results as an array.
* A DB_Error object on failure.
$query,
$params = array(),
$fetchmode = DB_FETCHMODE_DEFAULT
- ) {
+ )
+ {
// compat check, the params and fetchmode parameters used to
// have the opposite order
if (!is_array($params)) {
// }}}
// {{{ getCol()
- /**
- * Fetches a single column from a query result and returns it as an
- * indexed array
- *
- * @param string $query the SQL query
- * @param mixed $col which column to return (integer [column number,
- * starting at 0] or string [column name])
- * @param mixed $params array, string or numeric data to be used in
- * execution of the statement. Quantity of items
- * passed must match quantity of placeholders in
- * query: meaning 1 placeholder for non-array
- * parameters or 1 placeholder per array element.
- *
- * @return array the results as an array. A DB_Error object on failure.
- *
- * @see DB_common::query()
- */
- public function &getCol($query, $col = 0, $params = array())
- {
- $params = (array)$params;
- if (sizeof($params) > 0) {
- $sth = $this->prepare($query);
-
- if (DB::isError($sth)) {
- return $sth;
- }
-
- $res = $this->execute($sth, $params);
- $this->freePrepared($sth);
- } else {
- $res = $this->query($query);
- }
-
- if (DB::isError($res)) {
- return $res;
- }
-
- $fetchmode = is_int($col) ? DB_FETCHMODE_ORDERED : DB_FETCHMODE_ASSOC;
-
- if (!is_array($row = $res->fetchRow($fetchmode))) {
- $ret = array();
- } else {
- if (!array_key_exists($col, $row)) {
- $ret = $this->raiseError(DB_ERROR_NOSUCHFIELD);
- } else {
- $ret = array($row[$col]);
- while (is_array($row = $res->fetchRow($fetchmode))) {
- $ret[] = $row[$col];
- }
- }
- }
-
- $res->free();
-
- if (DB::isError($row)) {
- $ret = $row;
- }
-
- return $ret;
- }
-
- // }}}
- // {{{ getAssoc()
-
/**
* Fetches an entire query result and returns it as an
* associative array using the first column as the key
* Keep in mind that database functions in PHP usually return string
* values for results regardless of the database's internal type.
*
- * @param string $query the SQL query
- * @param bool $force_array used only when the query returns
+ * @param string $query the SQL query
+ * @param bool $force_array used only when the query returns
* exactly two columns. If true, the values
* of the returned array will be one-element
* arrays instead of scalars.
- * @param mixed $params array, string or numeric data to be used in
+ * @param mixed $params array, string or numeric data to be used in
* execution of the statement. Quantity of
* items passed must match quantity of
* placeholders in query: meaning 1
* placeholder for non-array parameters or
* 1 placeholder per array element.
- * @param int $fetchmode the fetch mode to use
- * @param bool $group if true, the values of the returned array
+ * @param int $fetchmode the fetch mode to use
+ * @param bool $group if true, the values of the returned array
* is wrapped in another array. If the same
* key value (in the first column) repeats
* itself, the values will be appended to
* this array instead of overwriting the
* existing values.
*
- * @return array the associative array containing the query results.
+ * @return array|object
* A DB_Error object on failure.
*/
public function &getAssoc(
$params = array(),
$fetchmode = DB_FETCHMODE_DEFAULT,
$group = false
- ) {
+ )
+ {
$params = (array)$params;
if (sizeof($params) > 0) {
$sth = $this->prepare($query);
}
// }}}
- // {{{ getAll()
+ // {{{ getAssoc()
/**
* Fetches all of the rows from a query result
*
- * @param string $query the SQL query
- * @param mixed $params array, string or numeric data to be used in
+ * @param string $query the SQL query
+ * @param mixed $params array, string or numeric data to be used in
* execution of the statement. Quantity of
* items passed must match quantity of
* placeholders in query: meaning 1
* placeholder for non-array parameters or
* 1 placeholder per array element.
- * @param int $fetchmode the fetch mode to use:
+ * @param int $fetchmode the fetch mode to use:
* + DB_FETCHMODE_ORDERED
* + DB_FETCHMODE_ASSOC
* + DB_FETCHMODE_ORDERED | DB_FETCHMODE_FLIPPED
* + DB_FETCHMODE_ASSOC | DB_FETCHMODE_FLIPPED
*
- * @return array the nested array. A DB_Error object on failure.
+ * @return array|object
*/
public function &getAll(
$query,
$params = array(),
$fetchmode = DB_FETCHMODE_DEFAULT
- ) {
+ )
+ {
// compat check, the params and fetchmode parameters used to
// have the opposite order
if (!is_array($params)) {
}
// }}}
- // {{{ autoCommit()
+ // {{{ getAll()
/**
* Enables or disables automatic commits
*
- * @param bool $onoff true turns it on, false turns it off
+ * @param bool $onoff true turns it on, false turns it off
*
- * @return int DB_OK on success. A DB_Error object if the driver
+ * @return int|object
* doesn't support auto-committing transactions.
*/
public function autoCommit($onoff = false)
}
// }}}
- // {{{ commit()
+ // {{{ autoCommit()
/**
* Commits the current transaction
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function commit()
{
}
// }}}
- // {{{ rollback()
+ // {{{ commit()
/**
* Reverts the current transaction
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function rollback()
{
}
// }}}
- // {{{ numRows()
+ // {{{ rollback()
/**
* Determines the number of rows in a query result
*
- * @param resource $result the query result idenifier produced by PHP
+ * @param resource $result the query result idenifier produced by PHP
*
- * @return int the number of rows. A DB_Error object on failure.
+ * @return int|object
*/
public function numRows($result)
{
}
// }}}
- // {{{ affectedRows()
+ // {{{ numRows()
/**
* Determines the number of rows affected by a data maniuplation query
*
* 0 is returned for queries that don't manipulate data.
*
- * @return int the number of rows. A DB_Error object on failure.
+ * @return int|object
*/
public function affectedRows()
{
}
// }}}
- // {{{ getSequenceName()
+ // {{{ affectedRows()
/**
* Generates the name used inside the database for a sequence
* The createSequence() docblock contains notes about storing sequence
* names.
*
- * @param string $sqn the sequence's public name
+ * @param string $sqn the sequence's public name
*
* @return string the sequence's name in the backend
*
);
}
+ // }}}
+ // {{{ getSequenceName()
+
+ /**
+ * Returns the value of an option
+ *
+ * @param string $option the option name you're curious about
+ *
+ * @return mixed the option's value
+ */
+ public function getOption($option)
+ {
+ if (isset($this->options[$option])) {
+ return $this->options[$option];
+ }
+ return $this->raiseError("unknown option $option");
+ }
+
// }}}
// {{{ nextId()
/**
* Returns the next free id in a sequence
*
- * @param string $seq_name name of the sequence
- * @param boolean $ondemand when true, the seqence is automatically
+ * @param string $seq_name name of the sequence
+ * @param boolean $ondemand when true, the seqence is automatically
* created if it does not exist
*
- * @return int the next id number in the sequence.
+ * @return int|object
* A DB_Error object on failure.
*
* @see DB_common::createSequence(), DB_common::dropSequence(),
*
* <var>seqname_format</var> is set via setOption().
*
- * @param string $seq_name name of the new sequence
+ * @param string $seq_name name of the new sequence
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_common::dropSequence(), DB_common::getSequenceName(),
* DB_common::nextID()
/**
* Deletes a sequence
*
- * @param string $seq_name name of the sequence to be deleted
+ * @param string $seq_name name of the sequence to be deleted
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_common::createSequence(), DB_common::getSequenceName(),
* DB_common::nextID()
// }}}
// {{{ raiseError()
- /**
- * Communicates an error and invoke error callbacks, etc
- *
- * Basically a wrapper for PEAR::raiseError without the message string.
- *
- * @param mixed integer error code, or a PEAR error object (all
- * other parameters are ignored if this parameter is
- * an object
- * @param int error mode, see PEAR_Error docs
- * @param mixed if error mode is PEAR_ERROR_TRIGGER, this is the
- * error level (E_USER_NOTICE etc). If error mode is
- * PEAR_ERROR_CALLBACK, this is the callback function,
- * either as a function name, or as an array of an
- * object and method name. For other error modes this
- * parameter is ignored.
- * @param string extra debug information. Defaults to the last
- * query and native error code.
- * @param mixed native error code, integer or string depending the
- * backend
- * @param mixed dummy parameter for E_STRICT compatibility with
- * PEAR::raiseError
- * @param mixed dummy parameter for E_STRICT compatibility with
- * PEAR::raiseError
- *
- * @return object the PEAR_Error object
- *
- * @see PEAR_Error
- */
- public function &raiseError(
- $code = DB_ERROR,
- $mode = null,
- $options = null,
- $userinfo = null,
- $nativecode = null,
- $dummy1 = null,
- $dummy2 = null
- ) {
- // The error is yet a DB error object
- if (is_object($code)) {
- // because we the static PEAR::raiseError, our global
- // handler should be used if it is set
- if ($mode === null && !empty($this->_default_error_mode)) {
- $mode = $this->_default_error_mode;
- $options = $this->_default_error_options;
- }
- $tmp = PEAR::raiseError(
- $code,
- null,
- $mode,
- $options,
- null,
- null,
- true
- );
- return $tmp;
- }
-
- if ($userinfo === null) {
- $userinfo = $this->last_query;
- }
-
- if ($nativecode) {
- $userinfo .= ' [nativecode=' . trim($nativecode) . ']';
- } else {
- $userinfo .= ' [DB Error: ' . DB::errorMessage($code) . ']';
- }
-
- $tmp = PEAR::raiseError(
- null,
- $code,
- $mode,
- $options,
- $userinfo,
- 'DB_Error',
- true
- );
- return $tmp;
- }
-
- // }}}
- // {{{ errorNative()
-
/**
* Gets the DBMS' native error code produced by the last query
*
}
// }}}
- // {{{ errorCode()
+ // {{{ errorNative()
/**
* Maps native error codes to DB's portable ones
*
* Uses the <var>$errorcode_map</var> property defined in each driver.
*
- * @param string|int $nativecode the error code returned by the DBMS
+ * @param string|int $nativecode the error code returned by the DBMS
*
* @return int the portable DB error code. Return DB_ERROR if the
* current driver doesn't have a mapping for the
}
// }}}
- // {{{ errorMessage()
+ // {{{ errorCode()
/**
* Maps a DB error code to a textual message
*
- * @param integer $dbcode the DB error code
+ * @param integer $dbcode the DB error code
*
* @return string the error message corresponding to the error code
* submitted. FALSE if the error code is unknown.
}
// }}}
- // {{{ tableInfo()
+ // {{{ errorMessage()
/**
* Returns information about a table or a result set
* If the 'portability' option has <samp>DB_PORTABILITY_LOWERCASE</samp>
* turned on, the names of tables and fields will be lowercased.
*
- * @param object|string $result DB_result object from a query or a
+ * @param object|string $result DB_result object from a query or a
* string containing the name of a table.
* While this also accepts a query result
* resource identifier, this behavior is
* deprecated.
- * @param int $mode either unused or one of the tableInfo modes:
+ * @param int $mode either unused or one of the tableInfo modes:
* <kbd>DB_TABLEINFO_ORDERTABLE</kbd>,
* <kbd>DB_TABLEINFO_ORDER</kbd> or
* <kbd>DB_TABLEINFO_FULL</kbd> (which does both).
* These are bitwise, so the first two can be
* combined using <kbd>|</kbd>.
*
- * @return array an associative array with the information requested.
+ * @return array|object
* A DB_Error object on failure.
*
* @see DB_common::setOption()
}
// }}}
- // {{{ getTables()
+ // {{{ tableInfo()
/**
* Lists the tables in the current database
}
// }}}
- // {{{ getListOf()
+ // {{{ getTables()
/**
* Lists internal database information
*
- * @param string $type type of information being sought.
+ * @param string $type type of information being sought.
* Common items being sought are:
* tables, databases, users, views, functions
* Each DBMS's has its own capabilities.
*
- * @return array an array listing the items sought.
+ * @return array|object
* A DB DB_Error object on failure.
*/
public function getListOf($type)
}
// }}}
- // {{{ getSpecialQuery()
+ // {{{ getListOf()
/**
* Obtains the query string needed for listing a given type of objects
*
- * @param string $type the kind of objects you want to retrieve
+ * @param string $type the kind of objects you want to retrieve
*
* @return string the SQL query string or null if the driver doesn't
* support the object type requested
return $this->raiseError(DB_ERROR_UNSUPPORTED);
}
+ // }}}
+ // {{{ getSpecialQuery()
+
+ /**
+ * Fetches a single column from a query result and returns it as an
+ * indexed array
+ *
+ * @param string $query the SQL query
+ * @param mixed $col which column to return (integer [column number,
+ * starting at 0] or string [column name])
+ * @param mixed $params array, string or numeric data to be used in
+ * execution of the statement. Quantity of items
+ * passed must match quantity of placeholders in
+ * query: meaning 1 placeholder for non-array
+ * parameters or 1 placeholder per array element.
+ *
+ * @return array the results as an array. A DB_Error object on failure.
+ *
+ * @see DB_common::query()
+ */
+ public function &getCol($query, $col = 0, $params = array())
+ {
+ $params = (array)$params;
+ if (sizeof($params) > 0) {
+ $sth = $this->prepare($query);
+
+ if (DB::isError($sth)) {
+ return $sth;
+ }
+
+ $res = $this->execute($sth, $params);
+ $this->freePrepared($sth);
+ } else {
+ $res = $this->query($query);
+ }
+
+ if (DB::isError($res)) {
+ return $res;
+ }
+
+ $fetchmode = is_int($col) ? DB_FETCHMODE_ORDERED : DB_FETCHMODE_ASSOC;
+
+ if (!is_array($row = $res->fetchRow($fetchmode))) {
+ $ret = array();
+ } else {
+ if (!array_key_exists($col, $row)) {
+ $ret = $this->raiseError(DB_ERROR_NOSUCHFIELD);
+ } else {
+ $ret = array($row[$col]);
+ while (is_array($row = $res->fetchRow($fetchmode))) {
+ $ret[] = $row[$col];
+ }
+ }
+ }
+
+ $res->free();
+
+ if (DB::isError($row)) {
+ $ret = $row;
+ }
+
+ return $ret;
+ }
+
// }}}
// {{{ nextQueryIsManip()
}
$this->_next_query_manip = false;
return $this->_last_query_manip;
- $manip = $this->_next_query_manip;
}
// }}}
/**
* Right-trims all strings in an array
*
- * @param array $array the array to be trimmed (passed by reference)
+ * @param array $array the array to be trimmed (passed by reference)
*
* @return void
*
/**
* Converts all null values in an array to empty strings
*
- * @param array $array the array to be de-nullified (passed by reference)
+ * @param array $array the array to be de-nullified (passed by reference)
*
* @return void
*
/**
* Obtain the DB_common class so it can be extended from
*/
-require_once 'DB/common.php';
+//require_once 'DB/common.php';
+require_once 'common.php';
/**
* The methods PEAR DB uses to interact with PHP's dbase extension
* @var array
*/
public $features = array(
- 'limit' => false,
- 'new_link' => false,
- 'numrows' => true,
- 'pconnect' => false,
- 'prepare' => false,
- 'ssl' => false,
- 'transactions' => false,
+ 'limit' => false,
+ 'new_link' => false,
+ 'numrows' => true,
+ 'pconnect' => false,
+ 'prepare' => false,
+ 'ssl' => false,
+ 'transactions' => false,
);
/**
* A mapping of native error codes to DB error codes
* @var array
*/
- public $errorcode_map = array(
- );
+ public $errorcode_map = array();
/**
* The raw database connection created by PHP
* );
*
* $db = DB::connect($dsn, $options);
- * if (PEAR::isError($db)) {
+ * if ((new PEAR)->isError($db)) {
* die($db->getMessage());
* }
* </code>
*
- * @param array $dsn the data source name
- * @param bool $persistent should the connection be persistent?
+ * @param array $dsn the data source name
+ * @param bool $persistent should the connection be persistent?
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function connect($dsn, $persistent = false)
{
null,
null,
'the dbase file does not exist and '
- . 'it could not be created because '
- . 'the "fields" element of the DSN '
- . 'is not properly set'
+ . 'it could not be created because '
+ . 'the "fields" element of the DSN '
+ . 'is not properly set'
);
}
$this->connection = @dbase_create(
null,
null,
'the dbase file does not exist and '
- . 'the attempt to create it failed: '
- . $php_errormsg
+ . 'the attempt to create it failed: '
+ . $php_errormsg
);
}
} else {
* DB_result::fetchInto() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result the query result resource
- * @param array $arr the referenced array to put the data in
- * @param int $fetchmode how the resulting array should be indexed
- * @param int $rownum the row number to fetch (0 = first row)
+ * @param resource $result the query result resource
+ * @param array $arr the referenced array to put the data in
+ * @param int $fetchmode how the resulting array should be indexed
+ * @param int $rownum the row number to fetch (0 = first row)
*
* @return mixed DB_OK on success, NULL when the end of a result set is
* reached or on failure
* This method is a no-op for dbase, as there aren't result resources in
* the same sense as most other database backends.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
* @return bool TRUE on success, FALSE if $result is invalid
*
* DB_result::numCols() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
- *
+ * @param $foo
* @return int the number of columns. A DB_Error object on failure.
*
* @see DB_result::numCols()
* DB_result::numRows() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
- *
+ * @param $foo
* @return int the number of rows. A DB_Error object on failure.
*
* @see DB_result::numRows()
{
return $boolean ? 'T' : 'F';
}
-
+
// }}}
// {{{ tableInfo()
/**
* Returns information about the current database
*
- * @param mixed $result THIS IS UNUSED IN DBASE. The current database
+ * @param mixed $result THIS IS UNUSED IN DBASE. The current database
* is examined regardless of what is provided here.
- * @param int $mode a valid tableInfo mode
+ * @param int $mode a valid tableInfo mode
*
- * @return array an associative array with the information requested.
+ * @return array|object
* A DB_Error object on failure.
*
* @see DB_common::tableInfo()
}
$id = array();
- $i = 0;
+ $i = 0;
$line = fread($db, 32);
while (!feof($db)) {
$pos = strpos(substr($line, 0, 10), chr(0));
$pos = ($pos == 0 ? 10 : $pos);
$id[$i] = array(
- 'name' => substr($line, 0, $pos),
- 'type' => $this->types[substr($line, 11, 1)],
+ 'name' => substr($line, 0, $pos),
+ 'type' => $this->types[substr($line, 11, 1)],
'length' => ord(substr($line, 16, 1)),
'precision' => ord(substr($line, 17, 1)),
);
$case_func = 'strval';
}
- $res = array();
+ $res = array();
$count = count($id);
if ($mode) {
for ($i = 0; $i < $count; $i++) {
$res[$i] = array(
'table' => $this->dsn['database'],
- 'name' => $case_func($id[$i]['name']),
- 'type' => $id[$i]['type'],
- 'len' => $id[$i]['length'],
+ 'name' => $case_func($id[$i]['name']),
+ 'type' => $id[$i]['type'],
+ 'len' => $id[$i]['length'],
'flags' => ''
);
if ($mode & DB_TABLEINFO_ORDER) {
/**
* Obtain the DB_common class so it can be extended from
*/
-require_once 'DB/common.php';
+//require_once 'DB/common.php';
+require_once 'common.php';
/**
* The methods PEAR DB uses to interact with PHP's fbsql extension
* @var array
*/
public $features = array(
- 'limit' => 'alter',
- 'new_link' => false,
- 'numrows' => true,
- 'pconnect' => true,
- 'prepare' => false,
- 'ssl' => false,
- 'transactions' => true,
+ 'limit' => 'alter',
+ 'new_link' => false,
+ 'numrows' => true,
+ 'pconnect' => true,
+ 'prepare' => false,
+ 'ssl' => false,
+ 'transactions' => true,
);
/**
* @var array
*/
public $errorcode_map = array(
- 22 => DB_ERROR_SYNTAX,
- 85 => DB_ERROR_ALREADY_EXISTS,
+ 22 => DB_ERROR_SYNTAX,
+ 85 => DB_ERROR_ALREADY_EXISTS,
108 => DB_ERROR_SYNTAX,
116 => DB_ERROR_NOSUCHTABLE,
124 => DB_ERROR_VALUE_COUNT_ON_ROW,
*
* Don't call this method directly. Use DB::connect() instead.
*
- * @param array $dsn the data source name
- * @param bool $persistent should the connection be persistent?
+ * @param array $dsn the data source name
+ * @param bool $persistent should the connection be persistent?
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function connect($dsn, $persistent = false)
{
// }}}
// {{{ disconnect()
+ /**
+ * Produces a DB_Error object regarding the current problem
+ *
+ * @param int $errno if the error is being manually raised pass a
+ * DB_ERROR* constant here. If this isn't passed
+ * the error information gathered from the DBMS.
+ *
+ * @return object the DB_Error object
+ *
+ * @see DB_common::raiseError(),
+ * DB_fbsql::errorNative(), DB_common::errorCode()
+ */
+ public function fbsqlRaiseError($errno = null)
+ {
+ if ($errno === null) {
+ $errno = $this->errorCode(fbsql_errno($this->connection));
+ }
+ return $this->raiseError(
+ $errno,
+ null,
+ null,
+ null,
+ @fbsql_error($this->connection)
+ );
+ }
+
+ // }}}
+ // {{{ simpleQuery()
+
/**
* Disconnects from the database server
*
}
// }}}
- // {{{ simpleQuery()
+ // {{{ nextResult()
/**
* Sends a query to the database server
}
// }}}
- // {{{ nextResult()
+ // {{{ fetchInto()
/**
* Move the internal fbsql result pointer to the next available result
}
// }}}
- // {{{ fetchInto()
+ // {{{ freeResult()
/**
* Places a row from the result set into the given array
* DB_result::fetchInto() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result the query result resource
- * @param array $arr the referenced array to put the data in
- * @param int $fetchmode how the resulting array should be indexed
- * @param int $rownum the row number to fetch (0 = first row)
+ * @param resource $result the query result resource
+ * @param array $arr the referenced array to put the data in
+ * @param int $fetchmode how the resulting array should be indexed
+ * @param int $rownum the row number to fetch (0 = first row)
*
* @return mixed DB_OK on success, NULL when the end of a result set is
* reached or on failure
}
// }}}
- // {{{ freeResult()
+ // {{{ autoCommit()
/**
* Deletes the result set and frees the memory occupied by the result set
* DB_result::free() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
* @return bool TRUE on success, FALSE if $result is invalid
*
}
// }}}
- // {{{ autoCommit()
+ // {{{ commit()
/**
* Enables or disables automatic commits
*
- * @param bool $onoff true turns it on, false turns it off
+ * @param bool $onoff true turns it on, false turns it off
*
* @return int DB_OK on success. A DB_Error object if the driver
* doesn't support auto-committing transactions.
*/
- public function autoCommit($onoff=false)
+ public function autoCommit($onoff = false)
{
if ($onoff) {
$this->query("SET COMMIT TRUE");
} else {
$this->query("SET COMMIT FALSE");
}
+ return null;
}
// }}}
- // {{{ commit()
+ // {{{ rollback()
/**
* Commits the current transaction
public function commit()
{
@fbsql_commit($this->connection);
+ return 0;
}
// }}}
- // {{{ rollback()
+ // {{{ numCols()
/**
* Reverts the current transaction
public function rollback()
{
@fbsql_rollback($this->connection);
+ return 0;
}
// }}}
- // {{{ numCols()
+ // {{{ numRows()
/**
* Gets the number of columns in a result set
* DB_result::numCols() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
- * @return int the number of columns. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_result::numCols()
*/
}
// }}}
- // {{{ numRows()
+ // {{{ affectedRows()
/**
* Gets the number of rows in a result set
* DB_result::numRows() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
- * @return int the number of rows. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_result::numRows()
*/
}
// }}}
- // {{{ affectedRows()
+ // {{{ nextId()
/**
* Determines the number of rows affected by a data maniuplation query
return $result;
}
- // }}}
- // {{{ nextId()
-
/**
* Returns the next free id in a sequence
*
- * @param string $seq_name name of the sequence
- * @param boolean $ondemand when true, the seqence is automatically
+ * @param string $seq_name name of the sequence
+ * @param boolean $ondemand when true, the seqence is automatically
* created if it does not exist
*
- * @return int the next id number in the sequence.
+ * @return int|object
* A DB_Error object on failure.
*
* @see DB_common::nextID(), DB_common::getSequenceName(),
return $tmp[0];
}
+ // }}}
+ // {{{ dropSequence()
+
/**
* Creates a new sequence
*
- * @param string $seq_name name of the new sequence
+ * @param string $seq_name name of the new sequence
*
* @return int DB_OK on success. A DB_Error object on failure.
*
{
$seqname = $this->getSequenceName($seq_name);
$res = $this->query('CREATE TABLE ' . $seqname
- . ' (id INTEGER NOT NULL,'
- . ' PRIMARY KEY(id))');
+ . ' (id INTEGER NOT NULL,'
+ . ' PRIMARY KEY(id))');
if ($res) {
$res = $this->query('SET UNIQUE = 0 FOR ' . $seqname);
}
}
// }}}
- // {{{ dropSequence()
+ // {{{ modifyLimitQuery()
/**
* Deletes a sequence
*
- * @param string $seq_name name of the sequence to be deleted
+ * @param string $seq_name name of the sequence to be deleted
*
* @return int DB_OK on success. A DB_Error object on failure.
*
public function dropSequence($seq_name)
{
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)
- . ' RESTRICT');
+ . ' RESTRICT');
}
// }}}
- // {{{ modifyLimitQuery()
+ // {{{ quoteBoolean()
/**
* Adds LIMIT clauses to a query string according to current DBMS standards
*
- * @param string $query the query to modify
- * @param int $from the row to start to fetching (0 = the first row)
- * @param int $count the numbers of rows to fetch
- * @param mixed $params array, string or numeric data to be used in
+ * @param string $query the query to modify
+ * @param int $from the row to start to fetching (0 = the first row)
+ * @param int $count the numbers of rows to fetch
+ * @param mixed $params array, string or numeric data to be used in
* execution of the statement. Quantity of items
* passed must match quantity of placeholders in
* query: meaning 1 placeholder for non-array
}
// }}}
- // {{{ quoteBoolean()
+ // {{{ quoteFloat()
/**
* Formats a boolean value for use within a query in a locale-independent
{
return $boolean ? 'TRUE' : 'FALSE';
}
-
+
// }}}
- // {{{ quoteFloat()
+ // {{{ fbsqlRaiseError()
/**
* Formats a float value for use within a query in a locale-independent
{
return $this->escapeSimple(str_replace(',', '.', strval(floatval($float))));
}
-
- // }}}
- // {{{ fbsqlRaiseError()
-
- /**
- * Produces a DB_Error object regarding the current problem
- *
- * @param int $errno if the error is being manually raised pass a
- * DB_ERROR* constant here. If this isn't passed
- * the error information gathered from the DBMS.
- *
- * @return object the DB_Error object
- *
- * @see DB_common::raiseError(),
- * DB_fbsql::errorNative(), DB_common::errorCode()
- */
- public function fbsqlRaiseError($errno = null)
- {
- if ($errno === null) {
- $errno = $this->errorCode(fbsql_errno($this->connection));
- }
- return $this->raiseError(
- $errno,
- null,
- null,
- null,
- @fbsql_error($this->connection)
- );
- }
// }}}
// {{{ errorNative()
/**
* Returns information about a table or a result set
*
- * @param object|string $result DB_result object from a query or a
+ * @param object|string $result DB_result object from a query or a
* string containing the name of a table.
* While this also accepts a query result
* resource identifier, this behavior is
* deprecated.
- * @param int $mode a valid tableInfo mode
+ * @param int $mode a valid tableInfo mode
*
- * @return array an associative array with the information requested.
+ * @return array|object
* A DB_Error object on failure.
*
* @see DB_common::tableInfo()
}
$count = @fbsql_num_fields($id);
- $res = array();
+ $res = array();
if ($mode) {
$res['num_fields'] = $count;
for ($i = 0; $i < $count; $i++) {
$res[$i] = array(
'table' => $case_func(@fbsql_field_table($id, $i)),
- 'name' => $case_func(@fbsql_field_name($id, $i)),
- 'type' => @fbsql_field_type($id, $i),
- 'len' => @fbsql_field_len($id, $i),
+ 'name' => $case_func(@fbsql_field_name($id, $i)),
+ 'type' => @fbsql_field_type($id, $i),
+ 'len' => @fbsql_field_len($id, $i),
'flags' => @fbsql_field_flags($id, $i),
);
if ($mode & DB_TABLEINFO_ORDER) {
/**
* Obtains the query string needed for listing a given type of objects
*
- * @param string $type the kind of objects you want to retrieve
+ * @param string $type the kind of objects you want to retrieve
*
* @return string the SQL query string or null if the driver doesn't
* support the object type requested
switch ($type) {
case 'tables':
return 'SELECT "table_name" FROM information_schema.tables'
- . ' t0, information_schema.schemata t1'
- . ' WHERE t0.schema_pk=t1.schema_pk AND'
- . ' "table_type" = \'BASE TABLE\''
- . ' AND "schema_name" = current_schema';
+ . ' t0, information_schema.schemata t1'
+ . ' WHERE t0.schema_pk=t1.schema_pk AND'
+ . ' "table_type" = \'BASE TABLE\''
+ . ' AND "schema_name" = current_schema';
case 'views':
return 'SELECT "table_name" FROM information_schema.tables'
- . ' t0, information_schema.schemata t1'
- . ' WHERE t0.schema_pk=t1.schema_pk AND'
- . ' "table_type" = \'VIEW\''
- . ' AND "schema_name" = current_schema';
+ . ' t0, information_schema.schemata t1'
+ . ' WHERE t0.schema_pk=t1.schema_pk AND'
+ . ' "table_type" = \'VIEW\''
+ . ' AND "schema_name" = current_schema';
case 'users':
return 'SELECT "user_name" from information_schema.users';
case 'functions':
return 'SELECT "routine_name" FROM'
- . ' information_schema.psm_routines'
- . ' t0, information_schema.schemata t1'
- . ' WHERE t0.schema_pk=t1.schema_pk'
- . ' AND "routine_kind"=\'FUNCTION\''
- . ' AND "schema_name" = current_schema';
+ . ' information_schema.psm_routines'
+ . ' t0, information_schema.schemata t1'
+ . ' WHERE t0.schema_pk=t1.schema_pk'
+ . ' AND "routine_kind"=\'FUNCTION\''
+ . ' AND "schema_name" = current_schema';
case 'procedures':
return 'SELECT "routine_name" FROM'
- . ' information_schema.psm_routines'
- . ' t0, information_schema.schemata t1'
- . ' WHERE t0.schema_pk=t1.schema_pk'
- . ' AND "routine_kind"=\'PROCEDURE\''
- . ' AND "schema_name" = current_schema';
+ . ' information_schema.psm_routines'
+ . ' t0, information_schema.schemata t1'
+ . ' WHERE t0.schema_pk=t1.schema_pk'
+ . ' AND "routine_kind"=\'PROCEDURE\''
+ . ' AND "schema_name" = current_schema';
default:
return null;
}
/**
* Obtain the DB_common class so it can be extended from
*/
-require_once 'DB/common.php';
+//require_once 'DB/common.php';
+require_once 'common.php';
/**
* The methods PEAR DB uses to interact with PHP's interbase extension
* @var array
*/
public $features = array(
- 'limit' => false,
- 'new_link' => false,
- 'numrows' => 'emulate',
- 'pconnect' => true,
- 'prepare' => true,
- 'ssl' => false,
- 'transactions' => true,
+ 'limit' => false,
+ 'new_link' => false,
+ 'numrows' => 'emulate',
+ 'pconnect' => true,
+ 'prepare' => true,
+ 'ssl' => false,
+ 'transactions' => true,
);
/**
* Functional only with InterBase 6 and up.
* + role Functional only with InterBase 5 and up.
*
- * @param array $dsn the data source name
- * @param bool $persistent should the connection be persistent?
+ * @param array $dsn the data source name
+ * @param bool $persistent should the connection be persistent?
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function connect($dsn, $persistent = false)
{
$params = array(
$dsn['hostspec']
- ? ($dsn['hostspec'] . ':' . $dsn['database'])
- : $dsn['database'],
+ ? ($dsn['hostspec'] . ':' . $dsn['database'])
+ : $dsn['database'],
$dsn['username'] ? $dsn['username'] : null,
$dsn['password'] ? $dsn['password'] : null,
isset($dsn['charset']) ? $dsn['charset'] : null,
isset($dsn['buffers']) ? $dsn['buffers'] : null,
isset($dsn['dialect']) ? $dsn['dialect'] : null,
- isset($dsn['role']) ? $dsn['role'] : null,
+ isset($dsn['role']) ? $dsn['role'] : null,
);
$connect_function = $persistent ? 'ibase_pconnect' : 'ibase_connect';
// }}}
// {{{ disconnect()
+ /**
+ * Produces a DB_Error object regarding the current problem
+ *
+ * @param int $errno if the error is being manually raised pass a
+ * DB_ERROR* constant here. If this isn't passed
+ * the error information gathered from the DBMS.
+ *
+ * @return object the DB_Error object
+ *
+ * @see DB_common::raiseError(),
+ * DB_ibase::errorNative(), DB_ibase::errorCode()
+ */
+ public function &ibaseRaiseError($errno = null)
+ {
+ if ($errno === null) {
+ $errno = $this->errorCode($this->errorNative());
+ }
+ $tmp = $this->raiseError($errno, null, null, null, @ibase_errmsg());
+ return $tmp;
+ }
+
+ // }}}
+ // {{{ simpleQuery()
+
+ /**
+ * Maps native error codes to DB's portable ones
+ *
+ * @param int $nativecode the error code returned by the DBMS
+ *
+ * @return int the portable DB error code. Return DB_ERROR if the
+ * current driver doesn't have a mapping for the
+ * $nativecode submitted.
+ *
+ * @since Method available since Release 1.7.0
+ */
+ public function errorCode($nativecode = null)
+ {
+ if (isset($this->errorcode_map[$nativecode])) {
+ return $this->errorcode_map[$nativecode];
+ }
+
+ static $error_regexps;
+ if (!isset($error_regexps)) {
+ $error_regexps = array(
+ '/generator .* is not defined/'
+ => DB_ERROR_SYNTAX, // for compat. w ibase_errcode()
+ '/violation of [\w ]+ constraint/i'
+ => DB_ERROR_CONSTRAINT,
+ '/table.*(not exist|not found|unknown)/i'
+ => DB_ERROR_NOSUCHTABLE,
+ '/table .* already exists/i'
+ => DB_ERROR_ALREADY_EXISTS,
+ '/unsuccessful metadata update .* failed attempt to store duplicate value/i'
+ => DB_ERROR_ALREADY_EXISTS,
+ '/unsuccessful metadata update .* not found/i'
+ => DB_ERROR_NOT_FOUND,
+ '/validation error for column .* value "\*\*\* null/i'
+ => DB_ERROR_CONSTRAINT_NOT_NULL,
+ '/conversion error from string/i'
+ => DB_ERROR_INVALID_NUMBER,
+ '/no permission for/i'
+ => DB_ERROR_ACCESS_VIOLATION,
+ '/arithmetic exception, numeric overflow, or string truncation/i'
+ => DB_ERROR_INVALID,
+ '/feature is not supported/i'
+ => DB_ERROR_NOT_CAPABLE,
+ );
+ }
+
+ $errormsg = @ibase_errmsg();
+ foreach ($error_regexps as $regexp => $code) {
+ if (preg_match($regexp, $errormsg)) {
+ return $code;
+ }
+ }
+ return DB_ERROR;
+ }
+
+ // }}}
+ // {{{ modifyLimitQuery()
+
+ /**
+ * Gets the DBMS' native error code produced by the last query
+ *
+ * @return int the DBMS' error code. NULL if there is no error code.
+ *
+ * @since Method available since Release 1.7.0
+ */
+ public function errorNative()
+ {
+ if (function_exists('ibase_errcode')) {
+ return @ibase_errcode();
+ }
+ if (preg_match(
+ '/^Dynamic SQL Error SQL error code = ([0-9-]+)/i',
+ @ibase_errmsg(),
+ $m
+ )) {
+ return (int)$m[1];
+ }
+ return null;
+ }
+
+ // }}}
+ // {{{ nextResult()
+
/**
* Disconnects from the database server
*
}
// }}}
- // {{{ simpleQuery()
+ // {{{ fetchInto()
/**
* Sends a query to the database server
}
// }}}
- // {{{ modifyLimitQuery()
+ // {{{ freeResult()
/**
* Adds LIMIT clauses to a query string according to current DBMS standards
*
* Only works with Firebird.
*
- * @param string $query the query to modify
- * @param int $from the row to start to fetching (0 = the first row)
- * @param int $count the numbers of rows to fetch
- * @param mixed $params array, string or numeric data to be used in
+ * @param string $query the query to modify
+ * @param int $from the row to start to fetching (0 = the first row)
+ * @param int $count the numbers of rows to fetch
+ * @param mixed $params array, string or numeric data to be used in
* execution of the statement. Quantity of items
* passed must match quantity of placeholders in
* query: meaning 1 placeholder for non-array
}
// }}}
- // {{{ nextResult()
+ // {{{ freeQuery()
/**
* Move the internal ibase result pointer to the next available result
}
// }}}
- // {{{ fetchInto()
+ // {{{ affectedRows()
/**
* Places a row from the result set into the given array
* DB_result::fetchInto() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result the query result resource
- * @param array $arr the referenced array to put the data in
- * @param int $fetchmode how the resulting array should be indexed
- * @param int $rownum the row number to fetch (0 = first row)
+ * @param resource $result the query result resource
+ * @param array $arr the referenced array to put the data in
+ * @param int $fetchmode how the resulting array should be indexed
+ * @param int $rownum the row number to fetch (0 = first row)
*
* @return mixed DB_OK on success, NULL when the end of a result set is
* reached or on failure
}
// }}}
- // {{{ freeResult()
+ // {{{ numCols()
/**
* Deletes the result set and frees the memory occupied by the result set
* DB_result::free() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
* @return bool TRUE on success, FALSE if $result is invalid
*
}
// }}}
- // {{{ freeQuery()
+ // {{{ prepare()
public function freeQuery($query)
{
}
// }}}
- // {{{ affectedRows()
+ // {{{ execute()
/**
* Determines the number of rows affected by a data maniuplation query
*
* 0 is returned for queries that don't manipulate data.
*
- * @return int the number of rows. A DB_Error object on failure.
+ * @return int|object
*/
public function affectedRows()
{
return $this->ibaseRaiseError(DB_ERROR_NOT_CAPABLE);
}
- // }}}
- // {{{ numCols()
-
/**
* Gets the number of columns in a result set
*
* DB_result::numCols() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
- * @return int the number of columns. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_result::numCols()
*/
}
// }}}
- // {{{ prepare()
+ // {{{ autoCommit()
/**
* Prepares a query for multiple execution with execute().
*/
public function prepare($query)
{
- $tokens = preg_split(
+ $tokens = preg_split(
'/((?<!\\\)[&?!])/',
$query,
-1,
PREG_SPLIT_DELIM_CAPTURE
);
- $token = 0;
- $types = array();
+ $token = 0;
+ $types = array();
$newquery = '';
foreach ($tokens as $key => $val) {
$newquery = substr($newquery, 0, -1);
$this->last_query = $query;
$newquery = $this->modifyQuery($newquery);
- $stmt = @ibase_prepare($this->connection, $newquery);
+ $stmt = @ibase_prepare(/*$this->connection,*/ $newquery);
if ($stmt === false) {
$stmt = $this->ibaseRaiseError();
} else {
$this->prepare_types[(int)$stmt] = $types;
- $this->manip_query[(int)$stmt] = DB::isManip($query);
+ $this->manip_query[(int)$stmt] = DB::isManip($query);
}
return $stmt;
}
// }}}
- // {{{ execute()
+ // {{{ commit()
/**
* Executes a DB statement prepared with prepare().
*
- * @param resource $stmt a DB statement resource returned from prepare()
- * @param mixed $data array, string or numeric data to be used in
+ * @param resource $stmt a DB statement resource returned from prepare()
+ * @param mixed $data array, string or numeric data to be used in
* execution of the statement. Quantity of items
* passed must match quantity of placeholders in
* query: meaning 1 for non-array items or the
return $tmp;
}
+ // }}}
+ // {{{ rollback()
+
/**
* Frees the internal resources associated with a prepared query
*
- * @param resource $stmt the prepared statement's PHP resource
- * @param bool $free_resource should the PHP resource be freed too?
+ * @param resource $stmt the prepared statement's PHP resource
+ * @param bool $free_resource should the PHP resource be freed too?
* Use false if you need to get data
* from the result set later.
*
}
// }}}
- // {{{ autoCommit()
+ // {{{ transactionInit()
/**
* Enables or disables automatic commits
*
- * @param bool $onoff true turns it on, false turns it off
+ * @param bool $onoff true turns it on, false turns it off
*
* @return int DB_OK on success. A DB_Error object if the driver
* doesn't support auto-committing transactions.
}
// }}}
- // {{{ commit()
+ // {{{ nextId()
/**
* Commits the current transaction
}
// }}}
- // {{{ rollback()
+ // {{{ createSequence()
/**
* Reverts the current transaction
}
// }}}
- // {{{ transactionInit()
+ // {{{ dropSequence()
public function transactionInit($trans_args = 0)
{
return $trans_args
- ? @ibase_trans($trans_args, $this->connection)
- : @ibase_trans();
+ ? @ibase_trans($trans_args, $this->connection)
+ : @ibase_trans();
}
// }}}
- // {{{ nextId()
+ // {{{ _ibaseFieldFlags()
/**
* Returns the next free id in a sequence
*
- * @param string $seq_name name of the sequence
- * @param boolean $ondemand when true, the seqence is automatically
+ * @param string $seq_name name of the sequence
+ * @param boolean $ondemand when true, the seqence is automatically
* created if it does not exist
*
- * @return int the next id number in the sequence.
+ * @return int|object
* A DB_Error object on failure.
*
* @see DB_common::nextID(), DB_common::getSequenceName(),
do {
$this->pushErrorHandling(PEAR_ERROR_RETURN);
$result = $this->query("SELECT GEN_ID(${sqn}, 1) "
- . 'FROM RDB$GENERATORS '
- . "WHERE RDB\$GENERATOR_NAME='${sqn}'");
+ . 'FROM RDB$GENERATORS '
+ . "WHERE RDB\$GENERATOR_NAME='${sqn}'");
$this->popErrorHandling();
if ($ondemand && DB::isError($result)) {
$repeat = 1;
}
// }}}
- // {{{ createSequence()
+ // {{{ ibaseRaiseError()
/**
* Creates a new sequence
*
- * @param string $seq_name name of the new sequence
+ * @param string $seq_name name of the new sequence
*
* @return int DB_OK on success. A DB_Error object on failure.
*
}
// }}}
- // {{{ dropSequence()
+ // {{{ errorNative()
/**
* Deletes a sequence
*
- * @param string $seq_name name of the sequence to be deleted
+ * @param string $seq_name name of the sequence to be deleted
*
* @return int DB_OK on success. A DB_Error object on failure.
*
public function dropSequence($seq_name)
{
return $this->query('DELETE FROM RDB$GENERATORS '
- . "WHERE RDB\$GENERATOR_NAME='"
- . strtoupper($this->getSequenceName($seq_name))
- . "'");
- }
-
- // }}}
- // {{{ _ibaseFieldFlags()
-
- /**
- * Get the column's flags
- *
- * Supports "primary_key", "unique_key", "not_null", "default",
- * "computed" and "blob".
- *
- * @param string $field_name the name of the field
- * @param string $table_name the name of the table
- *
- * @return string the flags
- *
- * @access private
- */
- public function _ibaseFieldFlags($field_name, $table_name)
- {
- $sql = 'SELECT R.RDB$CONSTRAINT_TYPE CTYPE'
- .' FROM RDB$INDEX_SEGMENTS I'
- .' JOIN RDB$RELATION_CONSTRAINTS R ON I.RDB$INDEX_NAME=R.RDB$INDEX_NAME'
- .' WHERE I.RDB$FIELD_NAME=\'' . $field_name . '\''
- .' AND UPPER(R.RDB$RELATION_NAME)=\'' . strtoupper($table_name) . '\'';
-
- $result = @ibase_query($this->connection, $sql);
- if (!$result) {
- return $this->ibaseRaiseError();
- }
-
- $flags = '';
- if ($obj = @ibase_fetch_object($result)) {
- @ibase_free_result($result);
- if (isset($obj->CTYPE) && trim($obj->CTYPE) == 'PRIMARY KEY') {
- $flags .= 'primary_key ';
- }
- if (isset($obj->CTYPE) && trim($obj->CTYPE) == 'UNIQUE') {
- $flags .= 'unique_key ';
- }
- }
-
- $sql = 'SELECT R.RDB$NULL_FLAG AS NFLAG,'
- .' R.RDB$DEFAULT_SOURCE AS DSOURCE,'
- .' F.RDB$FIELD_TYPE AS FTYPE,'
- .' F.RDB$COMPUTED_SOURCE AS CSOURCE'
- .' FROM RDB$RELATION_FIELDS R '
- .' JOIN RDB$FIELDS F ON R.RDB$FIELD_SOURCE=F.RDB$FIELD_NAME'
- .' WHERE UPPER(R.RDB$RELATION_NAME)=\'' . strtoupper($table_name) . '\''
- .' AND R.RDB$FIELD_NAME=\'' . $field_name . '\'';
-
- $result = @ibase_query($this->connection, $sql);
- if (!$result) {
- return $this->ibaseRaiseError();
- }
- if ($obj = @ibase_fetch_object($result)) {
- @ibase_free_result($result);
- if (isset($obj->NFLAG)) {
- $flags .= 'not_null ';
- }
- if (isset($obj->DSOURCE)) {
- $flags .= 'default ';
- }
- if (isset($obj->CSOURCE)) {
- $flags .= 'computed ';
- }
- if (isset($obj->FTYPE) && $obj->FTYPE == 261) {
- $flags .= 'blob ';
- }
- }
-
- return trim($flags);
- }
-
- // }}}
- // {{{ ibaseRaiseError()
-
- /**
- * Produces a DB_Error object regarding the current problem
- *
- * @param int $errno if the error is being manually raised pass a
- * DB_ERROR* constant here. If this isn't passed
- * the error information gathered from the DBMS.
- *
- * @return object the DB_Error object
- *
- * @see DB_common::raiseError(),
- * DB_ibase::errorNative(), DB_ibase::errorCode()
- */
- public function &ibaseRaiseError($errno = null)
- {
- if ($errno === null) {
- $errno = $this->errorCode($this->errorNative());
- }
- $tmp = $this->raiseError($errno, null, null, null, @ibase_errmsg());
- return $tmp;
- }
-
- // }}}
- // {{{ errorNative()
-
- /**
- * Gets the DBMS' native error code produced by the last query
- *
- * @return int the DBMS' error code. NULL if there is no error code.
- *
- * @since Method available since Release 1.7.0
- */
- public function errorNative()
- {
- if (function_exists('ibase_errcode')) {
- return @ibase_errcode();
- }
- if (preg_match(
- '/^Dynamic SQL Error SQL error code = ([0-9-]+)/i',
- @ibase_errmsg(),
- $m
- )) {
- return (int)$m[1];
- }
- return null;
+ . "WHERE RDB\$GENERATOR_NAME='"
+ . strtoupper($this->getSequenceName($seq_name))
+ . "'");
}
// }}}
// {{{ errorCode()
- /**
- * Maps native error codes to DB's portable ones
- *
- * @param int $nativecode the error code returned by the DBMS
- *
- * @return int the portable DB error code. Return DB_ERROR if the
- * current driver doesn't have a mapping for the
- * $nativecode submitted.
- *
- * @since Method available since Release 1.7.0
- */
- public function errorCode($nativecode = null)
- {
- if (isset($this->errorcode_map[$nativecode])) {
- return $this->errorcode_map[$nativecode];
- }
-
- static $error_regexps;
- if (!isset($error_regexps)) {
- $error_regexps = array(
- '/generator .* is not defined/'
- => DB_ERROR_SYNTAX, // for compat. w ibase_errcode()
- '/violation of [\w ]+ constraint/i'
- => DB_ERROR_CONSTRAINT,
- '/table.*(not exist|not found|unknown)/i'
- => DB_ERROR_NOSUCHTABLE,
- '/table .* already exists/i'
- => DB_ERROR_ALREADY_EXISTS,
- '/unsuccessful metadata update .* failed attempt to store duplicate value/i'
- => DB_ERROR_ALREADY_EXISTS,
- '/unsuccessful metadata update .* not found/i'
- => DB_ERROR_NOT_FOUND,
- '/validation error for column .* value "\*\*\* null/i'
- => DB_ERROR_CONSTRAINT_NOT_NULL,
- '/conversion error from string/i'
- => DB_ERROR_INVALID_NUMBER,
- '/no permission for/i'
- => DB_ERROR_ACCESS_VIOLATION,
- '/arithmetic exception, numeric overflow, or string truncation/i'
- => DB_ERROR_INVALID,
- '/feature is not supported/i'
- => DB_ERROR_NOT_CAPABLE,
- );
- }
-
- $errormsg = @ibase_errmsg();
- foreach ($error_regexps as $regexp => $code) {
- if (preg_match($regexp, $errormsg)) {
- return $code;
- }
- }
- return DB_ERROR;
- }
-
- // }}}
- // {{{ tableInfo()
-
/**
* Returns information about a table or a result set
*
* NOTE: only supports 'table' and 'flags' if <var>$result</var>
* is a table name.
*
- * @param object|string $result DB_result object from a query or a
+ * @param object|string $result DB_result object from a query or a
* string containing the name of a table.
* While this also accepts a query result
* resource identifier, this behavior is
* deprecated.
- * @param int $mode a valid tableInfo mode
+ * @param int $mode a valid tableInfo mode
*
- * @return array an associative array with the information requested.
+ * @return array|object
* A DB_Error object on failure.
*
* @see DB_common::tableInfo()
}
$count = @ibase_num_fields($id);
- $res = array();
+ $res = array();
if ($mode) {
$res['num_fields'] = $count;
$info = @ibase_field_info($id, $i);
$res[$i] = array(
'table' => $got_string ? $case_func($result) : '',
- 'name' => $case_func($info['name']),
- 'type' => $info['type'],
- 'len' => $info['length'],
+ 'name' => $case_func($info['name']),
+ 'type' => $info['type'],
+ 'len' => $info['length'],
'flags' => ($got_string)
- ? $this->_ibaseFieldFlags($info['name'], $result)
- : '',
+ ? $this->_ibaseFieldFlags($info['name'], $result)
+ : '',
);
if ($mode & DB_TABLEINFO_ORDER) {
$res['order'][$res[$i]['name']] = $i;
return $res;
}
+ // }}}
+ // {{{ tableInfo()
+
+ /**
+ * Get the column's flags
+ *
+ * Supports "primary_key", "unique_key", "not_null", "default",
+ * "computed" and "blob".
+ *
+ * @param string $field_name the name of the field
+ * @param string $table_name the name of the table
+ *
+ * @return string the flags
+ *
+ * @access private
+ */
+ public function _ibaseFieldFlags($field_name, $table_name)
+ {
+ $sql = 'SELECT R.RDB$CONSTRAINT_TYPE CTYPE'
+ . ' FROM RDB$INDEX_SEGMENTS I'
+ . ' JOIN RDB$RELATION_CONSTRAINTS R ON I.RDB$INDEX_NAME=R.RDB$INDEX_NAME'
+ . ' WHERE I.RDB$FIELD_NAME=\'' . $field_name . '\''
+ . ' AND UPPER(R.RDB$RELATION_NAME)=\'' . strtoupper($table_name) . '\'';
+
+ $result = @ibase_query($this->connection, $sql);
+ if (!$result) {
+ return $this->ibaseRaiseError();
+ }
+
+ $flags = '';
+ if ($obj = @ibase_fetch_object($result)) {
+ @ibase_free_result($result);
+ if (isset($obj->CTYPE) && trim($obj->CTYPE) == 'PRIMARY KEY') {
+ $flags .= 'primary_key ';
+ }
+ if (isset($obj->CTYPE) && trim($obj->CTYPE) == 'UNIQUE') {
+ $flags .= 'unique_key ';
+ }
+ }
+
+ $sql = 'SELECT R.RDB$NULL_FLAG AS NFLAG,'
+ . ' R.RDB$DEFAULT_SOURCE AS DSOURCE,'
+ . ' F.RDB$FIELD_TYPE AS FTYPE,'
+ . ' F.RDB$COMPUTED_SOURCE AS CSOURCE'
+ . ' FROM RDB$RELATION_FIELDS R '
+ . ' JOIN RDB$FIELDS F ON R.RDB$FIELD_SOURCE=F.RDB$FIELD_NAME'
+ . ' WHERE UPPER(R.RDB$RELATION_NAME)=\'' . strtoupper($table_name) . '\''
+ . ' AND R.RDB$FIELD_NAME=\'' . $field_name . '\'';
+
+ $result = @ibase_query($this->connection, $sql);
+ if (!$result) {
+ return $this->ibaseRaiseError();
+ }
+ if ($obj = @ibase_fetch_object($result)) {
+ @ibase_free_result($result);
+ if (isset($obj->NFLAG)) {
+ $flags .= 'not_null ';
+ }
+ if (isset($obj->DSOURCE)) {
+ $flags .= 'default ';
+ }
+ if (isset($obj->CSOURCE)) {
+ $flags .= 'computed ';
+ }
+ if (isset($obj->FTYPE) && $obj->FTYPE == 261) {
+ $flags .= 'blob ';
+ }
+ }
+
+ return trim($flags);
+ }
+
// }}}
// {{{ getSpecialQuery()
/**
* Obtains the query string needed for listing a given type of objects
*
- * @param string $type the kind of objects you want to retrieve
+ * @param string $type the kind of objects you want to retrieve
*
* @return string the SQL query string or null if the driver doesn't
* support the object type requested
switch ($type) {
case 'tables':
return 'SELECT DISTINCT R.RDB$RELATION_NAME FROM '
- . 'RDB$RELATION_FIELDS R WHERE R.RDB$SYSTEM_FLAG=0';
+ . 'RDB$RELATION_FIELDS R WHERE R.RDB$SYSTEM_FLAG=0';
case 'views':
return 'SELECT DISTINCT RDB$VIEW_NAME from RDB$VIEW_RELATIONS';
case 'users':
/**
* Obtain the DB_common class so it can be extended from
*/
-require_once 'DB/common.php';
+//require_once 'DB/common.php';
+require_once 'common.php';
/**
* The methods PEAR DB uses to interact with PHP's ifx extension
* @var array
*/
public $features = array(
- 'limit' => 'emulate',
- 'new_link' => false,
- 'numrows' => 'emulate',
- 'pconnect' => true,
- 'prepare' => false,
- 'ssl' => false,
- 'transactions' => true,
+ 'limit' => 'emulate',
+ 'new_link' => false,
+ 'numrows' => 'emulate',
+ 'pconnect' => true,
+ 'prepare' => false,
+ 'ssl' => false,
+ 'transactions' => true,
);
/**
* @var array
*/
public $errorcode_map = array(
- '-201' => DB_ERROR_SYNTAX,
- '-206' => DB_ERROR_NOSUCHTABLE,
- '-217' => DB_ERROR_NOSUCHFIELD,
- '-236' => DB_ERROR_VALUE_COUNT_ON_ROW,
- '-239' => DB_ERROR_CONSTRAINT,
- '-253' => DB_ERROR_SYNTAX,
- '-268' => DB_ERROR_CONSTRAINT,
- '-292' => DB_ERROR_CONSTRAINT_NOT_NULL,
- '-310' => DB_ERROR_ALREADY_EXISTS,
- '-316' => DB_ERROR_ALREADY_EXISTS,
- '-319' => DB_ERROR_NOT_FOUND,
- '-329' => DB_ERROR_NODBSELECTED,
- '-346' => DB_ERROR_CONSTRAINT,
- '-386' => DB_ERROR_CONSTRAINT_NOT_NULL,
- '-391' => DB_ERROR_CONSTRAINT_NOT_NULL,
- '-554' => DB_ERROR_SYNTAX,
- '-691' => DB_ERROR_CONSTRAINT,
- '-692' => DB_ERROR_CONSTRAINT,
- '-703' => DB_ERROR_CONSTRAINT_NOT_NULL,
- '-1202' => DB_ERROR_DIVZERO,
- '-1204' => DB_ERROR_INVALID_DATE,
- '-1205' => DB_ERROR_INVALID_DATE,
- '-1206' => DB_ERROR_INVALID_DATE,
- '-1209' => DB_ERROR_INVALID_DATE,
- '-1210' => DB_ERROR_INVALID_DATE,
- '-1212' => DB_ERROR_INVALID_DATE,
- '-1213' => DB_ERROR_INVALID_NUMBER,
+ '-201' => DB_ERROR_SYNTAX,
+ '-206' => DB_ERROR_NOSUCHTABLE,
+ '-217' => DB_ERROR_NOSUCHFIELD,
+ '-236' => DB_ERROR_VALUE_COUNT_ON_ROW,
+ '-239' => DB_ERROR_CONSTRAINT,
+ '-253' => DB_ERROR_SYNTAX,
+ '-268' => DB_ERROR_CONSTRAINT,
+ '-292' => DB_ERROR_CONSTRAINT_NOT_NULL,
+ '-310' => DB_ERROR_ALREADY_EXISTS,
+ '-316' => DB_ERROR_ALREADY_EXISTS,
+ '-319' => DB_ERROR_NOT_FOUND,
+ '-329' => DB_ERROR_NODBSELECTED,
+ '-346' => DB_ERROR_CONSTRAINT,
+ '-386' => DB_ERROR_CONSTRAINT_NOT_NULL,
+ '-391' => DB_ERROR_CONSTRAINT_NOT_NULL,
+ '-554' => DB_ERROR_SYNTAX,
+ '-691' => DB_ERROR_CONSTRAINT,
+ '-692' => DB_ERROR_CONSTRAINT,
+ '-703' => DB_ERROR_CONSTRAINT_NOT_NULL,
+ '-1202' => DB_ERROR_DIVZERO,
+ '-1204' => DB_ERROR_INVALID_DATE,
+ '-1205' => DB_ERROR_INVALID_DATE,
+ '-1206' => DB_ERROR_INVALID_DATE,
+ '-1209' => DB_ERROR_INVALID_DATE,
+ '-1210' => DB_ERROR_INVALID_DATE,
+ '-1212' => DB_ERROR_INVALID_DATE,
+ '-1213' => DB_ERROR_INVALID_NUMBER,
);
/**
*
* Don't call this method directly. Use DB::connect() instead.
*
- * @param array $dsn the data source name
- * @param bool $persistent should the connection be persistent?
+ * @param array $dsn the data source name
+ * @param bool $persistent should the connection be persistent?
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function connect($dsn, $persistent = false)
{
// }}}
// {{{ disconnect()
+ /**
+ * Produces a DB_Error object regarding the current problem
+ *
+ * @param int $errno if the error is being manually raised pass a
+ * DB_ERROR* constant here. If this isn't passed
+ * the error information gathered from the DBMS.
+ *
+ * @return object the DB_Error object
+ *
+ * @see DB_common::raiseError(),
+ * DB_ifx::errorNative(), DB_ifx::errorCode()
+ */
+ public function ifxRaiseError($errno = null)
+ {
+ if ($errno === null) {
+ $errno = $this->errorCode(ifx_error());
+ }
+ return $this->raiseError(
+ $errno,
+ null,
+ null,
+ null,
+ $this->errorNative()
+ );
+ }
+
+ // }}}
+ // {{{ simpleQuery()
+
+ /**
+ * Maps native error codes to DB's portable ones.
+ *
+ * Requires that the DB implementation's constructor fills
+ * in the <var>$errorcode_map</var> property.
+ *
+ * @param string $nativecode error code returned by the database
+ * @return int a portable DB error code, or DB_ERROR if this DB
+ * implementation has no mapping for the given error code.
+ */
+ public function errorCode($nativecode)
+ {
+ if (preg_match('/SQLCODE=(.*)]/', $nativecode, $match)) {
+ $code = $match[1];
+ if (isset($this->errorcode_map[$code])) {
+ return $this->errorcode_map[$code];
+ }
+ }
+ return DB_ERROR;
+ }
+
+ // }}}
+ // {{{ nextResult()
+
+ /**
+ * Gets the DBMS' native error code and message produced by the last query
+ *
+ * @return string the DBMS' error code and message
+ */
+ public function errorNative()
+ {
+ return @ifx_error() . ' ' . @ifx_errormsg();
+ }
+
+ // }}}
+ // {{{ affectedRows()
+
/**
* Disconnects from the database server
*
}
// }}}
- // {{{ simpleQuery()
+ // {{{ fetchInto()
/**
* Sends a query to the database server
{
$ismanip = $this->_checkManip($query);
$this->last_query = $query;
- $this->affected = null;
+ $this->affected = null;
if (preg_match('/(SELECT|EXECUTE)/i', $query)) { //TESTME: Use !DB::isManip()?
// the scroll is needed for fetching absolute row numbers
// in a select query result
}
// }}}
- // {{{ nextResult()
+ // {{{ numCols()
/**
* Move the internal ifx result pointer to the next available result
}
// }}}
- // {{{ affectedRows()
+ // {{{ freeResult()
/**
* Determines the number of rows affected by a data maniuplation query
}
// }}}
- // {{{ fetchInto()
+ // {{{ autoCommit()
/**
* Places a row from the result set into the given array
* DB_result::fetchInto() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result the query result resource
- * @param array $arr the referenced array to put the data in
- * @param int $fetchmode how the resulting array should be indexed
- * @param int $rownum the row number to fetch (0 = first row)
+ * @param resource $result the query result resource
+ * @param array $arr the referenced array to put the data in
+ * @param int $fetchmode how the resulting array should be indexed
+ * @param int $rownum the row number to fetch (0 = first row)
*
* @return mixed DB_OK on success, NULL when the end of a result set is
* reached or on failure
return null;
}
if ($fetchmode !== DB_FETCHMODE_ASSOC) {
- $i=0;
+ $i = 0;
$order = array();
foreach ($arr as $val) {
$order[$i++] = $val;
}
$arr = $order;
} elseif ($fetchmode == DB_FETCHMODE_ASSOC &&
- $this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
+ $this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
$arr = array_change_key_case($arr, CASE_LOWER);
}
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
}
// }}}
- // {{{ numCols()
+ // {{{ commit()
/**
* Gets the number of columns in a result set
* DB_result::numCols() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
- * @return int the number of columns. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_result::numCols()
*/
}
// }}}
- // {{{ freeResult()
+ // {{{ rollback()
/**
* Deletes the result set and frees the memory occupied by the result set
* DB_result::free() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
* @return bool TRUE on success, FALSE if $result is invalid
*
}
// }}}
- // {{{ autoCommit()
+ // {{{ ifxRaiseError()
/**
* Enables or disables automatic commits
*
- * @param bool $onoff true turns it on, false turns it off
+ * @param bool $onoff true turns it on, false turns it off
*
* @return int DB_OK on success. A DB_Error object if the driver
* doesn't support auto-committing transactions.
}
// }}}
- // {{{ commit()
+ // {{{ errorNative()
/**
* Commits the current transaction
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function commit()
{
}
// }}}
- // {{{ rollback()
+ // {{{ errorCode()
/**
* Reverts the current transaction
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function rollback()
{
return DB_OK;
}
- // }}}
- // {{{ ifxRaiseError()
-
- /**
- * Produces a DB_Error object regarding the current problem
- *
- * @param int $errno if the error is being manually raised pass a
- * DB_ERROR* constant here. If this isn't passed
- * the error information gathered from the DBMS.
- *
- * @return object the DB_Error object
- *
- * @see DB_common::raiseError(),
- * DB_ifx::errorNative(), DB_ifx::errorCode()
- */
- public function ifxRaiseError($errno = null)
- {
- if ($errno === null) {
- $errno = $this->errorCode(ifx_error());
- }
- return $this->raiseError(
- $errno,
- null,
- null,
- null,
- $this->errorNative()
- );
- }
-
- // }}}
- // {{{ errorNative()
-
- /**
- * Gets the DBMS' native error code and message produced by the last query
- *
- * @return string the DBMS' error code and message
- */
- public function errorNative()
- {
- return @ifx_error() . ' ' . @ifx_errormsg();
- }
-
- // }}}
- // {{{ errorCode()
-
- /**
- * Maps native error codes to DB's portable ones.
- *
- * Requires that the DB implementation's constructor fills
- * in the <var>$errorcode_map</var> property.
- *
- * @param string $nativecode error code returned by the database
- * @return int a portable DB error code, or DB_ERROR if this DB
- * implementation has no mapping for the given error code.
- */
- public function errorCode($nativecode)
- {
- if (preg_match('/SQLCODE=(.*)]/', $nativecode, $match)) {
- $code = $match[1];
- if (isset($this->errorcode_map[$code])) {
- return $this->errorcode_map[$code];
- }
- }
- return DB_ERROR;
- }
-
// }}}
// {{{ tableInfo()
* an error will be raised saying
* <samp>can't distinguish duplicate field names</samp>.
*
- * @param object|string $result DB_result object from a query or a
+ * @param object|string $result DB_result object from a query or a
* string containing the name of a table.
* While this also accepts a query result
* resource identifier, this behavior is
* deprecated.
- * @param int $mode a valid tableInfo mode
+ * @param int $mode a valid tableInfo mode
*
- * @return array an associative array with the information requested.
+ * @return array|object
* A DB_Error object on failure.
*
* @see DB_common::tableInfo()
$case_func = 'strval';
}
- $i = 0;
+ $i = 0;
$res = array();
if ($mode) {
$props = explode(';', $value);
$res[$i] = array(
'table' => $got_string ? $case_func($result) : '',
- 'name' => $case_func($key),
- 'type' => $props[0],
- 'len' => $props[1],
+ 'name' => $case_func($key),
+ 'type' => $props[0],
+ 'len' => $props[1],
'flags' => $props[4] == 'N' ? 'not_null' : '',
);
if ($mode & DB_TABLEINFO_ORDER) {
/**
* Obtains the query string needed for listing a given type of objects
*
- * @param string $type the kind of objects you want to retrieve
+ * @param string $type the kind of objects you want to retrieve
*
* @return string the SQL query string or null if the driver doesn't
* support the object type requested
/**
* Obtain the DB_common class so it can be extended from
*/
-require_once 'DB/common.php';
+//require_once 'DB/common.php';
+require_once 'common.php';
/**
* The methods PEAR DB uses to interact with PHP's msql extension
* @var array
*/
public $features = array(
- 'limit' => 'emulate',
- 'new_link' => false,
- 'numrows' => true,
- 'pconnect' => true,
- 'prepare' => false,
- 'ssl' => false,
- 'transactions' => false,
+ 'limit' => 'emulate',
+ 'new_link' => false,
+ 'numrows' => true,
+ 'pconnect' => true,
+ 'prepare' => false,
+ 'ssl' => false,
+ 'transactions' => false,
);
/**
* A mapping of native error codes to DB error codes
* @var array
*/
- public $errorcode_map = array(
- );
+ public $errorcode_map = array();
/**
* The raw database connection created by PHP
* );
*
* $db = DB::connect($dsn, $options);
- * if (PEAR::isError($db)) {
+ * if ((new PEAR)->isError($db)) {
* die($db->getMessage());
* }
* </code>
*
- * @param array $dsn the data source name
- * @param bool $persistent should the connection be persistent?
+ * @param array $dsn the data source name
+ * @param bool $persistent should the connection be persistent?
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function connect($dsn, $persistent = false)
{
$params = array();
if ($dsn['hostspec']) {
$params[] = $dsn['port']
- ? $dsn['hostspec'] . ',' . $dsn['port']
- : $dsn['hostspec'];
+ ? $dsn['hostspec'] . ',' . $dsn['port']
+ : $dsn['hostspec'];
}
$connect_function = $persistent ? 'msql_pconnect' : 'msql_connect';
// }}}
// {{{ disconnect()
+ /**
+ * Produces a DB_Error object regarding the current problem
+ *
+ * @param int $errno if the error is being manually raised pass a
+ * DB_ERROR* constant here. If this isn't passed
+ * the error information gathered from the DBMS.
+ *
+ * @return object the DB_Error object
+ *
+ * @see DB_common::raiseError(),
+ * DB_msql::errorNative(), DB_msql::errorCode()
+ */
+ public function msqlRaiseError($errno = null)
+ {
+ $native = $this->errorNative();
+ if ($errno === null) {
+ $errno = $this->errorCode($native);
+ }
+ return $this->raiseError($errno, null, null, null, $native);
+ }
+
+ // }}}
+ // {{{ simpleQuery()
+
+ /**
+ * Gets the DBMS' native error message produced by the last query
+ *
+ * @return string the DBMS' error message
+ */
+ public function errorNative()
+ {
+ return @msql_error();
+ }
+
+
+ // }}}
+ // {{{ nextResult()
+
+ /**
+ * Determines PEAR::DB error code from the database's text error message
+ *
+ * @param string $errormsg the error message returned from the database
+ *
+ * @return integer the error number from a DB_ERROR* constant
+ */
+ public function errorCode($errormsg)
+ {
+ static $error_regexps;
+
+ // PHP 5.2+ prepends the function name to $php_errormsg, so we need
+ // this hack to work around it, per bug #9599.
+ $errormsg = preg_replace('/^msql[a-z_]+\(\): /', '', $errormsg);
+
+ if (!isset($error_regexps)) {
+ $error_regexps = array(
+ '/^Access to database denied/i'
+ => DB_ERROR_ACCESS_VIOLATION,
+ '/^Bad index name/i'
+ => DB_ERROR_ALREADY_EXISTS,
+ '/^Bad order field/i'
+ => DB_ERROR_SYNTAX,
+ '/^Bad type for comparison/i'
+ => DB_ERROR_SYNTAX,
+ '/^Can\'t perform LIKE on/i'
+ => DB_ERROR_SYNTAX,
+ '/^Can\'t use TEXT fields in LIKE comparison/i'
+ => DB_ERROR_SYNTAX,
+ '/^Couldn\'t create temporary table/i'
+ => DB_ERROR_CANNOT_CREATE,
+ '/^Error creating table file/i'
+ => DB_ERROR_CANNOT_CREATE,
+ '/^Field .* cannot be null$/i'
+ => DB_ERROR_CONSTRAINT_NOT_NULL,
+ '/^Index (field|condition) .* cannot be null$/i'
+ => DB_ERROR_SYNTAX,
+ '/^Invalid date format/i'
+ => DB_ERROR_INVALID_DATE,
+ '/^Invalid time format/i'
+ => DB_ERROR_INVALID,
+ '/^Literal value for .* is wrong type$/i'
+ => DB_ERROR_INVALID_NUMBER,
+ '/^No Database Selected/i'
+ => DB_ERROR_NODBSELECTED,
+ '/^No value specified for field/i'
+ => DB_ERROR_VALUE_COUNT_ON_ROW,
+ '/^Non unique value for unique index/i'
+ => DB_ERROR_CONSTRAINT,
+ '/^Out of memory for temporary table/i'
+ => DB_ERROR_CANNOT_CREATE,
+ '/^Permission denied/i'
+ => DB_ERROR_ACCESS_VIOLATION,
+ '/^Reference to un-selected table/i'
+ => DB_ERROR_SYNTAX,
+ '/^syntax error/i'
+ => DB_ERROR_SYNTAX,
+ '/^Table .* exists$/i'
+ => DB_ERROR_ALREADY_EXISTS,
+ '/^Unknown database/i'
+ => DB_ERROR_NOSUCHDB,
+ '/^Unknown field/i'
+ => DB_ERROR_NOSUCHFIELD,
+ '/^Unknown (index|system variable)/i'
+ => DB_ERROR_NOT_FOUND,
+ '/^Unknown table/i'
+ => DB_ERROR_NOSUCHTABLE,
+ '/^Unqualified field/i'
+ => DB_ERROR_SYNTAX,
+ );
+ }
+
+ foreach ($error_regexps as $regexp => $code) {
+ if (preg_match($regexp, $errormsg)) {
+ return $code;
+ }
+ }
+ return DB_ERROR;
+ }
+
+ // }}}
+ // {{{ fetchInto()
+
/**
* Disconnects from the database server
*
}
// }}}
- // {{{ simpleQuery()
+ // {{{ freeResult()
/**
* Sends a query to the database server
}
}
-
// }}}
- // {{{ nextResult()
+ // {{{ numCols()
/**
* Move the internal msql result pointer to the next available result
}
// }}}
- // {{{ fetchInto()
+ // {{{ numRows()
/**
* Places a row from the result set into the given array
* 4.3.11 and 5.0.4. Make sure your version of PHP meets or exceeds
* those versions.
*
- * @param resource $result the query result resource
- * @param array $arr the referenced array to put the data in
- * @param int $fetchmode how the resulting array should be indexed
- * @param int $rownum the row number to fetch (0 = first row)
+ * @param resource $result the query result resource
+ * @param array $arr the referenced array to put the data in
+ * @param int $fetchmode how the resulting array should be indexed
+ * @param int $rownum the row number to fetch (0 = first row)
*
* @return mixed DB_OK on success, NULL when the end of a result set is
* reached or on failure
}
// }}}
- // {{{ freeResult()
+ // {{{ affected()
/**
* Deletes the result set and frees the memory occupied by the result set
* DB_result::free() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
* @return bool TRUE on success, FALSE if $result is invalid
*
}
// }}}
- // {{{ numCols()
+ // {{{ nextId()
/**
* Gets the number of columns in a result set
* DB_result::numCols() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
- * @return int the number of columns. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_result::numCols()
*/
}
// }}}
- // {{{ numRows()
+ // {{{ createSequence()
/**
* Gets the number of rows in a result set
* DB_result::numRows() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
- * @return int the number of rows. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_result::numRows()
*/
}
// }}}
- // {{{ affected()
+ // {{{ dropSequence()
/**
* Determines the number of rows affected by a data maniuplation query
}
// }}}
- // {{{ nextId()
+ // {{{ quoteIdentifier()
/**
* Returns the next free id in a sequence
*
- * @param string $seq_name name of the sequence
- * @param boolean $ondemand when true, the seqence is automatically
+ * @param string $seq_name name of the sequence
+ * @param boolean $ondemand when true, the seqence is automatically
* created if it does not exist
*
- * @return int the next id number in the sequence.
+ * @return int|object
* A DB_Error object on failure.
*
* @see DB_common::nextID(), DB_common::getSequenceName(),
}
// }}}
- // {{{ createSequence()
+ // {{{ quoteFloat()
/**
* Creates a new sequence
* Also creates a new table to associate the sequence with. Uses
* a separate table to ensure portability with other drivers.
*
- * @param string $seq_name name of the new sequence
+ * @param string $seq_name name of the new sequence
*
* @return int DB_OK on success. A DB_Error object on failure.
*
{
$seqname = $this->getSequenceName($seq_name);
$res = $this->query('CREATE TABLE ' . $seqname
- . ' (id INTEGER NOT NULL)');
+ . ' (id INTEGER NOT NULL)');
if (DB::isError($res)) {
return $res;
}
}
// }}}
- // {{{ dropSequence()
+ // {{{ escapeSimple()
/**
* Deletes a sequence
*
- * @param string $seq_name name of the sequence to be deleted
+ * @param string $seq_name name of the sequence to be deleted
*
* @return int DB_OK on success. A DB_Error object on failure.
*
}
// }}}
- // {{{ quoteIdentifier()
+ // {{{ msqlRaiseError()
/**
* mSQL does not support delimited identifiers
*
- * @param string $str the identifier name to be quoted
+ * @param string $str the identifier name to be quoted
*
* @return object a DB_Error object
*
}
// }}}
- // {{{ quoteFloat()
+ // {{{ errorNative()
/**
* Formats a float value for use within a query in a locale-independent
{
return $this->escapeSimple(str_replace(',', '.', strval(floatval($float))));
}
-
+
// }}}
- // {{{ escapeSimple()
+ // {{{ errorCode()
/**
* Escapes a string according to the current DBMS's standards
*
- * @param string $str the string to be escaped
+ * @param string $str the string to be escaped
*
* @return string the escaped string
*
return addslashes($str);
}
- // }}}
- // {{{ msqlRaiseError()
-
- /**
- * Produces a DB_Error object regarding the current problem
- *
- * @param int $errno if the error is being manually raised pass a
- * DB_ERROR* constant here. If this isn't passed
- * the error information gathered from the DBMS.
- *
- * @return object the DB_Error object
- *
- * @see DB_common::raiseError(),
- * DB_msql::errorNative(), DB_msql::errorCode()
- */
- public function msqlRaiseError($errno = null)
- {
- $native = $this->errorNative();
- if ($errno === null) {
- $errno = $this->errorCode($native);
- }
- return $this->raiseError($errno, null, null, null, $native);
- }
-
- // }}}
- // {{{ errorNative()
-
- /**
- * Gets the DBMS' native error message produced by the last query
- *
- * @return string the DBMS' error message
- */
- public function errorNative()
- {
- return @msql_error();
- }
-
- // }}}
- // {{{ errorCode()
-
- /**
- * Determines PEAR::DB error code from the database's text error message
- *
- * @param string $errormsg the error message returned from the database
- *
- * @return integer the error number from a DB_ERROR* constant
- */
- public function errorCode($errormsg)
- {
- static $error_regexps;
-
- // PHP 5.2+ prepends the function name to $php_errormsg, so we need
- // this hack to work around it, per bug #9599.
- $errormsg = preg_replace('/^msql[a-z_]+\(\): /', '', $errormsg);
-
- if (!isset($error_regexps)) {
- $error_regexps = array(
- '/^Access to database denied/i'
- => DB_ERROR_ACCESS_VIOLATION,
- '/^Bad index name/i'
- => DB_ERROR_ALREADY_EXISTS,
- '/^Bad order field/i'
- => DB_ERROR_SYNTAX,
- '/^Bad type for comparison/i'
- => DB_ERROR_SYNTAX,
- '/^Can\'t perform LIKE on/i'
- => DB_ERROR_SYNTAX,
- '/^Can\'t use TEXT fields in LIKE comparison/i'
- => DB_ERROR_SYNTAX,
- '/^Couldn\'t create temporary table/i'
- => DB_ERROR_CANNOT_CREATE,
- '/^Error creating table file/i'
- => DB_ERROR_CANNOT_CREATE,
- '/^Field .* cannot be null$/i'
- => DB_ERROR_CONSTRAINT_NOT_NULL,
- '/^Index (field|condition) .* cannot be null$/i'
- => DB_ERROR_SYNTAX,
- '/^Invalid date format/i'
- => DB_ERROR_INVALID_DATE,
- '/^Invalid time format/i'
- => DB_ERROR_INVALID,
- '/^Literal value for .* is wrong type$/i'
- => DB_ERROR_INVALID_NUMBER,
- '/^No Database Selected/i'
- => DB_ERROR_NODBSELECTED,
- '/^No value specified for field/i'
- => DB_ERROR_VALUE_COUNT_ON_ROW,
- '/^Non unique value for unique index/i'
- => DB_ERROR_CONSTRAINT,
- '/^Out of memory for temporary table/i'
- => DB_ERROR_CANNOT_CREATE,
- '/^Permission denied/i'
- => DB_ERROR_ACCESS_VIOLATION,
- '/^Reference to un-selected table/i'
- => DB_ERROR_SYNTAX,
- '/^syntax error/i'
- => DB_ERROR_SYNTAX,
- '/^Table .* exists$/i'
- => DB_ERROR_ALREADY_EXISTS,
- '/^Unknown database/i'
- => DB_ERROR_NOSUCHDB,
- '/^Unknown field/i'
- => DB_ERROR_NOSUCHFIELD,
- '/^Unknown (index|system variable)/i'
- => DB_ERROR_NOT_FOUND,
- '/^Unknown table/i'
- => DB_ERROR_NOSUCHTABLE,
- '/^Unqualified field/i'
- => DB_ERROR_SYNTAX,
- );
- }
-
- foreach ($error_regexps as $regexp => $code) {
- if (preg_match($regexp, $errormsg)) {
- return $code;
- }
- }
- return DB_ERROR;
- }
-
// }}}
// {{{ tableInfo()
/**
* Returns information about a table or a result set
*
- * @param object|string $result DB_result object from a query or a
+ * @param object|string $result DB_result object from a query or a
* string containing the name of a table.
* While this also accepts a query result
* resource identifier, this behavior is
* deprecated.
- * @param int $mode a valid tableInfo mode
+ * @param int $mode a valid tableInfo mode
*
- * @return array an associative array with the information requested.
+ * @return array|object
* A DB_Error object on failure.
*
* @see DB_common::setOption()
}
$count = @msql_num_fields($id);
- $res = array();
+ $res = array();
if ($mode) {
$res['num_fields'] = $count;
$res[$i] = array(
'table' => $case_func($tmp->table),
- 'name' => $case_func($tmp->name),
- 'type' => $tmp->type,
- 'len' => msql_field_len($id, $i),
+ 'name' => $case_func($tmp->name),
+ 'type' => $tmp->type,
+ 'len' => msql_field_len($id, $i),
'flags' => $flags,
);
/**
* Obtain a list of a given type of objects
*
- * @param string $type the kind of objects you want to retrieve
+ * @param string $type the kind of objects you want to retrieve
*
- * @return array the array containing the list of objects requested
+ * @return array|object
*
* @access protected
* @see DB_common::getListOf()
/**
* Obtain the DB_common class so it can be extended from
*/
-require_once 'DB/common.php';
+//require_once 'DB/common.php';
+require_once 'common.php';
/**
* The methods PEAR DB uses to interact with PHP's mssql extension
* @var array
*/
public $features = array(
- 'limit' => 'emulate',
- 'new_link' => false,
- 'numrows' => true,
- 'pconnect' => true,
- 'prepare' => false,
- 'ssl' => false,
- 'transactions' => true,
+ 'limit' => 'emulate',
+ 'new_link' => false,
+ 'numrows' => true,
+ 'pconnect' => true,
+ 'prepare' => false,
+ 'ssl' => false,
+ 'transactions' => true,
);
/**
*/
// XXX Add here error codes ie: 'S100E' => DB_ERROR_SYNTAX
public $errorcode_map = array(
- 102 => DB_ERROR_SYNTAX,
- 110 => DB_ERROR_VALUE_COUNT_ON_ROW,
- 155 => DB_ERROR_NOSUCHFIELD,
- 156 => DB_ERROR_SYNTAX,
- 170 => DB_ERROR_SYNTAX,
- 207 => DB_ERROR_NOSUCHFIELD,
- 208 => DB_ERROR_NOSUCHTABLE,
- 245 => DB_ERROR_INVALID_NUMBER,
- 319 => DB_ERROR_SYNTAX,
- 321 => DB_ERROR_NOSUCHFIELD,
- 325 => DB_ERROR_SYNTAX,
- 336 => DB_ERROR_SYNTAX,
- 515 => DB_ERROR_CONSTRAINT_NOT_NULL,
- 547 => DB_ERROR_CONSTRAINT,
- 1018 => DB_ERROR_SYNTAX,
- 1035 => DB_ERROR_SYNTAX,
- 1913 => DB_ERROR_ALREADY_EXISTS,
- 2209 => DB_ERROR_SYNTAX,
- 2223 => DB_ERROR_SYNTAX,
- 2248 => DB_ERROR_SYNTAX,
- 2256 => DB_ERROR_SYNTAX,
- 2257 => DB_ERROR_SYNTAX,
- 2627 => DB_ERROR_CONSTRAINT,
- 2714 => DB_ERROR_ALREADY_EXISTS,
- 3607 => DB_ERROR_DIVZERO,
- 3701 => DB_ERROR_NOSUCHTABLE,
- 7630 => DB_ERROR_SYNTAX,
- 8134 => DB_ERROR_DIVZERO,
- 9303 => DB_ERROR_SYNTAX,
- 9317 => DB_ERROR_SYNTAX,
- 9318 => DB_ERROR_SYNTAX,
- 9331 => DB_ERROR_SYNTAX,
- 9332 => DB_ERROR_SYNTAX,
+ 102 => DB_ERROR_SYNTAX,
+ 110 => DB_ERROR_VALUE_COUNT_ON_ROW,
+ 155 => DB_ERROR_NOSUCHFIELD,
+ 156 => DB_ERROR_SYNTAX,
+ 170 => DB_ERROR_SYNTAX,
+ 207 => DB_ERROR_NOSUCHFIELD,
+ 208 => DB_ERROR_NOSUCHTABLE,
+ 245 => DB_ERROR_INVALID_NUMBER,
+ 319 => DB_ERROR_SYNTAX,
+ 321 => DB_ERROR_NOSUCHFIELD,
+ 325 => DB_ERROR_SYNTAX,
+ 336 => DB_ERROR_SYNTAX,
+ 515 => DB_ERROR_CONSTRAINT_NOT_NULL,
+ 547 => DB_ERROR_CONSTRAINT,
+ 1018 => DB_ERROR_SYNTAX,
+ 1035 => DB_ERROR_SYNTAX,
+ 1913 => DB_ERROR_ALREADY_EXISTS,
+ 2209 => DB_ERROR_SYNTAX,
+ 2223 => DB_ERROR_SYNTAX,
+ 2248 => DB_ERROR_SYNTAX,
+ 2256 => DB_ERROR_SYNTAX,
+ 2257 => DB_ERROR_SYNTAX,
+ 2627 => DB_ERROR_CONSTRAINT,
+ 2714 => DB_ERROR_ALREADY_EXISTS,
+ 3607 => DB_ERROR_DIVZERO,
+ 3701 => DB_ERROR_NOSUCHTABLE,
+ 7630 => DB_ERROR_SYNTAX,
+ 8134 => DB_ERROR_DIVZERO,
+ 9303 => DB_ERROR_SYNTAX,
+ 9317 => DB_ERROR_SYNTAX,
+ 9318 => DB_ERROR_SYNTAX,
+ 9331 => DB_ERROR_SYNTAX,
+ 9332 => DB_ERROR_SYNTAX,
15253 => DB_ERROR_SYNTAX,
);
*
* Don't call this method directly. Use DB::connect() instead.
*
- * @param array $dsn the data source name
- * @param bool $persistent should the connection be persistent?
+ * @param array $dsn the data source name
+ * @param bool $persistent should the connection be persistent?
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function connect($dsn, $persistent = false)
{
);
if ($dsn['port']) {
$params[0] .= ((substr(PHP_OS, 0, 3) == 'WIN') ? ',' : ':')
- . $dsn['port'];
+ . $dsn['port'];
}
$connect_function = $persistent ? 'mssql_pconnect' : 'mssql_connect';
// }}}
// {{{ nextResult()
+ /**
+ * Produces a DB_Error object regarding the current problem
+ *
+ * @param null $code
+ * @return object the DB_Error object
+ *
+ * @see DB_common::raiseError(),
+ * DB_mssql::errorNative(), DB_mssql::errorCode()
+ */
+ public function mssqlRaiseError($code = null)
+ {
+ $message = @mssql_get_last_message();
+ if (!$code) {
+ $code = $this->errorNative();
+ }
+ return $this->raiseError(
+ $this->errorCode($code, $message),
+ null,
+ null,
+ null,
+ "$code - $message"
+ );
+ }
+
+ // }}}
+ // {{{ fetchInto()
+
+ /**
+ * Gets the DBMS' native error code produced by the last query
+ *
+ * @return int the DBMS' error code
+ */
+ public function errorNative()
+ {
+ $res = @mssql_query('select @@ERROR as ErrorCode', $this->connection);
+ if (!$res) {
+ return DB_ERROR;
+ }
+ $row = @mssql_fetch_row($res);
+ return $row[0];
+ }
+
+ // }}}
+ // {{{ freeResult()
+
+ /**
+ * Determines PEAR::DB error code from mssql's native codes.
+ *
+ * If <var>$nativecode</var> isn't known yet, it will be looked up.
+ *
+ * @param mixed $nativecode mssql error code, if known
+ * @param string $msg
+ * @return integer an error number from a DB error constant
+ * @see errorNative()
+ */
+ public function errorCode($nativecode = null, $msg = '')
+ {
+ if (!$nativecode) {
+ $nativecode = $this->errorNative();
+ }
+ if (isset($this->errorcode_map[$nativecode])) {
+ if ($nativecode == 3701
+ && preg_match('/Cannot drop the index/i', $msg)) {
+ return DB_ERROR_NOT_FOUND;
+ }
+ return $this->errorcode_map[$nativecode];
+ } else {
+ return DB_ERROR;
+ }
+ }
+
+ // }}}
+ // {{{ numCols()
+
/**
* Move the internal mssql result pointer to the next available result
*
}
// }}}
- // {{{ fetchInto()
+ // {{{ numRows()
/**
* Places a row from the result set into the given array
* DB_result::fetchInto() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result the query result resource
- * @param array $arr the referenced array to put the data in
- * @param int $fetchmode how the resulting array should be indexed
- * @param int $rownum the row number to fetch (0 = first row)
+ * @param resource $result the query result resource
+ * @param array $arr the referenced array to put the data in
+ * @param int $fetchmode how the resulting array should be indexed
+ * @param int $rownum the row number to fetch (0 = first row)
*
* @return mixed DB_OK on success, NULL when the end of a result set is
* reached or on failure
}
// }}}
- // {{{ freeResult()
+ // {{{ autoCommit()
/**
* Deletes the result set and frees the memory occupied by the result set
* DB_result::free() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
* @return bool TRUE on success, FALSE if $result is invalid
*
}
// }}}
- // {{{ numCols()
+ // {{{ commit()
/**
* Gets the number of columns in a result set
* DB_result::numCols() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
- * @return int the number of columns. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_result::numCols()
*/
}
// }}}
- // {{{ numRows()
+ // {{{ rollback()
/**
* Gets the number of rows in a result set
* DB_result::numRows() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
- * @return int the number of rows. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_result::numRows()
*/
}
// }}}
- // {{{ autoCommit()
+ // {{{ affectedRows()
/**
* Enables or disables automatic commits
*
- * @param bool $onoff true turns it on, false turns it off
+ * @param bool $onoff true turns it on, false turns it off
*
* @return int DB_OK on success. A DB_Error object if the driver
* doesn't support auto-committing transactions.
}
// }}}
- // {{{ commit()
+ // {{{ nextId()
/**
* Commits the current transaction
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function commit()
{
return DB_OK;
}
- // }}}
- // {{{ rollback()
-
/**
* Reverts the current transaction
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function rollback()
{
}
// }}}
- // {{{ affectedRows()
+ // {{{ dropSequence()
/**
* Determines the number of rows affected by a data maniuplation query
*
* 0 is returned for queries that don't manipulate data.
*
- * @return int the number of rows. A DB_Error object on failure.
+ * @return int|object
*/
public function affectedRows()
{
}
// }}}
- // {{{ nextId()
+ // {{{ escapeSimple()
/**
* Returns the next free id in a sequence
*
- * @param string $seq_name name of the sequence
- * @param boolean $ondemand when true, the seqence is automatically
+ * @param string $seq_name name of the sequence
+ * @param boolean $ondemand when true, the seqence is automatically
* created if it does not exist
*
- * @return int the next id number in the sequence.
+ * @return int|object
* A DB_Error object on failure.
*
* @see DB_common::nextID(), DB_common::getSequenceName(),
return $result[0];
}
+ // }}}
+ // {{{ quoteIdentifier()
+
/**
* Creates a new sequence
*
- * @param string $seq_name name of the new sequence
+ * @param string $seq_name name of the new sequence
*
* @return int DB_OK on success. A DB_Error object on failure.
*
public function createSequence($seq_name)
{
return $this->query('CREATE TABLE '
- . $this->getSequenceName($seq_name)
- . ' ([id] [int] IDENTITY (1, 1) NOT NULL,'
- . ' [vapor] [int] NULL)');
+ . $this->getSequenceName($seq_name)
+ . ' ([id] [int] IDENTITY (1, 1) NOT NULL,'
+ . ' [vapor] [int] NULL)');
}
// }}}
- // {{{ dropSequence()
+ // {{{ mssqlRaiseError()
/**
* Deletes a sequence
*
- * @param string $seq_name name of the sequence to be deleted
+ * @param string $seq_name name of the sequence to be deleted
*
* @return int DB_OK on success. A DB_Error object on failure.
*
}
// }}}
- // {{{ escapeSimple()
+ // {{{ errorNative()
/**
* Escapes a string in a manner suitable for SQL Server.
*
- * @param string $str the string to be escaped
+ * @param string $str the string to be escaped
* @return string the escaped string
*
* @see DB_common::quoteSmart()
}
// }}}
- // {{{ quoteIdentifier()
+ // {{{ errorCode()
/**
* Quotes a string so it can be safely used as a table or column name
*
- * @param string $str identifier name to be quoted
+ * @param string $str identifier name to be quoted
*
* @return string quoted identifier string
*
return '[' . str_replace(']', ']]', $str) . ']';
}
- // }}}
- // {{{ mssqlRaiseError()
-
- /**
- * Produces a DB_Error object regarding the current problem
- *
- * @param int $errno if the error is being manually raised pass a
- * DB_ERROR* constant here. If this isn't passed
- * the error information gathered from the DBMS.
- *
- * @return object the DB_Error object
- *
- * @see DB_common::raiseError(),
- * DB_mssql::errorNative(), DB_mssql::errorCode()
- */
- public function mssqlRaiseError($code = null)
- {
- $message = @mssql_get_last_message();
- if (!$code) {
- $code = $this->errorNative();
- }
- return $this->raiseError(
- $this->errorCode($code, $message),
- null,
- null,
- null,
- "$code - $message"
- );
- }
-
- // }}}
- // {{{ errorNative()
-
- /**
- * Gets the DBMS' native error code produced by the last query
- *
- * @return int the DBMS' error code
- */
- public function errorNative()
- {
- $res = @mssql_query('select @@ERROR as ErrorCode', $this->connection);
- if (!$res) {
- return DB_ERROR;
- }
- $row = @mssql_fetch_row($res);
- return $row[0];
- }
-
- // }}}
- // {{{ errorCode()
-
- /**
- * Determines PEAR::DB error code from mssql's native codes.
- *
- * If <var>$nativecode</var> isn't known yet, it will be looked up.
- *
- * @param mixed $nativecode mssql error code, if known
- * @return integer an error number from a DB error constant
- * @see errorNative()
- */
- public function errorCode($nativecode = null, $msg = '')
- {
- if (!$nativecode) {
- $nativecode = $this->errorNative();
- }
- if (isset($this->errorcode_map[$nativecode])) {
- if ($nativecode == 3701
- && preg_match('/Cannot drop the index/i', $msg)) {
- return DB_ERROR_NOT_FOUND;
- }
- return $this->errorcode_map[$nativecode];
- } else {
- return DB_ERROR;
- }
- }
-
// }}}
// {{{ tableInfo()
* NOTE: only supports 'table' and 'flags' if <var>$result</var>
* is a table name.
*
- * @param object|string $result DB_result object from a query or a
+ * @param object|string $result DB_result object from a query or a
* string containing the name of a table.
* While this also accepts a query result
* resource identifier, this behavior is
* deprecated.
- * @param int $mode a valid tableInfo mode
+ * @param int $mode a valid tableInfo mode
*
- * @return array an associative array with the information requested.
+ * @return array|object
* A DB_Error object on failure.
*
* @see DB_common::tableInfo()
}
$count = @mssql_num_fields($id);
- $res = array();
+ $res = array();
if ($mode) {
$res['num_fields'] = $count;
$res[$i] = array(
'table' => $got_string ? $case_func($result) : '',
- 'name' => $case_func(@mssql_field_name($id, $i)),
- 'type' => @mssql_field_type($id, $i),
- 'len' => @mssql_field_length($id, $i),
+ 'name' => $case_func(@mssql_field_name($id, $i)),
+ 'type' => @mssql_field_type($id, $i),
+ 'len' => @mssql_field_length($id, $i),
'flags' => $flags,
);
if ($mode & DB_TABLEINFO_ORDER) {
* not useful at all - is the behaviour of mysql_field_flags that primary
* keys are alway unique? is the interpretation of multiple_key correct?
*
- * @param string $table the table name
- * @param string $column the field name
+ * @param string $table the table name
+ * @param string $column the field name
*
- * @return string the flags
+ * @return array|string
*
* @access private
* @author Joern Barthel <j_barthel@web.de>
}
if (array_key_exists($column, $flags)) {
- return(implode(' ', $flags[$column]));
+ return (implode(' ', $flags[$column]));
}
return '';
}
* Adds a string to the flags array if the flag is not yet in there
* - if there is no flag present the array is created
*
- * @param array &$array the reference to the flag-array
- * @param string $value the flag value
+ * @param array &$array the reference to the flag-array
+ * @param string $value the flag value
*
* @return void
*
/**
* Obtains the query string needed for listing a given type of objects
*
- * @param string $type the kind of objects you want to retrieve
+ * @param string $type the kind of objects you want to retrieve
*
* @return string the SQL query string or null if the driver doesn't
* support the object type requested
switch ($type) {
case 'tables':
return "SELECT name FROM sysobjects WHERE type = 'U'"
- . ' ORDER BY name';
+ . ' ORDER BY name';
case 'views':
return "SELECT name FROM sysobjects WHERE type = 'V'";
default:
/**
* Obtain the DB_common class so it can be extended from
*/
-require_once 'DB/common.php';
+//require_once 'DB/common.php';
+require_once 'common.php';
/**
* The methods PEAR DB uses to interact with PHP's mysql extension
* @var array
*/
public $features = array(
- 'limit' => 'alter',
- 'new_link' => '4.2.0',
- 'numrows' => true,
- 'pconnect' => true,
- 'prepare' => false,
- 'ssl' => false,
- 'transactions' => true,
+ 'limit' => 'alter',
+ 'new_link' => '4.2.0',
+ 'numrows' => true,
+ 'pconnect' => true,
+ 'prepare' => false,
+ 'ssl' => false,
+ 'transactions' => true,
);
/**
* Only used if PHP is at version 4.3.0 or greater.
* Available since PEAR DB 1.7.0.
*
- * @param array $dsn the data source name
- * @param bool $persistent should the connection be persistent?
+ * @param array $dsn the data source name
+ * @param bool $persistent should the connection be persistent?
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function connect($dsn, $persistent = false)
{
$params[0] = ':' . $dsn['socket'];
} else {
$params[0] = $dsn['hostspec'] ? $dsn['hostspec']
- : 'localhost';
+ : 'localhost';
if ($dsn['port']) {
$params[0] .= ':' . $dsn['port'];
}
}
if (version_compare(phpversion(), '4.3.0', '>=')) {
$params[] = isset($dsn['client_flags'])
- ? $dsn['client_flags'] : null;
+ ? $dsn['client_flags'] : null;
}
$connect_function = $persistent ? 'mysql_pconnect' : 'mysql_connect';
// }}}
// {{{ disconnect()
+ /**
+ * Produces a DB_Error object regarding the current problem
+ *
+ * @param int $errno if the error is being manually raised pass a
+ * DB_ERROR* constant here. If this isn't passed
+ * the error information gathered from the DBMS.
+ *
+ * @return object the DB_Error object
+ *
+ * @see DB_common::raiseError(),
+ * DB_mysql::errorNative(), DB_common::errorCode()
+ */
+ public function mysqlRaiseError($errno = null)
+ {
+ if ($errno === null) {
+ if ($this->options['portability'] & DB_PORTABILITY_ERRORS) {
+ $this->errorcode_map[1022] = DB_ERROR_CONSTRAINT;
+ $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT_NOT_NULL;
+ $this->errorcode_map[1062] = DB_ERROR_CONSTRAINT;
+ } else {
+ // Doing this in case mode changes during runtime.
+ $this->errorcode_map[1022] = DB_ERROR_ALREADY_EXISTS;
+ $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT;
+ $this->errorcode_map[1062] = DB_ERROR_ALREADY_EXISTS;
+ }
+ $errno = $this->errorCode(mysql_errno($this->connection));
+ }
+ return $this->raiseError(
+ $errno,
+ null,
+ null,
+ null,
+ @mysql_errno($this->connection) . ' ** ' .
+ @mysql_error($this->connection)
+ );
+ }
+
+ // }}}
+ // {{{ simpleQuery()
+
/**
* Disconnects from the database server
*
}
// }}}
- // {{{ simpleQuery()
+ // {{{ nextResult()
/**
* Sends a query to the database server
}
// }}}
- // {{{ nextResult()
+ // {{{ fetchInto()
+
+ /**
+ * Changes a query string for various DBMS specific reasons
+ *
+ * This little hack lets you know how many rows were deleted
+ * when running a "DELETE FROM table" query. Only implemented
+ * if the DB_PORTABILITY_DELETE_COUNT portability option is on.
+ *
+ * @param string $query the query string to modify
+ *
+ * @return string the modified query string
+ *
+ * @access protected
+ * @see DB_common::setOption()
+ */
+ public function modifyQuery($query)
+ {
+ if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) {
+ // "DELETE FROM table" gives 0 affected rows in MySQL.
+ // This little hack lets you know how many rows were deleted.
+ if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) {
+ $query = preg_replace(
+ '/^\s*DELETE\s+FROM\s+(\S+)\s*$/',
+ 'DELETE FROM \1 WHERE 1=1',
+ $query
+ );
+ }
+ }
+ return $query;
+ }
+
+ // }}}
+ // {{{ freeResult()
/**
* Move the internal mysql result pointer to the next available result
}
// }}}
- // {{{ fetchInto()
+ // {{{ numCols()
/**
* Places a row from the result set into the given array
* DB_result::fetchInto() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result the query result resource
- * @param array $arr the referenced array to put the data in
- * @param int $fetchmode how the resulting array should be indexed
- * @param int $rownum the row number to fetch (0 = first row)
+ * @param resource $result the query result resource
+ * @param array $arr the referenced array to put the data in
+ * @param int $fetchmode how the resulting array should be indexed
+ * @param int $rownum the row number to fetch (0 = first row)
*
* @return mixed DB_OK on success, NULL when the end of a result set is
* reached or on failure
}
// }}}
- // {{{ freeResult()
+ // {{{ numRows()
/**
* Deletes the result set and frees the memory occupied by the result set
* DB_result::free() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
* @return bool TRUE on success, FALSE if $result is invalid
*
}
// }}}
- // {{{ numCols()
+ // {{{ autoCommit()
/**
* Gets the number of columns in a result set
* DB_result::numCols() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
- * @return int the number of columns. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_result::numCols()
*/
}
// }}}
- // {{{ numRows()
+ // {{{ commit()
/**
* Gets the number of rows in a result set
* DB_result::numRows() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
- * @return int the number of rows. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_result::numRows()
*/
}
// }}}
- // {{{ autoCommit()
+ // {{{ rollback()
/**
* Enables or disables automatic commits
*
- * @param bool $onoff true turns it on, false turns it off
+ * @param bool $onoff true turns it on, false turns it off
*
* @return int DB_OK on success. A DB_Error object if the driver
* doesn't support auto-committing transactions.
}
// }}}
- // {{{ commit()
+ // {{{ affectedRows()
/**
* Commits the current transaction
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function commit()
{
}
// }}}
- // {{{ rollback()
+ // {{{ nextId()
/**
* Reverts the current transaction
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function rollback()
{
}
// }}}
- // {{{ affectedRows()
+ // {{{ createSequence()
/**
* Determines the number of rows affected by a data maniuplation query
}
// }}}
- // {{{ nextId()
+ // {{{ dropSequence()
/**
* Returns the next free id in a sequence
*
- * @param string $seq_name name of the sequence
- * @param boolean $ondemand when true, the seqence is automatically
+ * @param string $seq_name name of the sequence
+ * @param boolean $ondemand when true, the seqence is automatically
* created if it does not exist
*
- * @return int the next id number in the sequence.
+ * @return int|object
* A DB_Error object on failure.
*
* @see DB_common::nextID(), DB_common::getSequenceName(),
do {
$repeat = 0;
$this->pushErrorHandling(PEAR_ERROR_RETURN);
- $result = $this->query("UPDATE ${seqname} ".
- 'SET id=LAST_INSERT_ID(id+1)');
+ $result = $this->query("UPDATE ${seqname} " .
+ 'SET id=LAST_INSERT_ID(id+1)');
$this->popErrorHandling();
if ($result === DB_OK) {
// COMMON CASE
// Release the lock
$result = $this->getOne('SELECT RELEASE_LOCK('
- . "'${seqname}_lock')");
+ . "'${seqname}_lock')");
if (DB::isError($result)) {
return $this->raiseError($result);
}
$repeat = 1;
}
} elseif (DB::isError($result) &&
- $result->getCode() == DB_ERROR_ALREADY_EXISTS) {
+ $result->getCode() == DB_ERROR_ALREADY_EXISTS) {
// BACKWARDS COMPAT
// see _BCsequence() comment
$result = $this->_BCsequence($seqname);
}
// }}}
- // {{{ createSequence()
+ // {{{ _BCsequence()
/**
* Creates a new sequence
*
- * @param string $seq_name name of the new sequence
+ * @param string $seq_name name of the new sequence
*
* @return int DB_OK on success. A DB_Error object on failure.
*
{
$seqname = $this->getSequenceName($seq_name);
$res = $this->query('CREATE TABLE ' . $seqname
- . ' (id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,'
- . ' PRIMARY KEY(id))');
+ . ' (id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,'
+ . ' PRIMARY KEY(id))');
if (DB::isError($res)) {
return $res;
}
}
// }}}
- // {{{ dropSequence()
-
- /**
- * Deletes a sequence
- *
- * @param string $seq_name name of the sequence to be deleted
- *
- * @return int DB_OK on success. A DB_Error object on failure.
- *
- * @see DB_common::dropSequence(), DB_common::getSequenceName(),
- * DB_mysql::nextID(), DB_mysql::createSequence()
- */
- public function dropSequence($seq_name)
- {
- return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
- }
-
- // }}}
- // {{{ _BCsequence()
+ // {{{ quoteIdentifier()
/**
* Backwards compatibility with old sequence emulation implementation
* (clean up the dupes)
*
- * @param string $seqname the sequence name to clean up
+ * @param string $seqname the sequence name to clean up
*
- * @return bool true on success. A DB_Error object on failure.
+ * @return bool|object
*
* @access private
*/
// We should probably do something if $highest_id isn't
// numeric, but I'm at a loss as how to handle that...
$result = $this->query('DELETE FROM ' . $seqname
- . " WHERE id <> $highest_id");
+ . " WHERE id <> $highest_id");
if (DB::isError($result)) {
return $result;
}
}
// }}}
- // {{{ quoteIdentifier()
+ // {{{ escapeSimple()
+
+ /**
+ * Deletes a sequence
+ *
+ * @param string $seq_name name of the sequence to be deleted
+ *
+ * @return int DB_OK on success. A DB_Error object on failure.
+ *
+ * @see DB_common::dropSequence(), DB_common::getSequenceName(),
+ * DB_mysql::nextID(), DB_mysql::createSequence()
+ */
+ public function dropSequence($seq_name)
+ {
+ return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
+ }
+
+ // }}}
+ // {{{ modifyQuery()
/**
* Quotes a string so it can be safely used as a table or column name
* WARNING: Older versions of MySQL can't handle the backtick
* character (<kbd>`</kbd>) in table or column names.
*
- * @param string $str identifier name to be quoted
+ * @param string $str identifier name to be quoted
*
* @return string quoted identifier string
*
}
// }}}
- // {{{ escapeSimple()
+ // {{{ modifyLimitQuery()
/**
* Escapes a string according to the current DBMS's standards
*
- * @param string $str the string to be escaped
+ * @param string $str the string to be escaped
*
* @return string the escaped string
*
}
// }}}
- // {{{ modifyQuery()
-
- /**
- * Changes a query string for various DBMS specific reasons
- *
- * This little hack lets you know how many rows were deleted
- * when running a "DELETE FROM table" query. Only implemented
- * if the DB_PORTABILITY_DELETE_COUNT portability option is on.
- *
- * @param string $query the query string to modify
- *
- * @return string the modified query string
- *
- * @access protected
- * @see DB_common::setOption()
- */
- public function modifyQuery($query)
- {
- if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) {
- // "DELETE FROM table" gives 0 affected rows in MySQL.
- // This little hack lets you know how many rows were deleted.
- if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) {
- $query = preg_replace(
- '/^\s*DELETE\s+FROM\s+(\S+)\s*$/',
- 'DELETE FROM \1 WHERE 1=1',
- $query
- );
- }
- }
- return $query;
- }
-
- // }}}
- // {{{ modifyLimitQuery()
+ // {{{ mysqlRaiseError()
/**
* Adds LIMIT clauses to a query string according to current DBMS standards
*
- * @param string $query the query to modify
- * @param int $from the row to start to fetching (0 = the first row)
- * @param int $count the numbers of rows to fetch
- * @param mixed $params array, string or numeric data to be used in
+ * @param string $query the query to modify
+ * @param int $from the row to start to fetching (0 = the first row)
+ * @param int $count the numbers of rows to fetch
+ * @param mixed $params array, string or numeric data to be used in
* execution of the statement. Quantity of items
* passed must match quantity of placeholders in
* query: meaning 1 placeholder for non-array
}
}
- // }}}
- // {{{ mysqlRaiseError()
-
- /**
- * Produces a DB_Error object regarding the current problem
- *
- * @param int $errno if the error is being manually raised pass a
- * DB_ERROR* constant here. If this isn't passed
- * the error information gathered from the DBMS.
- *
- * @return object the DB_Error object
- *
- * @see DB_common::raiseError(),
- * DB_mysql::errorNative(), DB_common::errorCode()
- */
- public function mysqlRaiseError($errno = null)
- {
- if ($errno === null) {
- if ($this->options['portability'] & DB_PORTABILITY_ERRORS) {
- $this->errorcode_map[1022] = DB_ERROR_CONSTRAINT;
- $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT_NOT_NULL;
- $this->errorcode_map[1062] = DB_ERROR_CONSTRAINT;
- } else {
- // Doing this in case mode changes during runtime.
- $this->errorcode_map[1022] = DB_ERROR_ALREADY_EXISTS;
- $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT;
- $this->errorcode_map[1062] = DB_ERROR_ALREADY_EXISTS;
- }
- $errno = $this->errorCode(mysql_errno($this->connection));
- }
- return $this->raiseError(
- $errno,
- null,
- null,
- null,
- @mysql_errno($this->connection) . ' ** ' .
- @mysql_error($this->connection)
- );
- }
-
// }}}
// {{{ errorNative()
/**
* Returns information about a table or a result set
*
- * @param object|string $result DB_result object from a query or a
+ * @param object|string $result DB_result object from a query or a
* string containing the name of a table.
* While this also accepts a query result
* resource identifier, this behavior is
* deprecated.
- * @param int $mode a valid tableInfo mode
+ * @param int $mode a valid tableInfo mode
*
- * @return array an associative array with the information requested.
+ * @return array|object
* A DB_Error object on failure.
*
* @see DB_common::tableInfo()
return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED);
}
}
-
+
/*
* Probably received a table name.
* Create a result resource identifier.
}
$count = @mysql_num_fields($id);
- $res = array();
+ $res = array();
if ($mode) {
$res['num_fields'] = $count;
for ($i = 0; $i < $count; $i++) {
$res[$i] = array(
'table' => $case_func(@mysql_field_table($id, $i)),
- 'name' => $case_func(@mysql_field_name($id, $i)),
- 'type' => @mysql_field_type($id, $i),
- 'len' => @mysql_field_len($id, $i),
+ 'name' => $case_func(@mysql_field_name($id, $i)),
+ 'type' => @mysql_field_type($id, $i),
+ 'len' => @mysql_field_len($id, $i),
'flags' => @mysql_field_flags($id, $i),
);
if ($mode & DB_TABLEINFO_ORDER) {
/**
* Obtains the query string needed for listing a given type of objects
*
- * @param string $type the kind of objects you want to retrieve
+ * @param string $type the kind of objects you want to retrieve
*
* @return string the SQL query string or null if the driver doesn't
* support the object type requested
/**
* Obtain the DB_common class so it can be extended from
*/
-require_once 'DB/common.php';
+//require_once 'DB/common.php';
+require_once 'common.php';
/**
* The methods PEAR DB uses to interact with PHP's mysqli extension
* @var array
*/
public $features = array(
- 'limit' => 'alter',
- 'new_link' => false,
- 'numrows' => true,
- 'pconnect' => false,
- 'prepare' => false,
- 'ssl' => true,
- 'transactions' => true,
+ 'limit' => 'alter',
+ 'new_link' => false,
+ 'numrows' => true,
+ 'pconnect' => false,
+ 'prepare' => false,
+ 'ssl' => true,
+ 'transactions' => true,
);
/**
* @since Property available since Release 1.6.5
*/
public $mysqli_flags = array(
- MYSQLI_NOT_NULL_FLAG => 'not_null',
- MYSQLI_PRI_KEY_FLAG => 'primary_key',
- MYSQLI_UNIQUE_KEY_FLAG => 'unique_key',
- MYSQLI_MULTIPLE_KEY_FLAG => 'multiple_key',
- MYSQLI_BLOB_FLAG => 'blob',
- MYSQLI_UNSIGNED_FLAG => 'unsigned',
- MYSQLI_ZEROFILL_FLAG => 'zerofill',
- MYSQLI_AUTO_INCREMENT_FLAG => 'auto_increment',
- MYSQLI_TIMESTAMP_FLAG => 'timestamp',
- MYSQLI_SET_FLAG => 'set',
+ MYSQLI_NOT_NULL_FLAG => 'not_null',
+ MYSQLI_PRI_KEY_FLAG => 'primary_key',
+ MYSQLI_UNIQUE_KEY_FLAG => 'unique_key',
+ MYSQLI_MULTIPLE_KEY_FLAG => 'multiple_key',
+ MYSQLI_BLOB_FLAG => 'blob',
+ MYSQLI_UNSIGNED_FLAG => 'unsigned',
+ MYSQLI_ZEROFILL_FLAG => 'zerofill',
+ MYSQLI_AUTO_INCREMENT_FLAG => 'auto_increment',
+ MYSQLI_TIMESTAMP_FLAG => 'timestamp',
+ MYSQLI_SET_FLAG => 'set',
// MYSQLI_NUM_FLAG => 'numeric', // unnecessary
// MYSQLI_PART_KEY_FLAG => 'multiple_key', // duplicatvie
- MYSQLI_GROUP_FLAG => 'group_by'
+ MYSQLI_GROUP_FLAG => 'group_by'
);
/**
* @since Property available since Release 1.6.5
*/
public $mysqli_types = array(
- MYSQLI_TYPE_DECIMAL => 'decimal',
- MYSQLI_TYPE_TINY => 'tinyint',
- MYSQLI_TYPE_SHORT => 'int',
- MYSQLI_TYPE_LONG => 'int',
- MYSQLI_TYPE_FLOAT => 'float',
- MYSQLI_TYPE_DOUBLE => 'double',
+ MYSQLI_TYPE_DECIMAL => 'decimal',
+ MYSQLI_TYPE_TINY => 'tinyint',
+ MYSQLI_TYPE_SHORT => 'int',
+ MYSQLI_TYPE_LONG => 'int',
+ MYSQLI_TYPE_FLOAT => 'float',
+ MYSQLI_TYPE_DOUBLE => 'double',
// MYSQLI_TYPE_NULL => 'DEFAULT NULL', // let flags handle it
- MYSQLI_TYPE_TIMESTAMP => 'timestamp',
- MYSQLI_TYPE_LONGLONG => 'bigint',
- MYSQLI_TYPE_INT24 => 'mediumint',
- MYSQLI_TYPE_DATE => 'date',
- MYSQLI_TYPE_TIME => 'time',
- MYSQLI_TYPE_DATETIME => 'datetime',
- MYSQLI_TYPE_YEAR => 'year',
- MYSQLI_TYPE_NEWDATE => 'date',
- MYSQLI_TYPE_ENUM => 'enum',
- MYSQLI_TYPE_SET => 'set',
- MYSQLI_TYPE_TINY_BLOB => 'tinyblob',
+ MYSQLI_TYPE_TIMESTAMP => 'timestamp',
+ MYSQLI_TYPE_LONGLONG => 'bigint',
+ MYSQLI_TYPE_INT24 => 'mediumint',
+ MYSQLI_TYPE_DATE => 'date',
+ MYSQLI_TYPE_TIME => 'time',
+ MYSQLI_TYPE_DATETIME => 'datetime',
+ MYSQLI_TYPE_YEAR => 'year',
+ MYSQLI_TYPE_NEWDATE => 'date',
+ MYSQLI_TYPE_ENUM => 'enum',
+ MYSQLI_TYPE_SET => 'set',
+ MYSQLI_TYPE_TINY_BLOB => 'tinyblob',
MYSQLI_TYPE_MEDIUM_BLOB => 'mediumblob',
- MYSQLI_TYPE_LONG_BLOB => 'longblob',
- MYSQLI_TYPE_BLOB => 'blob',
- MYSQLI_TYPE_VAR_STRING => 'varchar',
- MYSQLI_TYPE_STRING => 'char',
- MYSQLI_TYPE_GEOMETRY => 'geometry',
+ MYSQLI_TYPE_LONG_BLOB => 'longblob',
+ MYSQLI_TYPE_BLOB => 'blob',
+ MYSQLI_TYPE_VAR_STRING => 'varchar',
+ MYSQLI_TYPE_STRING => 'char',
+ MYSQLI_TYPE_GEOMETRY => 'geometry',
/* These constants are conditionally compiled in ext/mysqli, so we'll
* define them by number rather than constant. */
- 16 => 'bit',
- 246 => 'decimal',
+ 16 => 'bit',
+ 246 => 'decimal',
);
* );
*
* $db = DB::connect($dsn, $options);
- * if (PEAR::isError($db)) {
+ * if ((new PEAR)->isError($db)) {
* die($db->getMessage());
* }
* </code>
*
- * @param array $dsn the data source name
- * @param bool $persistent should the connection be persistent?
+ * @param array $dsn the data source name
+ * @param bool $persistent should the connection be persistent?
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function connect($dsn, $persistent = false)
{
@ini_set('track_errors', 1);
$php_errormsg = '';
- if (((int) $this->getOption('ssl')) === 1) {
+ if (((int)$this->getOption('ssl')) === 1) {
$init = mysqli_init();
mysqli_ssl_set(
$init,
- empty($dsn['key']) ? null : $dsn['key'],
- empty($dsn['cert']) ? null : $dsn['cert'],
- empty($dsn['ca']) ? null : $dsn['ca'],
+ empty($dsn['key']) ? null : $dsn['key'],
+ empty($dsn['cert']) ? null : $dsn['cert'],
+ empty($dsn['ca']) ? null : $dsn['ca'],
empty($dsn['capath']) ? null : $dsn['capath'],
empty($dsn['cipher']) ? null : $dsn['cipher']
);
// }}}
// {{{ nextResult()
+ /**
+ * Produces a DB_Error object regarding the current problem
+ *
+ * @param int $errno if the error is being manually raised pass a
+ * DB_ERROR* constant here. If this isn't passed
+ * the error information gathered from the DBMS.
+ *
+ * @return object the DB_Error object
+ *
+ * @see DB_common::raiseError(),
+ * DB_mysqli::errorNative(), DB_common::errorCode()
+ */
+ public function mysqliRaiseError($errno = null)
+ {
+ if ($errno === null) {
+ if ($this->options['portability'] & DB_PORTABILITY_ERRORS) {
+ $this->errorcode_map[1022] = DB_ERROR_CONSTRAINT;
+ $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT_NOT_NULL;
+ $this->errorcode_map[1062] = DB_ERROR_CONSTRAINT;
+ } else {
+ // Doing this in case mode changes during runtime.
+ $this->errorcode_map[1022] = DB_ERROR_ALREADY_EXISTS;
+ $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT;
+ $this->errorcode_map[1062] = DB_ERROR_ALREADY_EXISTS;
+ }
+ $errno = $this->errorCode(mysqli_errno($this->connection));
+ }
+ return $this->raiseError(
+ $errno,
+ null,
+ null,
+ null,
+ @mysqli_errno($this->connection) . ' ** ' .
+ @mysqli_error($this->connection)
+ );
+ }
+
+ // }}}
+ // {{{ fetchInto()
+
/**
* Move the internal mysql result pointer to the next available result.
*
}
// }}}
- // {{{ fetchInto()
+ // {{{ freeResult()
/**
* Places a row from the result set into the given array
* DB_result::fetchInto() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result the query result resource
- * @param array $arr the referenced array to put the data in
- * @param int $fetchmode how the resulting array should be indexed
- * @param int $rownum the row number to fetch (0 = first row)
+ * @param resource $result the query result resource
+ * @param array $arr the referenced array to put the data in
+ * @param int $fetchmode how the resulting array should be indexed
+ * @param int $rownum the row number to fetch (0 = first row)
*
* @return mixed DB_OK on success, NULL when the end of a result set is
* reached or on failure
}
// }}}
- // {{{ freeResult()
+ // {{{ numCols()
/**
* Deletes the result set and frees the memory occupied by the result set
* DB_result::free() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
* @return bool TRUE on success, FALSE if $result is invalid
*
*/
public function freeResult($result)
{
- if (! $result instanceof mysqli_result) {
+ if (!$result instanceof mysqli_result) {
return false;
}
mysqli_free_result($result);
}
// }}}
- // {{{ numCols()
+ // {{{ numRows()
/**
* Gets the number of columns in a result set
* DB_result::numCols() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
- * @return int the number of columns. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_result::numCols()
*/
}
// }}}
- // {{{ numRows()
+ // {{{ autoCommit()
/**
* Gets the number of rows in a result set
* DB_result::numRows() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
- * @return int the number of rows. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_result::numRows()
*/
}
// }}}
- // {{{ autoCommit()
+ // {{{ commit()
/**
* Enables or disables automatic commits
*
- * @param bool $onoff true turns it on, false turns it off
+ * @param bool $onoff true turns it on, false turns it off
*
* @return int DB_OK on success. A DB_Error object if the driver
* doesn't support auto-committing transactions.
}
// }}}
- // {{{ commit()
+ // {{{ rollback()
/**
* Commits the current transaction
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function commit()
{
}
// }}}
- // {{{ rollback()
+ // {{{ affectedRows()
/**
* Reverts the current transaction
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function rollback()
{
}
// }}}
- // {{{ affectedRows()
+ // {{{ nextId()
/**
* Determines the number of rows affected by a data maniuplation query
}
}
- // }}}
- // {{{ nextId()
-
/**
* Returns the next free id in a sequence
*
- * @param string $seq_name name of the sequence
- * @param boolean $ondemand when true, the seqence is automatically
+ * @param string $seq_name name of the sequence
+ * @param boolean $ondemand when true, the seqence is automatically
* created if it does not exist
*
- * @return int the next id number in the sequence.
+ * @return int|object
* A DB_Error object on failure.
*
* @see DB_common::nextID(), DB_common::getSequenceName(),
$repeat = 0;
$this->pushErrorHandling(PEAR_ERROR_RETURN);
$result = $this->query('UPDATE ' . $seqname
- . ' SET id = LAST_INSERT_ID(id + 1)');
+ . ' SET id = LAST_INSERT_ID(id + 1)');
$this->popErrorHandling();
if ($result === DB_OK) {
// COMMON CASE
// so fill it and return 1
// Obtain a user-level lock
$result = $this->getOne('SELECT GET_LOCK('
- . "'${seqname}_lock', 10)");
+ . "'${seqname}_lock', 10)");
if (DB::isError($result)) {
return $this->raiseError($result);
}
// add the default value
$result = $this->query('REPLACE INTO ' . $seqname
- . ' (id) VALUES (0)');
+ . ' (id) VALUES (0)');
if (DB::isError($result)) {
return $this->raiseError($result);
}
// Release the lock
$result = $this->getOne('SELECT RELEASE_LOCK('
- . "'${seqname}_lock')");
+ . "'${seqname}_lock')");
if (DB::isError($result)) {
return $this->raiseError($result);
}
return 1;
}
} elseif (DB::isError($result) &&
- $result->getCode() == DB_ERROR_ALREADY_EXISTS) {
+ $result->getCode() == DB_ERROR_ALREADY_EXISTS) {
// BACKWARDS COMPAT
// see _BCsequence() comment
$result = $this->_BCsequence($seqname);
return $this->raiseError($result);
}
+ // }}}
+ // {{{ dropSequence()
+
/**
* Creates a new sequence
*
- * @param string $seq_name name of the new sequence
+ * @param string $seq_name name of the new sequence
*
* @return int DB_OK on success. A DB_Error object on failure.
*
{
$seqname = $this->getSequenceName($seq_name);
$res = $this->query('CREATE TABLE ' . $seqname
- . ' (id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,'
- . ' PRIMARY KEY(id))');
+ . ' (id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,'
+ . ' PRIMARY KEY(id))');
if (DB::isError($res)) {
return $res;
}
return $this->query("INSERT INTO ${seqname} (id) VALUES (0)");
}
- // }}}
- // {{{ dropSequence()
-
- /**
- * Deletes a sequence
- *
- * @param string $seq_name name of the sequence to be deleted
- *
- * @return int DB_OK on success. A DB_Error object on failure.
- *
- * @see DB_common::dropSequence(), DB_common::getSequenceName(),
- * DB_mysql::nextID(), DB_mysql::createSequence()
- */
- public function dropSequence($seq_name)
- {
- return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
- }
-
// }}}
// {{{ _BCsequence()
* Backwards compatibility with old sequence emulation implementation
* (clean up the dupes)
*
- * @param string $seqname the sequence name to clean up
+ * @param string $seqname the sequence name to clean up
*
- * @return bool true on success. A DB_Error object on failure.
+ * @return bool|object
*
* @access private
*/
// We should probably do something if $highest_id isn't
// numeric, but I'm at a loss as how to handle that...
$result = $this->query('DELETE FROM ' . $seqname
- . " WHERE id <> $highest_id");
+ . " WHERE id <> $highest_id");
if (DB::isError($result)) {
return $result;
}
// }}}
// {{{ quoteIdentifier()
+ /**
+ * Deletes a sequence
+ *
+ * @param string $seq_name name of the sequence to be deleted
+ *
+ * @return int DB_OK on success. A DB_Error object on failure.
+ *
+ * @see DB_common::dropSequence(), DB_common::getSequenceName(),
+ * DB_mysql::nextID(), DB_mysql::createSequence()
+ */
+ public function dropSequence($seq_name)
+ {
+ return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
+ }
+
+ // }}}
+ // {{{ escapeSimple()
+
/**
* Quotes a string so it can be safely used as a table or column name
* (WARNING: using names that require this is a REALLY BAD IDEA)
* WARNING: Older versions of MySQL can't handle the backtick
* character (<kbd>`</kbd>) in table or column names.
*
- * @param string $str identifier name to be quoted
+ * @param string $str identifier name to be quoted
*
* @return string quoted identifier string
*
}
// }}}
- // {{{ escapeSimple()
+ // {{{ modifyLimitQuery()
/**
* Escapes a string according to the current DBMS's standards
*
- * @param string $str the string to be escaped
+ * @param string $str the string to be escaped
*
* @return string the escaped string
*
}
// }}}
- // {{{ modifyLimitQuery()
+ // {{{ mysqliRaiseError()
/**
* Adds LIMIT clauses to a query string according to current DBMS standards
*
- * @param string $query the query to modify
- * @param int $from the row to start to fetching (0 = the first row)
- * @param int $count the numbers of rows to fetch
- * @param mixed $params array, string or numeric data to be used in
+ * @param string $query the query to modify
+ * @param int $from the row to start to fetching (0 = the first row)
+ * @param int $count the numbers of rows to fetch
+ * @param mixed $params array, string or numeric data to be used in
* execution of the statement. Quantity of items
* passed must match quantity of placeholders in
* query: meaning 1 placeholder for non-array
}
}
- // }}}
- // {{{ mysqliRaiseError()
-
- /**
- * Produces a DB_Error object regarding the current problem
- *
- * @param int $errno if the error is being manually raised pass a
- * DB_ERROR* constant here. If this isn't passed
- * the error information gathered from the DBMS.
- *
- * @return object the DB_Error object
- *
- * @see DB_common::raiseError(),
- * DB_mysqli::errorNative(), DB_common::errorCode()
- */
- public function mysqliRaiseError($errno = null)
- {
- if ($errno === null) {
- if ($this->options['portability'] & DB_PORTABILITY_ERRORS) {
- $this->errorcode_map[1022] = DB_ERROR_CONSTRAINT;
- $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT_NOT_NULL;
- $this->errorcode_map[1062] = DB_ERROR_CONSTRAINT;
- } else {
- // Doing this in case mode changes during runtime.
- $this->errorcode_map[1022] = DB_ERROR_ALREADY_EXISTS;
- $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT;
- $this->errorcode_map[1062] = DB_ERROR_ALREADY_EXISTS;
- }
- $errno = $this->errorCode(mysqli_errno($this->connection));
- }
- return $this->raiseError(
- $errno,
- null,
- null,
- null,
- @mysqli_errno($this->connection) . ' ** ' .
- @mysqli_error($this->connection)
- );
- }
-
// }}}
// {{{ errorNative()
/**
* Returns information about a table or a result set
*
- * @param object|string $result DB_result object from a query or a
+ * @param object|string $result DB_result object from a query or a
* string containing the name of a table.
* While this also accepts a query result
* resource identifier, this behavior is
* deprecated.
- * @param int $mode a valid tableInfo mode
+ * @param int $mode a valid tableInfo mode
*
- * @return array an associative array with the information requested.
+ * @return array|object
* A DB_Error object on failure.
*
* @see DB_common::setOption()
}
$count = @mysqli_num_fields($id);
- $res = array();
+ $res = array();
if ($mode) {
$res['num_fields'] = $count;
$res[$i] = array(
'table' => $case_func($tmp->table),
- 'name' => $case_func($tmp->name),
- 'type' => isset($this->mysqli_types[$tmp->type])
- ? $this->mysqli_types[$tmp->type]
- : 'unknown',
+ 'name' => $case_func($tmp->name),
+ 'type' => isset($this->mysqli_types[$tmp->type])
+ ? $this->mysqli_types[$tmp->type]
+ : 'unknown',
// http://bugs.php.net/?id=36579
// Doc Bug #36579: mysqli_fetch_field length handling
// https://bugs.php.net/bug.php?id=62426
// Bug #62426: mysqli_fetch_field_direct returns incorrect
// length on UTF8 fields
- 'len' => $tmp->length,
+ 'len' => $tmp->length,
'flags' => $flags,
);
/**
* Obtains the query string needed for listing a given type of objects
*
- * @param string $type the kind of objects you want to retrieve
+ * @param string $type the kind of objects you want to retrieve
*
* @return string the SQL query string or null if the driver doesn't
* support the object type requested
}
}
- public function getVersion() {
+ public function getVersion()
+ {
return mysqli_get_server_version($this->connection);
}
/**
* Obtain the DB_common class so it can be extended from
*/
-require_once 'DB/common.php';
+//require_once 'DB/common.php';
+require_once 'common.php';
/**
* The methods PEAR DB uses to interact with PHP's oci8 extension
* @var array
*/
public $features = array(
- 'limit' => 'alter',
- 'new_link' => '5.0.0',
- 'numrows' => 'subquery',
- 'pconnect' => true,
- 'prepare' => true,
- 'ssl' => false,
- 'transactions' => true,
+ 'limit' => 'alter',
+ 'new_link' => '5.0.0',
+ 'numrows' => 'subquery',
+ 'pconnect' => true,
+ 'prepare' => true,
+ 'ssl' => false,
+ 'transactions' => true,
);
/**
* @var array
*/
public $errorcode_map = array(
- 1 => DB_ERROR_CONSTRAINT,
- 900 => DB_ERROR_SYNTAX,
- 904 => DB_ERROR_NOSUCHFIELD,
- 913 => DB_ERROR_VALUE_COUNT_ON_ROW,
- 921 => DB_ERROR_SYNTAX,
- 923 => DB_ERROR_SYNTAX,
- 942 => DB_ERROR_NOSUCHTABLE,
- 955 => DB_ERROR_ALREADY_EXISTS,
- 1400 => DB_ERROR_CONSTRAINT_NOT_NULL,
- 1401 => DB_ERROR_INVALID,
- 1407 => DB_ERROR_CONSTRAINT_NOT_NULL,
- 1418 => DB_ERROR_NOT_FOUND,
- 1476 => DB_ERROR_DIVZERO,
- 1722 => DB_ERROR_INVALID_NUMBER,
- 2289 => DB_ERROR_NOSUCHTABLE,
- 2291 => DB_ERROR_CONSTRAINT,
- 2292 => DB_ERROR_CONSTRAINT,
- 2449 => DB_ERROR_CONSTRAINT,
+ 1 => DB_ERROR_CONSTRAINT,
+ 900 => DB_ERROR_SYNTAX,
+ 904 => DB_ERROR_NOSUCHFIELD,
+ 913 => DB_ERROR_VALUE_COUNT_ON_ROW,
+ 921 => DB_ERROR_SYNTAX,
+ 923 => DB_ERROR_SYNTAX,
+ 942 => DB_ERROR_NOSUCHTABLE,
+ 955 => DB_ERROR_ALREADY_EXISTS,
+ 1400 => DB_ERROR_CONSTRAINT_NOT_NULL,
+ 1401 => DB_ERROR_INVALID,
+ 1407 => DB_ERROR_CONSTRAINT_NOT_NULL,
+ 1418 => DB_ERROR_NOT_FOUND,
+ 1476 => DB_ERROR_DIVZERO,
+ 1722 => DB_ERROR_INVALID_NUMBER,
+ 2289 => DB_ERROR_NOSUCHTABLE,
+ 2291 => DB_ERROR_CONSTRAINT,
+ 2292 => DB_ERROR_CONSTRAINT,
+ 2449 => DB_ERROR_CONSTRAINT,
12899 => DB_ERROR_INVALID,
);
* not portable to other DBMS's.
* Available since PEAR DB 1.7.0.
*
- * @param array $dsn the data source name
- * @param bool $persistent should the connection be persistent?
+ * @param array $dsn the data source name
+ * @param bool $persistent should the connection be persistent?
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function connect($dsn, $persistent = false)
{
$connect_function = 'oci_new_connect';
} else {
$connect_function = $persistent ? 'oci_pconnect'
- : 'oci_connect';
+ : 'oci_connect';
}
if (isset($this->dsn['port']) && $this->dsn['port']) {
- $db = '//'.$db.':'.$this->dsn['port'];
+ $db = '//' . $db . ':' . $this->dsn['port'];
}
$char = empty($dsn['charset']) ? null : $dsn['charset'];
// }}}
// {{{ nextResult()
+ /**
+ * Changes a query string for various DBMS specific reasons
+ *
+ * "SELECT 2+2" must be "SELECT 2+2 FROM dual" in Oracle.
+ *
+ * @param string $query the query string to modify
+ *
+ * @return string the modified query string
+ *
+ * @access protected
+ */
+ public function modifyQuery($query)
+ {
+ if (preg_match('/^\s*SELECT/i', $query) &&
+ !preg_match('/\sFROM\s/i', $query)) {
+ $query .= ' FROM dual';
+ }
+ return $query;
+ }
+
+ // }}}
+ // {{{ fetchInto()
+
+ /**
+ * Produces a DB_Error object regarding the current problem
+ *
+ * @param int $errno if the error is being manually raised pass a
+ * DB_ERROR* constant here. If this isn't passed
+ * the error information gathered from the DBMS.
+ *
+ * @return object the DB_Error object
+ *
+ * @see DB_common::raiseError(),
+ * DB_oci8::errorNative(), DB_oci8::errorCode()
+ */
+ public function oci8RaiseError($errno = null)
+ {
+ if ($errno === null) {
+ $error = @OCIError($this->connection);
+ return $this->raiseError(
+ $this->errorCode($error['code']),
+ null,
+ null,
+ null,
+ $error['message']
+ );
+ } elseif (is_resource($errno)) {
+ $error = @OCIError($errno);
+ return $this->raiseError(
+ $this->errorCode($error['code']),
+ null,
+ null,
+ null,
+ $error['message']
+ );
+ }
+ return $this->raiseError($this->errorCode($errno));
+ }
+
+ // }}}
+ // {{{ freeResult()
+
/**
* Move the internal oracle result pointer to the next available result
*
return false;
}
- // }}}
- // {{{ fetchInto()
-
/**
* Places a row from the result set into the given array
*
* DB_result::fetchInto() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result the query result resource
- * @param array $arr the referenced array to put the data in
- * @param int $fetchmode how the resulting array should be indexed
- * @param int $rownum the row number to fetch (0 = first row)
+ * @param resource $result the query result resource
+ * @param array $arr the referenced array to put the data in
+ * @param int $fetchmode how the resulting array should be indexed
+ * @param int $rownum the row number to fetch (0 = first row)
*
* @return mixed DB_OK on success, NULL when the end of a result set is
* reached or on failure
return $this->raiseError(DB_ERROR_NOT_CAPABLE);
}
if ($fetchmode & DB_FETCHMODE_ASSOC) {
- $moredata = @OCIFetchInto($result, $arr, OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS);
+ $moredata = @OCIFetchInto($result, $arr, OCI_ASSOC + OCI_RETURN_NULLS + OCI_RETURN_LOBS);
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE &&
$moredata) {
$arr = array_change_key_case($arr, CASE_LOWER);
}
} else {
- $moredata = OCIFetchInto($result, $arr, OCI_RETURN_NULLS+OCI_RETURN_LOBS);
+ $moredata = OCIFetchInto($result, $arr, OCI_RETURN_NULLS + OCI_RETURN_LOBS);
}
if (!$moredata) {
return null;
}
// }}}
- // {{{ freeResult()
+ // {{{ numRows()
/**
* Deletes the result set and frees the memory occupied by the result set
* DB_result::free() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
* @return bool TRUE on success, FALSE if $result is invalid
*
return is_resource($result) ? OCIFreeStatement($result) : false;
}
+ // }}}
+ // {{{ numCols()
+
/**
* Frees the internal resources associated with a prepared query
*
- * @param resource $stmt the prepared statement's resource
- * @param bool $free_resource should the PHP resource be freed too?
+ * @param resource $stmt the prepared statement's resource
+ * @param bool $free_resource should the PHP resource be freed too?
* Use false if you need to get data
* from the result set later.
*
}
// }}}
- // {{{ numRows()
+ // {{{ prepare()
/**
* Gets the number of rows in a result set
* DB_result::numRows() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
- * @return int the number of rows. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_result::numRows(), DB_common::setOption()
*/
// emulate numRows for Oracle. yuck.
if ($this->options['portability'] & DB_PORTABILITY_NUMROWS &&
$result === $this->last_stmt) {
- $countquery = 'SELECT COUNT(*) FROM ('.$this->last_query.')';
+ $countquery = 'SELECT COUNT(*) FROM (' . $this->last_query . ')';
$save_query = $this->last_query;
$save_stmt = $this->last_stmt;
// Restore the last query and statement.
$this->last_query = $save_query;
$this->last_stmt = $save_stmt;
-
+
if (DB::isError($count) ||
DB::isError($row = $count->fetchRow(DB_FETCHMODE_ORDERED))) {
return $this->raiseError(DB_ERROR_NOT_CAPABLE);
}
// }}}
- // {{{ numCols()
+ // {{{ execute()
/**
* Gets the number of columns in a result set
* DB_result::numCols() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
- * @return int the number of columns. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_result::numCols()
*/
}
// }}}
- // {{{ prepare()
+ // {{{ autoCommit()
+
+ /**
+ * Enables or disables automatic commits
+ *
+ * @param bool $onoff true turns it on, false turns it off
+ *
+ * @return int DB_OK on success. A DB_Error object if the driver
+ * doesn't support auto-committing transactions.
+ */
+ public function autoCommit($onoff = false)
+ {
+ $this->autocommit = (bool)$onoff;;
+ return DB_OK;
+ }
+
+ // }}}
+ // {{{ commit()
+
+ /**
+ * Commits the current transaction
+ *
+ * @return int|object
+ */
+ public function commit()
+ {
+ $result = @OCICommit($this->connection);
+ if (!$result) {
+ return $this->oci8RaiseError();
+ }
+ return DB_OK;
+ }
+
+ // }}}
+ // {{{ rollback()
+
+ /**
+ * Reverts the current transaction
+ *
+ * @return int|object
+ */
+ public function rollback()
+ {
+ $result = @OCIRollback($this->connection);
+ if (!$result) {
+ return $this->oci8RaiseError();
+ }
+ return DB_OK;
+ }
+
+ // }}}
+ // {{{ affectedRows()
+
+ /**
+ * Determines the number of rows affected by a data maniuplation query
+ *
+ * 0 is returned for queries that don't manipulate data.
+ *
+ * @return int|object
+ */
+ public function affectedRows()
+ {
+ if ($this->last_stmt === false) {
+ return $this->oci8RaiseError();
+ }
+ $result = @OCIRowCount($this->last_stmt);
+ if ($result === false) {
+ return $this->oci8RaiseError($this->last_stmt);
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ modifyQuery()
+
+ /**
+ * Adds LIMIT clauses to a query string according to current DBMS standards
+ *
+ * @param string $query the query to modify
+ * @param int $from the row to start to fetching (0 = the first row)
+ * @param int $count the numbers of rows to fetch
+ * @param mixed $params array, string or numeric data to be used in
+ * execution of the statement. Quantity of items
+ * passed must match quantity of placeholders in
+ * query: meaning 1 placeholder for non-array
+ * parameters or 1 placeholder per array element.
+ *
+ * @return string the query string with LIMIT clauses added
+ *
+ * @access protected
+ */
+ public function modifyLimitQuery($query, $from, $count, $params = array())
+ {
+ // Let Oracle return the name of the columns instead of
+ // coding a "home" SQL parser
+
+ if (count($params)) {
+ $result = $this->prepare("SELECT * FROM ($query) "
+ . 'WHERE NULL = NULL');
+ $tmp = $this->execute($result, $params);
+ } else {
+ $q_fields = "SELECT * FROM ($query) WHERE NULL = NULL";
+
+ if (!$result = @OCIParse($this->connection, $q_fields)) {
+ $this->last_query = $q_fields;
+ return $this->oci8RaiseError();
+ }
+ if (!@OCIExecute($result, OCI_DEFAULT)) {
+ $this->last_query = $q_fields;
+ return $this->oci8RaiseError($result);
+ }
+ }
+
+ $ncols = OCINumCols($result);
+ $cols = array();
+ for ($i = 1; $i <= $ncols; $i++) {
+ $cols[] = '"' . OCIColumnName($result, $i) . '"';
+ }
+ $fields = implode(', ', $cols);
+ // XXX Test that (tip by John Lim)
+ //if (preg_match('/^\s*SELECT\s+/is', $query, $match)) {
+ // // Introduce the FIRST_ROWS Oracle query optimizer
+ // $query = substr($query, strlen($match[0]), strlen($query));
+ // $query = "SELECT /* +FIRST_ROWS */ " . $query;
+ //}
+
+ // Construct the query
+ // more at: http://marc.theaimsgroup.com/?l=php-db&m=99831958101212&w=2
+ // Perhaps this could be optimized with the use of Unions
+ $query = "SELECT $fields FROM" .
+ " (SELECT rownum as linenum, $fields FROM" .
+ " ($query)" .
+ ' WHERE rownum <= ' . ($from + $count) .
+ ') WHERE linenum >= ' . ++$from;
+ return $query;
+ }
+
+ // }}}
+ // {{{ modifyLimitQuery()
/**
* Prepares a query for multiple execution with execute().
* "UPDATE foo SET col=? WHERE col='over \& under'"
* </code>
*
- * @param string $query the query to be prepared
+ * @param string $query the query to be prepared
*
* @return mixed DB statement resource on success. DB_Error on failure.
*
*/
public function prepare($query)
{
- $tokens = preg_split(
+ $tokens = preg_split(
'/((?<!\\\)[&?!])/',
$query,
-1,
PREG_SPLIT_DELIM_CAPTURE
);
- $binds = count($tokens) - 1;
- $token = 0;
- $types = array();
+ $binds = count($tokens) - 1;
+ $token = 0;
+ $types = array();
$newquery = '';
foreach ($tokens as $key => $val) {
}
// }}}
- // {{{ execute()
+ // {{{ nextId()
/**
* Executes a DB statement prepared with prepare().
* ocisetprefetch(), see the "result_buffering" option in setOptions().
* This option was added in Release 1.7.0.
*
- * @param resource $stmt a DB statement resource returned from prepare()
- * @param mixed $data array, string or numeric data to be used in
+ * @param resource $stmt a DB statement resource returned from prepare()
+ * @param mixed $data array, string or numeric data to be used in
* execution of the statement. Quantity of items
* passed must match quantity of placeholders in
* query: meaning 1 for non-array items or the
return $tmp;
}
- // }}}
- // {{{ autoCommit()
-
/**
- * Enables or disables automatic commits
- *
- * @param bool $onoff true turns it on, false turns it off
- *
- * @return int DB_OK on success. A DB_Error object if the driver
- * doesn't support auto-committing transactions.
- */
- public function autoCommit($onoff = false)
- {
- $this->autocommit = (bool)$onoff;
- ;
- return DB_OK;
- }
-
- // }}}
- // {{{ commit()
-
- /**
- * Commits the current transaction
- *
- * @return int DB_OK on success. A DB_Error object on failure.
- */
- public function commit()
- {
- $result = @OCICommit($this->connection);
- if (!$result) {
- return $this->oci8RaiseError();
- }
- return DB_OK;
- }
-
- // }}}
- // {{{ rollback()
-
- /**
- * Reverts the current transaction
- *
- * @return int DB_OK on success. A DB_Error object on failure.
- */
- public function rollback()
- {
- $result = @OCIRollback($this->connection);
- if (!$result) {
- return $this->oci8RaiseError();
- }
- return DB_OK;
- }
-
- // }}}
- // {{{ affectedRows()
-
- /**
- * Determines the number of rows affected by a data maniuplation query
- *
- * 0 is returned for queries that don't manipulate data.
- *
- * @return int the number of rows. A DB_Error object on failure.
- */
- public function affectedRows()
- {
- if ($this->last_stmt === false) {
- return $this->oci8RaiseError();
- }
- $result = @OCIRowCount($this->last_stmt);
- if ($result === false) {
- return $this->oci8RaiseError($this->last_stmt);
- }
- return $result;
- }
-
- // }}}
- // {{{ modifyQuery()
-
- /**
- * Changes a query string for various DBMS specific reasons
- *
- * "SELECT 2+2" must be "SELECT 2+2 FROM dual" in Oracle.
- *
- * @param string $query the query string to modify
- *
- * @return string the modified query string
- *
- * @access protected
- */
- public function modifyQuery($query)
- {
- if (preg_match('/^\s*SELECT/i', $query) &&
- !preg_match('/\sFROM\s/i', $query)) {
- $query .= ' FROM dual';
- }
- return $query;
- }
-
- // }}}
- // {{{ modifyLimitQuery()
-
- /**
- * Adds LIMIT clauses to a query string according to current DBMS standards
- *
- * @param string $query the query to modify
- * @param int $from the row to start to fetching (0 = the first row)
- * @param int $count the numbers of rows to fetch
- * @param mixed $params array, string or numeric data to be used in
- * execution of the statement. Quantity of items
- * passed must match quantity of placeholders in
- * query: meaning 1 placeholder for non-array
- * parameters or 1 placeholder per array element.
- *
- * @return string the query string with LIMIT clauses added
+ * Formats a float value for use within a query in a locale-independent
+ * manner.
*
- * @access protected
+ * @param float the float value to be quoted.
+ * @return string the quoted string.
+ * @see DB_common::quoteSmart()
+ * @since Method available since release 1.7.8.
*/
- public function modifyLimitQuery($query, $from, $count, $params = array())
+ public function quoteFloat($float)
{
- // Let Oracle return the name of the columns instead of
- // coding a "home" SQL parser
-
- if (count($params)) {
- $result = $this->prepare("SELECT * FROM ($query) "
- . 'WHERE NULL = NULL');
- $tmp = $this->execute($result, $params);
- } else {
- $q_fields = "SELECT * FROM ($query) WHERE NULL = NULL";
-
- if (!$result = @OCIParse($this->connection, $q_fields)) {
- $this->last_query = $q_fields;
- return $this->oci8RaiseError();
- }
- if (!@OCIExecute($result, OCI_DEFAULT)) {
- $this->last_query = $q_fields;
- return $this->oci8RaiseError($result);
- }
- }
-
- $ncols = OCINumCols($result);
- $cols = array();
- for ($i = 1; $i <= $ncols; $i++) {
- $cols[] = '"' . OCIColumnName($result, $i) . '"';
- }
- $fields = implode(', ', $cols);
- // XXX Test that (tip by John Lim)
- //if (preg_match('/^\s*SELECT\s+/is', $query, $match)) {
- // // Introduce the FIRST_ROWS Oracle query optimizer
- // $query = substr($query, strlen($match[0]), strlen($query));
- // $query = "SELECT /* +FIRST_ROWS */ " . $query;
- //}
-
- // Construct the query
- // more at: http://marc.theaimsgroup.com/?l=php-db&m=99831958101212&w=2
- // Perhaps this could be optimized with the use of Unions
- $query = "SELECT $fields FROM".
- " (SELECT rownum as linenum, $fields FROM".
- " ($query)".
- ' WHERE rownum <= '. ($from + $count) .
- ') WHERE linenum >= ' . ++$from;
- return $query;
+ return $this->escapeSimple(str_replace(',', '.', strval(floatval($float))));
}
// }}}
- // {{{ nextId()
+ // {{{ dropSequence()
/**
* Returns the next free id in a sequence
*
- * @param string $seq_name name of the sequence
- * @param boolean $ondemand when true, the seqence is automatically
+ * @param string $seq_name name of the sequence
+ * @param boolean $ondemand when true, the seqence is automatically
* created if it does not exist
*
- * @return int the next id number in the sequence.
+ * @return int|object
* A DB_Error object on failure.
*
* @see DB_common::nextID(), DB_common::getSequenceName(),
return $arr[0];
}
+ // }}}
+ // {{{ oci8RaiseError()
+
/**
* Creates a new sequence
*
- * @param string $seq_name name of the new sequence
+ * @param string $seq_name name of the new sequence
*
* @return int DB_OK on success. A DB_Error object on failure.
*
public function createSequence($seq_name)
{
return $this->query('CREATE SEQUENCE '
- . $this->getSequenceName($seq_name));
+ . $this->getSequenceName($seq_name));
}
// }}}
- // {{{ dropSequence()
+ // {{{ errorNative()
/**
* Deletes a sequence
*
- * @param string $seq_name name of the sequence to be deleted
+ * @param string $seq_name name of the sequence to be deleted
*
* @return int DB_OK on success. A DB_Error object on failure.
*
public function dropSequence($seq_name)
{
return $this->query('DROP SEQUENCE '
- . $this->getSequenceName($seq_name));
+ . $this->getSequenceName($seq_name));
}
// }}}
- // {{{ oci8RaiseError()
-
- /**
- * Produces a DB_Error object regarding the current problem
- *
- * @param int $errno if the error is being manually raised pass a
- * DB_ERROR* constant here. If this isn't passed
- * the error information gathered from the DBMS.
- *
- * @return object the DB_Error object
- *
- * @see DB_common::raiseError(),
- * DB_oci8::errorNative(), DB_oci8::errorCode()
- */
- public function oci8RaiseError($errno = null)
- {
- if ($errno === null) {
- $error = @OCIError($this->connection);
- return $this->raiseError(
- $this->errorCode($error['code']),
- null,
- null,
- null,
- $error['message']
- );
- } elseif (is_resource($errno)) {
- $error = @OCIError($errno);
- return $this->raiseError(
- $this->errorCode($error['code']),
- null,
- null,
- null,
- $error['message']
- );
- }
- return $this->raiseError($this->errorCode($errno));
- }
-
- // }}}
- // {{{ errorNative()
+ // {{{ tableInfo()
/**
* Gets the DBMS' native error code produced by the last query
}
// }}}
- // {{{ tableInfo()
+ // {{{ getSpecialQuery()
/**
* Returns information about a table or a result set
*
* NOTE: flags won't contain index information.
*
- * @param object|string $result DB_result object from a query or a
+ * @param object|string $result DB_result object from a query or a
* string containing the name of a table.
* While this also accepts a query result
* resource identifier, this behavior is
* deprecated.
- * @param int $mode a valid tableInfo mode
+ * @param int $mode a valid tableInfo mode
*
- * @return array an associative array with the information requested.
+ * @return array|object
* A DB_Error object on failure.
*
* @see DB_common::tableInfo()
*/
$result = strtoupper($result);
$q_fields = 'SELECT column_name, data_type, data_length, '
- . 'nullable '
- . 'FROM user_tab_columns '
- . "WHERE table_name='$result' ORDER BY column_id";
+ . 'nullable '
+ . 'FROM user_tab_columns '
+ . "WHERE table_name='$result' ORDER BY column_id";
$this->last_query = $q_fields;
if (!@OCIExecute($stmt, OCI_DEFAULT)) {
return $this->oci8RaiseError($stmt);
}
-
+
$i = 0;
while (@OCIFetch($stmt)) {
$res[$i] = array(
'table' => $case_func($result),
- 'name' => $case_func(@OCIResult($stmt, 1)),
- 'type' => @OCIResult($stmt, 2),
- 'len' => @OCIResult($stmt, 3),
+ 'name' => $case_func(@OCIResult($stmt, 1)),
+ 'type' => @OCIResult($stmt, 2),
+ 'len' => @OCIResult($stmt, 3),
'flags' => (@OCIResult($stmt, 4) == 'N') ? 'not_null' : '',
);
if ($mode & DB_TABLEINFO_ORDER) {
for ($i = 0; $i < $count; $i++) {
$res[$i] = array(
'table' => '',
- 'name' => $case_func(@OCIColumnName($result, $i+1)),
- 'type' => @OCIColumnType($result, $i+1),
- 'len' => @OCIColumnSize($result, $i+1),
+ 'name' => $case_func(@OCIColumnName($result, $i + 1)),
+ 'type' => @OCIColumnType($result, $i + 1),
+ 'len' => @OCIColumnSize($result, $i + 1),
'flags' => '',
);
if ($mode & DB_TABLEINFO_ORDER) {
}
// }}}
- // {{{ getSpecialQuery()
+ // {{{ quoteFloat()
/**
* Obtains the query string needed for listing a given type of objects
*
- * @param string $type the kind of objects you want to retrieve
+ * @param string $type the kind of objects you want to retrieve
*
* @return string the SQL query string or null if the driver doesn't
* support the object type requested
}
}
- // }}}
- // {{{ quoteFloat()
-
- /**
- * Formats a float value for use within a query in a locale-independent
- * manner.
- *
- * @param float the float value to be quoted.
- * @return string the quoted string.
- * @see DB_common::quoteSmart()
- * @since Method available since release 1.7.8.
- */
- public function quoteFloat($float)
- {
- return $this->escapeSimple(str_replace(',', '.', strval(floatval($float))));
- }
-
// }}}
}
/**
* Obtain the DB_common class so it can be extended from
*/
-require_once 'DB/common.php';
+//require_once 'DB/common.php';
+require_once 'common.php';
/**
* The methods PEAR DB uses to interact with PHP's odbc extension
* @var array
*/
public $features = array(
- 'limit' => 'emulate',
- 'new_link' => false,
- 'numrows' => true,
- 'pconnect' => true,
- 'prepare' => false,
- 'ssl' => false,
- 'transactions' => false,
+ 'limit' => 'emulate',
+ 'new_link' => false,
+ 'numrows' => true,
+ 'pconnect' => true,
+ 'prepare' => false,
+ 'ssl' => false,
+ 'transactions' => false,
);
/**
* PEAR DB's odbc driver supports the following extra DSN options:
* + cursor The type of cursor to be used for this connection.
*
- * @param array $dsn the data source name
- * @param bool $persistent should the connection be persistent?
+ * @param array $dsn the data source name
+ * @param bool $persistent should the connection be persistent?
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function connect($dsn, $persistent = false)
{
// }}}
// {{{ disconnect()
+ /**
+ * Gets the DBMS' native error code and message produced by the last query
+ *
+ * @return string the DBMS' error code and message
+ */
+ public function errorNative()
+ {
+ if (!is_resource($this->connection)) {
+ return @odbc_error() . ' ' . @odbc_errormsg();
+ }
+ return @odbc_error($this->connection) . ' ' . @odbc_errormsg($this->connection);
+ }
+
+ // }}}
+ // {{{ simpleQuery()
+
/**
* Disconnects from the database server
*
- * @return bool TRUE on success, FALSE on failure
+ * @return bool|void
*/
public function disconnect()
{
}
// }}}
- // {{{ simpleQuery()
+ // {{{ nextResult()
/**
* Sends a query to the database server
}
// }}}
- // {{{ nextResult()
+ // {{{ fetchInto()
+
+ /**
+ * Produces a DB_Error object regarding the current problem
+ *
+ * @param int $errno if the error is being manually raised pass a
+ * DB_ERROR* constant here. If this isn't passed
+ * the error information gathered from the DBMS.
+ *
+ * @return object the DB_Error object
+ *
+ * @see DB_common::raiseError(),
+ * DB_odbc::errorNative(), DB_common::errorCode()
+ */
+ public function odbcRaiseError($errno = null)
+ {
+ if ($errno === null) {
+ switch ($this->dbsyntax) {
+ case 'access':
+ if ($this->options['portability'] & DB_PORTABILITY_ERRORS) {
+ $this->errorcode_map['07001'] = DB_ERROR_NOSUCHFIELD;
+ } else {
+ // Doing this in case mode changes during runtime.
+ $this->errorcode_map['07001'] = DB_ERROR_MISMATCH;
+ }
+
+ $native_code = odbc_error($this->connection);
+
+ // S1000 is for "General Error." Let's be more specific.
+ if ($native_code == 'S1000') {
+ $errormsg = odbc_errormsg($this->connection);
+ static $error_regexps;
+ if (!isset($error_regexps)) {
+ $error_regexps = array(
+ '/includes related records.$/i' => DB_ERROR_CONSTRAINT,
+ '/cannot contain a Null value/i' => DB_ERROR_CONSTRAINT_NOT_NULL,
+ );
+ }
+ foreach ($error_regexps as $regexp => $code) {
+ if (preg_match($regexp, $errormsg)) {
+ return $this->raiseError(
+ $code,
+ null,
+ null,
+ null,
+ $native_code . ' ' . $errormsg
+ );
+ }
+ }
+ $errno = DB_ERROR;
+ } else {
+ $errno = $this->errorCode($native_code);
+ }
+ break;
+ default:
+ $errno = $this->errorCode(odbc_error($this->connection));
+ }
+ }
+ return $this->raiseError(
+ $errno,
+ null,
+ null,
+ null,
+ $this->errorNative()
+ );
+ }
+
+ // }}}
+ // {{{ freeResult()
/**
* Move the internal odbc result pointer to the next available result
}
// }}}
- // {{{ fetchInto()
+ // {{{ numCols()
/**
* Places a row from the result set into the given array
* DB_result::fetchInto() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result the query result resource
- * @param array $arr the referenced array to put the data in
- * @param int $fetchmode how the resulting array should be indexed
- * @param int $rownum the row number to fetch (0 = first row)
+ * @param resource $result the query result resource
+ * @param array $arr the referenced array to put the data in
+ * @param int $fetchmode how the resulting array should be indexed
+ * @param int $rownum the row number to fetch (0 = first row)
*
* @return mixed DB_OK on success, NULL when the end of a result set is
* reached or on failure
}
if ($fetchmode !== DB_FETCHMODE_ORDERED) {
for ($i = 0; $i < count($arr); $i++) {
- $colName = @odbc_field_name($result, $i+1);
+ $colName = @odbc_field_name($result, $i + 1);
$a[$colName] = $arr[$i];
}
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
}
// }}}
- // {{{ freeResult()
+ // {{{ affectedRows()
/**
* Deletes the result set and frees the memory occupied by the result set
* DB_result::free() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
* @return bool TRUE on success, FALSE if $result is invalid
*
}
// }}}
- // {{{ numCols()
+ // {{{ numRows()
/**
* Gets the number of columns in a result set
* DB_result::numCols() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
- * @return int the number of columns. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_result::numCols()
*/
}
// }}}
- // {{{ affectedRows()
+ // {{{ quoteIdentifier()
/**
* Determines the number of rows affected by a data maniuplation query
*
* 0 is returned for queries that don't manipulate data.
*
- * @return int the number of rows. A DB_Error object on failure.
+ * @return int|object
*/
public function affectedRows()
{
}
// }}}
- // {{{ numRows()
+ // {{{ nextId()
/**
* Gets the number of rows in a result set
* DB_result::numRows() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
- * @return int the number of rows. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_result::numRows()
*/
return $nrows;
}
- // }}}
- // {{{ quoteIdentifier()
-
/**
* Quotes a string so it can be safely used as a table or column name
*
* Use 'mssql' as the dbsyntax in the DB DSN only if you've unchecked
* "Use ANSI quoted identifiers" when setting up the ODBC data source.
*
- * @param string $str identifier name to be quoted
+ * @param string $str identifier name to be quoted
*
* @return string quoted identifier string
*
}
// }}}
- // {{{ nextId()
+ // {{{ dropSequence()
/**
* Returns the next free id in a sequence
*
- * @param string $seq_name name of the sequence
- * @param boolean $ondemand when true, the seqence is automatically
+ * @param string $seq_name name of the sequence
+ * @param boolean $ondemand when true, the seqence is automatically
* created if it does not exist
*
- * @return int the next id number in the sequence.
+ * @return int|object
* A DB_Error object on failure.
*
* @see DB_common::nextID(), DB_common::getSequenceName(),
return $row[0];
}
+ // }}}
+ // {{{ autoCommit()
+
/**
* Creates a new sequence
*
- * @param string $seq_name name of the new sequence
+ * @param string $seq_name name of the new sequence
*
* @return int DB_OK on success. A DB_Error object on failure.
*
public function createSequence($seq_name)
{
return $this->query('CREATE TABLE '
- . $this->getSequenceName($seq_name)
- . ' (id integer NOT NULL,'
- . ' PRIMARY KEY(id))');
+ . $this->getSequenceName($seq_name)
+ . ' (id integer NOT NULL,'
+ . ' PRIMARY KEY(id))');
}
// }}}
- // {{{ dropSequence()
+ // {{{ commit()
/**
* Deletes a sequence
*
- * @param string $seq_name name of the sequence to be deleted
+ * @param string $seq_name name of the sequence to be deleted
*
* @return int DB_OK on success. A DB_Error object on failure.
*
}
// }}}
- // {{{ autoCommit()
+ // {{{ rollback()
/**
* Enables or disables automatic commits
*
- * @param bool $onoff true turns it on, false turns it off
+ * @param bool $onoff true turns it on, false turns it off
*
- * @return int DB_OK on success. A DB_Error object if the driver
+ * @return int|object
* doesn't support auto-committing transactions.
*/
public function autoCommit($onoff = false)
}
// }}}
- // {{{ commit()
+ // {{{ odbcRaiseError()
/**
* Commits the current transaction
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function commit()
{
}
// }}}
- // {{{ rollback()
+ // {{{ errorNative()
/**
* Reverts the current transaction
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function rollback()
{
return DB_OK;
}
- // }}}
- // {{{ odbcRaiseError()
-
- /**
- * Produces a DB_Error object regarding the current problem
- *
- * @param int $errno if the error is being manually raised pass a
- * DB_ERROR* constant here. If this isn't passed
- * the error information gathered from the DBMS.
- *
- * @return object the DB_Error object
- *
- * @see DB_common::raiseError(),
- * DB_odbc::errorNative(), DB_common::errorCode()
- */
- public function odbcRaiseError($errno = null)
- {
- if ($errno === null) {
- switch ($this->dbsyntax) {
- case 'access':
- if ($this->options['portability'] & DB_PORTABILITY_ERRORS) {
- $this->errorcode_map['07001'] = DB_ERROR_NOSUCHFIELD;
- } else {
- // Doing this in case mode changes during runtime.
- $this->errorcode_map['07001'] = DB_ERROR_MISMATCH;
- }
-
- $native_code = odbc_error($this->connection);
-
- // S1000 is for "General Error." Let's be more specific.
- if ($native_code == 'S1000') {
- $errormsg = odbc_errormsg($this->connection);
- static $error_regexps;
- if (!isset($error_regexps)) {
- $error_regexps = array(
- '/includes related records.$/i' => DB_ERROR_CONSTRAINT,
- '/cannot contain a Null value/i' => DB_ERROR_CONSTRAINT_NOT_NULL,
- );
- }
- foreach ($error_regexps as $regexp => $code) {
- if (preg_match($regexp, $errormsg)) {
- return $this->raiseError(
- $code,
- null,
- null,
- null,
- $native_code . ' ' . $errormsg
- );
- }
- }
- $errno = DB_ERROR;
- } else {
- $errno = $this->errorCode($native_code);
- }
- break;
- default:
- $errno = $this->errorCode(odbc_error($this->connection));
- }
- }
- return $this->raiseError(
- $errno,
- null,
- null,
- null,
- $this->errorNative()
- );
- }
-
- // }}}
- // {{{ errorNative()
-
- /**
- * Gets the DBMS' native error code and message produced by the last query
- *
- * @return string the DBMS' error code and message
- */
- public function errorNative()
- {
- if (!is_resource($this->connection)) {
- return @odbc_error() . ' ' . @odbc_errormsg();
- }
- return @odbc_error($this->connection) . ' ' . @odbc_errormsg($this->connection);
- }
-
// }}}
// {{{ tableInfo()
/**
* Returns information about a table or a result set
*
- * @param object|string $result DB_result object from a query or a
+ * @param object|string $result DB_result object from a query or a
* string containing the name of a table.
* While this also accepts a query result
* resource identifier, this behavior is
* deprecated.
- * @param int $mode a valid tableInfo mode
+ * @param int $mode a valid tableInfo mode
*
- * @return array an associative array with the information requested.
+ * @return array|object
* A DB_Error object on failure.
*
* @see DB_common::tableInfo()
}
$count = @odbc_num_fields($id);
- $res = array();
+ $res = array();
if ($mode) {
$res['num_fields'] = $count;
$col = $i + 1;
$res[$i] = array(
'table' => $got_string ? $case_func($result) : '',
- 'name' => $case_func(@odbc_field_name($id, $col)),
- 'type' => @odbc_field_type($id, $col),
- 'len' => @odbc_field_len($id, $col),
+ 'name' => $case_func(@odbc_field_name($id, $col)),
+ 'type' => @odbc_field_type($id, $col),
+ 'len' => @odbc_field_len($id, $col),
'flags' => '',
);
if ($mode & DB_TABLEINFO_ORDER) {
*
* Thanks to symbol1@gmail.com and Philippe.Jausions@11abacus.com.
*
- * @param string $type the kind of objects you want to retrieve
+ * @param string $type the kind of objects you want to retrieve
*
- * @return string the list of objects requested
+ * @return array|string
*
* @access protected
* @see DB_common::getListOf()
* in the odbc_tables() call because some backends choke on this:
* odbc_tables($this->connection, '', '', '', 'TABLE')
*/
- $res = @odbc_tables($this->connection);
+ $res = @odbc_tables($this->connection);
if (!$res) {
return $this->odbcRaiseError();
}
/**
* Obtain the DB_common class so it can be extended from
*/
-require_once 'DB/common.php';
+//require_once 'DB/common.php';
+require_once 'common.php';
/**
* The methods PEAR DB uses to interact with PHP's pgsql extension
* @var array
*/
public $features = array(
- 'limit' => 'alter',
- 'new_link' => '4.3.0',
- 'numrows' => true,
- 'pconnect' => true,
- 'prepare' => false,
- 'ssl' => true,
- 'transactions' => true,
+ 'limit' => 'alter',
+ 'new_link' => '4.3.0',
+ 'numrows' => true,
+ 'pconnect' => true,
+ 'prepare' => false,
+ 'ssl' => true,
+ 'transactions' => true,
);
/**
* A mapping of native error codes to DB error codes
* @var array
*/
- public $errorcode_map = array(
- );
+ public $errorcode_map = array();
/**
* The raw database connection created by PHP
* );
*
* $db = DB::connect($dsn, $options);
- * if (PEAR::isError($db)) {
+ * if ((new PEAR)->isError($db)) {
* die($db->getMessage());
* }
* </code>
*
- * @param array $dsn the data source name
- * @param bool $persistent should the connection be persistent?
+ * @param array $dsn the data source name
+ * @param bool $persistent should the connection be persistent?
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*
* @link http://www.postgresql.org/docs/current/static/libpq.html#LIBPQ-CONNECT
*/
// }}}
// {{{ nextResult()
+ /**
+ * Checks if the given query is a manipulation query. This also takes into
+ * account the _next_query_manip flag and sets the _last_query_manip flag
+ * (and resets _next_query_manip) according to the result.
+ *
+ * @param string The query to check.
+ *
+ * @return boolean true if the query is a manipulation query, false
+ * otherwise
+ *
+ * @access protected
+ */
+ public function _checkManip($query)
+ {
+ return (preg_match('/^\s*(SAVEPOINT|RELEASE)\s+/i', $query)
+ || parent::_checkManip($query));
+ }
+
+ // }}}
+ // {{{ fetchInto()
+
+ /**
+ * Produces a DB_Error object regarding the current problem
+ *
+ * @param int $errno if the error is being manually raised pass a
+ * DB_ERROR* constant here. If this isn't passed
+ * the error information gathered from the DBMS.
+ *
+ * @return object the DB_Error object
+ *
+ * @see DB_common::raiseError(),
+ * DB_pgsql::errorNative(), DB_pgsql::errorCode()
+ */
+ public function pgsqlRaiseError($errno = null)
+ {
+ $native = $this->errorNative();
+ if (!$native) {
+ $native = 'Database connection has been lost.';
+ $errno = DB_ERROR_CONNECT_FAILED;
+ }
+ if ($errno === null) {
+ $errno = $this->errorCode($native);
+ }
+ return $this->raiseError($errno, null, null, null, $native);
+ }
+
+ // }}}
+ // {{{ freeResult()
+
+ /**
+ * Gets the DBMS' native error message produced by the last query
+ *
+ * {@internal Error messages are used instead of error codes
+ * in order to support older versions of PostgreSQL.}}
+ *
+ * @return string the DBMS' error message
+ */
+ public function errorNative()
+ {
+ return @pg_errormessage($this->connection);
+ }
+
+ // }}}
+ // {{{ quoteBoolean()
+
+ /**
+ * Determines PEAR::DB error code from the database's text error message.
+ *
+ * @param string $errormsg error message returned from the database
+ * @return integer an error number from a DB error constant
+ */
+ public function errorCode($errormsg)
+ {
+ static $error_regexps;
+ if (!isset($error_regexps)) {
+ $error_regexps = array(
+ '/column .* (of relation .*)?does not exist/i'
+ => DB_ERROR_NOSUCHFIELD,
+ '/(relation|sequence|table).*does not exist|class .* not found/i'
+ => DB_ERROR_NOSUCHTABLE,
+ '/index .* does not exist/'
+ => DB_ERROR_NOT_FOUND,
+ '/relation .* already exists/i'
+ => DB_ERROR_ALREADY_EXISTS,
+ '/(divide|division) by zero$/i'
+ => DB_ERROR_DIVZERO,
+ '/pg_atoi: error in .*: can\'t parse /i'
+ => DB_ERROR_INVALID_NUMBER,
+ '/invalid input syntax for( type)? (integer|numeric)/i'
+ => DB_ERROR_INVALID_NUMBER,
+ '/value .* is out of range for type \w*int/i'
+ => DB_ERROR_INVALID_NUMBER,
+ '/integer out of range/i'
+ => DB_ERROR_INVALID_NUMBER,
+ '/value too long for type character/i'
+ => DB_ERROR_INVALID,
+ '/attribute .* not found|relation .* does not have attribute/i'
+ => DB_ERROR_NOSUCHFIELD,
+ '/column .* specified in USING clause does not exist in (left|right) table/i'
+ => DB_ERROR_NOSUCHFIELD,
+ '/parser: parse error at or near/i'
+ => DB_ERROR_SYNTAX,
+ '/syntax error at/'
+ => DB_ERROR_SYNTAX,
+ '/column reference .* is ambiguous/i'
+ => DB_ERROR_SYNTAX,
+ '/permission denied/'
+ => DB_ERROR_ACCESS_VIOLATION,
+ '/violates not-null constraint/'
+ => DB_ERROR_CONSTRAINT_NOT_NULL,
+ '/violates [\w ]+ constraint/'
+ => DB_ERROR_CONSTRAINT,
+ '/referential integrity violation/'
+ => DB_ERROR_CONSTRAINT,
+ '/more expressions than target columns/i'
+ => DB_ERROR_VALUE_COUNT_ON_ROW,
+ );
+ }
+ foreach ($error_regexps as $regexp => $code) {
+ if (preg_match($regexp, $errormsg)) {
+ return $code;
+ }
+ }
+ // Fall back to DB_ERROR if there was no mapping.
+ return DB_ERROR;
+ }
+
+ // }}}
+ // {{{ escapeSimple()
+
+ /**
+ * Gets the number of rows in a result set
+ *
+ * This method is not meant to be called directly. Use
+ * DB_result::numRows() instead. It can't be declared "protected"
+ * because DB_result is a separate object.
+ *
+ * @param resource $result PHP's query result resource
+ *
+ * @return int|object
+ *
+ * @see DB_result::numRows()
+ */
+ public function numRows($result)
+ {
+ $rows = @pg_numrows($result);
+ if ($rows === null) {
+ return $this->pgsqlRaiseError();
+ }
+ return $rows;
+ }
+
+ // }}}
+ // {{{ numCols()
+
/**
* Move the internal pgsql result pointer to the next available result
*
}
// }}}
- // {{{ fetchInto()
+ // {{{ numRows()
/**
* Places a row from the result set into the given array
* DB_result::fetchInto() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result the query result resource
- * @param array $arr the referenced array to put the data in
- * @param int $fetchmode how the resulting array should be indexed
- * @param int $rownum the row number to fetch (0 = first row)
+ * @param resource $result the query result resource
+ * @param array $arr the referenced array to put the data in
+ * @param int $fetchmode how the resulting array should be indexed
+ * @param int $rownum the row number to fetch (0 = first row)
*
* @return mixed DB_OK on success, NULL when the end of a result set is
* reached or on failure
}
// }}}
- // {{{ freeResult()
+ // {{{ autoCommit()
/**
* Deletes the result set and frees the memory occupied by the result set
* DB_result::free() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
* @return bool TRUE on success, FALSE if $result is invalid
*
}
// }}}
- // {{{ quoteBoolean()
+ // {{{ commit()
/**
* Formats a boolean value for use within a query in a locale-independent
{
return $boolean ? 'TRUE' : 'FALSE';
}
-
+
// }}}
- // {{{ escapeSimple()
+ // {{{ rollback()
/**
* Escapes a string according to the current DBMS's standards
* {@internal PostgreSQL treats a backslash as an escape character,
* so they are escaped as well.
*
- * @param string $str the string to be escaped
+ * @param string $str the string to be escaped
*
* @return string the escaped string
*
}
// }}}
- // {{{ numCols()
+ // {{{ affectedRows()
/**
* Gets the number of columns in a result set
* DB_result::numCols() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
- * @return int the number of columns. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_result::numCols()
*/
}
// }}}
- // {{{ numRows()
-
- /**
- * Gets the number of rows in a result set
- *
- * This method is not meant to be called directly. Use
- * DB_result::numRows() instead. It can't be declared "protected"
- * because DB_result is a separate object.
- *
- * @param resource $result PHP's query result resource
- *
- * @return int the number of rows. A DB_Error object on failure.
- *
- * @see DB_result::numRows()
- */
- public function numRows($result)
- {
- $rows = @pg_numrows($result);
- if ($rows === null) {
- return $this->pgsqlRaiseError();
- }
- return $rows;
- }
-
- // }}}
- // {{{ autoCommit()
+ // {{{ nextId()
/**
* Enables or disables automatic commits
*
- * @param bool $onoff true turns it on, false turns it off
+ * @param bool $onoff true turns it on, false turns it off
*
* @return int DB_OK on success. A DB_Error object if the driver
* doesn't support auto-committing transactions.
}
// }}}
- // {{{ commit()
+ // {{{ createSequence()
/**
* Commits the current transaction
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function commit()
{
}
// }}}
- // {{{ rollback()
+ // {{{ dropSequence()
/**
* Reverts the current transaction
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function rollback()
{
}
// }}}
- // {{{ affectedRows()
+ // {{{ modifyLimitQuery()
/**
* Determines the number of rows affected by a data maniuplation query
}
// }}}
- // {{{ nextId()
+ // {{{ pgsqlRaiseError()
/**
* Returns the next free id in a sequence
*
- * @param string $seq_name name of the sequence
- * @param boolean $ondemand when true, the seqence is automatically
+ * @param string $seq_name name of the sequence
+ * @param boolean $ondemand when true, the seqence is automatically
* created if it does not exist
*
- * @return int the next id number in the sequence.
+ * @return int|object
* A DB_Error object on failure.
*
* @see DB_common::nextID(), DB_common::getSequenceName(),
}
// }}}
- // {{{ createSequence()
+ // {{{ errorNative()
/**
* Creates a new sequence
*
- * @param string $seq_name name of the new sequence
+ * @param string $seq_name name of the new sequence
*
* @return int DB_OK on success. A DB_Error object on failure.
*
}
// }}}
- // {{{ dropSequence()
+ // {{{ errorCode()
/**
* Deletes a sequence
*
- * @param string $seq_name name of the sequence to be deleted
+ * @param string $seq_name name of the sequence to be deleted
*
* @return int DB_OK on success. A DB_Error object on failure.
*
public function dropSequence($seq_name)
{
return $this->query('DROP SEQUENCE '
- . $this->getSequenceName($seq_name));
+ . $this->getSequenceName($seq_name));
}
// }}}
- // {{{ modifyLimitQuery()
+ // {{{ tableInfo()
/**
* Adds LIMIT clauses to a query string according to current DBMS standards
*
- * @param string $query the query to modify
- * @param int $from the row to start to fetching (0 = the first row)
- * @param int $count the numbers of rows to fetch
- * @param mixed $params array, string or numeric data to be used in
+ * @param string $query the query to modify
+ * @param int $from the row to start to fetching (0 = the first row)
+ * @param int $count the numbers of rows to fetch
+ * @param mixed $params array, string or numeric data to be used in
* execution of the statement. Quantity of items
* passed must match quantity of placeholders in
* query: meaning 1 placeholder for non-array
}
// }}}
- // {{{ pgsqlRaiseError()
-
- /**
- * Produces a DB_Error object regarding the current problem
- *
- * @param int $errno if the error is being manually raised pass a
- * DB_ERROR* constant here. If this isn't passed
- * the error information gathered from the DBMS.
- *
- * @return object the DB_Error object
- *
- * @see DB_common::raiseError(),
- * DB_pgsql::errorNative(), DB_pgsql::errorCode()
- */
- public function pgsqlRaiseError($errno = null)
- {
- $native = $this->errorNative();
- if (!$native) {
- $native = 'Database connection has been lost.';
- $errno = DB_ERROR_CONNECT_FAILED;
- }
- if ($errno === null) {
- $errno = $this->errorCode($native);
- }
- return $this->raiseError($errno, null, null, null, $native);
- }
-
- // }}}
- // {{{ errorNative()
-
- /**
- * Gets the DBMS' native error message produced by the last query
- *
- * {@internal Error messages are used instead of error codes
- * in order to support older versions of PostgreSQL.}}
- *
- * @return string the DBMS' error message
- */
- public function errorNative()
- {
- return @pg_errormessage($this->connection);
- }
-
- // }}}
- // {{{ errorCode()
-
- /**
- * Determines PEAR::DB error code from the database's text error message.
- *
- * @param string $errormsg error message returned from the database
- * @return integer an error number from a DB error constant
- */
- public function errorCode($errormsg)
- {
- static $error_regexps;
- if (!isset($error_regexps)) {
- $error_regexps = array(
- '/column .* (of relation .*)?does not exist/i'
- => DB_ERROR_NOSUCHFIELD,
- '/(relation|sequence|table).*does not exist|class .* not found/i'
- => DB_ERROR_NOSUCHTABLE,
- '/index .* does not exist/'
- => DB_ERROR_NOT_FOUND,
- '/relation .* already exists/i'
- => DB_ERROR_ALREADY_EXISTS,
- '/(divide|division) by zero$/i'
- => DB_ERROR_DIVZERO,
- '/pg_atoi: error in .*: can\'t parse /i'
- => DB_ERROR_INVALID_NUMBER,
- '/invalid input syntax for( type)? (integer|numeric)/i'
- => DB_ERROR_INVALID_NUMBER,
- '/value .* is out of range for type \w*int/i'
- => DB_ERROR_INVALID_NUMBER,
- '/integer out of range/i'
- => DB_ERROR_INVALID_NUMBER,
- '/value too long for type character/i'
- => DB_ERROR_INVALID,
- '/attribute .* not found|relation .* does not have attribute/i'
- => DB_ERROR_NOSUCHFIELD,
- '/column .* specified in USING clause does not exist in (left|right) table/i'
- => DB_ERROR_NOSUCHFIELD,
- '/parser: parse error at or near/i'
- => DB_ERROR_SYNTAX,
- '/syntax error at/'
- => DB_ERROR_SYNTAX,
- '/column reference .* is ambiguous/i'
- => DB_ERROR_SYNTAX,
- '/permission denied/'
- => DB_ERROR_ACCESS_VIOLATION,
- '/violates not-null constraint/'
- => DB_ERROR_CONSTRAINT_NOT_NULL,
- '/violates [\w ]+ constraint/'
- => DB_ERROR_CONSTRAINT,
- '/referential integrity violation/'
- => DB_ERROR_CONSTRAINT,
- '/more expressions than target columns/i'
- => DB_ERROR_VALUE_COUNT_ON_ROW,
- );
- }
- foreach ($error_regexps as $regexp => $code) {
- if (preg_match($regexp, $errormsg)) {
- return $code;
- }
- }
- // Fall back to DB_ERROR if there was no mapping.
- return DB_ERROR;
- }
-
- // }}}
- // {{{ tableInfo()
+ // {{{ _pgFieldFlags()
/**
* Returns information about a table or a result set
* NOTE: only supports 'table' and 'flags' if <var>$result</var>
* is a table name.
*
- * @param object|string $result DB_result object from a query or a
+ * @param object|string $result DB_result object from a query or a
* string containing the name of a table.
* While this also accepts a query result
* resource identifier, this behavior is
* deprecated.
- * @param int $mode a valid tableInfo mode
+ * @param int $mode a valid tableInfo mode
*
- * @return array an associative array with the information requested.
+ * @return array|object
* A DB_Error object on failure.
*
* @see DB_common::tableInfo()
}
$count = @pg_numfields($id);
- $res = array();
+ $res = array();
if ($mode) {
$res['num_fields'] = $count;
for ($i = 0; $i < $count; $i++) {
$res[$i] = array(
'table' => $got_string ? $case_func($result) : '',
- 'name' => $case_func(@pg_fieldname($id, $i)),
- 'type' => @pg_fieldtype($id, $i),
- 'len' => @pg_fieldsize($id, $i),
+ 'name' => $case_func(@pg_fieldname($id, $i)),
+ 'type' => @pg_fieldtype($id, $i),
+ 'len' => @pg_fieldsize($id, $i),
'flags' => $got_string
- ? $this->_pgFieldFlags($id, $i, $result)
- : '',
+ ? $this->_pgFieldFlags($id, $i, $result)
+ : '',
);
if ($mode & DB_TABLEINFO_ORDER) {
$res['order'][$res[$i]['name']] = $i;
}
// }}}
- // {{{ _pgFieldFlags()
+ // {{{ getSpecialQuery()
/**
* Get a column's flags
* and "multiple_key". The default value is passed through
* rawurlencode() in case there are spaces in it.
*
- * @param int $resource the PostgreSQL result identifier
- * @param int $num_field the field number
+ * @param int $resource the PostgreSQL result identifier
+ * @param int $num_field the field number
*
+ * @param $table_name
* @return string the flags
*
* @access private
AND $tableWhere");
if (@pg_numrows($result) > 0) {
$row = @pg_fetch_row($result, 0);
- $flags = ($row[0] == 't') ? 'not_null ' : '';
+ $flags = ($row[0] == 't') ? 'not_null ' : '';
if ($row[1] == 't') {
$result = @pg_exec($this->connection, "SELECT a.adsrc
AND $tableWhere");
$count = @pg_numrows($result);
- for ($i = 0; $i < $count ; $i++) {
+ for ($i = 0; $i < $count; $i++) {
$row = @pg_fetch_row($result, $i);
$keys = explode(' ', $row[2]);
}
// }}}
- // {{{ getSpecialQuery()
+ // {{{ _checkManip()
/**
* Obtains the query string needed for listing a given type of objects
*
- * @param string $type the kind of objects you want to retrieve
+ * @param string $type the kind of objects you want to retrieve
*
* @return string the SQL query string or null if the driver doesn't
* support the object type requested
switch ($type) {
case 'tables':
return 'SELECT c.relname AS "Name"'
- . ' FROM pg_class c, pg_user u'
- . ' WHERE c.relowner = u.usesysid'
- . " AND c.relkind = 'r'"
- . ' AND NOT EXISTS'
- . ' (SELECT 1 FROM pg_views'
- . ' WHERE viewname = c.relname)'
- . " AND c.relname !~ '^(pg_|sql_)'"
- . ' UNION'
- . ' SELECT c.relname AS "Name"'
- . ' FROM pg_class c'
- . " WHERE c.relkind = 'r'"
- . ' AND NOT EXISTS'
- . ' (SELECT 1 FROM pg_views'
- . ' WHERE viewname = c.relname)'
- . ' AND NOT EXISTS'
- . ' (SELECT 1 FROM pg_user'
- . ' WHERE usesysid = c.relowner)'
- . " AND c.relname !~ '^pg_'";
+ . ' FROM pg_class c, pg_user u'
+ . ' WHERE c.relowner = u.usesysid'
+ . " AND c.relkind = 'r'"
+ . ' AND NOT EXISTS'
+ . ' (SELECT 1 FROM pg_views'
+ . ' WHERE viewname = c.relname)'
+ . " AND c.relname !~ '^(pg_|sql_)'"
+ . ' UNION'
+ . ' SELECT c.relname AS "Name"'
+ . ' FROM pg_class c'
+ . " WHERE c.relkind = 'r'"
+ . ' AND NOT EXISTS'
+ . ' (SELECT 1 FROM pg_views'
+ . ' WHERE viewname = c.relname)'
+ . ' AND NOT EXISTS'
+ . ' (SELECT 1 FROM pg_user'
+ . ' WHERE usesysid = c.relowner)'
+ . " AND c.relname !~ '^pg_'";
case 'schema.tables':
return "SELECT schemaname || '.' || tablename"
- . ' AS "Name"'
- . ' FROM pg_catalog.pg_tables'
- . ' WHERE schemaname NOT IN'
- . " ('pg_catalog', 'information_schema', 'pg_toast')";
+ . ' AS "Name"'
+ . ' FROM pg_catalog.pg_tables'
+ . ' WHERE schemaname NOT IN'
+ . " ('pg_catalog', 'information_schema', 'pg_toast')";
case 'schema.views':
return "SELECT schemaname || '.' || viewname from pg_views WHERE schemaname"
- . " NOT IN ('information_schema', 'pg_catalog')";
+ . " NOT IN ('information_schema', 'pg_catalog')";
case 'views':
// Table cols: viewname | viewowner | definition
return 'SELECT viewname from pg_views WHERE schemaname'
- . " NOT IN ('information_schema', 'pg_catalog')";
+ . " NOT IN ('information_schema', 'pg_catalog')";
case 'users':
// cols: usename |usesysid|usecreatedb|usetrace|usesuper|usecatupd|passwd |valuntil
return 'SELECT usename FROM pg_user';
return null;
}
}
-
- // }}}
- // {{{ _checkManip()
-
- /**
- * Checks if the given query is a manipulation query. This also takes into
- * account the _next_query_manip flag and sets the _last_query_manip flag
- * (and resets _next_query_manip) according to the result.
- *
- * @param string The query to check.
- *
- * @return boolean true if the query is a manipulation query, false
- * otherwise
- *
- * @access protected
- */
- public function _checkManip($query)
- {
- return (preg_match('/^\s*(SAVEPOINT|RELEASE)\s+/i', $query)
- || parent::_checkManip($query));
- }
}
/*
/**
* Obtain the DB_common class so it can be extended from
*/
-require_once 'DB/common.php';
+//require_once 'DB/common.php';
+require_once 'common.php';
/**
* The methods PEAR DB uses to interact with PHP's sqlite extension
* @var array
*/
public $features = array(
- 'limit' => 'alter',
- 'new_link' => false,
- 'numrows' => true,
- 'pconnect' => true,
- 'prepare' => false,
- 'ssl' => false,
- 'transactions' => false,
+ 'limit' => 'alter',
+ 'new_link' => false,
+ 'numrows' => true,
+ 'pconnect' => true,
+ 'prepare' => false,
+ 'ssl' => false,
+ 'transactions' => false,
);
/**
*
* @var array
*/
- public $errorcode_map = array(
- );
+ public $errorcode_map = array();
/**
* The raw database connection created by PHP
* @var array
*/
public $keywords = array(
- 'BLOB' => '',
- 'BOOLEAN' => '',
+ 'BLOB' => '',
+ 'BOOLEAN' => '',
'CHARACTER' => '',
- 'CLOB' => '',
- 'FLOAT' => '',
- 'INTEGER' => '',
- 'KEY' => '',
- 'NATIONAL' => '',
- 'NUMERIC' => '',
- 'NVARCHAR' => '',
- 'PRIMARY' => '',
- 'TEXT' => '',
+ 'CLOB' => '',
+ 'FLOAT' => '',
+ 'INTEGER' => '',
+ 'KEY' => '',
+ 'NATIONAL' => '',
+ 'NUMERIC' => '',
+ 'NVARCHAR' => '',
+ 'PRIMARY' => '',
+ 'TEXT' => '',
'TIMESTAMP' => '',
- 'UNIQUE' => '',
- 'VARCHAR' => '',
- 'VARYING' => '',
+ 'UNIQUE' => '',
+ 'VARCHAR' => '',
+ 'VARYING' => '',
);
/**
* );
*
* $db = DB::connect($dsn, $options);
- * if (PEAR::isError($db)) {
+ * if ((new PEAR)->isError($db)) {
* die($db->getMessage());
* }
* </code>
*
- * @param array $dsn the data source name
- * @param bool $persistent should the connection be persistent?
+ * @param array $dsn the data source name
+ * @param bool $persistent should the connection be persistent?
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function connect($dsn, $persistent = false)
{
// }}}
// {{{ disconnect()
+ /**
+ * Produces a DB_Error object regarding the current problem
+ *
+ * @param int $errno if the error is being manually raised pass a
+ * DB_ERROR* constant here. If this isn't passed
+ * the error information gathered from the DBMS.
+ *
+ * @return object the DB_Error object
+ *
+ * @see DB_common::raiseError(),
+ * DB_sqlite::errorNative(), DB_sqlite::errorCode()
+ */
+ public function sqliteRaiseError($errno = null)
+ {
+ $native = $this->errorNative();
+ if ($errno === null) {
+ $errno = $this->errorCode($native);
+ }
+
+ $errorcode = @sqlite_last_error($this->connection);
+ $userinfo = "$errorcode ** $this->last_query";
+
+ return $this->raiseError($errno, null, null, $userinfo, $native);
+ }
+
+ // }}}
+ // {{{ simpleQuery()
+
+ /**
+ * Gets the DBMS' native error message produced by the last query
+ *
+ * {@internal This is used to retrieve more meaningfull error messages
+ * because sqlite_last_error() does not provide adequate info.}}
+ *
+ * @return string the DBMS' error message
+ */
+ public function errorNative()
+ {
+ return $this->_lasterror;
+ }
+
+ // }}}
+ // {{{ nextResult()
+
+ /**
+ * Determines PEAR::DB error code from the database's text error message
+ *
+ * @param string $errormsg the error message returned from the database
+ *
+ * @return integer the DB error number
+ */
+ public function errorCode($errormsg)
+ {
+ static $error_regexps;
+
+ // PHP 5.2+ prepends the function name to $php_errormsg, so we need
+ // this hack to work around it, per bug #9599.
+ $errormsg = preg_replace('/^sqlite[a-z_]+\(\): /', '', $errormsg);
+
+ if (!isset($error_regexps)) {
+ $error_regexps = array(
+ '/^no such table:/' => DB_ERROR_NOSUCHTABLE,
+ '/^no such index:/' => DB_ERROR_NOT_FOUND,
+ '/^(table|index) .* already exists$/' => DB_ERROR_ALREADY_EXISTS,
+ '/PRIMARY KEY must be unique/i' => DB_ERROR_CONSTRAINT,
+ '/is not unique/' => DB_ERROR_CONSTRAINT,
+ '/columns .* are not unique/i' => DB_ERROR_CONSTRAINT,
+ '/uniqueness constraint failed/' => DB_ERROR_CONSTRAINT,
+ '/may not be NULL/' => DB_ERROR_CONSTRAINT_NOT_NULL,
+ '/^no such column:/' => DB_ERROR_NOSUCHFIELD,
+ '/no column named/' => DB_ERROR_NOSUCHFIELD,
+ '/column not present in both tables/i' => DB_ERROR_NOSUCHFIELD,
+ '/^near ".*": syntax error$/' => DB_ERROR_SYNTAX,
+ '/[0-9]+ values for [0-9]+ columns/i' => DB_ERROR_VALUE_COUNT_ON_ROW,
+ );
+ }
+ foreach ($error_regexps as $regexp => $code) {
+ if (preg_match($regexp, $errormsg)) {
+ return $code;
+ }
+ }
+ // Fall back to DB_ERROR if there was no mapping.
+ return DB_ERROR;
+ }
+
+ // }}}
+ // {{{ fetchInto()
+
/**
* Disconnects from the database server
*
- * @return bool TRUE on success, FALSE on failure
+ * @return bool|void
*/
public function disconnect()
{
}
// }}}
- // {{{ simpleQuery()
+ // {{{ freeResult()
/**
* Sends a query to the database server
}
// }}}
- // {{{ nextResult()
+ // {{{ numCols()
+
+ /**
+ * Changes a query string for various DBMS specific reasons
+ *
+ * This little hack lets you know how many rows were deleted
+ * when running a "DELETE FROM table" query. Only implemented
+ * if the DB_PORTABILITY_DELETE_COUNT portability option is on.
+ *
+ * @param string $query the query string to modify
+ *
+ * @return string the modified query string
+ *
+ * @access protected
+ * @see DB_common::setOption()
+ */
+ public function modifyQuery($query)
+ {
+ if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) {
+ if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) {
+ $query = preg_replace(
+ '/^\s*DELETE\s+FROM\s+(\S+)\s*$/',
+ 'DELETE FROM \1 WHERE 1=1',
+ $query
+ );
+ }
+ }
+ return $query;
+ }
+
+ // }}}
+ // {{{ numRows()
+
+ /**
+ * Gets the number of rows in a result set
+ *
+ * This method is not meant to be called directly. Use
+ * DB_result::numRows() instead. It can't be declared "protected"
+ * because DB_result is a separate object.
+ *
+ * @param resource $result PHP's query result resource
+ *
+ * @return int|object
+ *
+ * @see DB_result::numRows()
+ */
+ public function numRows($result)
+ {
+ $rows = @sqlite_num_rows($result);
+ if ($rows === null) {
+ return $this->sqliteRaiseError();
+ }
+ return $rows;
+ }
+
+ // }}}
+ // {{{ affected()
/**
* Move the internal sqlite result pointer to the next available result
*
- * @param resource $result the valid sqlite result resource
+ * @param resource $result the valid sqlite result resource
*
* @return bool true if a result is available otherwise return false
*/
}
// }}}
- // {{{ fetchInto()
+ // {{{ dropSequence()
/**
* Places a row from the result set into the given array
* DB_result::fetchInto() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result the query result resource
- * @param array $arr the referenced array to put the data in
- * @param int $fetchmode how the resulting array should be indexed
- * @param int $rownum the row number to fetch (0 = first row)
+ * @param resource $result the query result resource
+ * @param array $arr the referenced array to put the data in
+ * @param int $fetchmode how the resulting array should be indexed
+ * @param int $rownum the row number to fetch (0 = first row)
*
* @return mixed DB_OK on success, NULL when the end of a result set is
* reached or on failure
return DB_OK;
}
- // }}}
- // {{{ freeResult()
-
/**
* Deletes the result set and frees the memory occupied by the result set
*
* DB_result::free() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
* @return bool TRUE on success, FALSE if $result is invalid
*
}
// }}}
- // {{{ numCols()
+ // {{{ nextId()
/**
* Gets the number of columns in a result set
* DB_result::numCols() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
- * @return int the number of columns. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_result::numCols()
*/
}
// }}}
- // {{{ numRows()
-
- /**
- * Gets the number of rows in a result set
- *
- * This method is not meant to be called directly. Use
- * DB_result::numRows() instead. It can't be declared "protected"
- * because DB_result is a separate object.
- *
- * @param resource $result PHP's query result resource
- *
- * @return int the number of rows. A DB_Error object on failure.
- *
- * @see DB_result::numRows()
- */
- public function numRows($result)
- {
- $rows = @sqlite_num_rows($result);
- if ($rows === null) {
- return $this->sqliteRaiseError();
- }
- return $rows;
- }
-
- // }}}
- // {{{ affected()
+ // {{{ getDbFileStats()
/**
* Determines the number of rows affected by a data maniuplation query
}
// }}}
- // {{{ dropSequence()
+ // {{{ escapeSimple()
/**
* Deletes a sequence
*
- * @param string $seq_name name of the sequence to be deleted
+ * @param string $seq_name name of the sequence to be deleted
*
* @return int DB_OK on success. A DB_Error object on failure.
*
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
}
- /**
- * Creates a new sequence
- *
- * @param string $seq_name name of the new sequence
- *
- * @return int DB_OK on success. A DB_Error object on failure.
- *
- * @see DB_common::createSequence(), DB_common::getSequenceName(),
- * DB_sqlite::nextID(), DB_sqlite::dropSequence()
- */
- public function createSequence($seq_name)
- {
- $seqname = $this->getSequenceName($seq_name);
- $query = 'CREATE TABLE ' . $seqname .
- ' (id INTEGER UNSIGNED PRIMARY KEY) ';
- $result = $this->query($query);
- if (DB::isError($result)) {
- return($result);
- }
- $query = "CREATE TRIGGER ${seqname}_cleanup AFTER INSERT ON $seqname
- BEGIN
- DELETE FROM $seqname WHERE id<LAST_INSERT_ROWID();
- END ";
- $result = $this->query($query);
- if (DB::isError($result)) {
- return($result);
- }
- }
-
// }}}
- // {{{ nextId()
+ // {{{ modifyLimitQuery()
/**
* Returns the next free id in a sequence
*
- * @param string $seq_name name of the sequence
- * @param boolean $ondemand when true, the seqence is automatically
+ * @param string $seq_name name of the sequence
+ * @param boolean $ondemand when true, the seqence is automatically
* created if it does not exist
*
- * @return int the next id number in the sequence.
+ * @return int|object
* A DB_Error object on failure.
*
* @see DB_common::nextID(), DB_common::getSequenceName(),
return $id;
}
} elseif ($ondemand && DB::isError($result) &&
- $result->getCode() == DB_ERROR_NOSUCHTABLE) {
+ $result->getCode() == DB_ERROR_NOSUCHTABLE) {
$result = $this->createSequence($seq_name);
if (DB::isError($result)) {
return $this->raiseError($result);
}
// }}}
- // {{{ getDbFileStats()
+ // {{{ modifyQuery()
+
+ /**
+ * Creates a new sequence
+ *
+ * @param string $seq_name name of the new sequence
+ *
+ * @return int DB_OK on success. A DB_Error object on failure.
+ *
+ * @see DB_common::createSequence(), DB_common::getSequenceName(),
+ * DB_sqlite::nextID(), DB_sqlite::dropSequence()
+ */
+ public function createSequence($seq_name)
+ {
+ $seqname = $this->getSequenceName($seq_name);
+ $query = 'CREATE TABLE ' . $seqname .
+ ' (id INTEGER UNSIGNED PRIMARY KEY) ';
+ $result = $this->query($query);
+ if (DB::isError($result)) {
+ return ($result);
+ }
+ $query = "CREATE TRIGGER ${seqname}_cleanup AFTER INSERT ON $seqname
+ BEGIN
+ DELETE FROM $seqname WHERE id<LAST_INSERT_ROWID();
+ END ";
+ $result = $this->query($query);
+ //if (DB::isError($result)) {
+ return ($result);
+ //}
+ }
+
+ // }}}
+ // {{{ sqliteRaiseError()
/**
* Get the file stats for the current database
* atime, mtime, ctime, blksize, blocks or a numeric key between
* 0 and 12.
*
- * @param string $arg the array key for stats()
+ * @param string $arg the array key for stats()
*
* @return mixed an array on an unspecified key, integer on a passed
* arg and false at a stats error
if (((int)$arg <= 12) & ((int)$arg >= 0)) {
return false;
}
- return $stats[$arg ];
+ return $stats[$arg];
}
if (array_key_exists(trim($arg), $stats)) {
- return $stats[$arg ];
+ return $stats[$arg];
}
}
return $stats;
}
// }}}
- // {{{ escapeSimple()
+ // {{{ errorNative()
/**
* Escapes a string according to the current DBMS's standards
* containing binary data. See the
* {@link http://php.net/sqlite_escape_string PHP manual} for more info.
*
- * @param string $str the string to be escaped
+ * @param string $str the string to be escaped
*
* @return string the escaped string
*
}
// }}}
- // {{{ modifyLimitQuery()
+ // {{{ errorCode()
/**
* Adds LIMIT clauses to a query string according to current DBMS standards
*
- * @param string $query the query to modify
- * @param int $from the row to start to fetching (0 = the first row)
- * @param int $count the numbers of rows to fetch
- * @param mixed $params array, string or numeric data to be used in
+ * @param string $query the query to modify
+ * @param int $from the row to start to fetching (0 = the first row)
+ * @param int $count the numbers of rows to fetch
+ * @param mixed $params array, string or numeric data to be used in
* execution of the statement. Quantity of items
* passed must match quantity of placeholders in
* query: meaning 1 placeholder for non-array
return "$query LIMIT $count OFFSET $from";
}
- // }}}
- // {{{ modifyQuery()
-
- /**
- * Changes a query string for various DBMS specific reasons
- *
- * This little hack lets you know how many rows were deleted
- * when running a "DELETE FROM table" query. Only implemented
- * if the DB_PORTABILITY_DELETE_COUNT portability option is on.
- *
- * @param string $query the query string to modify
- *
- * @return string the modified query string
- *
- * @access protected
- * @see DB_common::setOption()
- */
- public function modifyQuery($query)
- {
- if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) {
- if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) {
- $query = preg_replace(
- '/^\s*DELETE\s+FROM\s+(\S+)\s*$/',
- 'DELETE FROM \1 WHERE 1=1',
- $query
- );
- }
- }
- return $query;
- }
-
- // }}}
- // {{{ sqliteRaiseError()
-
- /**
- * Produces a DB_Error object regarding the current problem
- *
- * @param int $errno if the error is being manually raised pass a
- * DB_ERROR* constant here. If this isn't passed
- * the error information gathered from the DBMS.
- *
- * @return object the DB_Error object
- *
- * @see DB_common::raiseError(),
- * DB_sqlite::errorNative(), DB_sqlite::errorCode()
- */
- public function sqliteRaiseError($errno = null)
- {
- $native = $this->errorNative();
- if ($errno === null) {
- $errno = $this->errorCode($native);
- }
-
- $errorcode = @sqlite_last_error($this->connection);
- $userinfo = "$errorcode ** $this->last_query";
-
- return $this->raiseError($errno, null, null, $userinfo, $native);
- }
-
- // }}}
- // {{{ errorNative()
-
- /**
- * Gets the DBMS' native error message produced by the last query
- *
- * {@internal This is used to retrieve more meaningfull error messages
- * because sqlite_last_error() does not provide adequate info.}}
- *
- * @return string the DBMS' error message
- */
- public function errorNative()
- {
- return $this->_lasterror;
- }
-
- // }}}
- // {{{ errorCode()
-
- /**
- * Determines PEAR::DB error code from the database's text error message
- *
- * @param string $errormsg the error message returned from the database
- *
- * @return integer the DB error number
- */
- public function errorCode($errormsg)
- {
- static $error_regexps;
-
- // PHP 5.2+ prepends the function name to $php_errormsg, so we need
- // this hack to work around it, per bug #9599.
- $errormsg = preg_replace('/^sqlite[a-z_]+\(\): /', '', $errormsg);
-
- if (!isset($error_regexps)) {
- $error_regexps = array(
- '/^no such table:/' => DB_ERROR_NOSUCHTABLE,
- '/^no such index:/' => DB_ERROR_NOT_FOUND,
- '/^(table|index) .* already exists$/' => DB_ERROR_ALREADY_EXISTS,
- '/PRIMARY KEY must be unique/i' => DB_ERROR_CONSTRAINT,
- '/is not unique/' => DB_ERROR_CONSTRAINT,
- '/columns .* are not unique/i' => DB_ERROR_CONSTRAINT,
- '/uniqueness constraint failed/' => DB_ERROR_CONSTRAINT,
- '/may not be NULL/' => DB_ERROR_CONSTRAINT_NOT_NULL,
- '/^no such column:/' => DB_ERROR_NOSUCHFIELD,
- '/no column named/' => DB_ERROR_NOSUCHFIELD,
- '/column not present in both tables/i' => DB_ERROR_NOSUCHFIELD,
- '/^near ".*": syntax error$/' => DB_ERROR_SYNTAX,
- '/[0-9]+ values for [0-9]+ columns/i' => DB_ERROR_VALUE_COUNT_ON_ROW,
- );
- }
- foreach ($error_regexps as $regexp => $code) {
- if (preg_match($regexp, $errormsg)) {
- return $code;
- }
- }
- // Fall back to DB_ERROR if there was no mapping.
- return DB_ERROR;
- }
-
// }}}
// {{{ tableInfo()
/**
* Returns information about a table
*
- * @param string $result a string containing the name of a table
- * @param int $mode a valid tableInfo mode
+ * @param string $result a string containing the name of a table
+ * @param int $mode a valid tableInfo mode
*
- * @return array an associative array with the information requested.
+ * @return array|object
* A DB_Error object on failure.
*
* @see DB_common::tableInfo()
null,
null,
'This DBMS can not obtain tableInfo' .
- ' from result sets'
+ ' from result sets'
);
}
}
$count = count($id);
- $res = array();
+ $res = array();
if ($mode) {
$res['num_fields'] = $count;
if (strpos($id[$i]['type'], '(') !== false) {
$bits = explode('(', $id[$i]['type']);
$type = $bits[0];
- $len = rtrim($bits[1], ')');
+ $len = rtrim($bits[1], ')');
} else {
$type = $id[$i]['type'];
- $len = 0;
+ $len = 0;
}
$flags = '';
$res[$i] = array(
'table' => $case_func($result),
- 'name' => $case_func($id[$i]['name']),
- 'type' => $type,
- 'len' => $len,
+ 'name' => $case_func($id[$i]['name']),
+ 'type' => $type,
+ 'len' => $len,
'flags' => $flags,
);
/**
* Obtains the query string needed for listing a given type of objects
*
- * @param string $type the kind of objects you want to retrieve
- * @param array $args SQLITE DRIVER ONLY: a private array of arguments
+ * @param string $type the kind of objects you want to retrieve
+ * @param array $args SQLITE DRIVER ONLY: a private array of arguments
* used by the getSpecialQuery(). Do not use
* this directly.
*
return 'SELECT * FROM sqlite_master;';
case 'tables':
return "SELECT name FROM sqlite_master WHERE type='table' "
- . 'UNION ALL SELECT name FROM sqlite_temp_master '
- . "WHERE type='table' ORDER BY name;";
+ . 'UNION ALL SELECT name FROM sqlite_temp_master '
+ . "WHERE type='table' ORDER BY name;";
case 'schema':
return 'SELECT sql FROM (SELECT * FROM sqlite_master '
- . 'UNION ALL SELECT * FROM sqlite_temp_master) '
- . "WHERE type!='meta' "
- . 'ORDER BY tbl_name, type DESC, name;';
+ . 'UNION ALL SELECT * FROM sqlite_temp_master) '
+ . "WHERE type!='meta' "
+ . 'ORDER BY tbl_name, type DESC, name;';
case 'schemax':
case 'schema_x':
/*
* array('table' => 'table3')));
*/
return 'SELECT sql FROM (SELECT * FROM sqlite_master '
- . 'UNION ALL SELECT * FROM sqlite_temp_master) '
- . "WHERE tbl_name LIKE '{$args['table']}' "
- . "AND type!='meta' "
- . 'ORDER BY type DESC, name;';
+ . 'UNION ALL SELECT * FROM sqlite_temp_master) '
+ . "WHERE tbl_name LIKE '{$args['table']}' "
+ . "AND type!='meta' "
+ . 'ORDER BY type DESC, name;';
case 'alter':
/*
* SQLite does not support ALTER TABLE; this is a helper query
// {{{ properties
/** the name of the table (or view, if the backend database supports
- updates in views) we hold data from */
+ * updates in views) we hold data from */
public $_table = null;
/** which column(s) in the table contains primary keys, can be a
- string for single-column primary keys, or an array of strings
- for multiple-column primary keys */
+ * string for single-column primary keys, or an array of strings
+ * for multiple-column primary keys */
public $_keycolumn = null;
/** DB connection handle used for all transactions */
public $_dbh = null;
/** an assoc with the names of database fields stored as properties
- in this object */
+ * in this object */
public $_properties = array();
/** an assoc with the names of the properties in this object that
- have been changed since they were fetched from the database */
+ * have been changed since they were fetched from the database */
public $_changes = array();
/** flag that decides if data in this object can be changed.
- objects that don't have their table's key column in their
- property lists will be flagged as read-only. */
+ * objects that don't have their table's key column in their
+ * property lists will be flagged as read-only. */
public $_readonly = false;
/** function or method that implements a validator for fields that
- are set, this validator function returns true if the field is
- valid, false if not */
+ * are set, this validator function returns true if the field is
+ * valid, false if not */
public $_validator = null;
// }}}
// {{{ _makeWhere()
/**
- * Utility method to build a "WHERE" clause to locate ourselves in
- * the table.
- *
- * XXX future improvement: use rowids?
- *
- * @access private
+ * Create a new (empty) row in the configured table for this
+ * object.
+ * @param $newpk
+ * @return |null
*/
- public function _makeWhere($keyval = null)
+ public function insert($newpk)
{
if (is_array($this->_keycolumn)) {
- if ($keyval === null) {
- for ($i = 0; $i < sizeof($this->_keycolumn); $i++) {
- $keyval[] = $this->{$this->_keycolumn[$i]};
- }
- }
- $whereclause = '';
- for ($i = 0; $i < sizeof($this->_keycolumn); $i++) {
- if ($i > 0) {
- $whereclause .= ' AND ';
- }
- $whereclause .= $this->_keycolumn[$i];
- if (is_null($keyval[$i])) {
- // there's not much point in having a NULL key,
- // but we support it anyway
- $whereclause .= ' IS NULL';
- } else {
- $whereclause .= ' = ' . $this->_dbh->quote($keyval[$i]);
- }
- }
+ $primarykey = $this->_keycolumn;
} else {
- if ($keyval === null) {
- $keyval = @$this->{$this->_keycolumn};
- }
- $whereclause = $this->_keycolumn;
- if (is_null($keyval)) {
- // there's not much point in having a NULL key,
- // but we support it anyway
- $whereclause .= ' IS NULL';
- } else {
- $whereclause .= ' = ' . $this->_dbh->quote($keyval);
- }
+ $primarykey = array($this->_keycolumn);
}
- return $whereclause;
+ settype($newpk, "array");
+ for ($i = 0; $i < sizeof($primarykey); $i++) {
+ $pkvals[] = $this->_dbh->quote($newpk[$i]);
+ }
+
+ $sth = $this->_dbh->query("INSERT INTO $this->_table (" .
+ implode(",", $primarykey) . ") VALUES(" .
+ implode(",", $pkvals) . ")");
+ if (DB::isError($sth)) {
+ return $sth;
+ }
+ if (sizeof($newpk) == 1) {
+ $newpk = $newpk[0];
+ }
+ $this->setup($newpk);
+ return null;
}
// }}}
*
* @param $keyval mixed the key[s] of the row to fetch (string or array)
*
- * @return int DB_OK on success, a DB error if not
+ * @return int|object
*/
public function setup($keyval)
{
// {{{ insert()
/**
- * Create a new (empty) row in the configured table for this
- * object.
+ * Utility method to build a "WHERE" clause to locate ourselves in
+ * the table.
+ *
+ * XXX future improvement: use rowids?
+ *
+ * @access private
+ * @param null $keyval
+ * @return mixed|string|null
*/
- public function insert($newpk)
+ public function _makeWhere($keyval = null)
{
if (is_array($this->_keycolumn)) {
- $primarykey = $this->_keycolumn;
+ if ($keyval === null) {
+ for ($i = 0; $i < sizeof($this->_keycolumn); $i++) {
+ $keyval[] = $this->{$this->_keycolumn[$i]};
+ }
+ }
+ $whereclause = '';
+ for ($i = 0; $i < sizeof($this->_keycolumn); $i++) {
+ if ($i > 0) {
+ $whereclause .= ' AND ';
+ }
+ $whereclause .= $this->_keycolumn[$i];
+ if (is_null($keyval[$i])) {
+ // there's not much point in having a NULL key,
+ // but we support it anyway
+ $whereclause .= ' IS NULL';
+ } else {
+ $whereclause .= ' = ' . $this->_dbh->quote($keyval[$i]);
+ }
+ }
} else {
- $primarykey = array($this->_keycolumn);
- }
- settype($newpk, "array");
- for ($i = 0; $i < sizeof($primarykey); $i++) {
- $pkvals[] = $this->_dbh->quote($newpk[$i]);
- }
-
- $sth = $this->_dbh->query("INSERT INTO $this->_table (" .
- implode(",", $primarykey) . ") VALUES(" .
- implode(",", $pkvals) . ")");
- if (DB::isError($sth)) {
- return $sth;
- }
- if (sizeof($newpk) == 1) {
- $newpk = $newpk[0];
+ if ($keyval === null) {
+ $keyval = @$this->{$this->_keycolumn};
+ }
+ $whereclause = $this->_keycolumn;
+ if (is_null($keyval)) {
+ // there's not much point in having a NULL key,
+ // but we support it anyway
+ $whereclause .= ' IS NULL';
+ } else {
+ $whereclause .= ' = ' . $this->_dbh->quote($keyval);
+ }
}
- $this->setup($newpk);
+ return $whereclause;
}
// }}}
/**
* Static method used to create new DB storage objects.
+ * @param $table
* @param $data assoc. array where the keys are the names
* of properties/columns
* @return object a new instance of DB_storage or a subclass of it
/**
* Modify an attriute value.
+ * @param $property
+ * @param $newvalue
+ * @return bool|object
*/
public function set($property, $newvalue)
{
/**
* Stores changes to this object in the database.
*
- * @return DB_OK or a DB error
+ * @return DB_OK|int
*/
public function store()
{
true
);
}
- $query = 'DELETE FROM ' . $this->_table .' WHERE '.
+ $query = 'DELETE FROM ' . $this->_table . ' WHERE ' .
$this->_makeWhere();
$res = $this->_dbh->query($query);
if (DB::isError($res)) {
* @category Database
* @package DB
* @author Sterling Hughes <sterling@php.net>
- * @author Antônio Carlos Venâncio Júnior <floripa@php.net>
+ * @author Ant�nio Carlos Ven�ncio J�nior <floripa@php.net>
* @author Daniel Convissor <danielc@php.net>
* @copyright 1997-2007 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
/**
* Obtain the DB_common class so it can be extended from
*/
-require_once 'DB/common.php';
+//require_once 'DB/common.php';
+require_once 'common.php';
/**
* The methods PEAR DB uses to interact with PHP's sybase extension
* @category Database
* @package DB
* @author Sterling Hughes <sterling@php.net>
- * @author Antônio Carlos Venâncio Júnior <floripa@php.net>
+ * @author Ant�nio Carlos Ven�ncio J�nior <floripa@php.net>
* @author Daniel Convissor <danielc@php.net>
* @copyright 1997-2007 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @var array
*/
public $features = array(
- 'limit' => 'emulate',
- 'new_link' => false,
- 'numrows' => true,
- 'pconnect' => true,
- 'prepare' => false,
- 'ssl' => false,
- 'transactions' => true,
+ 'limit' => 'emulate',
+ 'new_link' => false,
+ 'numrows' => true,
+ 'pconnect' => true,
+ 'prepare' => false,
+ 'ssl' => false,
+ 'transactions' => true,
);
/**
* A mapping of native error codes to DB error codes
* @var array
*/
- public $errorcode_map = array(
- );
+ public $errorcode_map = array();
/**
* The raw database connection created by PHP
* + charset The character set to use on this connection.
* Available since PEAR DB 1.7.0.
*
- * @param array $dsn the data source name
- * @param bool $persistent should the connection be persistent?
+ * @param array $dsn the data source name
+ * @param bool $persistent should the connection be persistent?
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function connect($dsn, $persistent = false)
{
// }}}
// {{{ nextResult()
+ /**
+ * Produces a DB_Error object regarding the current problem
+ *
+ * @param int $errno if the error is being manually raised pass a
+ * DB_ERROR* constant here. If this isn't passed
+ * the error information gathered from the DBMS.
+ *
+ * @return object the DB_Error object
+ *
+ * @see DB_common::raiseError(),
+ * DB_sybase::errorNative(), DB_sybase::errorCode()
+ */
+ public function sybaseRaiseError($errno = null)
+ {
+ $native = $this->errorNative();
+ if ($errno === null) {
+ $errno = $this->errorCode($native);
+ }
+ return $this->raiseError($errno, null, null, null, $native);
+ }
+
+ // }}}
+ // {{{ fetchInto()
+
+ /**
+ * Gets the DBMS' native error message produced by the last query
+ *
+ * @return string the DBMS' error message
+ */
+ public function errorNative()
+ {
+ return @sybase_get_last_message();
+ }
+
+ // }}}
+ // {{{ freeResult()
+
+ /**
+ * Determines PEAR::DB error code from the database's text error message.
+ *
+ * @param string $errormsg error message returned from the database
+ * @return integer an error number from a DB error constant
+ */
+ public function errorCode($errormsg)
+ {
+ static $error_regexps;
+
+ // PHP 5.2+ prepends the function name to $php_errormsg, so we need
+ // this hack to work around it, per bug #9599.
+ $errormsg = preg_replace('/^sybase[a-z_]+\(\): /', '', $errormsg);
+
+ if (!isset($error_regexps)) {
+ $error_regexps = array(
+ '/Incorrect syntax near/'
+ => DB_ERROR_SYNTAX,
+ '/^Unclosed quote before the character string [\"\'].*[\"\']\./'
+ => DB_ERROR_SYNTAX,
+ '/Implicit conversion (from datatype|of NUMERIC value)/i'
+ => DB_ERROR_INVALID_NUMBER,
+ '/Cannot drop the table [\"\'].+[\"\'], because it doesn\'t exist in the system catalogs\./'
+ => DB_ERROR_NOSUCHTABLE,
+ '/Only the owner of object [\"\'].+[\"\'] or a user with System Administrator \(SA\) role can run this command\./'
+ => DB_ERROR_ACCESS_VIOLATION,
+ '/^.+ permission denied on object .+, database .+, owner .+/'
+ => DB_ERROR_ACCESS_VIOLATION,
+ '/^.* permission denied, database .+, owner .+/'
+ => DB_ERROR_ACCESS_VIOLATION,
+ '/[^.*] not found\./'
+ => DB_ERROR_NOSUCHTABLE,
+ '/There is already an object named/'
+ => DB_ERROR_ALREADY_EXISTS,
+ '/Invalid column name/'
+ => DB_ERROR_NOSUCHFIELD,
+ '/does not allow null values/'
+ => DB_ERROR_CONSTRAINT_NOT_NULL,
+ '/Command has been aborted/'
+ => DB_ERROR_CONSTRAINT,
+ '/^Cannot drop the index .* because it doesn\'t exist/i'
+ => DB_ERROR_NOT_FOUND,
+ '/^There is already an index/i'
+ => DB_ERROR_ALREADY_EXISTS,
+ '/^There are fewer columns in the INSERT statement than values specified/i'
+ => DB_ERROR_VALUE_COUNT_ON_ROW,
+ '/Divide by zero/i'
+ => DB_ERROR_DIVZERO,
+ );
+ }
+
+ foreach ($error_regexps as $regexp => $code) {
+ if (preg_match($regexp, $errormsg)) {
+ return $code;
+ }
+ }
+ return DB_ERROR;
+ }
+
+ // }}}
+ // {{{ numCols()
+
/**
* Move the internal sybase result pointer to the next available result
*
}
// }}}
- // {{{ fetchInto()
+ // {{{ numRows()
/**
* Places a row from the result set into the given array
* DB_result::fetchInto() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result the query result resource
- * @param array $arr the referenced array to put the data in
- * @param int $fetchmode how the resulting array should be indexed
- * @param int $rownum the row number to fetch (0 = first row)
+ * @param resource $result the query result resource
+ * @param array $arr the referenced array to put the data in
+ * @param int $fetchmode how the resulting array should be indexed
+ * @param int $rownum the row number to fetch (0 = first row)
*
* @return mixed DB_OK on success, NULL when the end of a result set is
* reached or on failure
}
// }}}
- // {{{ freeResult()
+ // {{{ affectedRows()
/**
* Deletes the result set and frees the memory occupied by the result set
* DB_result::free() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
* @return bool TRUE on success, FALSE if $result is invalid
*
}
// }}}
- // {{{ numCols()
+ // {{{ nextId()
/**
* Gets the number of columns in a result set
* DB_result::numCols() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
- * @return int the number of columns. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_result::numCols()
*/
return $cols;
}
- // }}}
- // {{{ numRows()
-
/**
* Gets the number of rows in a result set
*
* DB_result::numRows() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
- * @param resource $result PHP's query result resource
+ * @param resource $result PHP's query result resource
*
- * @return int the number of rows. A DB_Error object on failure.
+ * @return int|object
*
* @see DB_result::numRows()
*/
}
// }}}
- // {{{ affectedRows()
+ // {{{ dropSequence()
/**
* Determines the number of rows affected by a data maniuplation query
}
// }}}
- // {{{ nextId()
+ // {{{ quoteFloat()
/**
* Returns the next free id in a sequence
*
- * @param string $seq_name name of the sequence
- * @param boolean $ondemand when true, the seqence is automatically
+ * @param string $seq_name name of the sequence
+ * @param boolean $ondemand when true, the seqence is automatically
* created if it does not exist
*
- * @return int the next id number in the sequence.
+ * @return int|object
* A DB_Error object on failure.
*
* @see DB_common::nextID(), DB_common::getSequenceName(),
return $result[0];
}
+ // }}}
+ // {{{ autoCommit()
+
/**
* Creates a new sequence
*
- * @param string $seq_name name of the new sequence
+ * @param string $seq_name name of the new sequence
*
* @return int DB_OK on success. A DB_Error object on failure.
*
public function createSequence($seq_name)
{
return $this->query('CREATE TABLE '
- . $this->getSequenceName($seq_name)
- . ' (id numeric(10, 0) IDENTITY NOT NULL,'
- . ' vapor int NULL)');
+ . $this->getSequenceName($seq_name)
+ . ' (id numeric(10, 0) IDENTITY NOT NULL,'
+ . ' vapor int NULL)');
}
// }}}
- // {{{ dropSequence()
+ // {{{ commit()
/**
* Deletes a sequence
*
- * @param string $seq_name name of the sequence to be deleted
+ * @param string $seq_name name of the sequence to be deleted
*
* @return int DB_OK on success. A DB_Error object on failure.
*
}
// }}}
- // {{{ quoteFloat()
+ // {{{ rollback()
/**
* Formats a float value for use within a query in a locale-independent
{
return $this->escapeSimple(str_replace(',', '.', strval(floatval($float))));
}
-
+
// }}}
- // {{{ autoCommit()
+ // {{{ sybaseRaiseError()
/**
* Enables or disables automatic commits
*
- * @param bool $onoff true turns it on, false turns it off
+ * @param bool $onoff true turns it on, false turns it off
*
* @return int DB_OK on success. A DB_Error object if the driver
* doesn't support auto-committing transactions.
}
// }}}
- // {{{ commit()
+ // {{{ errorNative()
/**
* Commits the current transaction
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function commit()
{
}
// }}}
- // {{{ rollback()
+ // {{{ errorCode()
/**
* Reverts the current transaction
*
- * @return int DB_OK on success. A DB_Error object on failure.
+ * @return int|object
*/
public function rollback()
{
return DB_OK;
}
- // }}}
- // {{{ sybaseRaiseError()
-
- /**
- * Produces a DB_Error object regarding the current problem
- *
- * @param int $errno if the error is being manually raised pass a
- * DB_ERROR* constant here. If this isn't passed
- * the error information gathered from the DBMS.
- *
- * @return object the DB_Error object
- *
- * @see DB_common::raiseError(),
- * DB_sybase::errorNative(), DB_sybase::errorCode()
- */
- public function sybaseRaiseError($errno = null)
- {
- $native = $this->errorNative();
- if ($errno === null) {
- $errno = $this->errorCode($native);
- }
- return $this->raiseError($errno, null, null, null, $native);
- }
-
- // }}}
- // {{{ errorNative()
-
- /**
- * Gets the DBMS' native error message produced by the last query
- *
- * @return string the DBMS' error message
- */
- public function errorNative()
- {
- return @sybase_get_last_message();
- }
-
- // }}}
- // {{{ errorCode()
-
- /**
- * Determines PEAR::DB error code from the database's text error message.
- *
- * @param string $errormsg error message returned from the database
- * @return integer an error number from a DB error constant
- */
- public function errorCode($errormsg)
- {
- static $error_regexps;
-
- // PHP 5.2+ prepends the function name to $php_errormsg, so we need
- // this hack to work around it, per bug #9599.
- $errormsg = preg_replace('/^sybase[a-z_]+\(\): /', '', $errormsg);
-
- if (!isset($error_regexps)) {
- $error_regexps = array(
- '/Incorrect syntax near/'
- => DB_ERROR_SYNTAX,
- '/^Unclosed quote before the character string [\"\'].*[\"\']\./'
- => DB_ERROR_SYNTAX,
- '/Implicit conversion (from datatype|of NUMERIC value)/i'
- => DB_ERROR_INVALID_NUMBER,
- '/Cannot drop the table [\"\'].+[\"\'], because it doesn\'t exist in the system catalogs\./'
- => DB_ERROR_NOSUCHTABLE,
- '/Only the owner of object [\"\'].+[\"\'] or a user with System Administrator \(SA\) role can run this command\./'
- => DB_ERROR_ACCESS_VIOLATION,
- '/^.+ permission denied on object .+, database .+, owner .+/'
- => DB_ERROR_ACCESS_VIOLATION,
- '/^.* permission denied, database .+, owner .+/'
- => DB_ERROR_ACCESS_VIOLATION,
- '/[^.*] not found\./'
- => DB_ERROR_NOSUCHTABLE,
- '/There is already an object named/'
- => DB_ERROR_ALREADY_EXISTS,
- '/Invalid column name/'
- => DB_ERROR_NOSUCHFIELD,
- '/does not allow null values/'
- => DB_ERROR_CONSTRAINT_NOT_NULL,
- '/Command has been aborted/'
- => DB_ERROR_CONSTRAINT,
- '/^Cannot drop the index .* because it doesn\'t exist/i'
- => DB_ERROR_NOT_FOUND,
- '/^There is already an index/i'
- => DB_ERROR_ALREADY_EXISTS,
- '/^There are fewer columns in the INSERT statement than values specified/i'
- => DB_ERROR_VALUE_COUNT_ON_ROW,
- '/Divide by zero/i'
- => DB_ERROR_DIVZERO,
- );
- }
-
- foreach ($error_regexps as $regexp => $code) {
- if (preg_match($regexp, $errormsg)) {
- return $code;
- }
- }
- return DB_ERROR;
- }
-
// }}}
// {{{ tableInfo()
* NOTE: only supports 'table' and 'flags' if <var>$result</var>
* is a table name.
*
- * @param object|string $result DB_result object from a query or a
+ * @param object|string $result DB_result object from a query or a
* string containing the name of a table.
* While this also accepts a query result
* resource identifier, this behavior is
* deprecated.
- * @param int $mode a valid tableInfo mode
+ * @param int $mode a valid tableInfo mode
*
- * @return array an associative array with the information requested.
+ * @return array|object
* A DB_Error object on failure.
*
* @see DB_common::tableInfo()
}
$count = @sybase_num_fields($id);
- $res = array();
+ $res = array();
if ($mode) {
$res['num_fields'] = $count;
// column_source is often blank
$res[$i] = array(
'table' => $got_string
- ? $case_func($result)
- : $case_func($f->column_source),
- 'name' => $case_func($f->name),
- 'type' => $f->type,
- 'len' => $f->max_length,
+ ? $case_func($result)
+ : $case_func($f->column_source),
+ 'name' => $case_func($f->name),
+ 'type' => $f->type,
+ 'len' => $f->max_length,
'flags' => '',
);
if ($res[$i]['table']) {
* + <samp>unique_key</samp> (unique index, unique check or primary_key)
* + <samp>multiple_key</samp> (multi-key index)
*
- * @param string $table the table name
- * @param string $column the field name
+ * @param string $table the table name
+ * @param string $column the field name
*
* @return string space delimited string of flags. Empty string if none.
*
}
if (array_key_exists($column, $flags)) {
- return(implode(' ', $flags[$column]));
+ return (implode(' ', $flags[$column]));
}
return '';
* Adds a string to the flags array if the flag is not yet in there
* - if there is no flag present the array is created
*
- * @param array $array reference of flags array to add a value to
- * @param mixed $value value to add to the flag array
+ * @param array $array reference of flags array to add a value to
+ * @param mixed $value value to add to the flag array
*
* @return void
*
/**
* Obtains the query string needed for listing a given type of objects
*
- * @param string $type the kind of objects you want to retrieve
+ * @param string $type the kind of objects you want to retrieve
*
* @return string the SQL query string or null if the driver doesn't
* support the object type requested
switch ($type) {
case 'tables':
return "SELECT name FROM sysobjects WHERE type = 'U'"
- . ' ORDER BY name';
+ . ' ORDER BY name';
case 'views':
return "SELECT name FROM sysobjects WHERE type = 'V'";
default: