1<?php 2/* 3V4.65 22 July 2005 (c) 2000-2005 John Lim (jlim#natsoft.com.my). All rights reserved. 4 Released under both BSD license and Lesser GPL library license. 5 Whenever there is any discrepancy between the two licenses, 6 the BSD license will take precedence. 7Set tabs to 4 for best viewing. 8 9 Latest version is available at http://adodb.sourceforge.net 10 11 Requires ODBC. Works on Windows and Unix. 12 13 Problems: 14 Where is float/decimal type in pdo_param_type 15 LOB handling for CLOB/BLOB differs significantly 16*/ 17// security - hide paths 18if (!defined('ADODB_DIR')) die(); 19 20 21/* 22enum pdo_param_type { 23PDO_PARAM_NULL, 0 24 25/* int as in long (the php native int type). 26 * If you mark a column as an int, PDO expects get_col to return 27 * a pointer to a long 28PDO_PARAM_INT, 1 29 30/* get_col ptr should point to start of the string buffer 31PDO_PARAM_STR, 2 32 33/* get_col: when len is 0 ptr should point to a php_stream *, 34 * otherwise it should behave like a string. Indicate a NULL field 35 * value by setting the ptr to NULL 36PDO_PARAM_LOB, 3 37 38/* get_col: will expect the ptr to point to a new PDOStatement object handle, 39 * but this isn't wired up yet 40PDO_PARAM_STMT, 4 /* hierarchical result set 41 42/* get_col ptr should point to a zend_bool 43PDO_PARAM_BOOL, 5 44 45 46/* magic flag to denote a parameter as being input/output 47PDO_PARAM_INPUT_OUTPUT = 0x80000000 48}; 49*/ 50 51function adodb_pdo_type($t) 52{ 53 switch($t) { 54 case 2: return 'VARCHAR'; 55 case 3: return 'BLOB'; 56 default: return 'NUMERIC'; 57 } 58} 59 60/*-------------------------------------------------------------------------------------- 61--------------------------------------------------------------------------------------*/ 62 63//////////////////////////////////////////////// 64 65 66 67class ADODB_pdo_base extends ADODB_pdo { 68 69 function _init($parentDriver) 70 { 71 $parentDriver->_bindInputArray = false; 72 #$parentDriver->_connectionID->setAttribute(PDO_MYSQL_ATTR_USE_BUFFERED_QUERY,true); 73 } 74 75 function ServerInfo() 76 { 77 return ADOConnection::ServerInfo(); 78 } 79 80 function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0) 81 { 82 $ret = ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); 83 return $ret; 84 } 85 86 function MetaTables() 87 { 88 return false; 89 } 90 91 function MetaColumns() 92 { 93 return false; 94 } 95} 96 97 98class ADODB_pdo extends ADOConnection { 99 var $databaseType = "pdo"; 100 var $dataProvider = "pdo"; 101 var $fmtDate = "'Y-m-d'"; 102 var $fmtTimeStamp = "'Y-m-d, h:i:sA'"; 103 var $replaceQuote = "''"; // string to use to replace quotes 104 var $hasAffectedRows = true; 105 var $_bindInputArray = true; 106 var $_genSeqSQL = "create table %s (id integer)"; 107 var $_autocommit = true; 108 var $_haserrorfunctions = true; 109 var $_lastAffectedRows = 0; 110 111 var $_errormsg = false; 112 var $_errorno = false; 113 114 var $dsnType = ''; 115 var $stmt = false; 116 117 function ADODB_pdo() 118 { 119 } 120 121 function _UpdatePDO() 122 { 123 $d = &$this->_driver; 124 $this->fmtDate = $d->fmtDate; 125 $this->fmtTimeStamp = $d->fmtTimeStamp; 126 $this->replaceQuote = $d->replaceQuote; 127 $this->sysDate = $d->sysDate; 128 $this->sysTimeStamp = $d->sysTimeStamp; 129 $this->random = $d->random; 130 $this->concat_operator = $d->concat_operator; 131 132 $d->_init($this); 133 } 134 135 function Time() 136 { 137 return false; 138 } 139 140 // returns true or false 141 function _connect($argDSN, $argUsername, $argPassword, $argDatabasename, $persist=false) 142 { 143 $at = strpos($argDSN,':'); 144 $this->dsnType = substr($argDSN,0,$at); 145 146 try { 147 $this->_connectionID = new PDO($argDSN, $argUsername, $argPassword); 148 } catch (Exception $e) { 149 $this->_connectionID = false; 150 $this->_errorno = -1; 151 //var_dump($e); 152 $this->_errormsg = 'Connection attempt failed: '.$e->getMessage(); 153 return false; 154 } 155 156 if ($this->_connectionID) { 157 switch(ADODB_ASSOC_CASE){ 158 case 0: $m = PDO_CASE_LOWER; break; 159 case 1: $m = PDO_CASE_UPPER; break; 160 default: 161 case 2: $m = PDO_CASE_NATURAL; break; 162 } 163 164 //$this->_connectionID->setAttribute(PDO_ATTR_ERRMODE,PDO_ERRMODE_SILENT ); 165 $this->_connectionID->setAttribute(PDO_ATTR_CASE,$m); 166 167 $class = 'ADODB_pdo_'.$this->dsnType; 168 //$this->_connectionID->setAttribute(PDO_ATTR_AUTOCOMMIT,true); 169 switch($this->dsnType) { 170 case 'oci': 171 case 'mysql': 172 case 'pgsql': 173 include_once(ADODB_DIR.'/drivers/adodb-pdo_'.$this->dsnType.'.inc.php'); 174 break; 175 } 176 if (class_exists($class)) 177 $this->_driver = new $class(); 178 else 179 $this->_driver = new ADODB_pdo_base(); 180 181 $this->_driver->_connectionID = $this->_connectionID; 182 $this->_UpdatePDO(); 183 return true; 184 } 185 $this->_driver = new ADODB_pdo_base(); 186 return false; 187 } 188 189 // returns true or false 190 function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename) 191 { 192 return $this->_connect($argDSN, $argUsername, $argPassword, $argDatabasename, true); 193 } 194 195 /*------------------------------------------------------------------------------*/ 196 197 198 function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0) 199 { 200 $save = $this->_driver->fetchMode; 201 $this->_driver->fetchMode = $this->fetchMode; 202 $ret = $this->_driver->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); 203 $this->_driver->fetchMode = $save; 204 return $ret; 205 } 206 207 208 function ServerInfo() 209 { 210 return $this->_driver->ServerInfo(); 211 } 212 213 function MetaTables($ttype=false,$showSchema=false,$mask=false) 214 { 215 return $this->_driver->MetaTables($ttype,$showSchema,$mask); 216 } 217 218 function MetaColumns($table,$normalize=true) 219 { 220 return $this->_driver->MetaColumns($table,$normalize); 221 } 222 223 function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) 224 { 225 $obj = $stmt[1]; 226 if ($type) $obj->bindParam($name,$var,$type,$maxLen); 227 else $obj->bindParam($name, $var); 228 } 229 230 231 function ErrorMsg() 232 { 233 if ($this->_errormsg !== false) return $this->_errormsg; 234 if (!empty($this->_stmt)) $arr = $this->_stmt->errorInfo(); 235 else if (!empty($this->_connectionID)) $arr = $this->_connectionID->errorInfo(); 236 else return 'No Connection Established'; 237 238 239 if ($arr) { 240 if (sizeof($arr)<2) return ''; 241 if ((integer)$arr[1]) return $arr[2]; 242 else return ''; 243 } else return '-1'; 244 } 245 246 247 function ErrorNo() 248 { 249 if ($this->_errorno !== false) return $this->_errorno; 250 if (!empty($this->_stmt)) $err = $this->_stmt->errorCode(); 251 else if (!empty($this->_connectionID)) { 252 $arr = $this->_connectionID->errorInfo(); 253 if (isset($arr[0])) $err = $arr[0]; 254 else $err = -1; 255 } else 256 return 0; 257 258 if ($err == '00000') return 0; // allows empty check 259 return $err; 260 } 261 262 function BeginTrans() 263 { 264 if (!$this->hasTransactions) return false; 265 if ($this->transOff) return true; 266 $this->transCnt += 1; 267 $this->_autocommit = false; 268 $this->_connectionID->setAttribute(PDO_ATTR_AUTOCOMMIT,false); 269 return $this->_connectionID->beginTransaction(); 270 } 271 272 function CommitTrans($ok=true) 273 { 274 if (!$this->hasTransactions) return false; 275 if ($this->transOff) return true; 276 if (!$ok) return $this->RollbackTrans(); 277 if ($this->transCnt) $this->transCnt -= 1; 278 $this->_autocommit = true; 279 280 $ret = $this->_connectionID->commit(); 281 $this->_connectionID->setAttribute(PDO_ATTR_AUTOCOMMIT,true); 282 return $ret; 283 } 284 285 function RollbackTrans() 286 { 287 if (!$this->hasTransactions) return false; 288 if ($this->transOff) return true; 289 if ($this->transCnt) $this->transCnt -= 1; 290 $this->_autocommit = true; 291 292 $ret = $this->_connectionID->rollback(); 293 $this->_connectionID->setAttribute(PDO_ATTR_AUTOCOMMIT,true); 294 return $ret; 295 } 296 297 function Prepare($sql) 298 { 299 $this->_stmt = $this->_connectionID->prepare($sql); 300 if ($this->_stmt) return array($sql,$this->_stmt); 301 302 return false; 303 } 304 305 function PrepareStmt($sql) 306 { 307 $stmt = $this->_connectionID->prepare($sql); 308 if (!$stmt) return false; 309 $obj = new ADOPDOStatement($stmt,$this); 310 return $obj; 311 } 312 313 /* returns queryID or false */ 314 function _query($sql,$inputarr=false) 315 { 316 if (is_array($sql)) { 317 $stmt = $sql[1]; 318 } else { 319 $stmt = $this->_connectionID->prepare($sql); 320 } 321 322 if ($stmt) { 323 if ($inputarr) $ok = $stmt->execute($inputarr); 324 else $ok = $stmt->execute(); 325 } 326 327 328 $this->_errormsg = false; 329 $this->_errorno = false; 330 331 if ($ok) { 332 $this->_stmt = $stmt; 333 return $stmt; 334 } 335 336 if ($stmt) { 337 338 $arr = $stmt->errorinfo(); 339 if ((integer)$arr[1]) { 340 $this->_errormsg = $arr[2]; 341 $this->_errorno = $arr[1]; 342 } 343 344 } else { 345 $this->_errormsg = false; 346 $this->_errorno = false; 347 } 348 return false; 349 } 350 351 // returns true or false 352 function _close() 353 { 354 $this->_stmt = false; 355 return true; 356 } 357 358 function _affectedrows() 359 { 360 return ($this->_stmt) ? $this->_stmt->rowCount() : 0; 361 } 362 363 function _insertid() 364 { 365 return ($this->_connectionID) ? $this->_connectionID->lastInsertId() : 0; 366 } 367} 368 369class ADOPDOStatement { 370 371 var $databaseType = "pdo"; 372 var $dataProvider = "pdo"; 373 var $_stmt; 374 var $_connectionID; 375 376 function ADOPDOStatement($stmt,$connection) 377 { 378 $this->_stmt = $stmt; 379 $this->_connectionID = $connection; 380 } 381 382 function Execute($inputArr=false) 383 { 384 $savestmt = $this->_connectionID->_stmt; 385 $rs = $this->_connectionID->Execute(array(false,$this->_stmt),$inputArr); 386 $this->_connectionID->_stmt = $savestmt; 387 return $rs; 388 } 389 390 function InParameter(&$var,$name,$maxLen=4000,$type=false) 391 { 392 393 if ($type) $this->_stmt->bindParam($name,$var,$type,$maxLen); 394 else $this->_stmt->bindParam($name, $var); 395 } 396 397 function Affected_Rows() 398 { 399 return ($this->_stmt) ? $this->_stmt->rowCount() : 0; 400 } 401 402 function ErrorMsg() 403 { 404 if ($this->_stmt) $arr = $this->_stmt->errorInfo(); 405 else $arr = $this->_connectionID->errorInfo(); 406 407 if (is_array($arr)) { 408 if ((integer) $arr[0] && isset($arr[2])) return $arr[2]; 409 else return ''; 410 } else return '-1'; 411 } 412 413 function NumCols() 414 { 415 return ($this->_stmt) ? $this->_stmt->columnCount() : 0; 416 } 417 418 function ErrorNo() 419 { 420 if ($this->_stmt) return $this->_stmt->errorCode(); 421 else return $this->_connectionID->errorInfo(); 422 } 423} 424 425/*-------------------------------------------------------------------------------------- 426 Class Name: Recordset 427--------------------------------------------------------------------------------------*/ 428 429class ADORecordSet_pdo extends ADORecordSet { 430 431 var $bind = false; 432 var $databaseType = "pdo"; 433 var $dataProvider = "pdo"; 434 435 function ADORecordSet_pdo($id,$mode=false) 436 { 437 if ($mode === false) { 438 global $ADODB_FETCH_MODE; 439 $mode = $ADODB_FETCH_MODE; 440 } 441 $this->adodbFetchMode = $mode; 442 switch($mode) { 443 case ADODB_FETCH_NUM: $mode = PDO_FETCH_NUM; break; 444 case ADODB_FETCH_ASSOC: $mode = PDO_FETCH_ASSOC; break; 445 446 case ADODB_FETCH_BOTH: 447 default: $mode = PDO_FETCH_BOTH; break; 448 } 449 $this->fetchMode = $mode; 450 451 $this->_queryID = $id; 452 $this->ADORecordSet($id); 453 } 454 455 456 function Init() 457 { 458 if ($this->_inited) return; 459 $this->_inited = true; 460 if ($this->_queryID) @$this->_initrs(); 461 else { 462 $this->_numOfRows = 0; 463 $this->_numOfFields = 0; 464 } 465 if ($this->_numOfRows != 0 && $this->_currentRow == -1) { 466 $this->_currentRow = 0; 467 if ($this->EOF = ($this->_fetch() === false)) { 468 $this->_numOfRows = 0; // _numOfRows could be -1 469 } 470 } else { 471 $this->EOF = true; 472 } 473 } 474 475 function _initrs() 476 { 477 global $ADODB_COUNTRECS; 478 479 $this->_numOfRows = ($ADODB_COUNTRECS) ? @$this->_queryID->rowCount() : -1; 480 if (!$this->_numOfRows) $this->_numOfRows = -1; 481 $this->_numOfFields = $this->_queryID->columnCount(); 482 } 483 484 // returns the field object 485 function &FetchField($fieldOffset = -1) 486 { 487 $off=$fieldOffset+1; // offsets begin at 1 488 489 $o= new ADOFieldObject(); 490 $arr = @$this->_queryID->getColumnMeta($fieldOffset); 491 if (!$arr) { 492 $o->name = 'bad getColumnMeta()'; 493 $o->max_length = -1; 494 $o->type = 'VARCHAR'; 495 $o->precision = 0; 496 # $false = false; 497 return $o; 498 } 499 //adodb_pr($arr); 500 $o->name = $arr['name']; 501 if (isset($arr['native_type'])) $o->type = $arr['native_type']; 502 else $o->type = adodb_pdo_type($arr['pdo_type']); 503 $o->max_length = $arr['len']; 504 $o->precision = $arr['precision']; 505 506 if (ADODB_ASSOC_CASE == 0) $o->name = strtolower($o->name); 507 else if (ADODB_ASSOC_CASE == 1) $o->name = strtoupper($o->name); 508 return $o; 509 } 510 511 function _seek($row) 512 { 513 return false; 514 } 515 516 function _fetch() 517 { 518 if (!$this->_queryID) return false; 519 520 $this->fields = $this->_queryID->fetch($this->fetchMode); 521 return !empty($this->fields); 522 } 523 524 function _close() 525 { 526 $this->_queryID = false; 527 } 528 529 function Fields($colname) 530 { 531 if ($this->adodbFetchMode != ADODB_FETCH_NUM) return @$this->fields[$colname]; 532 533 if (!$this->bind) { 534 $this->bind = array(); 535 for ($i=0; $i < $this->_numOfFields; $i++) { 536 $o = $this->FetchField($i); 537 $this->bind[strtoupper($o->name)] = $i; 538 } 539 } 540 return $this->fields[$this->bind[strtoupper($colname)]]; 541 } 542 543} 544 545?>