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