diff options
Diffstat (limited to 'devel-utf8/it_dbi.class')
-rw-r--r-- | devel-utf8/it_dbi.class | 860 |
1 files changed, 0 insertions, 860 deletions
diff --git a/devel-utf8/it_dbi.class b/devel-utf8/it_dbi.class deleted file mode 100644 index ba0606c..0000000 --- a/devel-utf8/it_dbi.class +++ /dev/null @@ -1,860 +0,0 @@ -<?php -/* -** $Id$ -** -** Copyright (C) 1995-2007 by the ITools Authors. -** This file is part of ITools - the Internet Tools Library -** -** ITools is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 3 of the License, or -** (at your option) any later version. -** -** ITools is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program. If not, see <http://www.gnu.org/licenses/>. -** -** dbi.class - UltraFlexible Database Interface 3000 -*/ - -class it_dbi -{ - # Default configuration of dbi class - var $_defaultconfig = array - ( - 'db' => null, - 'server' => "localhost", - 'server_update' => null, - 'user' => "itools", - 'pw' => "", - 'safety' => 1, # 0= never die, 1=die if query invalid, 2=die also if no results - #'keyfield' => 'ID', # Don't set to null here, filled later by _get_field_info() - #'charset' => # client charset (requires MySQL 5.0.7 or later) - 'classprefix' => "", - 'getfieldinfo' => true, # do not read schema. only select() allowed - 'localized_defaultlanguage' => "de", # Localize fields with this suffix, e.g. copy title_de to title on read - ); - - var $_key; # Key of currently loaded record or null (public readonly) - var $_fields; # Array of name => array(Field,Type,Null,Key,Default,Extra,Length) of fields (public readonly) - var $_convertfunc; # Array of name => convert function (currently intval and floatval) for this field's values - var $_link; # DB link identifier (private) - - -/** - * Constructor: Initialize the DBI interface - * @param $p optional array(key => value) of configuration data - * @param $query Optional initial query to run - */ -function it_dbi($p = array(), $query = null) -{ - # Shortcut: String config means use this table with default values - if (!is_array($p)) - $p = array('table' => $p); - - if ($p['home']) - $p['db'] = strtr(it::match('/www/([^/]*)', $p['home']), '.-', '__'); - - # If the global singleton defaults are for this db/server/server_update then use them. - $dp = (array)$GLOBALS['it_dbi']->_p; - if ((!isset($p['db']) || ($p['db'] == $dp['db'])) && (!isset($p['server']) || ($p['server'] == $dp['server'])) && (!isset($p['server_update']) || ($p['server_update'] == $dp['server_update']))) - $p += $dp; - - # Combine our settings with user's defaults and class defaults - $p += (array)$GLOBALS['it_dbi_defaultconfig'] + array('db' => $GLOBALS['ULTRADB']) + $this->_defaultconfig + array('charset' => strtr(strtolower(ini_get('default_charset')), array('iso-8859-1' => 'latin1', 'utf-8' => 'utf8'))); - unset($this->_defaultconfig); # to shorten ED() output - - $this->_p = $p; - - if ($p['table']) # Standard use: create a table object - { - if (!isset($GLOBALS['it_dbi'])) - new it_dbi; - - if ($p['getfieldinfo']) - $this->_p += $this->_get_field_info(); # Get $this->_fields and p[keyfield, autoincrement, randomid] - - if (is_array($query)) - { - # Call with all arguments except first one - $args = func_get_args(); - array_shift($args); - call_user_func_array(array($this, "select"), $args); - } - elseif (isset($query)) - $this->read($query); - } - else - $GLOBALS['it_dbi'] =& $this; -} - -/** - * function Tablename($query) - * Constructor. Returns record object from table Tablename. - * If $query is set, it encodes a SELECT to execute and store in the returned object, see select() - * Note: Old second parameter $config has been deprecated and will be removed - */ #:} - -/** - * Factory: Create classes of all database tables. Call statically. - * @param $p array(key => value) of configuration data - */ -function createclasses($p = array()) -{ - # Make sure singleton exists - $dbi = $GLOBALS['it_dbi'] ? $GLOBALS['it_dbi'] : new it_dbi($p); - - $p += $dbi->_p; - - $dbid = "{$p['user']}@{$p['server']}:{$p['db']}"; - $state = it_dbi::_state_get($dbid); - - if (!$tables = $state['tables']) - { - for ($tables = array(), $res = $dbi->query('SHOW TABLES', $p); $row = mysql_fetch_row($res);) - $tables[] = $row[0]; - - $state = it_dbi::_state_get($dbid); # State could have been modified by query above - $state['tables'] = $tables; - it_dbi::_state_put($dbid, $state); - } - - foreach ($tables as $table) - { - # Either create class in autoloader or manually just below - if (!class_exists($p['classprefix'] . $table)) - it_dbi::createclass(array('table' => $table) + $p); - } -} - - -/** - * Convert table given by name into a class - */ -function createclass($p) -{ - # Shortcut: String config means use this table with default values - if (!is_array($p)) - $p = array('table' => $p); - - # Make sure singleton exists - $dbi = $GLOBALS['it_dbi'] ? $GLOBALS['it_dbi'] : new it_dbi(array('table' => null) + $p); - $p += $dbi->_p; # FIXME: (has to be checked for side effects!) - $dbid = "{$p['user']}@{$p['server']}:{$p['db']}"; - - if (!isset($dbi->_tables[$dbid])) - { - $state = it_dbi::_state_get($dbid); - $dbi->_tables[$dbid] = array(); - - if (!($tables = $state['tables'])) - { - for ($tables = array(), $res = $dbi->query('SHOW TABLES', $p); $row = mysql_fetch_row($res);) - $tables[] = $row[0]; - - $state = it_dbi::_state_get($dbid); # State could have been modified by query above - $state['tables'] = $tables; - it_dbi::_state_put($dbid, $state); - } - - foreach ($tables as $table) - $dbi->_tables[$dbid][$table] = true; - } - - if ($p['forcecreate'] || $dbi->_tables[$dbid][$p['table']]) # Do not generate classes for non-existant tables (can be overridden by forcecreate => true, used in tests/it_dbi.t) - { - $classname = $p['classprefix'] . $p['table']; - - if (substr($classname, 0, 4) != 'PMA_') # It is designed behaviour that an error is generated if this class already exists! - { - $interface = function_exists("interface_exists") && interface_exists("Iterator", false) ? "implements Iterator" : ""; - $code = "class $classname extends it_dbi $interface - { - function $classname(/* \$query ... */) - { - \$args = func_get_args(); - \$query = array_shift(\$args); # Preserve type (scalar/array) in single parameter case - - foreach (\$args as \$arg) - \$query = array_merge((array)\$query, (array)\$arg); - - \$this->it_dbi(" . var_export($p, true) . ", \$query); - } - }"; - - debug("it_dbi::createclass('{$p['table']}'): creating class $classname, dbid=$dbid", 5); - eval($code); - } - } -} - - -/** - * INTERNAL: Connect to mysql server and maintain a global link cache - */ -function _connect($p = array()) -{ - $p += $this->_p; - $dbid = "{$p['user']}@{$p['server']}:{$p['db']}"; - $state = it_dbi::_state_get($dbid); - - if ($p['reconnect'] || !($this->_link = $state['link'])) - { - # Force new link if same server/user was seen before (mysql ignores selected db) - if ($GLOBALS['it_dbi']->_connected["{$p['server']}/{$p['user']}"]++) - $this->_link = @mysql_connect($p['server'], $p['user'], $p['pw'], true); - else - $this->_link = @mysql_connect($p['server'], $p['user'], $p['pw']); - - if (!$this->_link) - { - # One retry after a short delay - it::log('sqllog', "it_dbi(): retrying DB link (mysql_connect {$p['server']}, {$p['db']}): " . mysql_error()); - sleep(1); - $this->_link = @mysql_connect($p['server'], $p['user'], $p['pw'], true); - } - - if (!$this->_link) - $this->_fatal("_connect(): can't create DB link (mysql_connect {$p['user']}@{$p['server']}, {$p['db']})"); - - if (!(@mysql_select_db($p['db'], $this->_link))) - $this->_fatal("_connect(): can't select database \"{$p['db']}\""); - - # set charset used for this connection - if ($p['charset']) - if (!mysql_set_charset($p['charset'], $this->_link)) - $this->_fatal("_connect(): can't set charset \"{$p['charset']}\""); - - # NOTE: This overwrites old state but that is on purpose. New link means we should refetch all info about connection - $state['link'] = $this->_link; - it_dbi::_state_put($dbid, $state, false); # Store only locally as link is not shared anyway - } -} - - -/** - * INTERNAL: construct SQL SET clause of changed values from member vars and tags array. - */ -function _set($tags, $allfields = false) -{ - $r = array(); - foreach((array)$tags as $field => $value) - { - if (substr($field, 0, 1) == '-') # Unquoted value (always added) - $r[] = substr($field, 1)."=$value"; - else if ($allfields || ($value !== $this->_data[$field])) - $r[] = "`$field`=".(isset($value) ? $this->escape_string($value) : 'NULL'); - } - - return $r ? 'SET '.implode(', ', $r) : ''; -} - - -/** - * Create an SQL query (the stuff after 'WHERE') according to an array of selection criteria. - * - * Example: - * $sql = $table->_where(array('Type' => 'bar', - * 'Date >=' => '1999-01-01', '-Date <' => 'NOW()', - * 'User NI' => 'chris'), 'ORDER BY Date'); - * - * @param $params optional array of fieldname => value tupels. These are ANDed to form a WHERE clause. - * fieldname can contain an operator (separated by space), the default operator is '='. - * The special operator 'NI' specifies that the argument must be contained in a comma-separated list. - * @param $link DB link used to escape values (not used anymore) - * @param $omit_where Do not add 'WHERE ' to result - * @return The generated SQL clause - * @see select() - * @see iterate() - */ -function _where($params = "", $dummy_link = null, $omit_where = false) -{ - if (is_array($params) && (count($params) > 0)) - { - $query = ''; - $stringquery = ''; - $sep = ''; - - foreach($params as $field => $value) - { - if (is_int($field)) /* no key specified; just append */ - { - if (strcasecmp($value, 'OR')) - $stringquery .= " $value"; - else - $sep = ' OR '; - } - else - { - $needs_where = true; - - if (!isset($value)) - { - $op = 'IS'; - $qval = 'NULL'; - } - else - { - if (preg_match('/^(\S+)\s+(\S.*)$/', $field, $regs)) - { - $field = $regs[1]; - $op = strtoupper($regs[2]); - } - else - $op = '='; - - # If field name starts with '-', the raw value is taken, no escaping is done and no quotes are put around it. - if (substr($field, 0, 1) == '-') - { - $field = substr($field, 1); # Strip that '-' sign - $qval = $value; - } - else if (!is_array($value)) - $qval = $this->escape_string((string)$value); - } - - switch ($op) - { - case 'NI': - if ($value) - { - $parts = array(); - foreach ((array)$value as $val) - $parts[] = "CONCAT(',',$field,',') LIKE " . $this->escape_string("%,$val,%"); - - $query .= $sep . "(" . join(" OR ", $parts) . ")"; - } - else - $query .= $sep . "1"; - break; - - case 'MATCH': - $qval = join(' ', (array)$value); - $query .= "$sep$op ($field) AGAINST (" . $this->escape_string($qval) . " IN BOOLEAN MODE)"; - break; - - case 'IN': - case 'NOT IN': - if (is_array($value)) - { - if ($value) - { - $qvals = array(); - - foreach ($value as $val) - $qvals[] = $this->escape_string($val); - - $query .= "$sep$field $op (" . join(",", $qvals) . ")"; # null is mapped to '' - } - else - $query .= $sep . (($op == 'IN') ? "0" : "1"); - - break; - } - /* FALLTHROUGH */ - - default: - if (isset($qval)) - $query .= "$sep$field $op $qval"; - else - it::fatal('Undefined $qval when constructing query due to invalid $value (array)'); - break; - } - $sep = ' AND '; - } - } - - $query .= $stringquery; - - if ($needs_where && !$omit_where) - $query = "WHERE $query"; - } - - return $query; -} - - -/** - * Internal: Output class name::error message and terminate execution. - */ -function _fatal($text) -{ - $text = get_class($this).'::'.$text; - - if ($this->_link && ($errstr = mysql_error($this->_link))) - $text = "\"$errstr\" in $text [errno " . mysql_errno($this->_link) . "]"; - - if ($this->_link && ($res = @mysql_fetch_row(mysql_query('select database()', $this->_link)))) # dont create extra errs - $text .= ", DB: " . $res[0]; - - it::fatal($text . ", Server: " . $this->_p['server']); - /* NOT REACHED */ -} - - -/** - * Post-process data after reading a record. - * This is a stub-function that can be overloaded. - */ -function _read_post_process() -{ -} - - -/** - * Pre-process data before writing a record. - * This is a stub-function that can be overloaded. - * @param $tags Reference to update/create tags, can be modified as needed - * @param $command SQL command ('INSERT', 'REPLACE' or 'UPDATE') - */ -function _write_pre_process(&$tags, $command) # NOPHPLINT -{ -} - - -/** - * Clear record - */ -function clear($pp = true) -{ - foreach ((array)$this->_fields + (array)$this->_localizedfields as $field => $dummy) - unset($this->$field); - unset($this->_key, $this->_data); - - $pp && $this->_read_post_process(); -} - - -/** - * Semi-internal: send a raw SQL query and return mysql result value - * @param $query complete SQL query string - * @return raw MySQL result. May die if query fails and safety is big enough - */ -function query($query, $p = array()) -{ - $p += $this->_p; - $start = gettimeofday(true); - - if ($p['server_update'] && !preg_match('/^(EXPLAIN|SELECT|SHOW) /i', $query)) - { - debug("switching to update server \"{$p['server_update']}\"", 5); - $this->_p['server'] = $p['server'] = $p['server_update']; - unset($this->_p['server_update'], $p['server_update'], $this->_link); - } - - $this->_connect($p); # must be called after update server switching code - - debug("{$p['user']}@{$p['server']}:{$p['db']}" . '.' . get_class($this) . "::query(\"$query\")", 4); - - if (!($result = mysql_query($query, $this->_link)) && $p['safety']) - { - $errno = mysql_errno($this->_link); - if (($p['safety'] < 2) && ($errno == 1062)) # Duplicate entry - return false; - - if ($errno == 2006) # mysql server has gone away: retry - { - it::log('sqllog', "it_dbi(): reconnecting mysql_connect {$p['server']}, {$p['db']}"); - $this->_connect(array('reconnect' => true)); - $result = mysql_query($query, $this->_link); - } - - if (!$result) - $this->_fatal("query(\"$query\") failed"); - } - else if (preg_match('/^(CREATE|ALTER|DROP) /i', $query)) - { - # Purge cache for schema changes (after modifying table) - $dbid = "{$p['user']}@{$p['server']}:{$p['db']}"; - it_dbi::_state_purgeshared($dbid); - } - - - $msec = round(1000 * (gettimeofday(true) - $start)); - $slow = $msec >= 2000; - if ($GLOBALS['debug_sqllog'] || $GLOBALS['debug_sqltrace'] || $slow) - { - $backtrace = (EDC('sqltrace') || $slow) ? it_debug::backtrace(1) : null; - it::log('sqllog', "$msec\t$query\t$backtrace\t" . $this->_p['server'] . ($slow ? "\tSLOW" : "")); - - $this->_sqllog[] = array( - 'time' => $msec, - 'query' => $query, - ) + ($backtrace ? array('backtrace' => $backtrace) : array()); - } - - return $result; -} - - -/** - * Read a single record by primary key, not destroying old query result $this->_result - * @param $id primary key. If null, record is cleared - * @return True if record could be read, false if not. - */ -function read($id=null) -{ - $old_result = $this->_result; - $old_nofetch = $this->_nofetch; - $result = $this->select(array($this->_p['keyfield'] => $id)); - $this->_result = $old_result; - $this->_nofetch = $old_nofetch; - return $result; -} - - -/** - * Select a set of records from table and fetch the first one - * @param $query One or more optional arrays of (field => value) or sqlstring pairs. Defaults to null (select all records) - * Fields will be joined by AND - * Fields can contain a compare operator: 'name LIKE' => "j%" or 'amount >' => 100 - * Fields can start with - to prevent quoting of right side: '-modified' => "CURDATE()" - * $query can contain magic field 'SELECT' for things like 'COUNT(*)' or 'DISTINCT foo', defaults to '*' - * $query can contain magic field 'JOIN' for things like 'tableA LEFT JOIN tableB ON a=b', defaults to table name - * $query can contain 'CALC_FOUND_ROWS', if true member var _found_rows contains number of matching rows before LIMIT - * $query can contain 'NOFETCH', if true the first row is not prefetched (e.g. when directly using _result) - * @return Number of matching rows, use iterate() to fetch the next record - * @see iterate() - * @see _where() - */ -function select(/* $query = array|string, ... */) -{ - $query = array(); - foreach (func_get_args() as $arg) - $query = array_merge($query, (array)$arg); - - $this->_connect(); - - $result = 0; - $calc_found_rows = false; - - $what = '*'; - if (isset($query['SELECT'])) - { - $what = $query['SELECT']; - unset($query['SELECT']); - } - - $join = $this->_p['table']; - if (isset($query['JOIN'])) # WARNING: this field gets abused for "tablename USE INDEX (fast2) - { - $join = $query['JOIN']; - unset($query['JOIN']); - } - - unset($this->_found_rows); - if (isset($query['CALC_FOUND_ROWS']) && $query['CALC_FOUND_ROWS']) - { - $calc_found_rows = true; - $what = 'SQL_CALC_FOUND_ROWS '.$what; - } - unset($query['CALC_FOUND_ROWS']); # Always unset, so CALC_FOUND_ROWS => false doesn't generate bogus query - - if (EDC('nocache')) - $what = 'SQL_NO_CACHE ' . $what; - - $nofetch = $this->_nofetch = $query['NOFETCH']; - unset($query['NOFETCH']); - - $this->clear(false); - if ($this->_result = $this->query($sql = "SELECT $what FROM $join " . $this->_where($query, $this->_link))) - { - $result = mysql_num_rows($this->_result); - - if ($calc_found_rows) - { - list($count) = mysql_fetch_row($this->query('SELECT FOUND_ROWS()')); - $this->_found_rows = intval($count); - } - - if (!$this->iterate() && ($this->_p['safety'] >= 2)) - $this->_fatal("select(): query produced no results: \"$sql\""); - } - - $this->_nofetch = !$nofetch; - - return $result; -} - - -/** - * Puts next result from previous select() in member variables - * @return true if another record was fetched, false if no more records - * @see select() - */ -function iterate() -{ - if (!$this->_nofetch) - { - if ($this->_data = mysql_fetch_assoc($this->_result)) - { - if ($localizedfields = $this->_localizedfields) - foreach ($localizedfields as $field => $dummy) - unset($this->$field); - - foreach ($this->_data as $field => $value) - $this->$field = (isset($value) && $this->_convertfunc[$field]) ? ($this->_data[$field] = $this->_convertfunc[$field]($value)) : $value; - - if ($localizedfields) - { - $lang = T_lang(); - foreach ($localizedfields as $field => $dummy) - { - $value = $this->{$field . "_" . $lang}; - - if (!isset($value)) - $value = $this->{$field . "_" . $this->_p['localized_defaultlanguage']}; - - if (isset($value)) - { - if (isset($this->$field)) - it::fatal("Field name clash: Overwriting {$this->_p['table']}.$field with {$field}_{$lang}, only use one of those fields"); - else - $this->$field = $value; - } - } - } - - if (!empty($this->_p['keyfield'])) - $this->_key = $this->_data[$this->_p['keyfield']]; - } - else - $this->clear(false); - - $this->_read_post_process(); - } - else - $this->_nofetch = false; - - return (bool)$this->_data; -} - - -/** - * Insert a record into table. Values are taken from member vars and $tags. - * After inserting, all values are valid (record is read back). - * Does not destroy internal state of last select() call - * @param $tags Additional key => value pairs (these have priority over member vars) - */ -function insert($tags = array(), $command = "INSERT") -{ - $this->_connect(); - - /* Pre-processing, $tags is passed by reference and may be modified here */ - $this->_write_pre_process($tags, $command); - - if ($this->_p['randomid'] && !isset($tags[$this->_p['keyfield']])) - $tags[$this->_p['keyfield']] = md5(uniqid(mt_rand())); - - $set = $this->_set($tags, true); - - if ($result = $this->query("$command INTO {$this->_p['table']} " . $set)) - { - $id = ($this->_p['autoincrement'] && !isset($tags[$this->_p['keyfield']])) ? mysql_insert_id($this->_link) : $tags[$this->_p['keyfield']]; - if ($this->_p['keyfield'] && !$this->read($id) && $this->_p['safety']) - $this->_fatal("insert(): can't read record back (key truncated?), id=\"$id\""); - } - else - $this->clear(false); - - return $result; -} - - -/** - * Replace a record in a table - * @param $tags Additional key => value pairs (these have priority over member vars) - * Does not destroy internal state of last select() call - * @see insert() - */ -function replace($tags = array()) -{ - return $this->insert($tags, "REPLACE"); -} - - -/** - * Update current record or a number of records given by where condition - * @param $tags key => value pairs (these have priority over changes in member vars) - * @param $where condition to select records to be modified (if not current record) - * @return number of updated records (or false on error). WARNING: read LIMIT docs before using it - * Does not destroy internal state of last select() call - */ -function update($tags = array(), $where = null) -{ - $this->_connect(); - $result = true; - - /* Pre-processing, $tags is passed by reference and may be modified here */ - $this->_write_pre_process($tags, 'UPDATE'); - - if ($set = $this->_set($tags, isset($where))) - { - if (!isset($where)) - $where = array($this->_p['keyfield'] => $this->_data[$this->_p['keyfield']]); - - if ($result = $this->query("UPDATE {$this->_p['table']} $set " . $this->_where($where, $this->_link))) - { - $result = mysql_affected_rows($this->_link); - - if (array_key_exists($this->_p['keyfield'], $tags)) # Did we just update the key? - $this->_key = $tags[$this->_p['keyfield']]; - - if (isset($this->_key) && $this->read($this->_key)) - $this->_nofetch = false; # So we can do while(iterate()) update(); - } - } - - return $result; -} - - -/** - * Delete a record - * Does not destroy query result $this->_result - * @param $query optional query for WHERE, default: delete currently loaded record - * @return number of deleted records - */ -function delete($query = null) -{ - $this->_connect(); - $result = 0; - - if (!$query && $this->_p['keyfield']) - { - $query = array($this->_p['keyfield'] => $this->_key); - $this->clear(); - } - - if ($query && $this->query("DELETE FROM {$this->_p['table']} " . $this->_where($query, $this->_link))) - $result = mysql_affected_rows($this->_link); - - return $result; -} - - -/** - * Escapes a string for use in a DB query - * @param The string to be quoted - * @return The quoted value - */ -function escape_string($str) -{ - $this->_connect(); - return "'" . mysql_real_escape_string($str, $this->_link) . "'"; -} - - -/** - * INTERNAL: Store information about a table's fields in $this->_fields, possibly from cache. - * @return array(keyfield, autoincrement, randomid) - */ -function _get_field_info() -{ - $result = array(); - $dbid = "{$this->_p['user']}@{$this->_p['server']}:{$this->_p['db']}"; - $state = it_dbi::_state_get($dbid); - - if (!($this->_fields = $state['fields'][$this->_p['table']])) - { - debug("it_dbi(): no fields for {$dbid}.{$this->_p['table']}, calculating.", 5); - for ($res = $this->query('SHOW COLUMNS FROM ' . $this->_p['table']); $res && ($field = mysql_fetch_assoc($res)); ) - { - $this->_fields[$field['Field']] = $field + array('Length' => preg_match('/date|time/', $field['Type']) ? 20 : intval(it::match('\d+', $field['Type']))); - if (preg_match('/^(tiny|small|medium|)int|^float|^double/', $field['Type'])) - $this->_convertfunc[$field['Field']] = it::match('int', $field['Type']) ? "intval" : "floatval"; - } - - # Consider all fields which have _{localized_defaultlanguage} suffix as localized - foreach (preg_grep('/_' . $this->_p['localized_defaultlanguage'] . '$/', array_keys((array)$this->_fields)) as $field) - $this->_localizedfields[substr($field, 0, -1 - strlen($this->_p['localized_defaultlanguage']))] = true; - - $state = it_dbi::_state_get($dbid); # State could have been modified by query above - $state['fields'][$this->_p['table']] = $this->_fields; - $state['convertfunc'][$this->_p['table']] = $this->_convertfunc; - it_dbi::_state_put($dbid, $state); - } - else # Existing _fields, copy other info too - $this->_convertfunc = $state['convertfunc'][$this->_p['table']]; - - foreach((array)$this->_fields as $field) - { - if ($field['Key'] == 'PRI') - { - $result = array('keyfield' => $field['Field'], 'autoincrement' => (strpos($field['Extra'], "auto_increment") !== false), - 'randomid' => (strpos($field['Type'], "char") !== false)); - break; - } - } - - unset($GLOBALS['it_dbi']->_p['table'], $GLOBALS['it_dbi']->_p['keyfield']); # Remove cruft - return $result; -} - -function _state_get($dbid) -{ - if (!($result = $GLOBALS['it_dbi']->_state[$dbid])) - $result = $GLOBALS['it_dbi']->_state[$dbid] = (array)it_cache::get("dbi:$dbid"); - - #var_dump("get", $dbid, $result); - return $result; -} - -function _state_put($dbid, $state, $shared = true) -{ - #var_dump("put", $dbid, $state); - $GLOBALS['it_dbi']->_state[$dbid] = $state; - if ($shared) - it_cache::put("dbi:$dbid", array('link' => null) + (array)$state); # link is not transferable -} - -function _state_purgeshared($dbid) -{ - #var_dump("purgeshared", $dbid); - it_cache::put("dbi:$dbid", array()); # Nuke shared cache -} - -# -# Implement PHP 5 Iterator interface to make foreach work -# Example: foreach (new T_User('firstname' => "foo") as $foouser) { ... } -# -function current() -{ - return $this; -} - -function key() -{ - return isset($this->_key) ? $this->_key : $this->_iteratorkey++; -} - -function next() -{ - $this->iterate(); -} - -function rewind() -{ - if (!$this->_result) # Object without query used in foreach - $this->select(); - - # Only rewind if not already at start and results present - if (!$this->_nofetch && mysql_num_rows($this->_result)) - mysql_data_seek($this->_result, 0); - - $this->_iteratorkey = 0; - $this->iterate(); -} - -function valid() -{ - return (bool)$this->_data; -} - -} /* End class it_dbi */ - -?> |