See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]
1 <?php 2 /** 3 * Microsoft ADO driver (PHP5 compat version). 4 * 5 * Requires ADO. Works only on MS Windows. 6 * 7 * This file is part of ADOdb, a Database Abstraction Layer library for PHP. 8 * 9 * @package ADOdb 10 * @link https://adodb.org Project's web site and documentation 11 * @link https://github.com/ADOdb/ADOdb Source code and issue tracker 12 * 13 * The ADOdb Library is dual-licensed, released under both the BSD 3-Clause 14 * and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option, 15 * any later version. This means you can use it in proprietary products. 16 * See the LICENSE.md file distributed with this source code for details. 17 * @license BSD-3-Clause 18 * @license LGPL-2.1-or-later 19 * 20 * @copyright 2000-2013 John Lim 21 * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community 22 */ 23 24 // security - hide paths 25 if (!defined('ADODB_DIR')) die(); 26 27 define("_ADODB_ADO_LAYER", 1 ); 28 /*-------------------------------------------------------------------------------------- 29 --------------------------------------------------------------------------------------*/ 30 31 32 class ADODB_ado extends ADOConnection { 33 var $databaseType = "ado"; 34 var $_bindInputArray = false; 35 var $fmtDate = "'Y-m-d'"; 36 var $fmtTimeStamp = "'Y-m-d, h:i:sA'"; 37 var $replaceQuote = "''"; // string to use to replace quotes 38 var $dataProvider = "ado"; 39 var $hasAffectedRows = true; 40 var $adoParameterType = 201; // 201 = long varchar, 203=long wide varchar, 205 = long varbinary 41 var $_affectedRows = false; 42 var $_thisTransactions; 43 var $_cursor_type = 3; // 3=adOpenStatic,0=adOpenForwardOnly,1=adOpenKeyset,2=adOpenDynamic 44 var $_cursor_location = 3; // 2=adUseServer, 3 = adUseClient; 45 var $_lock_type = -1; 46 var $_execute_option = -1; 47 var $poorAffectedRows = true; 48 var $charPage; 49 50 function __construct() 51 { 52 $this->_affectedRows = new VARIANT; 53 } 54 55 function ServerInfo() 56 { 57 if (!empty($this->_connectionID)) $desc = $this->_connectionID->provider; 58 return array('description' => $desc, 'version' => ''); 59 } 60 61 function _affectedrows() 62 { 63 return $this->_affectedRows; 64 } 65 66 // you can also pass a connection string like this: 67 // 68 // $DB->Connect('USER ID=sa;PASSWORD=pwd;SERVER=mangrove;DATABASE=ai',false,false,'SQLOLEDB'); 69 function _connect($argHostname, $argUsername, $argPassword,$argDBorProvider, $argProvider= '') 70 { 71 // two modes 72 // - if $argProvider is empty, we assume that $argDBorProvider holds provider -- this is for backward compat 73 // - if $argProvider is not empty, then $argDBorProvider holds db 74 75 76 if ($argProvider) { 77 $argDatabasename = $argDBorProvider; 78 } else { 79 $argDatabasename = ''; 80 if ($argDBorProvider) $argProvider = $argDBorProvider; 81 else if (stripos($argHostname,'PROVIDER') === false) /* full conn string is not in $argHostname */ 82 $argProvider = 'MSDASQL'; 83 } 84 85 86 try { 87 $u = 'UID'; 88 $p = 'PWD'; 89 90 if (!empty($this->charPage)) 91 $dbc = new COM('ADODB.Connection',null,$this->charPage); 92 else 93 $dbc = new COM('ADODB.Connection'); 94 95 if (! $dbc) return false; 96 97 /* special support if provider is mssql or access */ 98 if ($argProvider=='mssql') { 99 $u = 'User Id'; //User parameter name for OLEDB 100 $p = 'Password'; 101 $argProvider = "SQLOLEDB"; // SQL Server Provider 102 103 // not yet 104 //if ($argDatabasename) $argHostname .= ";Initial Catalog=$argDatabasename"; 105 106 //use trusted connection for SQL if username not specified 107 if (!$argUsername) $argHostname .= ";Trusted_Connection=Yes"; 108 } else if ($argProvider=='access') 109 $argProvider = "Microsoft.Jet.OLEDB.4.0"; // Microsoft Jet Provider 110 111 if ($argProvider) $dbc->Provider = $argProvider; 112 113 if ($argProvider) $argHostname = "PROVIDER=$argProvider;DRIVER={SQL Server};SERVER=$argHostname"; 114 115 116 if ($argDatabasename) $argHostname .= ";DATABASE=$argDatabasename"; 117 if ($argUsername) $argHostname .= ";$u=$argUsername"; 118 if ($argPassword)$argHostname .= ";$p=$argPassword"; 119 120 if ($this->debug) ADOConnection::outp( "Host=".$argHostname."<BR>\n version=$dbc->version"); 121 // @ added below for php 4.0.1 and earlier 122 @$dbc->Open((string) $argHostname); 123 124 $this->_connectionID = $dbc; 125 126 $dbc->CursorLocation = $this->_cursor_location; 127 return $dbc->State > 0; 128 } catch (exception $e) { 129 if ($this->debug) echo "<pre>",$argHostname,"\n",$e,"</pre>\n"; 130 } 131 132 return false; 133 } 134 135 // returns true or false 136 function _pconnect($argHostname, $argUsername, $argPassword, $argProvider='MSDASQL') 137 { 138 return $this->_connect($argHostname,$argUsername,$argPassword,$argProvider); 139 } 140 141 /* 142 adSchemaCatalogs = 1, 143 adSchemaCharacterSets = 2, 144 adSchemaCollations = 3, 145 adSchemaColumns = 4, 146 adSchemaCheckConstraints = 5, 147 adSchemaConstraintColumnUsage = 6, 148 adSchemaConstraintTableUsage = 7, 149 adSchemaKeyColumnUsage = 8, 150 adSchemaReferentialContraints = 9, 151 adSchemaTableConstraints = 10, 152 adSchemaColumnsDomainUsage = 11, 153 adSchemaIndexes = 12, 154 adSchemaColumnPrivileges = 13, 155 adSchemaTablePrivileges = 14, 156 adSchemaUsagePrivileges = 15, 157 adSchemaProcedures = 16, 158 adSchemaSchemata = 17, 159 adSchemaSQLLanguages = 18, 160 adSchemaStatistics = 19, 161 adSchemaTables = 20, 162 adSchemaTranslations = 21, 163 adSchemaProviderTypes = 22, 164 adSchemaViews = 23, 165 adSchemaViewColumnUsage = 24, 166 adSchemaViewTableUsage = 25, 167 adSchemaProcedureParameters = 26, 168 adSchemaForeignKeys = 27, 169 adSchemaPrimaryKeys = 28, 170 adSchemaProcedureColumns = 29, 171 adSchemaDBInfoKeywords = 30, 172 adSchemaDBInfoLiterals = 31, 173 adSchemaCubes = 32, 174 adSchemaDimensions = 33, 175 adSchemaHierarchies = 34, 176 adSchemaLevels = 35, 177 adSchemaMeasures = 36, 178 adSchemaProperties = 37, 179 adSchemaMembers = 38 180 181 */ 182 183 function MetaTables($ttype = false, $showSchema = false, $mask = false) 184 { 185 $arr= array(); 186 $dbc = $this->_connectionID; 187 188 $adors=@$dbc->OpenSchema(20);//tables 189 if ($adors){ 190 $f = $adors->Fields(2);//table/view name 191 $t = $adors->Fields(3);//table type 192 while (!$adors->EOF){ 193 $tt=substr($t->value,0,6); 194 if ($tt!='SYSTEM' && $tt !='ACCESS') 195 $arr[]=$f->value; 196 //print $f->value . ' ' . $t->value.'<br>'; 197 $adors->MoveNext(); 198 } 199 $adors->Close(); 200 } 201 202 return $arr; 203 } 204 205 function MetaColumns($table, $normalize=true) 206 { 207 $table = strtoupper($table); 208 $arr= array(); 209 $dbc = $this->_connectionID; 210 211 $adors=@$dbc->OpenSchema(4);//tables 212 213 if ($adors){ 214 $t = $adors->Fields(2);//table/view name 215 while (!$adors->EOF){ 216 217 218 if (strtoupper($t->Value) == $table) { 219 220 $fld = new ADOFieldObject(); 221 $c = $adors->Fields(3); 222 $fld->name = $c->Value; 223 $fld->type = 'CHAR'; // cannot discover type in ADO! 224 $fld->max_length = -1; 225 $arr[strtoupper($fld->name)]=$fld; 226 } 227 228 $adors->MoveNext(); 229 } 230 $adors->Close(); 231 } 232 233 return $arr; 234 } 235 236 /* returns queryID or false */ 237 function _query($sql,$inputarr=false) 238 { 239 try { // In PHP5, all COM errors are exceptions, so to maintain old behaviour... 240 241 $dbc = $this->_connectionID; 242 243 // return rs 244 245 $false = false; 246 247 if ($inputarr) { 248 249 if (!empty($this->charPage)) 250 $oCmd = new COM('ADODB.Command',null,$this->charPage); 251 else 252 $oCmd = new COM('ADODB.Command'); 253 $oCmd->ActiveConnection = $dbc; 254 $oCmd->CommandText = $sql; 255 $oCmd->CommandType = 1; 256 257 foreach ($inputarr as $val) { 258 $type = gettype($val); 259 $len=strlen($val); 260 if ($type == 'boolean') 261 $this->adoParameterType = 11; 262 else if ($type == 'integer') 263 $this->adoParameterType = 3; 264 else if ($type == 'double') 265 $this->adoParameterType = 5; 266 elseif ($type == 'string') 267 $this->adoParameterType = 202; 268 else if (($val === null) || (!defined($val))) 269 $len=1; 270 else 271 $this->adoParameterType = 130; 272 273 // name, type, direction 1 = input, len, 274 $p = $oCmd->CreateParameter('name',$this->adoParameterType,1,$len,$val); 275 276 $oCmd->Parameters->Append($p); 277 } 278 279 $p = false; 280 $rs = $oCmd->Execute(); 281 $e = $dbc->Errors; 282 if ($dbc->Errors->Count > 0) return $false; 283 return $rs; 284 } 285 286 $rs = @$dbc->Execute($sql,$this->_affectedRows, $this->_execute_option); 287 288 if ($dbc->Errors->Count > 0) return $false; 289 if (! $rs) return $false; 290 291 if ($rs->State == 0) { 292 $true = true; 293 return $true; // 0 = adStateClosed means no records returned 294 } 295 return $rs; 296 297 } catch (exception $e) { 298 299 } 300 return $false; 301 } 302 303 304 function BeginTrans() 305 { 306 if ($this->transOff) return true; 307 308 if (isset($this->_thisTransactions)) 309 if (!$this->_thisTransactions) return false; 310 else { 311 $o = $this->_connectionID->Properties("Transaction DDL"); 312 $this->_thisTransactions = $o ? true : false; 313 if (!$o) return false; 314 } 315 @$this->_connectionID->BeginTrans(); 316 $this->transCnt += 1; 317 return true; 318 } 319 function CommitTrans($ok=true) 320 { 321 if (!$ok) return $this->RollbackTrans(); 322 if ($this->transOff) return true; 323 324 @$this->_connectionID->CommitTrans(); 325 if ($this->transCnt) @$this->transCnt -= 1; 326 return true; 327 } 328 function RollbackTrans() { 329 if ($this->transOff) return true; 330 @$this->_connectionID->RollbackTrans(); 331 if ($this->transCnt) @$this->transCnt -= 1; 332 return true; 333 } 334 335 /* Returns: the last error message from previous database operation */ 336 337 function ErrorMsg() 338 { 339 if (!$this->_connectionID) return "No connection established"; 340 $errmsg = ''; 341 342 try { 343 $errc = $this->_connectionID->Errors; 344 if (!$errc) return "No Errors object found"; 345 if ($errc->Count == 0) return ''; 346 $err = $errc->Item($errc->Count-1); 347 $errmsg = $err->Description; 348 }catch(exception $e) { 349 } 350 return $errmsg; 351 } 352 353 function ErrorNo() 354 { 355 $errc = $this->_connectionID->Errors; 356 if ($errc->Count == 0) return 0; 357 $err = $errc->Item($errc->Count-1); 358 return $err->NativeError; 359 } 360 361 // returns true or false 362 function _close() 363 { 364 if ($this->_connectionID) $this->_connectionID->Close(); 365 $this->_connectionID = false; 366 return true; 367 } 368 369 370 } 371 372 /*-------------------------------------------------------------------------------------- 373 Class Name: Recordset 374 --------------------------------------------------------------------------------------*/ 375 376 class ADORecordSet_ado extends ADORecordSet { 377 378 var $bind = false; 379 var $databaseType = "ado"; 380 var $dataProvider = "ado"; 381 var $_tarr = false; // caches the types 382 var $_flds; // and field objects 383 var $canSeek = true; 384 var $hideErrors = true; 385 386 function __construct($id,$mode=false) 387 { 388 if ($mode === false) { 389 global $ADODB_FETCH_MODE; 390 $mode = $ADODB_FETCH_MODE; 391 } 392 $this->fetchMode = $mode; 393 parent::__construct($id); 394 } 395 396 397 // returns the field object 398 function FetchField($fieldOffset = -1) { 399 $off=$fieldOffset+1; // offsets begin at 1 400 401 $o= new ADOFieldObject(); 402 $rs = $this->_queryID; 403 if (!$rs) return false; 404 405 $f = $rs->Fields($fieldOffset); 406 $o->name = $f->Name; 407 $t = $f->Type; 408 $o->type = $this->MetaType($t); 409 $o->max_length = $f->DefinedSize; 410 $o->ado_type = $t; 411 412 413 //print "off=$off name=$o->name type=$o->type len=$o->max_length<br>"; 414 return $o; 415 } 416 417 /* Use associative array to get fields array */ 418 function Fields($colname) 419 { 420 if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname]; 421 if (!$this->bind) { 422 $this->bind = array(); 423 for ($i=0; $i < $this->_numOfFields; $i++) { 424 $o = $this->FetchField($i); 425 $this->bind[strtoupper($o->name)] = $i; 426 } 427 } 428 429 return $this->fields[$this->bind[strtoupper($colname)]]; 430 } 431 432 433 function _initrs() 434 { 435 $rs = $this->_queryID; 436 437 try { 438 $this->_numOfRows = $rs->RecordCount; 439 } catch (Exception $e) { 440 $this->_numOfRows = -1; 441 } 442 $f = $rs->Fields; 443 $this->_numOfFields = $f->Count; 444 } 445 446 447 // should only be used to move forward as we normally use forward-only cursors 448 function _seek($row) 449 { 450 $rs = $this->_queryID; 451 // absoluteposition doesn't work -- my maths is wrong ? 452 // $rs->AbsolutePosition->$row-2; 453 // return true; 454 if ($this->_currentRow > $row) return false; 455 @$rs->Move((integer)$row - $this->_currentRow-1); //adBookmarkFirst 456 return true; 457 } 458 459 /* 460 OLEDB types 461 462 enum DBTYPEENUM 463 { DBTYPE_EMPTY = 0, 464 DBTYPE_NULL = 1, 465 DBTYPE_I2 = 2, 466 DBTYPE_I4 = 3, 467 DBTYPE_R4 = 4, 468 DBTYPE_R8 = 5, 469 DBTYPE_CY = 6, 470 DBTYPE_DATE = 7, 471 DBTYPE_BSTR = 8, 472 DBTYPE_IDISPATCH = 9, 473 DBTYPE_ERROR = 10, 474 DBTYPE_BOOL = 11, 475 DBTYPE_VARIANT = 12, 476 DBTYPE_IUNKNOWN = 13, 477 DBTYPE_DECIMAL = 14, 478 DBTYPE_UI1 = 17, 479 DBTYPE_ARRAY = 0x2000, 480 DBTYPE_BYREF = 0x4000, 481 DBTYPE_I1 = 16, 482 DBTYPE_UI2 = 18, 483 DBTYPE_UI4 = 19, 484 DBTYPE_I8 = 20, 485 DBTYPE_UI8 = 21, 486 DBTYPE_GUID = 72, 487 DBTYPE_VECTOR = 0x1000, 488 DBTYPE_RESERVED = 0x8000, 489 DBTYPE_BYTES = 128, 490 DBTYPE_STR = 129, 491 DBTYPE_WSTR = 130, 492 DBTYPE_NUMERIC = 131, 493 DBTYPE_UDT = 132, 494 DBTYPE_DBDATE = 133, 495 DBTYPE_DBTIME = 134, 496 DBTYPE_DBTIMESTAMP = 135 497 498 ADO Types 499 500 adEmpty = 0, 501 adTinyInt = 16, 502 adSmallInt = 2, 503 adInteger = 3, 504 adBigInt = 20, 505 adUnsignedTinyInt = 17, 506 adUnsignedSmallInt = 18, 507 adUnsignedInt = 19, 508 adUnsignedBigInt = 21, 509 adSingle = 4, 510 adDouble = 5, 511 adCurrency = 6, 512 adDecimal = 14, 513 adNumeric = 131, 514 adBoolean = 11, 515 adError = 10, 516 adUserDefined = 132, 517 adVariant = 12, 518 adIDispatch = 9, 519 adIUnknown = 13, 520 adGUID = 72, 521 adDate = 7, 522 adDBDate = 133, 523 adDBTime = 134, 524 adDBTimeStamp = 135, 525 adBSTR = 8, 526 adChar = 129, 527 adVarChar = 200, 528 adLongVarChar = 201, 529 adWChar = 130, 530 adVarWChar = 202, 531 adLongVarWChar = 203, 532 adBinary = 128, 533 adVarBinary = 204, 534 adLongVarBinary = 205, 535 adChapter = 136, 536 adFileTime = 64, 537 adDBFileTime = 137, 538 adPropVariant = 138, 539 adVarNumeric = 139 540 */ 541 function MetaType($t,$len=-1,$fieldobj=false) 542 { 543 if (is_object($t)) { 544 $fieldobj = $t; 545 $t = $fieldobj->type; 546 $len = $fieldobj->max_length; 547 } 548 549 $t = strtoupper($t); 550 551 if (array_key_exists($t,$this->connection->customActualTypes)) 552 return $this->connection->customActualTypes[$t]; 553 554 if (!is_numeric($t)) 555 return $t; 556 557 switch ($t) { 558 case 0: 559 case 12: // variant 560 case 8: // bstr 561 case 129: //char 562 case 130: //wc 563 case 200: // varc 564 case 202:// varWC 565 case 128: // bin 566 case 204: // varBin 567 case 72: // guid 568 if ($len <= $this->blobSize) return 'C'; 569 570 case 201: 571 case 203: 572 return 'X'; 573 case 128: 574 case 204: 575 case 205: 576 return 'B'; 577 case 7: 578 case 133: return 'D'; 579 580 case 134: 581 case 135: return 'T'; 582 583 case 11: return 'L'; 584 585 case 16:// adTinyInt = 16, 586 case 2://adSmallInt = 2, 587 case 3://adInteger = 3, 588 case 4://adBigInt = 20, 589 case 17://adUnsignedTinyInt = 17, 590 case 18://adUnsignedSmallInt = 18, 591 case 19://adUnsignedInt = 19, 592 case 20://adUnsignedBigInt = 21, 593 return 'I'; 594 default: return ADODB_DEFAULT_METATYPE; 595 } 596 } 597 598 // time stamp not supported yet 599 function _fetch() 600 { 601 $rs = $this->_queryID; 602 if (!$rs or $rs->EOF) { 603 $this->fields = false; 604 return false; 605 } 606 $this->fields = array(); 607 608 if (!$this->_tarr) { 609 $tarr = array(); 610 $flds = array(); 611 for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) { 612 $f = $rs->Fields($i); 613 $flds[] = $f; 614 $tarr[] = $f->Type; 615 } 616 // bind types and flds only once 617 $this->_tarr = $tarr; 618 $this->_flds = $flds; 619 } 620 $t = reset($this->_tarr); 621 $f = reset($this->_flds); 622 623 if ($this->hideErrors) $olde = error_reporting(E_ERROR|E_CORE_ERROR);// sometimes $f->value be null 624 for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) { 625 //echo "<p>",$t,' ';var_dump($f->value); echo '</p>'; 626 switch($t) { 627 case 135: // timestamp 628 if (!strlen((string)$f->value)) $this->fields[] = false; 629 else { 630 if (!is_numeric($f->value)) # $val = variant_date_to_timestamp($f->value); 631 // VT_DATE stores dates as (float) fractional days since 1899/12/30 00:00:00 632 $val= (float) variant_cast($f->value,VT_R8)*3600*24-2209161600; 633 else 634 $val = $f->value; 635 $this->fields[] = adodb_date('Y-m-d H:i:s',$val); 636 } 637 break; 638 case 133:// A date value (yyyymmdd) 639 if ($val = $f->value) { 640 $this->fields[] = substr($val,0,4).'-'.substr($val,4,2).'-'.substr($val,6,2); 641 } else 642 $this->fields[] = false; 643 break; 644 case 7: // adDate 645 if (!strlen((string)$f->value)) $this->fields[] = false; 646 else { 647 if (!is_numeric($f->value)) $val = variant_date_to_timestamp($f->value); 648 else $val = $f->value; 649 650 if (($val % 86400) == 0) $this->fields[] = adodb_date('Y-m-d',$val); 651 else $this->fields[] = adodb_date('Y-m-d H:i:s',$val); 652 } 653 break; 654 case 1: // null 655 $this->fields[] = false; 656 break; 657 case 20: 658 case 21: // bigint (64 bit) 659 $this->fields[] = (float) $f->value; // if 64 bit PHP, could use (int) 660 break; 661 case 6: // currency is not supported properly; 662 ADOConnection::outp( '<b>'.$f->Name.': currency type not supported by PHP</b>'); 663 $this->fields[] = (float) $f->value; 664 break; 665 case 11: //BIT; 666 $val = ""; 667 if(is_bool($f->value)) { 668 if($f->value==true) $val = 1; 669 else $val = 0; 670 } 671 if(is_null($f->value)) $val = null; 672 673 $this->fields[] = $val; 674 break; 675 default: 676 $this->fields[] = $f->value; 677 break; 678 } 679 //print " $f->value $t, "; 680 $f = next($this->_flds); 681 $t = next($this->_tarr); 682 } // for 683 if ($this->hideErrors) error_reporting($olde); 684 @$rs->MoveNext(); // @ needed for some versions of PHP! 685 686 if ($this->fetchMode & ADODB_FETCH_ASSOC) { 687 $this->fields = $this->GetRowAssoc(); 688 } 689 return true; 690 } 691 692 function NextRecordSet() 693 { 694 $rs = $this->_queryID; 695 $this->_queryID = $rs->NextRecordSet(); 696 //$this->_queryID = $this->_QueryId->NextRecordSet(); 697 if ($this->_queryID == null) return false; 698 699 $this->_currentRow = -1; 700 $this->_currentPage = -1; 701 $this->bind = false; 702 $this->fields = false; 703 $this->_flds = false; 704 $this->_tarr = false; 705 706 $this->_inited = false; 707 $this->Init(); 708 return true; 709 } 710 711 function _close() { 712 $this->_flds = false; 713 try { 714 @$this->_queryID->Close();// by Pete Dishman (peterd@telephonetics.co.uk) 715 } catch (Exception $e) { 716 } 717 $this->_queryID = false; 718 } 719 720 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body