ILIAS  Release_4_4_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
MDB2.php
Go to the documentation of this file.
1 <?php
2 // vim: set et ts=4 sw=4 fdm=marker:
3 // +----------------------------------------------------------------------+
4 // | PHP versions 4 and 5 |
5 // +----------------------------------------------------------------------+
6 // | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, |
7 // | Stig. S. Bakken, Lukas Smith |
8 // | All rights reserved. |
9 // +----------------------------------------------------------------------+
10 // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
11 // | API as well as database abstraction for PHP applications. |
12 // | This LICENSE is in the BSD license style. |
13 // | |
14 // | Redistribution and use in source and binary forms, with or without |
15 // | modification, are permitted provided that the following conditions |
16 // | are met: |
17 // | |
18 // | Redistributions of source code must retain the above copyright |
19 // | notice, this list of conditions and the following disclaimer. |
20 // | |
21 // | Redistributions in binary form must reproduce the above copyright |
22 // | notice, this list of conditions and the following disclaimer in the |
23 // | documentation and/or other materials provided with the distribution. |
24 // | |
25 // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
26 // | Lukas Smith nor the names of his contributors may be used to endorse |
27 // | or promote products derived from this software without specific prior|
28 // | written permission. |
29 // | |
30 // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
31 // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
32 // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
33 // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
34 // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
35 // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
36 // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
37 // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
38 // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
39 // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
40 // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
41 // | POSSIBILITY OF SUCH DAMAGE. |
42 // +----------------------------------------------------------------------+
43 // | Author: Lukas Smith <smith@pooteeweet.org> |
44 // +----------------------------------------------------------------------+
45 //
46 // $Id: MDB2.php,v 1.292 2007/04/25 09:31:01 quipo Exp $
47 //
48 
55 require_once 'PEAR.php';
56 
57 // {{{ Error constants
58 
67 define('MDB2_OK', true);
68 define('MDB2_ERROR', -1);
69 define('MDB2_ERROR_SYNTAX', -2);
70 define('MDB2_ERROR_CONSTRAINT', -3);
71 define('MDB2_ERROR_NOT_FOUND', -4);
72 define('MDB2_ERROR_ALREADY_EXISTS', -5);
73 define('MDB2_ERROR_UNSUPPORTED', -6);
74 define('MDB2_ERROR_MISMATCH', -7);
75 define('MDB2_ERROR_INVALID', -8);
76 define('MDB2_ERROR_NOT_CAPABLE', -9);
77 define('MDB2_ERROR_TRUNCATED', -10);
78 define('MDB2_ERROR_INVALID_NUMBER', -11);
79 define('MDB2_ERROR_INVALID_DATE', -12);
80 define('MDB2_ERROR_DIVZERO', -13);
81 define('MDB2_ERROR_NODBSELECTED', -14);
82 define('MDB2_ERROR_CANNOT_CREATE', -15);
83 define('MDB2_ERROR_CANNOT_DELETE', -16);
84 define('MDB2_ERROR_CANNOT_DROP', -17);
85 define('MDB2_ERROR_NOSUCHTABLE', -18);
86 define('MDB2_ERROR_NOSUCHFIELD', -19);
87 define('MDB2_ERROR_NEED_MORE_DATA', -20);
88 define('MDB2_ERROR_NOT_LOCKED', -21);
89 define('MDB2_ERROR_VALUE_COUNT_ON_ROW', -22);
90 define('MDB2_ERROR_INVALID_DSN', -23);
91 define('MDB2_ERROR_CONNECT_FAILED', -24);
92 define('MDB2_ERROR_EXTENSION_NOT_FOUND',-25);
93 define('MDB2_ERROR_NOSUCHDB', -26);
94 define('MDB2_ERROR_ACCESS_VIOLATION', -27);
95 define('MDB2_ERROR_CANNOT_REPLACE', -28);
96 define('MDB2_ERROR_CONSTRAINT_NOT_NULL',-29);
97 define('MDB2_ERROR_DEADLOCK', -30);
98 define('MDB2_ERROR_CANNOT_ALTER', -31);
99 define('MDB2_ERROR_MANAGER', -32);
100 define('MDB2_ERROR_MANAGER_PARSE', -33);
101 define('MDB2_ERROR_LOADMODULE', -34);
102 define('MDB2_ERROR_INSUFFICIENT_DATA', -35);
103 // }}}
104 // {{{ Verbose constants
109 define('MDB2_PREPARE_MANIP', false);
110 define('MDB2_PREPARE_RESULT', null);
111 
112 // }}}
113 // {{{ Fetchmode constants
114 
119 define('MDB2_FETCHMODE_DEFAULT', 0);
120 
124 define('MDB2_FETCHMODE_ORDERED', 1);
125 
129 define('MDB2_FETCHMODE_ASSOC', 2);
130 
134 define('MDB2_FETCHMODE_OBJECT', 3);
135 
142 define('MDB2_FETCHMODE_FLIPPED', 4);
143 
144 // }}}
145 // {{{ Portability mode constants
146 
151 define('MDB2_PORTABILITY_NONE', 0);
152 
158 define('MDB2_PORTABILITY_FIX_CASE', 1);
159 
164 define('MDB2_PORTABILITY_RTRIM', 2);
165 
170 define('MDB2_PORTABILITY_DELETE_COUNT', 4);
171 
176 define('MDB2_PORTABILITY_NUMROWS', 8);
177 
191 define('MDB2_PORTABILITY_ERRORS', 16);
192 
198 define('MDB2_PORTABILITY_EMPTY_TO_NULL', 32);
199 
204 define('MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES', 64);
205 
210 define('MDB2_PORTABILITY_ALL', 127);
211 
212 // }}}
213 // {{{ Globals for class instance tracking
214 
219 $GLOBALS['_MDB2_databases'] = array();
220 $GLOBALS['_MDB2_dsninfo_default'] = array(
221  'phptype' => false,
222  'dbsyntax' => false,
223  'username' => false,
224  'password' => false,
225  'protocol' => false,
226  'hostspec' => false,
227  'port' => false,
228  'socket' => false,
229  'database' => false,
230  'mode' => false,
231 );
232 
233 // }}}
234 // {{{ class MDB2
235 
265 class MDB2
266 {
267  // {{{ function setOptions(&$db, $options)
268 
279  function setOptions(&$db, $options)
280  {
281  if (is_array($options)) {
282  foreach ($options as $option => $value) {
283  $test = $db->setOption($option, $value);
284  if (PEAR::isError($test)) {
285  return $test;
286  }
287  }
288  }
289  return MDB2_OK;
290  }
291 
292  // }}}
293  // {{{ function classExists($classname)
294 
304  function classExists($classname)
305  {
306  if (version_compare(phpversion(), "5.0", ">=")) {
307  return class_exists($classname, false);
308  }
309  return class_exists($classname);
310  }
311 
312  // }}}
313  // {{{ function loadClass($class_name, $debug)
314 
325  function loadClass($class_name, $debug)
326  {
327  if (!MDB2::classExists($class_name)) {
328  $file_name = str_replace('_', DIRECTORY_SEPARATOR, $class_name).'.php';
329  if ($debug) {
330  $include = include_once($file_name);
331  } else {
332  $include = @include_once($file_name);
333  }
334  if (!$include) {
335  if (!MDB2::fileExists($file_name)) {
336  $msg = "unable to find package '$class_name' file '$file_name'";
337  } else {
338  $msg = "unable to load class '$class_name' from file '$file_name'";
339  }
340  $err =& MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null, $msg);
341  return $err;
342  }
343  }
344  return MDB2_OK;
345  }
346 
347  // }}}
348  // {{{ function &factory($dsn, $options = false)
349 
374  function &factory($dsn, $options = false)
375  {
376  $dsninfo = MDB2::parseDSN($dsn);
377  if (empty($dsninfo['phptype'])) {
379  null, null, 'no RDBMS driver specified');
380  return $err;
381  }
382  $class_name = 'MDB2_Driver_'.$dsninfo['phptype'];
383 
384  $debug = (!empty($options['debug']));
385  $err = MDB2::loadClass($class_name, $debug);
386  if (PEAR::isError($err)) {
387  return $err;
388  }
389 
390  $db =& new $class_name();
391  $db->setDSN($dsninfo);
392  $err = MDB2::setOptions($db, $options);
393  if (PEAR::isError($err)) {
394  return $err;
395  }
396 
397  return $db;
398  }
399 
400  // }}}
401  // {{{ function &connect($dsn, $options = false)
402 
431  function &connect($dsn, $options = false)
432  {
433  $db =& MDB2::factory($dsn, $options);
434  if (PEAR::isError($db)) {
435  return $db;
436  }
437 
438  $err = $db->connect();
439  if (PEAR::isError($err)) {
440  $dsn = $db->getDSN('string', 'xxx');
441  $db->disconnect();
442  $err->addUserInfo($dsn);
443  return $err;
444  }
445 
446  return $db;
447  }
448 
449  // }}}
450  // {{{ function &singleton($dsn = null, $options = false)
451 
481  function &singleton($dsn = null, $options = false)
482  {
483  if ($dsn) {
484  $dsninfo = MDB2::parseDSN($dsn);
485  $dsninfo = array_merge($GLOBALS['_MDB2_dsninfo_default'], $dsninfo);
486  $keys = array_keys($GLOBALS['_MDB2_databases']);
487  for ($i=0, $j=count($keys); $i<$j; ++$i) {
488  if (isset($GLOBALS['_MDB2_databases'][$keys[$i]])) {
489  $tmp_dsn = $GLOBALS['_MDB2_databases'][$keys[$i]]->getDSN('array');
490  if (count(array_diff_assoc($tmp_dsn, $dsninfo)) == 0) {
491  MDB2::setOptions($GLOBALS['_MDB2_databases'][$keys[$i]], $options);
492  return $GLOBALS['_MDB2_databases'][$keys[$i]];
493  }
494  }
495  }
496  } elseif (is_array($GLOBALS['_MDB2_databases']) && reset($GLOBALS['_MDB2_databases'])) {
497  $db =& $GLOBALS['_MDB2_databases'][key($GLOBALS['_MDB2_databases'])];
498  return $db;
499  }
500  $db =& MDB2::factory($dsn, $options);
501  return $db;
502  }
503 
504  // }}}
505  // {{{ function loadFile($file)
506 
516  function loadFile($file)
517  {
518  $file_name = 'MDB2'.DIRECTORY_SEPARATOR.$file.'.php';
519  if (!MDB2::fileExists($file_name)) {
520  return MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null,
521  'unable to find: '.$file_name);
522  }
523  if (!include_once($file_name)) {
524  return MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null,
525  'unable to load driver class: '.$file_name);
526  }
527  return $file_name;
528  }
529 
530  // }}}
531  // {{{ function apiVersion()
532 
540  function apiVersion()
541  {
542  return '2.4.1';
543  }
544 
545  // }}}
546  // {{{ function &raiseError($code = null, $mode = null, $options = null, $userinfo = null)
547 
572  function &raiseError($code = null, $mode = null, $options = null, $userinfo = null)
573  {
574  $err =& PEAR::raiseError(null, $code, $mode, $options, $userinfo, 'MDB2_Error', true);
575  return $err;
576  }
577 
578  // }}}
579  // {{{ function isError($data, $code = null)
580 
594  function isError($data, $code = null)
595  {
596  if (is_a($data, 'MDB2_Error')) {
597  if (is_null($code)) {
598  return true;
599  } elseif (is_string($code)) {
600  return $data->getMessage() === $code;
601  } else {
602  $code = (array)$code;
603  return in_array($data->getCode(), $code);
604  }
605  }
606  return false;
607  }
608 
609  // }}}
610  // {{{ function isConnection($value)
611 
621  function isConnection($value)
622  {
623  return is_a($value, 'MDB2_Driver_Common');
624  }
625 
626  // }}}
627  // {{{ function isResult($value)
628 
638  function isResult($value)
639  {
640  return is_a($value, 'MDB2_Result');
641  }
642 
643  // }}}
644  // {{{ function isResultCommon($value)
645 
655  function isResultCommon($value)
656  {
657  return is_a($value, 'MDB2_Result_Common');
658  }
659 
660  // }}}
661  // {{{ function isStatement($value)
662 
672  function isStatement($value)
673  {
674  return is_a($value, 'MDB2_Statement');
675  }
676 
677  // }}}
678  // {{{ function errorMessage($value = null)
679 
692  function errorMessage($value = null)
693  {
694  static $errorMessages;
695 
696  if (is_array($value)) {
697  $errorMessages = $value;
698  return MDB2_OK;
699  }
700 
701  if (!isset($errorMessages)) {
702  $errorMessages = array(
703  MDB2_OK => 'no error',
704  MDB2_ERROR => 'unknown error',
705  MDB2_ERROR_ALREADY_EXISTS => 'already exists',
706  MDB2_ERROR_CANNOT_CREATE => 'can not create',
707  MDB2_ERROR_CANNOT_ALTER => 'can not alter',
708  MDB2_ERROR_CANNOT_REPLACE => 'can not replace',
709  MDB2_ERROR_CANNOT_DELETE => 'can not delete',
710  MDB2_ERROR_CANNOT_DROP => 'can not drop',
711  MDB2_ERROR_CONSTRAINT => 'constraint violation',
712  MDB2_ERROR_CONSTRAINT_NOT_NULL=> 'null value violates not-null constraint',
713  MDB2_ERROR_DIVZERO => 'division by zero',
714  MDB2_ERROR_INVALID => 'invalid',
715  MDB2_ERROR_INVALID_DATE => 'invalid date or time',
716  MDB2_ERROR_INVALID_NUMBER => 'invalid number',
717  MDB2_ERROR_MISMATCH => 'mismatch',
718  MDB2_ERROR_NODBSELECTED => 'no database selected',
719  MDB2_ERROR_NOSUCHFIELD => 'no such field',
720  MDB2_ERROR_NOSUCHTABLE => 'no such table',
721  MDB2_ERROR_NOT_CAPABLE => 'MDB2 backend not capable',
722  MDB2_ERROR_NOT_FOUND => 'not found',
723  MDB2_ERROR_NOT_LOCKED => 'not locked',
724  MDB2_ERROR_SYNTAX => 'syntax error',
725  MDB2_ERROR_UNSUPPORTED => 'not supported',
726  MDB2_ERROR_VALUE_COUNT_ON_ROW => 'value count on row',
727  MDB2_ERROR_INVALID_DSN => 'invalid DSN',
728  MDB2_ERROR_CONNECT_FAILED => 'connect failed',
729  MDB2_ERROR_NEED_MORE_DATA => 'insufficient data supplied',
730  MDB2_ERROR_EXTENSION_NOT_FOUND=> 'extension not found',
731  MDB2_ERROR_NOSUCHDB => 'no such database',
732  MDB2_ERROR_ACCESS_VIOLATION => 'insufficient permissions',
733  MDB2_ERROR_LOADMODULE => 'error while including on demand module',
734  MDB2_ERROR_TRUNCATED => 'truncated',
735  MDB2_ERROR_DEADLOCK => 'deadlock detected',
736  );
737  }
738 
739  if (is_null($value)) {
740  return $errorMessages;
741  }
742 
743  if (PEAR::isError($value)) {
744  $value = $value->getCode();
745  }
746 
747  return isset($errorMessages[$value]) ?
748  $errorMessages[$value] : $errorMessages[MDB2_ERROR];
749  }
750 
751  // }}}
752  // {{{ function parseDSN($dsn)
753 
791  function parseDSN($dsn)
792  {
793  $parsed = $GLOBALS['_MDB2_dsninfo_default'];
794 
795  if (is_array($dsn)) {
796  $dsn = array_merge($parsed, $dsn);
797  if (!$dsn['dbsyntax']) {
798  $dsn['dbsyntax'] = $dsn['phptype'];
799  }
800  return $dsn;
801  }
802 
803  // Find phptype and dbsyntax
804  if (($pos = strpos($dsn, '://')) !== false) {
805  $str = substr($dsn, 0, $pos);
806  $dsn = substr($dsn, $pos + 3);
807  } else {
808  $str = $dsn;
809  $dsn = null;
810  }
811 
812  // Get phptype and dbsyntax
813  // $str => phptype(dbsyntax)
814  if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) {
815  $parsed['phptype'] = $arr[1];
816  $parsed['dbsyntax'] = !$arr[2] ? $arr[1] : $arr[2];
817  } else {
818  $parsed['phptype'] = $str;
819  $parsed['dbsyntax'] = $str;
820  }
821 
822  if (!count($dsn)) {
823  return $parsed;
824  }
825 
826  // Get (if found): username and password
827  // $dsn => username:password@protocol+hostspec/database
828  if (($at = strrpos($dsn,'@')) !== false) {
829  $str = substr($dsn, 0, $at);
830  $dsn = substr($dsn, $at + 1);
831  if (($pos = strpos($str, ':')) !== false) {
832  $parsed['username'] = rawurldecode(substr($str, 0, $pos));
833  $parsed['password'] = rawurldecode(substr($str, $pos + 1));
834  } else {
835  $parsed['username'] = rawurldecode($str);
836  }
837  }
838 
839  // Find protocol and hostspec
840 
841  // $dsn => proto(proto_opts)/database
842  if (preg_match('|^([^(]+)\((.*?)\)/?(.*?)$|', $dsn, $match)) {
843  $proto = $match[1];
844  $proto_opts = $match[2] ? $match[2] : false;
845  $dsn = $match[3];
846 
847  // $dsn => protocol+hostspec/database (old format)
848  } else {
849  if (strpos($dsn, '+') !== false) {
850  list($proto, $dsn) = explode('+', $dsn, 2);
851  }
852  if ( strpos($dsn, '//') === 0
853  && strpos($dsn, '/', 2) !== false
854  && $parsed['phptype'] == 'oci8'
855  ) {
856  //oracle's "Easy Connect" syntax:
857  //"username/password@[//]host[:port][/service_name]"
858  //e.g. "scott/tiger@//mymachine:1521/oracle"
859  $proto_opts = $dsn;
860  $dsn = null;
861  } elseif (strpos($dsn, '/') !== false) {
862  list($proto_opts, $dsn) = explode('/', $dsn, 2);
863  } else {
864  $proto_opts = $dsn;
865  $dsn = null;
866  }
867  }
868 
869  // process the different protocol options
870  $parsed['protocol'] = (!empty($proto)) ? $proto : 'tcp';
871  $proto_opts = rawurldecode($proto_opts);
872  if (strpos($proto_opts, ':') !== false) {
873  list($proto_opts, $parsed['port']) = explode(':', $proto_opts);
874  }
875  if ($parsed['protocol'] == 'tcp') {
876  $parsed['hostspec'] = $proto_opts;
877  } elseif ($parsed['protocol'] == 'unix') {
878  $parsed['socket'] = $proto_opts;
879  }
880 
881  // Get dabase if any
882  // $dsn => database
883  if ($dsn) {
884  // /database
885  if (($pos = strpos($dsn, '?')) === false) {
886  $parsed['database'] = $dsn;
887  // /database?param1=value1&param2=value2
888  } else {
889  $parsed['database'] = substr($dsn, 0, $pos);
890  $dsn = substr($dsn, $pos + 1);
891  if (strpos($dsn, '&') !== false) {
892  $opts = explode('&', $dsn);
893  } else { // database?param1=value1
894  $opts = array($dsn);
895  }
896  foreach ($opts as $opt) {
897  list($key, $value) = explode('=', $opt);
898  if (!isset($parsed[$key])) {
899  // don't allow params overwrite
900  $parsed[$key] = rawurldecode($value);
901  }
902  }
903  }
904  }
905 
906  return $parsed;
907  }
908 
909  // }}}
910  // {{{ function fileExists($file)
911 
921  function fileExists($file)
922  {
923  // safe_mode does notwork with is_readable()
924  if (!@ini_get('safe_mode')) {
925  $dirs = explode(PATH_SEPARATOR, ini_get('include_path'));
926  foreach ($dirs as $dir) {
927  if (@is_readable($dir . DIRECTORY_SEPARATOR . $file)) {
928  return true;
929  }
930  }
931  } else {
932  $fp = @fopen($file, 'r', true);
933  if (is_resource($fp)) {
934  @fclose($fp);
935  return true;
936  }
937  }
938  return false;
939  }
940  // }}}
941 }
942 
943 // }}}
944 // {{{ class MDB2_Error extends PEAR_Error
945 
954 class MDB2_Error extends PEAR_Error
955 {
956  // {{{ constructor: function MDB2_Error($code = MDB2_ERROR, $mode = PEAR_ERROR_RETURN, $level = E_USER_NOTICE, $debuginfo = null)
957 
967  $level = E_USER_NOTICE, $debuginfo = null)
968  {
969  if (is_null($code)) {
970  $code = MDB2_ERROR;
971  }
972  $this->PEAR_Error('MDB2 Error: '.MDB2::errorMessage($code), $code,
973  $mode, $level, $debuginfo);
974  }
975 
976  // }}}
977 }
978 
979 // }}}
980 // {{{ class MDB2_Driver_Common extends PEAR
981 
990 {
991  // {{{ Variables (Properties)
992 
998  var $db_index = 0;
999 
1005  var $dsn = array();
1006 
1012  var $connected_dsn = array();
1013 
1019  var $connection = 0;
1020 
1027 
1033  var $database_name = '';
1034 
1041 
1048 
1054  var $supported = array(
1055  'sequences' => false,
1056  'indexes' => false,
1057  'affected_rows' => false,
1058  'summary_functions' => false,
1059  'order_by_text' => false,
1060  'transactions' => false,
1061  'savepoints' => false,
1062  'current_id' => false,
1063  'limit_queries' => false,
1064  'LOBs' => false,
1065  'replace' => false,
1066  'sub_selects' => false,
1067  'auto_increment' => false,
1068  'primary_key' => false,
1069  'result_introspection' => false,
1070  'prepared_statements' => false,
1071  'identifier_quoting' => false,
1072  'pattern_escaping' => false,
1073  'new_link' => false,
1074  );
1075 
1122  var $options = array(
1123  'ssl' => false,
1124  'field_case' => CASE_LOWER,
1125  'disable_query' => false,
1126  'result_class' => 'MDB2_Result_%s',
1127  'buffered_result_class' => 'MDB2_BufferedResult_%s',
1128  'result_wrap_class' => false,
1129  'result_buffering' => true,
1130  'fetch_class' => 'stdClass',
1131  'persistent' => false,
1132  'debug' => 0,
1133  'debug_handler' => 'MDB2_defaultDebugOutput',
1134  'debug_expanded_output' => false,
1135  'default_text_field_length' => 4096,
1136  'lob_buffer_length' => 8192,
1137  'log_line_break' => "\n",
1138  'idxname_format' => '%s_idx',
1139  'seqname_format' => '%s_seq',
1140  'savepoint_format' => 'MDB2_SAVEPOINT_%s',
1141  'statement_format' => 'MDB2_STATEMENT_%1$s_%2$s',
1142  'seqcol_name' => 'sequence',
1143  'quote_identifier' => false,
1144  'use_transactions' => true,
1145  'decimal_places' => 2,
1146  'portability' => MDB2_PORTABILITY_ALL,
1147  'modules' => array(
1148  'ex' => 'Extended',
1149  'dt' => 'Datatype',
1150  'mg' => 'Manager',
1151  'rv' => 'Reverse',
1152  'na' => 'Native',
1153  'fc' => 'Function',
1154  ),
1155  'emulate_prepared' => false,
1156  'datatype_map' => array(),
1157  'datatype_map_callback' => array(),
1158  'nativetype_map_callback' => array(),
1159  );
1160 
1166  var $string_quoting = array('start' => "'", 'end' => "'", 'escape' => false, 'escape_pattern' => false);
1167 
1173  var $identifier_quoting = array('start' => '"', 'end' => '"', 'escape' => '"');
1174 
1180  var $sql_comments = array(
1181  array('start' => '--', 'end' => "\n", 'escape' => false),
1182  array('start' => '/*', 'end' => '*/', 'escape' => false),
1183  );
1184 
1190  var $wildcards = array('%', '_');
1191 
1197  var $as_keyword = ' AS ';
1198 
1204  var $warnings = array();
1205 
1211  var $debug_output = '';
1212 
1218  var $in_transaction = false;
1219 
1226 
1233 
1239  var $offset = 0;
1240 
1246  var $limit = 0;
1247 
1254 
1261 
1268 
1275 
1281  var $modules = array();
1282 
1289 
1290  // }}}
1291  // {{{ constructor: function __construct()
1292 
1296  function __construct()
1297  {
1298  end($GLOBALS['_MDB2_databases']);
1299  $db_index = key($GLOBALS['_MDB2_databases']) + 1;
1300  $GLOBALS['_MDB2_databases'][$db_index] = &$this;
1301  $this->db_index = $db_index;
1302  }
1303 
1304  // }}}
1305  // {{{ function MDB2_Driver_Common()
1306 
1311  {
1312  $this->destructor_registered = false;
1313  $this->__construct();
1314  }
1315 
1316  // }}}
1317  // {{{ destructor: function __destruct()
1318 
1322  function __destruct()
1323  {
1324  $this->disconnect(false);
1325  }
1326 
1327  // }}}
1328  // {{{ function free()
1329 
1337  function free()
1338  {
1339  unset($GLOBALS['_MDB2_databases'][$this->db_index]);
1340  unset($this->db_index);
1341  return MDB2_OK;
1342  }
1343 
1344  // }}}
1345  // {{{ function __toString()
1346 
1354  function __toString()
1355  {
1356  $info = get_class($this);
1357  $info.= ': (phptype = '.$this->phptype.', dbsyntax = '.$this->dbsyntax.')';
1358  if ($this->connection) {
1359  $info.= ' [connected]';
1360  }
1361  return $info;
1362  }
1363 
1364  // }}}
1365  // {{{ function errorInfo($error = null)
1366 
1376  function errorInfo($error = null)
1377  {
1378  return array($error, null, null);
1379  }
1380 
1381  // }}}
1382  // {{{ function &raiseError($code = null, $mode = null, $options = null, $userinfo = null)
1383 
1407  function &raiseError($code = null, $mode = null, $options = null, $userinfo = null, $method = null)
1408  {
1409  $userinfo = "[Error message: $userinfo]\n";
1410  // The error is yet a MDB2 error object
1411  if (PEAR::isError($code)) {
1412  // because we use the static PEAR::raiseError, our global
1413  // handler should be used if it is set
1414  if (is_null($mode) && !empty($this->_default_error_mode)) {
1417  }
1418  if (is_null($userinfo)) {
1419  $userinfo = $code->getUserinfo();
1420  }
1421  $code = $code->getCode();
1422  } elseif ($code == MDB2_ERROR_NOT_FOUND) {
1423  // extension not loaded: don't call $this->errorInfo() or the script
1424  // will die
1425  } elseif (isset($this->connection)) {
1426  if (!empty($this->last_query)) {
1427  $userinfo.= "[Last executed query: {$this->last_query}]\n";
1428  }
1429  $native_errno = $native_msg = null;
1430  list($code, $native_errno, $native_msg) = $this->errorInfo($code);
1431  if (!is_null($native_errno) && $native_errno !== '') {
1432  $userinfo.= "[Native code: $native_errno]\n";
1433  }
1434  if (!is_null($native_msg) && $native_msg !== '') {
1435  $userinfo.= "[Native message: ". strip_tags($native_msg) ."]\n";
1436  }
1437  if (!is_null($method)) {
1438  $userinfo = $method.': '.$userinfo;
1439  }
1440  }
1441 
1442  $err =& PEAR::raiseError(null, $code, $mode, $options, $userinfo, 'MDB2_Error', true);
1443  if ($err->getMode() !== PEAR_ERROR_RETURN
1444  && isset($this->nested_transaction_counter) && !$this->has_transaction_error) {
1445  $this->has_transaction_error =& $err;
1446  }
1447  return $err;
1448  }
1449 
1450  // }}}
1451  // {{{ function resetWarnings()
1452 
1460  function resetWarnings()
1461  {
1462  $this->warnings = array();
1463  }
1464 
1465  // }}}
1466  // {{{ function getWarnings()
1467 
1477  function getWarnings()
1478  {
1479  return array_reverse($this->warnings);
1480  }
1481 
1482  // }}}
1483  // {{{ function setFetchMode($fetchmode, $object_class = 'stdClass')
1484 
1504  function setFetchMode($fetchmode, $object_class = 'stdClass')
1505  {
1506  switch ($fetchmode) {
1507  case MDB2_FETCHMODE_OBJECT:
1508  $this->options['fetch_class'] = $object_class;
1510  case MDB2_FETCHMODE_ASSOC:
1511  $this->fetchmode = $fetchmode;
1512  break;
1513  default:
1514  return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
1515  'invalid fetchmode mode', __FUNCTION__);
1516  }
1517 
1518  return MDB2_OK;
1519  }
1520 
1521  // }}}
1522  // {{{ function setOption($option, $value)
1523 
1534  function setOption($option, $value)
1535  {
1536  if (array_key_exists($option, $this->options)) {
1537  $this->options[$option] = $value;
1538  return MDB2_OK;
1539  }
1540  return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
1541  "unknown option $option", __FUNCTION__);
1542  }
1543 
1544  // }}}
1545  // {{{ function getOption($option)
1546 
1556  function getOption($option)
1557  {
1558  if (array_key_exists($option, $this->options)) {
1559  return $this->options[$option];
1560  }
1561  return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
1562  "unknown option $option", __FUNCTION__);
1563  }
1564 
1565  // }}}
1566  // {{{ function debug($message, $scope = '', $is_manip = null)
1567 
1582  function debug($message, $scope = '', $context = array())
1583  {
1584  if ($this->options['debug'] && $this->options['debug_handler']) {
1585  if (!$this->options['debug_expanded_output']) {
1586  if (!empty($context['when']) && $context['when'] !== 'pre') {
1587  return null;
1588  }
1589  $context = empty($context['is_manip']) ? false : $context['is_manip'];
1590  }
1591  return call_user_func_array($this->options['debug_handler'], array(&$this, $scope, $message, $context));
1592  }
1593  return null;
1594  }
1595 
1596  // }}}
1597  // {{{ function getDebugOutput()
1598 
1606  function getDebugOutput()
1607  {
1608  return $this->debug_output;
1609  }
1610 
1611  // }}}
1612  // {{{ function escape($text)
1613 
1625  function escape($text, $escape_wildcards = false)
1626  {
1627  if ($escape_wildcards) {
1628  $text = $this->escapePattern($text);
1629  }
1630 
1631  $text = str_replace($this->string_quoting['end'], $this->string_quoting['escape'] . $this->string_quoting['end'], $text);
1632  return $text;
1633  }
1634 
1635  // }}}
1636  // {{{ function escapePattern($text)
1637 
1652  function escapePattern($text)
1653  {
1654  if ($this->string_quoting['escape_pattern']) {
1655  $text = str_replace($this->string_quoting['escape_pattern'], $this->string_quoting['escape_pattern'] . $this->string_quoting['escape_pattern'], $text);
1656  foreach ($this->wildcards as $wildcard) {
1657  $text = str_replace($wildcard, $this->string_quoting['escape_pattern'] . $wildcard, $text);
1658  }
1659  }
1660  return $text;
1661  }
1662 
1663  // }}}
1664  // {{{ function quoteIdentifier($str, $check_option = false)
1665 
1700  function quoteIdentifier($str, $check_option = false)
1701  {
1702  if ($check_option && !$this->options['quote_identifier']) {
1703  return $str;
1704  }
1705  $str = str_replace($this->identifier_quoting['end'], $this->identifier_quoting['escape'] . $this->identifier_quoting['end'], $str);
1706  return $this->identifier_quoting['start'] . $str . $this->identifier_quoting['end'];
1707  }
1708 
1709  // }}}
1710  // {{{ function getAsKeyword()
1711 
1717  function getAsKeyword()
1718  {
1719  return $this->as_keyword;
1720  }
1721 
1722  // }}}
1723  // {{{ function getConnection()
1724 
1733  function getConnection()
1734  {
1735  $result = $this->connect();
1736  if (PEAR::isError($result)) {
1737  return $result;
1738  }
1739  return $this->connection;
1740  }
1741 
1742  // }}}
1743  // {{{ function _fixResultArrayValues(&$row, $mode)
1744 
1755  function _fixResultArrayValues(&$row, $mode)
1756  {
1757  switch ($mode) {
1759  foreach ($row as $key => $value) {
1760  if ($value === '') {
1761  $row[$key] = null;
1762  }
1763  }
1764  break;
1766  foreach ($row as $key => $value) {
1767  if (is_string($value)) {
1768  $row[$key] = rtrim($value);
1769  }
1770  }
1771  break;
1773  $tmp_row = array();
1774  foreach ($row as $key => $value) {
1775  $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value;
1776  }
1777  $row = $tmp_row;
1778  break;
1780  foreach ($row as $key => $value) {
1781  if ($value === '') {
1782  $row[$key] = null;
1783  } elseif (is_string($value)) {
1784  $row[$key] = rtrim($value);
1785  }
1786  }
1787  break;
1789  $tmp_row = array();
1790  foreach ($row as $key => $value) {
1791  if (is_string($value)) {
1792  $value = rtrim($value);
1793  }
1794  $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value;
1795  }
1796  $row = $tmp_row;
1797  break;
1799  $tmp_row = array();
1800  foreach ($row as $key => $value) {
1801  if ($value === '') {
1802  $value = null;
1803  }
1804  $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value;
1805  }
1806  $row = $tmp_row;
1807  break;
1809  $tmp_row = array();
1810  foreach ($row as $key => $value) {
1811  if ($value === '') {
1812  $value = null;
1813  } elseif (is_string($value)) {
1814  $value = rtrim($value);
1815  }
1816  $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value;
1817  }
1818  $row = $tmp_row;
1819  break;
1820  }
1821  }
1822 
1823  // }}}
1824  // {{{ function &loadModule($module, $property = null, $phptype_specific = null)
1825 
1840  function &loadModule($module, $property = null, $phptype_specific = null)
1841  {
1842  if (!$property) {
1843  $property = strtolower($module);
1844  }
1845 
1846  if (!isset($this->{$property})) {
1847  $version = $phptype_specific;
1848  if ($phptype_specific !== false) {
1849  $version = true;
1850  $class_name = 'MDB2_Driver_'.$module.'_'.$this->phptype;
1851  $file_name = str_replace('_', DIRECTORY_SEPARATOR, $class_name).'.php';
1852  }
1853  if ($phptype_specific === false
1854  || (!MDB2::classExists($class_name) && !MDB2::fileExists($file_name))
1855  ) {
1856  $version = false;
1857  $class_name = 'MDB2_'.$module;
1858  $file_name = str_replace('_', DIRECTORY_SEPARATOR, $class_name).'.php';
1859  }
1860 
1861  $err = MDB2::loadClass($class_name, $this->getOption('debug'));
1862  if (PEAR::isError($err)) {
1863  return $err;
1864  }
1865 
1866  // load modul in a specific version
1867  if ($version) {
1868  if (method_exists($class_name, 'getClassName')) {
1869  $class_name_new = call_user_func(array($class_name, 'getClassName'), $this->db_index);
1870  if ($class_name != $class_name_new) {
1871  $class_name = $class_name_new;
1872  $err = MDB2::loadClass($class_name, $this->getOption('debug'));
1873  if (PEAR::isError($err)) {
1874  return $err;
1875  }
1876  }
1877  }
1878  }
1879 
1880  if (!MDB2::classExists($class_name)) {
1881  $err =& $this->raiseError(MDB2_ERROR_LOADMODULE, null, null,
1882  "unable to load module '$module' into property '$property'", __FUNCTION__);
1883  return $err;
1884  }
1885  $this->{$property} =& new $class_name($this->db_index);
1886  $this->modules[$module] =& $this->{$property};
1887  if ($version) {
1888  // this will be used in the connect method to determine if the module
1889  // needs to be loaded with a different version if the server
1890  // version changed in between connects
1891  $this->loaded_version_modules[] = $property;
1892  }
1893  }
1894 
1895  return $this->{$property};
1896  }
1897 
1898  // }}}
1899  // {{{ function __call($method, $params)
1900 
1909  function __call($method, $params)
1910  {
1911  $module = null;
1912  if (preg_match('/^([a-z]+)([A-Z])(.*)$/', $method, $match)
1913  && isset($this->options['modules'][$match[1]])
1914  ) {
1915  $module = $this->options['modules'][$match[1]];
1916  $method = strtolower($match[2]).$match[3];
1917  if (!isset($this->modules[$module]) || !is_object($this->modules[$module])) {
1918  $result =& $this->loadModule($module);
1919  if (PEAR::isError($result)) {
1920  return $result;
1921  }
1922  }
1923  } else {
1924  foreach ($this->modules as $key => $foo) {
1925  if (is_object($this->modules[$key])
1926  && method_exists($this->modules[$key], $method)
1927  ) {
1928  $module = $key;
1929  break;
1930  }
1931  }
1932  }
1933  if (!is_null($module)) {
1934  return call_user_func_array(array(&$this->modules[$module], $method), $params);
1935  }
1936  trigger_error(sprintf('Call to undefined function: %s::%s().', get_class($this), $method), E_USER_ERROR);
1937  }
1938 
1939  // }}}
1940  // {{{ function beginTransaction($savepoint = null)
1941 
1950  function beginTransaction($savepoint = null)
1951  {
1952  $this->debug('Starting transaction', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint));
1953  return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
1954  'transactions are not supported', __FUNCTION__);
1955  }
1956 
1957  // }}}
1958  // {{{ function commit($savepoint = null)
1959 
1971  function commit($savepoint = null)
1972  {
1973  $this->debug('Committing transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint));
1974  return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
1975  'commiting transactions is not supported', __FUNCTION__);
1976  }
1977 
1978  // }}}
1979  // {{{ function rollback($savepoint = null)
1980 
1992  function rollback($savepoint = null)
1993  {
1994  $this->debug('Rolling back transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint));
1995  return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
1996  'rolling back transactions is not supported', __FUNCTION__);
1997  }
1998 
1999  // }}}
2000  // {{{ function inTransaction($ignore_nested = false)
2001 
2013  function inTransaction($ignore_nested = false)
2014  {
2015  if (!$ignore_nested && isset($this->nested_transaction_counter)) {
2017  }
2018  return $this->in_transaction;
2019  }
2020 
2021  // }}}
2022  // {{{ function setTransactionIsolation($isolation)
2023 
2040  function setTransactionIsolation($isolation, $options = array())
2041  {
2042  $this->debug('Setting transaction isolation level', __FUNCTION__, array('is_manip' => true));
2043  return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
2044  'isolation level setting is not supported', __FUNCTION__);
2045  }
2046 
2047  // }}}
2048  // {{{ function beginNestedTransaction($savepoint = false)
2049 
2064  {
2065  if ($this->in_transaction) {
2067  $savepoint = sprintf($this->options['savepoint_format'], $this->nested_transaction_counter);
2068  if ($this->supports('savepoints') && $savepoint) {
2069  return $this->beginTransaction($savepoint);
2070  }
2071  return MDB2_OK;
2072  }
2073  $this->has_transaction_error = false;
2074  $result = $this->beginTransaction();
2075  $this->nested_transaction_counter = 1;
2076  return $result;
2077  }
2078 
2079  // }}}
2080  // {{{ function completeNestedTransaction($force_rollback = false, $release = false)
2081 
2099  function completeNestedTransaction($force_rollback = false)
2100  {
2101  if ($this->nested_transaction_counter > 1) {
2102  $savepoint = sprintf($this->options['savepoint_format'], $this->nested_transaction_counter);
2103  if ($this->supports('savepoints') && $savepoint) {
2104  if ($force_rollback || $this->has_transaction_error) {
2105  $result = $this->rollback($savepoint);
2106  if (!PEAR::isError($result)) {
2107  $result = false;
2108  $this->has_transaction_error = false;
2109  }
2110  } else {
2111  $result = $this->commit($savepoint);
2112  }
2113  } else {
2114  $result = MDB2_OK;
2115  }
2117  return $result;
2118  }
2119 
2120  $this->nested_transaction_counter = null;
2121  $result = MDB2_OK;
2122 
2123  // transaction has not yet been rolled back
2124  if ($this->in_transaction) {
2125  if ($force_rollback || $this->has_transaction_error) {
2126  $result = $this->rollback();
2127  if (!PEAR::isError($result)) {
2128  $result = false;
2129  }
2130  } else {
2131  $result = $this->commit();
2132  }
2133  }
2134  $this->has_transaction_error = false;
2135  return $result;
2136  }
2137 
2138  // }}}
2139  // {{{ function failNestedTransaction($error = null, $immediately = false)
2140 
2156  function failNestedTransaction($error = null, $immediately = false)
2157  {
2158  if (is_null($error)) {
2159  $error = $this->has_transaction_error ? $this->has_transaction_error : true;
2160  } elseif (!$error) {
2161  $error = true;
2162  }
2163  $this->has_transaction_error = $error;
2164  if (!$immediately) {
2165  return MDB2_OK;
2166  }
2167  return $this->rollback();
2168  }
2169 
2170  // }}}
2171  // {{{ function getNestedTransactionError()
2172 
2187  {
2189  }
2190 
2191  // }}}
2192  // {{{ connect()
2193 
2199  function connect()
2200  {
2201  return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
2202  'method not implemented', __FUNCTION__);
2203  }
2204 
2205  // }}}
2206  // {{{ setCharset($charset, $connection = null)
2207 
2216  function setCharset($charset, $connection = null)
2217  {
2218  return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
2219  'method not implemented', __FUNCTION__);
2220  }
2221 
2222  // }}}
2223  // {{{ function disconnect($force = true)
2224 
2236  function disconnect($force = true)
2237  {
2238  $this->connection = 0;
2239  $this->connected_dsn = array();
2240  $this->connected_database_name = '';
2241  $this->opened_persistent = null;
2242  $this->connected_server_info = '';
2243  $this->in_transaction = null;
2244  $this->nested_transaction_counter = null;
2245  return MDB2_OK;
2246  }
2247 
2248  // }}}
2249  // {{{ function setDatabase($name)
2250 
2260  function setDatabase($name)
2261  {
2262  $previous_database_name = (isset($this->database_name)) ? $this->database_name : '';
2263  $this->database_name = $name;
2264  $this->disconnect(false);
2265  return $previous_database_name;
2266  }
2267 
2268  // }}}
2269  // {{{ function getDatabase()
2270 
2278  function getDatabase()
2279  {
2280  return $this->database_name;
2281  }
2282 
2283  // }}}
2284  // {{{ function setDSN($dsn)
2285 
2295  function setDSN($dsn)
2296  {
2297  $dsn_default = $GLOBALS['_MDB2_dsninfo_default'];
2299  if (array_key_exists('database', $dsn)) {
2300  $this->database_name = $dsn['database'];
2301  unset($dsn['database']);
2302  }
2303  $this->dsn = array_merge($dsn_default, $dsn);
2304  return $this->disconnect(false);
2305  }
2306 
2307  // }}}
2308  // {{{ function getDSN($type = 'string', $hidepw = false)
2309 
2320  function getDSN($type = 'string', $hidepw = false)
2321  {
2322  $dsn = array_merge($GLOBALS['_MDB2_dsninfo_default'], $this->dsn);
2323  $dsn['phptype'] = $this->phptype;
2324  $dsn['database'] = $this->database_name;
2325  if ($hidepw) {
2326  $dsn['password'] = $hidepw;
2327  }
2328  switch ($type) {
2329  // expand to include all possible options
2330  case 'string':
2331  $dsn = $dsn['phptype'].
2332  ($dsn['dbsyntax'] ? ('('.$dsn['dbsyntax'].')') : '').
2333  '://'.$dsn['username'].':'.
2334  $dsn['password'].'@'.$dsn['hostspec'].
2335  ($dsn['port'] ? (':'.$dsn['port']) : '').
2336  '/'.$dsn['database'];
2337  break;
2338  case 'array':
2339  default:
2340  break;
2341  }
2342  return $dsn;
2343  }
2344 
2345  // }}}
2346  // {{{ function &standaloneQuery($query, $types = null, $is_manip = false)
2347 
2360  function &standaloneQuery($query, $types = null, $is_manip = false)
2361  {
2363  $limit = $this->limit;
2364  $this->offset = $this->limit = 0;
2365  $query = $this->_modifyQuery($query, $is_manip, $limit, $offset);
2366 
2367  $connection = $this->getConnection();
2368  if (PEAR::isError($connection)) {
2369  return $connection;
2370  }
2371 
2372  $result =& $this->_doQuery($query, $is_manip, $connection, false);
2373  if (PEAR::isError($result)) {
2374  return $result;
2375  }
2376 
2377  if ($is_manip) {
2378  $affected_rows = $this->_affectedRows($connection, $result);
2379  return $affected_rows;
2380  }
2381  $result =& $this->_wrapResult($result, $types, true, false, $limit, $offset);
2382  return $result;
2383  }
2384 
2385  // }}}
2386  // {{{ function _modifyQuery($query, $is_manip, $limit, $offset)
2387 
2400  function _modifyQuery($query, $is_manip, $limit, $offset)
2401  {
2402  return $query;
2403  }
2404 
2405  // }}}
2406  // {{{ function &_doQuery($query, $is_manip = false, $connection = null, $database_name = null)
2407 
2419  function &_doQuery($query, $is_manip = false, $connection = null, $database_name = null)
2420  {
2421  $this->last_query = $query;
2422  $result = $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'pre'));
2423  if ($result) {
2424  if (PEAR::isError($result)) {
2425  return $result;
2426  }
2427  $query = $result;
2428  }
2429  $err =& $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
2430  'method not implemented', __FUNCTION__);
2431  return $err;
2432  }
2433 
2434  // }}}
2435  // {{{ function _affectedRows($connection, $result = null)
2436 
2448  {
2449  return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
2450  'method not implemented', __FUNCTION__);
2451  }
2452 
2453  // }}}
2454  // {{{ function &exec($query)
2455 
2465  function &exec($query)
2466  {
2468  $limit = $this->limit;
2469  $this->offset = $this->limit = 0;
2470  $query = $this->_modifyQuery($query, true, $limit, $offset);
2471 
2472  $connection = $this->getConnection();
2473  if (PEAR::isError($connection)) {
2474  return $connection;
2475  }
2476 
2477  $result =& $this->_doQuery($query, true, $connection, $this->database_name);
2478  if (PEAR::isError($result)) {
2479  return $result;
2480  }
2481 
2482  $affectedRows = $this->_affectedRows($connection, $result);
2483  return $affectedRows;
2484  }
2485 
2486  // }}}
2487  // {{{ function &query($query, $types = null, $result_class = true, $result_wrap_class = false)
2488 
2502  function &query($query, $types = null, $result_class = true, $result_wrap_class = false)
2503  {
2505  $limit = $this->limit;
2506  $this->offset = $this->limit = 0;
2507  $query = $this->_modifyQuery($query, false, $limit, $offset);
2508 
2509  $connection = $this->getConnection();
2510  if (PEAR::isError($connection)) {
2511  return $connection;
2512  }
2513 
2514  $result =& $this->_doQuery($query, false, $connection, $this->database_name);
2515  if (PEAR::isError($result)) {
2516  return $result;
2517  }
2518 
2519  $result =& $this->_wrapResult($result, $types, $result_class, $result_wrap_class, $limit, $offset);
2520  return $result;
2521  }
2522 
2523  // }}}
2524  // {{{ function &_wrapResult($result, $types = array(), $result_class = true, $result_wrap_class = false, $limit = null, $offset = null)
2525 
2541  function &_wrapResult($result, $types = array(), $result_class = true,
2542  $result_wrap_class = false, $limit = null, $offset = null)
2543  {
2544  if ($types === true) {
2545  if ($this->supports('result_introspection')) {
2546  $this->loadModule('Reverse', null, true);
2547  $tableInfo = $this->reverse->tableInfo($result);
2548  if (PEAR::isError($tableInfo)) {
2549  return $tableInfo;
2550  }
2551  $types = array();
2552  foreach ($tableInfo as $field) {
2553  $types[] = $field['mdb2type'];
2554  }
2555  } else {
2556  $types = null;
2557  }
2558  }
2559 
2560  if ($result_class === true) {
2561  $result_class = $this->options['result_buffering']
2562  ? $this->options['buffered_result_class'] : $this->options['result_class'];
2563  }
2564 
2565  if ($result_class) {
2566  $class_name = sprintf($result_class, $this->phptype);
2567  if (!MDB2::classExists($class_name)) {
2568  $err =& $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
2569  'result class does not exist '.$class_name, __FUNCTION__);
2570  return $err;
2571  }
2572  $result =& new $class_name($this, $result, $limit, $offset);
2573  if (!MDB2::isResultCommon($result)) {
2574  $err =& $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
2575  'result class is not extended from MDB2_Result_Common', __FUNCTION__);
2576  return $err;
2577  }
2578  if (!empty($types)) {
2579  $err = $result->setResultTypes($types);
2580  if (PEAR::isError($err)) {
2581  $result->free();
2582  return $err;
2583  }
2584  }
2585  }
2586  if ($result_wrap_class === true) {
2587  $result_wrap_class = $this->options['result_wrap_class'];
2588  }
2589  if ($result_wrap_class) {
2590  if (!MDB2::classExists($result_wrap_class)) {
2591  $err =& $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
2592  'result wrap class does not exist '.$result_wrap_class, __FUNCTION__);
2593  return $err;
2594  }
2595  $result =& new $result_wrap_class($result, $this->fetchmode);
2596  }
2597  return $result;
2598  }
2599 
2600  // }}}
2601  // {{{ function getServerVersion($native = false)
2602 
2612  function getServerVersion($native = false)
2613  {
2614  return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
2615  'method not implemented', __FUNCTION__);
2616  }
2617 
2618  // }}}
2619  // {{{ function setLimit($limit, $offset = null)
2620 
2631  function setLimit($limit, $offset = null)
2632  {
2633  if (!$this->supports('limit_queries')) {
2634  return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
2635  'limit is not supported by this driver', __FUNCTION__);
2636  }
2637  $limit = (int)$limit;
2638  if ($limit < 0) {
2639  return $this->raiseError(MDB2_ERROR_SYNTAX, null, null,
2640  'it was not specified a valid selected range row limit', __FUNCTION__);
2641  }
2642  $this->limit = $limit;
2643  if (!is_null($offset)) {
2644  $offset = (int)$offset;
2645  if ($offset < 0) {
2646  return $this->raiseError(MDB2_ERROR_SYNTAX, null, null,
2647  'it was not specified a valid first selected range row', __FUNCTION__);
2648  }
2649  $this->offset = $offset;
2650  }
2651  return MDB2_OK;
2652  }
2653 
2654  // }}}
2655  // {{{ function subSelect($query, $type = false)
2656 
2669  function subSelect($query, $type = false)
2670  {
2671  if ($this->supports('sub_selects') === true) {
2672  return $query;
2673  }
2674 
2675  if (!$this->supports('sub_selects')) {
2676  return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
2677  'method not implemented', __FUNCTION__);
2678  }
2679 
2680  $col = $this->queryCol($query, $type);
2681  if (PEAR::isError($col)) {
2682  return $col;
2683  }
2684  if (!is_array($col) || count($col) == 0) {
2685  return 'NULL';
2686  }
2687  if ($type) {
2688  $this->loadModule('Datatype', null, true);
2689  return $this->datatype->implodeArray($col, $type);
2690  }
2691  return implode(', ', $col);
2692  }
2693 
2694  // }}}
2695  // {{{ function replace($table, $fields)
2696 
2760  function replace($table, $fields)
2761  {
2762  if (!$this->supports('replace')) {
2763  return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
2764  'replace query is not supported', __FUNCTION__);
2765  }
2766  $count = count($fields);
2767  $condition = $values = array();
2768  for ($colnum = 0, reset($fields); $colnum < $count; next($fields), $colnum++) {
2769  $name = key($fields);
2770  if (isset($fields[$name]['null']) && $fields[$name]['null']) {
2771  $value = 'NULL';
2772  } else {
2773  $type = isset($fields[$name]['type']) ? $fields[$name]['type'] : null;
2774  $value = $this->quote($fields[$name]['value'], $type);
2775  }
2776  $values[$name] = $value;
2777  if (isset($fields[$name]['key']) && $fields[$name]['key']) {
2778  if ($value === 'NULL') {
2779  return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null,
2780  'key value '.$name.' may not be NULL', __FUNCTION__);
2781  }
2782  $condition[] = $name . '=' . $value;
2783  }
2784  }
2785  if (empty($condition)) {
2786  return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null,
2787  'not specified which fields are keys', __FUNCTION__);
2788  }
2789 
2790  $result = null;
2792  if (!$in_transaction && PEAR::isError($result = $this->beginTransaction())) {
2793  return $result;
2794  }
2795 
2796  $connection = $this->getConnection();
2797  if (PEAR::isError($connection)) {
2798  return $connection;
2799  }
2800 
2801  $condition = ' WHERE '.implode(' AND ', $condition);
2802  $query = "DELETE FROM $table$condition";
2803  $result =& $this->_doQuery($query, true, $connection);
2804  if (!PEAR::isError($result)) {
2805  $affected_rows = $this->_affectedRows($connection, $result);
2806  $insert = implode(', ', array_keys($values));
2807  $values = implode(', ', $values);
2808  $query = "INSERT INTO $table ($insert) VALUES ($values)";
2809  $result =& $this->_doQuery($query, true, $connection);
2810  if (!PEAR::isError($result)) {
2811  $affected_rows += $this->_affectedRows($connection, $result);;
2812  }
2813  }
2814 
2815  if (!$in_transaction) {
2816  if (PEAR::isError($result)) {
2817  $this->rollback();
2818  } else {
2819  $result = $this->commit();
2820  }
2821  }
2822 
2823  if (PEAR::isError($result)) {
2824  return $result;
2825  }
2826 
2827  return $affected_rows;
2828  }
2829 
2830  // }}}
2831  // {{{ function &prepare($query, $types = null, $result_types = null, $lobs = array())
2832 
2855  function &prepare($query, $types = null, $result_types = null, $lobs = array())
2856  {
2857  $is_manip = ($result_types === MDB2_PREPARE_MANIP);
2859  $limit = $this->limit;
2860  $this->offset = $this->limit = 0;
2861  $result = $this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'pre'));
2862  if ($result) {
2863  if (PEAR::isError($result)) {
2864  return $result;
2865  }
2866  $query = $result;
2867  }
2868  $placeholder_type_guess = $placeholder_type = null;
2869  $question = '?';
2870  $colon = ':';
2871  $positions = array();
2872  $position = 0;
2873  $ignores = $this->sql_comments;
2874  $ignores[] = $this->string_quoting;
2875  $ignores[] = $this->identifier_quoting;
2876  while ($position < strlen($query)) {
2877  $q_position = strpos($query, $question, $position);
2878  $c_position = strpos($query, $colon, $position);
2879  if ($q_position && $c_position) {
2880  $p_position = min($q_position, $c_position);
2881  } elseif ($q_position) {
2882  $p_position = $q_position;
2883  } elseif ($c_position) {
2884  $p_position = $c_position;
2885  } else {
2886  break;
2887  }
2888  if (is_null($placeholder_type)) {
2889  $placeholder_type_guess = $query[$p_position];
2890  }
2891 
2892  $new_pos = $this->_skipDelimitedStrings($query, $position, $p_position);
2893  if (PEAR::isError($new_pos)) {
2894  return $new_pos;
2895  }
2896  if ($new_pos != $position) {
2897  $position = $new_pos;
2898  continue; //evaluate again starting from the new position
2899  }
2900 
2901  if ($query[$position] == $placeholder_type_guess) {
2902  if (is_null($placeholder_type)) {
2903  $placeholder_type = $query[$p_position];
2904  $question = $colon = $placeholder_type;
2905  if (!empty($types) && is_array($types)) {
2906  if ($placeholder_type == ':') {
2907  if (is_int(key($types))) {
2908  $types_tmp = $types;
2909  $types = array();
2910  $count = -1;
2911  }
2912  } else {
2913  $types = array_values($types);
2914  }
2915  }
2916  }
2917  if ($placeholder_type == ':') {
2918  $parameter = preg_replace('/^.{'.($position+1).'}([a-z0-9_]+).*$/si', '\\1', $query);
2919  if ($parameter === '') {
2920  $err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null,
2921  'named parameter with an empty name', __FUNCTION__);
2922  return $err;
2923  }
2924  $positions[$p_position] = $parameter;
2925  $query = substr_replace($query, '?', $position, strlen($parameter)+1);
2926  // use parameter name in type array
2927  if (isset($count) && isset($types_tmp[++$count])) {
2928  $types[$parameter] = $types_tmp[$count];
2929  }
2930  } else {
2931  $positions[$p_position] = count($positions);
2932  }
2933  $position = $p_position + 1;
2934  } else {
2935  $position = $p_position;
2936  }
2937  }
2938  $class_name = 'MDB2_Statement_'.$this->phptype;
2939  $statement = null;
2940  $obj =& new $class_name($this, $statement, $positions, $query, $types, $result_types, $is_manip, $limit, $offset);
2941  $this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'post', 'result' => $obj));
2942  return $obj;
2943  }
2944 
2945  // }}}
2946  // {{{ function _skipDelimitedStrings($query, $position, $p_position)
2947 
2963  function _skipDelimitedStrings($query, $position, $p_position)
2964  {
2965  $ignores = $this->sql_comments;
2966  $ignores[] = $this->string_quoting;
2967  $ignores[] = $this->identifier_quoting;
2968 
2969  foreach ($ignores as $ignore) {
2970  if (!empty($ignore['start'])) {
2971  if (is_int($start_quote = strpos($query, $ignore['start'], $position)) && $start_quote < $p_position) {
2972  $end_quote = $start_quote;
2973  do {
2974  if (!is_int($end_quote = strpos($query, $ignore['end'], $end_quote + 1))) {
2975  if ($ignore['end'] === "\n") {
2976  $end_quote = strlen($query) - 1;
2977  } else {
2978  $err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null,
2979  'query with an unterminated text string specified', __FUNCTION__);
2980  return $err;
2981  }
2982  }
2983  } while ($ignore['escape'] && $query[($end_quote - 1)] == $ignore['escape']);
2984  $position = $end_quote + 1;
2985  return $position;
2986  }
2987  }
2988  }
2989  return $position;
2990  }
2991 
2992  // }}}
2993  // {{{ function quote($value, $type = null, $quote = true)
2994 
3009  function quote($value, $type = null, $quote = true, $escape_wildcards = false)
3010  {
3011  $result = $this->loadModule('Datatype', null, true);
3012  if (PEAR::isError($result)) {
3013  return $result;
3014  }
3015 
3016  return $this->datatype->quote($value, $type, $quote, $escape_wildcards);
3017  }
3018 
3019  // }}}
3020  // {{{ function getDeclaration($type, $name, $field)
3021 
3035  function getDeclaration($type, $name, $field)
3036  {
3037  $result = $this->loadModule('Datatype', null, true);
3038  if (PEAR::isError($result)) {
3039  return $result;
3040  }
3041  return $this->datatype->getDeclaration($type, $name, $field);
3042  }
3043 
3044  // }}}
3045  // {{{ function compareDefinition($current, $previous)
3046 
3057  function compareDefinition($current, $previous)
3058  {
3059  $result = $this->loadModule('Datatype', null, true);
3060  if (PEAR::isError($result)) {
3061  return $result;
3062  }
3063  return $this->datatype->compareDefinition($current, $previous);
3064  }
3065 
3066  // }}}
3067  // {{{ function supports($feature)
3068 
3081  function supports($feature)
3082  {
3083  if (array_key_exists($feature, $this->supported)) {
3084  return $this->supported[$feature];
3085  }
3086  return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
3087  "unknown support feature $feature", __FUNCTION__);
3088  }
3089 
3090  // }}}
3091  // {{{ function getSequenceName($sqn)
3092 
3102  function getSequenceName($sqn)
3103  {
3104  return sprintf($this->options['seqname_format'],
3105  preg_replace('/[^a-z0-9_\$.]/i', '_', $sqn));
3106  }
3107 
3108  // }}}
3109  // {{{ function getIndexName($idx)
3110 
3120  function getIndexName($idx)
3121  {
3122  return sprintf($this->options['idxname_format'],
3123  preg_replace('/[^a-z0-9_\$]/i', '_', $idx));
3124  }
3125 
3126  // }}}
3127  // {{{ function nextID($seq_name, $ondemand = true)
3128 
3139  function nextID($seq_name, $ondemand = true)
3140  {
3141  return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
3142  'method not implemented', __FUNCTION__);
3143  }
3144 
3145  // }}}
3146  // {{{ function lastInsertID($table = null, $field = null)
3147 
3159  function lastInsertID($table = null, $field = null)
3160  {
3161  return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
3162  'method not implemented', __FUNCTION__);
3163  }
3164 
3165  // }}}
3166  // {{{ function currID($seq_name)
3167 
3177  function currID($seq_name)
3178  {
3179  $this->warnings[] = 'database does not support getting current
3180  sequence value, the sequence value was incremented';
3181  return $this->nextID($seq_name);
3182  }
3183 
3184  // }}}
3185  // {{{ function queryOne($query, $type = null, $colnum = 0)
3186 
3203  function queryOne($query, $type = null, $colnum = 0)
3204  {
3205  $result = $this->query($query, $type);
3206  if (!MDB2::isResultCommon($result)) {
3207  return $result;
3208  }
3209 
3210  $one = $result->fetchOne($colnum);
3211  $result->free();
3212  return $one;
3213  }
3214 
3215  // }}}
3216  // {{{ function queryRow($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT)
3217 
3234  function queryRow($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT)
3235  {
3236  $result = $this->query($query, $types);
3237  if (!MDB2::isResultCommon($result)) {
3238  return $result;
3239  }
3240 
3241  $row = $result->fetchRow($fetchmode);
3242  $result->free();
3243  return $row;
3244  }
3245 
3246  // }}}
3247  // {{{ function queryCol($query, $type = null, $colnum = 0)
3248 
3264  function queryCol($query, $type = null, $colnum = 0)
3265  {
3266  $result = $this->query($query, $type);
3267  if (!MDB2::isResultCommon($result)) {
3268  return $result;
3269  }
3270 
3271  $col = $result->fetchCol($colnum);
3272  $result->free();
3273  return $col;
3274  }
3275 
3276  // }}}
3277  // {{{ function queryAll($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT, $rekey = false, $force_array = false, $group = false)
3278 
3303  function queryAll($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT,
3304  $rekey = false, $force_array = false, $group = false)
3305  {
3306  $result = $this->query($query, $types);
3307  if (!MDB2::isResultCommon($result)) {
3308  return $result;
3309  }
3310 
3311  $all = $result->fetchAll($fetchmode, $rekey, $force_array, $group);
3312  $result->free();
3313  return $all;
3314  }
3315 
3316  // }}}
3317 }
3318 
3319 // }}}
3320 // {{{ class MDB2_Result
3321 
3330 {
3331 }
3332 
3333 // }}}
3334 // {{{ class MDB2_Result_Common extends MDB2_Result
3335 
3344 {
3345  // {{{ Variables (Properties)
3346 
3347  var $db;
3348  var $result;
3349  var $rownum = -1;
3350  var $types = array();
3351  var $values = array();
3352  var $offset;
3353  var $offset_count = 0;
3354  var $limit;
3356 
3357  // }}}
3358  // {{{ constructor: function __construct(&$db, &$result, $limit = 0, $offset = 0)
3359 
3363  function __construct(&$db, &$result, $limit = 0, $offset = 0)
3364  {
3365  $this->db =& $db;
3366  $this->result =& $result;
3367  $this->offset = $offset;
3368  $this->limit = max(0, $limit - 1);
3369  }
3370 
3371  // }}}
3372  // {{{ function MDB2_Result_Common(&$db, &$result, $limit = 0, $offset = 0)
3373 
3378  {
3379  $this->__construct($db, $result, $limit, $offset);
3380  }
3381 
3382  // }}}
3383  // {{{ function setResultTypes($types)
3384 
3407  {
3408  $load = $this->db->loadModule('Datatype', null, true);
3409  if (PEAR::isError($load)) {
3410  return $load;
3411  }
3412  $types = $this->db->datatype->checkResultTypes($types);
3413  if (PEAR::isError($types)) {
3414  return $types;
3415  }
3416  $this->types = $types;
3417  return MDB2_OK;
3418  }
3419 
3420  // }}}
3421  // {{{ function seek($rownum = 0)
3422 
3432  function seek($rownum = 0)
3433  {
3434  $target_rownum = $rownum - 1;
3435  if ($this->rownum > $target_rownum) {
3436  return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
3437  'seeking to previous rows not implemented', __FUNCTION__);
3438  }
3439  while ($this->rownum < $target_rownum) {
3440  $this->fetchRow();
3441  }
3442  return MDB2_OK;
3443  }
3444 
3445  // }}}
3446  // {{{ function &fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null)
3447 
3458  function &fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null)
3459  {
3460  $err =& $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
3461  'method not implemented', __FUNCTION__);
3462  return $err;
3463  }
3464 
3465  // }}}
3466  // {{{ function fetchOne($colnum = 0)
3467 
3478  function fetchOne($colnum = 0, $rownum = null)
3479  {
3480  $fetchmode = is_numeric($colnum) ? MDB2_FETCHMODE_ORDERED : MDB2_FETCHMODE_ASSOC;
3481  $row = $this->fetchRow($fetchmode, $rownum);
3482  if (!is_array($row) || PEAR::isError($row)) {
3483  return $row;
3484  }
3485  if (!array_key_exists($colnum, $row)) {
3486  return $this->db->raiseError(MDB2_ERROR_TRUNCATED, null, null,
3487  'column is not defined in the result set: '.$colnum, __FUNCTION__);
3488  }
3489  return $row[$colnum];
3490  }
3491 
3492  // }}}
3493  // {{{ function fetchCol($colnum = 0)
3494 
3504  function fetchCol($colnum = 0)
3505  {
3506  $column = array();
3507  $fetchmode = is_numeric($colnum) ? MDB2_FETCHMODE_ORDERED : MDB2_FETCHMODE_ASSOC;
3508  $row = $this->fetchRow($fetchmode);
3509  if (is_array($row)) {
3510  if (!array_key_exists($colnum, $row)) {
3511  return $this->db->raiseError(MDB2_ERROR_TRUNCATED, null, null,
3512  'column is not defined in the result set: '.$colnum, __FUNCTION__);
3513  }
3514  do {
3515  $column[] = $row[$colnum];
3516  } while (is_array($row = $this->fetchRow($fetchmode)));
3517  }
3518  if (PEAR::isError($row)) {
3519  return $row;
3520  }
3521  return $column;
3522  }
3523 
3524  // }}}
3525  // {{{ function fetchAll($fetchmode = MDB2_FETCHMODE_DEFAULT, $rekey = false, $force_array = false, $group = false)
3526 
3550  function fetchAll($fetchmode = MDB2_FETCHMODE_DEFAULT, $rekey = false,
3551  $force_array = false, $group = false)
3552  {
3553  $all = array();
3554  $row = $this->fetchRow($fetchmode);
3555  if (PEAR::isError($row)) {
3556  return $row;
3557  } elseif (!$row) {
3558  return $all;
3559  }
3560 
3561  $shift_array = $rekey ? false : null;
3562  if (!is_null($shift_array)) {
3563  if (is_object($row)) {
3564  $colnum = count(get_object_vars($row));
3565  } else {
3566  $colnum = count($row);
3567  }
3568  if ($colnum < 2) {
3569  return $this->db->raiseError(MDB2_ERROR_TRUNCATED, null, null,
3570  'rekey feature requires atleast 2 column', __FUNCTION__);
3571  }
3572  $shift_array = (!$force_array && $colnum == 2);
3573  }
3574 
3575  if ($rekey) {
3576  do {
3577  if (is_object($row)) {
3578  $arr = get_object_vars($row);
3579  $key = reset($arr);
3580  unset($row->{$key});
3581  } else {
3582  if ($fetchmode & MDB2_FETCHMODE_ASSOC) {
3583  $key = reset($row);
3584  unset($row[key($row)]);
3585  } else {
3586  $key = array_shift($row);
3587  }
3588  if ($shift_array) {
3589  $row = array_shift($row);
3590  }
3591  }
3592  if ($group) {
3593  $all[$key][] = $row;
3594  } else {
3595  $all[$key] = $row;
3596  }
3597  } while (($row = $this->fetchRow($fetchmode)));
3598  } elseif ($fetchmode & MDB2_FETCHMODE_FLIPPED) {
3599  do {
3600  foreach ($row as $key => $val) {
3601  $all[$key][] = $val;
3602  }
3603  } while (($row = $this->fetchRow($fetchmode)));
3604  } else {
3605  do {
3606  $all[] = $row;
3607  } while (($row = $this->fetchRow($fetchmode)));
3608  }
3609 
3610  return $all;
3611  }
3612 
3613  // }}}
3614  // {{{ function rowCount()
3621  function rowCount()
3622  {
3623  return $this->rownum + 1;
3624  }
3625 
3626  // }}}
3627  // {{{ function numRows()
3628 
3636  function numRows()
3637  {
3638  return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
3639  'method not implemented', __FUNCTION__);
3640  }
3641 
3642  // }}}
3643  // {{{ function nextResult()
3644 
3652  function nextResult()
3653  {
3654  return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
3655  'method not implemented', __FUNCTION__);
3656  }
3657 
3658  // }}}
3659  // {{{ function getColumnNames()
3660 
3674  function getColumnNames($flip = false)
3675  {
3676  if (!isset($this->column_names)) {
3677  $result = $this->_getColumnNames();
3678  if (PEAR::isError($result)) {
3679  return $result;
3680  }
3681  $this->column_names = $result;
3682  }
3683  if ($flip) {
3684  return array_flip($this->column_names);
3685  }
3686  return $this->column_names;
3687  }
3688 
3689  // }}}
3690  // {{{ function _getColumnNames()
3691 
3702  function _getColumnNames()
3703  {
3704  return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
3705  'method not implemented', __FUNCTION__);
3706  }
3707 
3708  // }}}
3709  // {{{ function numCols()
3710 
3719  function numCols()
3720  {
3721  return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
3722  'method not implemented', __FUNCTION__);
3723  }
3724 
3725  // }}}
3726  // {{{ function getResource()
3727 
3735  function getResource()
3736  {
3737  return $this->result;
3738  }
3739 
3740  // }}}
3741  // {{{ function bindColumn($column, &$value, $type = null)
3742 
3754  function bindColumn($column, &$value, $type = null)
3755  {
3756  if (!is_numeric($column)) {
3757  $column_names = $this->getColumnNames();
3758  if ($this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
3759  if ($this->db->options['field_case'] == CASE_LOWER) {
3760  $column = strtolower($column);
3761  } else {
3762  $column = strtoupper($column);
3763  }
3764  }
3765  $column = $column_names[$column];
3766  }
3767  $this->values[$column] =& $value;
3768  if (!is_null($type)) {
3769  $this->types[$column] = $type;
3770  }
3771  return MDB2_OK;
3772  }
3773 
3774  // }}}
3775  // {{{ function _assignBindColumns($row)
3776 
3786  function _assignBindColumns($row)
3787  {
3788  $row = array_values($row);
3789  foreach ($row as $column => $value) {
3790  if (array_key_exists($column, $this->values)) {
3791  $this->values[$column] = $value;
3792  }
3793  }
3794  return MDB2_OK;
3795  }
3796 
3797  // }}}
3798  // {{{ function free()
3799 
3807  function free()
3808  {
3809  $this->result = false;
3810  return MDB2_OK;
3811  }
3812 
3813  // }}}
3814 }
3815 
3816 // }}}
3817 // {{{ class MDB2_Row
3818 
3827 {
3828  // {{{ constructor: function __construct(&$row)
3829 
3835  function __construct(&$row)
3836  {
3837  foreach ($row as $key => $value) {
3838  $this->$key = &$row[$key];
3839  }
3840  }
3841 
3842  // }}}
3843  // {{{ function MDB2_Row(&$row)
3844 
3850  function MDB2_Row(&$row)
3851  {
3852  $this->__construct($row);
3853  }
3854 
3855  // }}}
3856 }
3857 
3858 // }}}
3859 // {{{ class MDB2_Statement_Common
3860 
3869 {
3870  // {{{ Variables (Properties)
3871 
3872  var $db;
3874  var $query;
3876  var $types;
3877  var $values = array();
3878  var $limit;
3879  var $offset;
3881 
3882  // }}}
3883  // {{{ constructor: function __construct(&$db, &$statement, $positions, $query, $types, $result_types, $is_manip = false, $limit = null, $offset = null)
3884 
3888  function __construct(&$db, &$statement, $positions, $query, $types, $result_types, $is_manip = false, $limit = null, $offset = null)
3889  {
3890  $this->db =& $db;
3891  $this->statement =& $statement;
3892  $this->positions = $positions;
3893  $this->query = $query;
3894  $this->types = (array)$types;
3895  $this->result_types = (array)$result_types;
3896  $this->limit = $limit;
3897  $this->is_manip = $is_manip;
3898  $this->offset = $offset;
3899  }
3900 
3901  // }}}
3902  // {{{ function MDB2_Statement_Common(&$db, &$statement, $positions, $query, $types, $result_types, $is_manip = false, $limit = null, $offset = null)
3903 
3907  function MDB2_Statement_Common(&$db, &$statement, $positions, $query, $types, $result_types, $is_manip = false, $limit = null, $offset = null)
3908  {
3910  }
3911 
3912  // }}}
3913  // {{{ function bindValue($parameter, &$value, $type = null)
3914 
3928  function bindValue($parameter, $value, $type = null)
3929  {
3930  if (!is_numeric($parameter)) {
3931  $parameter = preg_replace('/^:(.*)$/', '\\1', $parameter);
3932  }
3933  if (!in_array($parameter, $this->positions)) {
3934  return $this->db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
3935  'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__);
3936  }
3937  $this->values[$parameter] = $value;
3938  if (!is_null($type)) {
3939  $this->types[$parameter] = $type;
3940  }
3941  return MDB2_OK;
3942  }
3943 
3944  // }}}
3945  // {{{ function bindValueArray($values, $types = null)
3946 
3960  function bindValueArray($values, $types = null)
3961  {
3962  $types = is_array($types) ? array_values($types) : array_fill(0, count($values), null);
3963  $parameters = array_keys($values);
3964  foreach ($parameters as $key => $parameter) {
3965  $err = $this->bindValue($parameter, $values[$parameter], $types[$key]);
3966  if (PEAR::isError($err)) {
3967  return $err;
3968  }
3969  }
3970  return MDB2_OK;
3971  }
3972 
3973  // }}}
3974  // {{{ function bindParam($parameter, &$value, $type = null)
3975 
3989  function bindParam($parameter, &$value, $type = null)
3990  {
3991  if (!is_numeric($parameter)) {
3992  $parameter = preg_replace('/^:(.*)$/', '\\1', $parameter);
3993  }
3994  if (!in_array($parameter, $this->positions)) {
3995  return $this->db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
3996  'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__);
3997  }
3998  $this->values[$parameter] =& $value;
3999  if (!is_null($type)) {
4000  $this->types[$parameter] = $type;
4001  }
4002  return MDB2_OK;
4003  }
4004 
4005  // }}}
4006  // {{{ function bindParamArray(&$values, $types = null)
4007 
4021  function bindParamArray(&$values, $types = null)
4022  {
4023  $types = is_array($types) ? array_values($types) : array_fill(0, count($values), null);
4024  $parameters = array_keys($values);
4025  foreach ($parameters as $key => $parameter) {
4026  $err = $this->bindParam($parameter, $values[$parameter], $types[$key]);
4027  if (PEAR::isError($err)) {
4028  return $err;
4029  }
4030  }
4031  return MDB2_OK;
4032  }
4033 
4034  // }}}
4035  // {{{ function &execute($values = null, $result_class = true, $result_wrap_class = false)
4036 
4050  function &execute($values = null, $result_class = true, $result_wrap_class = false)
4051  {
4052  if (is_null($this->positions)) {
4053  return $this->db->raiseError(MDB2_ERROR, null, null,
4054  'Prepared statement has already been freed', __FUNCTION__);
4055  }
4056 
4057  $values = (array)$values;
4058  if (!empty($values)) {
4059  $err = $this->bindValueArray($values);
4060  if (PEAR::isError($err)) {
4061  return $this->db->raiseError(MDB2_ERROR, null, null,
4062  'Binding Values failed with message: ' . $err->getMessage(), __FUNCTION__);
4063  }
4064  }
4065  $result =& $this->_execute($result_class, $result_wrap_class);
4066  return $result;
4067  }
4068 
4069  // }}}
4070  // {{{ function &_execute($result_class = true, $result_wrap_class = false)
4071 
4082  function &_execute($result_class = true, $result_wrap_class = false)
4083  {
4084  $this->last_query = $this->query;
4085  $query = '';
4086  $last_position = 0;
4087  foreach ($this->positions as $current_position => $parameter) {
4088  if (!array_key_exists($parameter, $this->values)) {
4089  return $this->db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
4090  'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__);
4091  }
4092  $value = $this->values[$parameter];
4093  $query.= substr($this->query, $last_position, $current_position - $last_position);
4094  if (!isset($value)) {
4095  $value_quoted = 'NULL';
4096  } else {
4097  $type = !empty($this->types[$parameter]) ? $this->types[$parameter] : null;
4098  $value_quoted = $this->db->quote($value, $type);
4099  if (PEAR::isError($value_quoted)) {
4100  return $value_quoted;
4101  }
4102  }
4103  $query.= $value_quoted;
4104  $last_position = $current_position + 1;
4105  }
4106  $query.= substr($this->query, $last_position);
4107 
4108  $this->db->offset = $this->offset;
4109  $this->db->limit = $this->limit;
4110  if ($this->is_manip) {
4111  $result = $this->db->exec($query);
4112  } else {
4113  $result =& $this->db->query($query, $this->result_types, $result_class, $result_wrap_class);
4114  }
4115  return $result;
4116  }
4117 
4118  // }}}
4119  // {{{ function free()
4120 
4128  function free()
4129  {
4130  if (is_null($this->positions)) {
4131  return $this->db->raiseError(MDB2_ERROR, null, null,
4132  'Prepared statement has already been freed', __FUNCTION__);
4133  }
4134 
4135  $this->statement = null;
4136  $this->positions = null;
4137  $this->query = null;
4138  $this->types = null;
4139  $this->result_types = null;
4140  $this->limit = null;
4141  $this->is_manip = null;
4142  $this->offset = null;
4143  $this->values = null;
4144 
4145  return MDB2_OK;
4146  }
4147 
4148  // }}}
4149 }
4150 
4151 // }}}
4152 // {{{ class MDB2_Module_Common
4153 
4162 {
4163  // {{{ Variables (Properties)
4164 
4173 
4174  // }}}
4175  // {{{ constructor: function __construct($db_index)
4176 
4181  {
4182  $this->db_index = $db_index;
4183  }
4184 
4185  // }}}
4186  // {{{ function MDB2_Module_Common($db_index)
4187 
4192  {
4193  $this->__construct($db_index);
4194  }
4195 
4196  // }}}
4197  // {{{ function &getDBInstance()
4198 
4206  function &getDBInstance()
4207  {
4208  if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) {
4209  $result =& $GLOBALS['_MDB2_databases'][$this->db_index];
4210  } else {
4212  'could not find MDB2 instance');
4213  }
4214  return $result;
4215  }
4216 
4217  // }}}
4218 }
4219 
4220 // }}}
4221 // {{{ function MDB2_closeOpenTransactions()
4222 
4232 {
4233  reset($GLOBALS['_MDB2_databases']);
4234  while (next($GLOBALS['_MDB2_databases'])) {
4235  $key = key($GLOBALS['_MDB2_databases']);
4236  if ($GLOBALS['_MDB2_databases'][$key]->opened_persistent
4237  && $GLOBALS['_MDB2_databases'][$key]->in_transaction
4238  ) {
4239  $GLOBALS['_MDB2_databases'][$key]->rollback();
4240  }
4241  }
4242 }
4243 
4244 // }}}
4245 // {{{ function MDB2_defaultDebugOutput(&$db, $scope, $message, $is_manip = null)
4246 
4263 function MDB2_defaultDebugOutput(&$db, $scope, $message, $context = array())
4264 {
4265  $db->debug_output.= $scope.'('.$db->db_index.'): ';
4266  $db->debug_output.= $message.$db->getOption('log_line_break');
4267  return $message;
4268 }
4269 
4270 // }}}
4271 ?>