updated adodb package to work with php 7.1
[openemr.git] / vendor / adodb / adodb-php / drivers / adodb-ado.inc.php
blob449cdd0053b1eb7f0a3d33492697655ce4f292b8
1 <?php
2 /*
3 @version v5.20.9 21-Dec-2016
4 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
5 @copyright (c) 2014 Damien Regad, Mark Newnham and the ADOdb community
6 Released under both BSD license and Lesser GPL library license.
7 Whenever there is any discrepancy between the two licenses,
8 the BSD license will take precedence.
9 Set tabs to 4 for best viewing.
11 Latest version is available at http://adodb.sourceforge.net
13 Microsoft ADO data driver. Requires ADO. Works only on MS Windows.
16 // security - hide paths
17 if (!defined('ADODB_DIR')) die();
19 define("_ADODB_ADO_LAYER", 1 );
20 /*--------------------------------------------------------------------------------------
21 --------------------------------------------------------------------------------------*/
24 class ADODB_ado extends ADOConnection {
25 var $databaseType = "ado";
26 var $_bindInputArray = false;
27 var $fmtDate = "'Y-m-d'";
28 var $fmtTimeStamp = "'Y-m-d, h:i:sA'";
29 var $replaceQuote = "''"; // string to use to replace quotes
30 var $dataProvider = "ado";
31 var $hasAffectedRows = true;
32 var $adoParameterType = 201; // 201 = long varchar, 203=long wide varchar, 205 = long varbinary
33 var $_affectedRows = false;
34 var $_thisTransactions;
35 var $_cursor_type = 3; // 3=adOpenStatic,0=adOpenForwardOnly,1=adOpenKeyset,2=adOpenDynamic
36 var $_cursor_location = 3; // 2=adUseServer, 3 = adUseClient;
37 var $_lock_type = -1;
38 var $_execute_option = -1;
39 var $poorAffectedRows = true;
40 var $charPage;
42 function __construct()
44 $this->_affectedRows = new VARIANT;
47 function ServerInfo()
49 if (!empty($this->_connectionID)) $desc = $this->_connectionID->provider;
50 return array('description' => $desc, 'version' => '');
53 function _affectedrows()
55 if (PHP_VERSION >= 5) return $this->_affectedRows;
57 return $this->_affectedRows->value;
60 // you can also pass a connection string like this:
62 // $DB->Connect('USER ID=sa;PASSWORD=pwd;SERVER=mangrove;DATABASE=ai',false,false,'SQLOLEDB');
63 function _connect($argHostname, $argUsername, $argPassword, $argProvider= 'MSDASQL')
65 $u = 'UID';
66 $p = 'PWD';
68 if (!empty($this->charPage))
69 $dbc = new COM('ADODB.Connection',null,$this->charPage);
70 else
71 $dbc = new COM('ADODB.Connection');
73 if (! $dbc) return false;
75 /* special support if provider is mssql or access */
76 if ($argProvider=='mssql') {
77 $u = 'User Id'; //User parameter name for OLEDB
78 $p = 'Password';
79 $argProvider = "SQLOLEDB"; // SQL Server Provider
81 // not yet
82 //if ($argDatabasename) $argHostname .= ";Initial Catalog=$argDatabasename";
84 //use trusted conection for SQL if username not specified
85 if (!$argUsername) $argHostname .= ";Trusted_Connection=Yes";
86 } else if ($argProvider=='access')
87 $argProvider = "Microsoft.Jet.OLEDB.4.0"; // Microsoft Jet Provider
89 if ($argProvider) $dbc->Provider = $argProvider;
91 if ($argUsername) $argHostname .= ";$u=$argUsername";
92 if ($argPassword)$argHostname .= ";$p=$argPassword";
94 if ($this->debug) ADOConnection::outp( "Host=".$argHostname."<BR>\n version=$dbc->version");
95 // @ added below for php 4.0.1 and earlier
96 @$dbc->Open((string) $argHostname);
98 $this->_connectionID = $dbc;
100 $dbc->CursorLocation = $this->_cursor_location;
101 return $dbc->State > 0;
104 // returns true or false
105 function _pconnect($argHostname, $argUsername, $argPassword, $argProvider='MSDASQL')
107 return $this->_connect($argHostname,$argUsername,$argPassword,$argProvider);
111 adSchemaCatalogs = 1,
112 adSchemaCharacterSets = 2,
113 adSchemaCollations = 3,
114 adSchemaColumns = 4,
115 adSchemaCheckConstraints = 5,
116 adSchemaConstraintColumnUsage = 6,
117 adSchemaConstraintTableUsage = 7,
118 adSchemaKeyColumnUsage = 8,
119 adSchemaReferentialContraints = 9,
120 adSchemaTableConstraints = 10,
121 adSchemaColumnsDomainUsage = 11,
122 adSchemaIndexes = 12,
123 adSchemaColumnPrivileges = 13,
124 adSchemaTablePrivileges = 14,
125 adSchemaUsagePrivileges = 15,
126 adSchemaProcedures = 16,
127 adSchemaSchemata = 17,
128 adSchemaSQLLanguages = 18,
129 adSchemaStatistics = 19,
130 adSchemaTables = 20,
131 adSchemaTranslations = 21,
132 adSchemaProviderTypes = 22,
133 adSchemaViews = 23,
134 adSchemaViewColumnUsage = 24,
135 adSchemaViewTableUsage = 25,
136 adSchemaProcedureParameters = 26,
137 adSchemaForeignKeys = 27,
138 adSchemaPrimaryKeys = 28,
139 adSchemaProcedureColumns = 29,
140 adSchemaDBInfoKeywords = 30,
141 adSchemaDBInfoLiterals = 31,
142 adSchemaCubes = 32,
143 adSchemaDimensions = 33,
144 adSchemaHierarchies = 34,
145 adSchemaLevels = 35,
146 adSchemaMeasures = 36,
147 adSchemaProperties = 37,
148 adSchemaMembers = 38
152 function MetaTables($ttype = false, $showSchema = false, $mask = false)
154 $arr= array();
155 $dbc = $this->_connectionID;
157 $adors=@$dbc->OpenSchema(20);//tables
158 if ($adors){
159 $f = $adors->Fields(2);//table/view name
160 $t = $adors->Fields(3);//table type
161 while (!$adors->EOF){
162 $tt=substr($t->value,0,6);
163 if ($tt!='SYSTEM' && $tt !='ACCESS')
164 $arr[]=$f->value;
165 //print $f->value . ' ' . $t->value.'<br>';
166 $adors->MoveNext();
168 $adors->Close();
171 return $arr;
174 function MetaColumns($table, $normalize=true)
176 $table = strtoupper($table);
177 $arr = array();
178 $dbc = $this->_connectionID;
180 $adors=@$dbc->OpenSchema(4);//tables
182 if ($adors){
183 $t = $adors->Fields(2);//table/view name
184 while (!$adors->EOF){
187 if (strtoupper($t->Value) == $table) {
189 $fld = new ADOFieldObject();
190 $c = $adors->Fields(3);
191 $fld->name = $c->Value;
192 $fld->type = 'CHAR'; // cannot discover type in ADO!
193 $fld->max_length = -1;
194 $arr[strtoupper($fld->name)]=$fld;
197 $adors->MoveNext();
199 $adors->Close();
201 $false = false;
202 return empty($arr) ? $false : $arr;
208 /* returns queryID or false */
209 function _query($sql,$inputarr=false)
212 $dbc = $this->_connectionID;
213 $false = false;
215 // return rs
216 if ($inputarr) {
218 if (!empty($this->charPage))
219 $oCmd = new COM('ADODB.Command',null,$this->charPage);
220 else
221 $oCmd = new COM('ADODB.Command');
222 $oCmd->ActiveConnection = $dbc;
223 $oCmd->CommandText = $sql;
224 $oCmd->CommandType = 1;
226 // Map by http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ado270/htm/mdmthcreateparam.asp
227 // Check issue http://bugs.php.net/bug.php?id=40664 !!!
228 while(list(, $val) = each($inputarr)) {
229 $type = gettype($val);
230 $len=strlen($val);
231 if ($type == 'boolean')
232 $this->adoParameterType = 11;
233 else if ($type == 'integer')
234 $this->adoParameterType = 3;
235 else if ($type == 'double')
236 $this->adoParameterType = 5;
237 elseif ($type == 'string')
238 $this->adoParameterType = 202;
239 else if (($val === null) || (!defined($val)))
240 $len=1;
241 else
242 $this->adoParameterType = 130;
244 // name, type, direction 1 = input, len,
245 $p = $oCmd->CreateParameter('name',$this->adoParameterType,1,$len,$val);
247 $oCmd->Parameters->Append($p);
249 $p = false;
250 $rs = $oCmd->Execute();
251 $e = $dbc->Errors;
252 if ($dbc->Errors->Count > 0) return $false;
253 return $rs;
256 $rs = @$dbc->Execute($sql,$this->_affectedRows, $this->_execute_option);
258 if ($dbc->Errors->Count > 0) return $false;
259 if (! $rs) return $false;
261 if ($rs->State == 0) {
262 $true = true;
263 return $true; // 0 = adStateClosed means no records returned
265 return $rs;
269 function BeginTrans()
271 if ($this->transOff) return true;
273 if (isset($this->_thisTransactions))
274 if (!$this->_thisTransactions) return false;
275 else {
276 $o = $this->_connectionID->Properties("Transaction DDL");
277 $this->_thisTransactions = $o ? true : false;
278 if (!$o) return false;
280 @$this->_connectionID->BeginTrans();
281 $this->transCnt += 1;
282 return true;
285 function CommitTrans($ok=true)
287 if (!$ok) return $this->RollbackTrans();
288 if ($this->transOff) return true;
290 @$this->_connectionID->CommitTrans();
291 if ($this->transCnt) @$this->transCnt -= 1;
292 return true;
294 function RollbackTrans() {
295 if ($this->transOff) return true;
296 @$this->_connectionID->RollbackTrans();
297 if ($this->transCnt) @$this->transCnt -= 1;
298 return true;
301 /* Returns: the last error message from previous database operation */
303 function ErrorMsg()
305 if (!$this->_connectionID) return "No connection established";
306 $errc = $this->_connectionID->Errors;
307 if (!$errc) return "No Errors object found";
308 if ($errc->Count == 0) return '';
309 $err = $errc->Item($errc->Count-1);
310 return $err->Description;
313 function ErrorNo()
315 $errc = $this->_connectionID->Errors;
316 if ($errc->Count == 0) return 0;
317 $err = $errc->Item($errc->Count-1);
318 return $err->NativeError;
321 // returns true or false
322 function _close()
324 if ($this->_connectionID) $this->_connectionID->Close();
325 $this->_connectionID = false;
326 return true;
332 /*--------------------------------------------------------------------------------------
333 Class Name: Recordset
334 --------------------------------------------------------------------------------------*/
336 class ADORecordSet_ado extends ADORecordSet {
338 var $bind = false;
339 var $databaseType = "ado";
340 var $dataProvider = "ado";
341 var $_tarr = false; // caches the types
342 var $_flds; // and field objects
343 var $canSeek = true;
344 var $hideErrors = true;
346 function __construct($id,$mode=false)
348 if ($mode === false) {
349 global $ADODB_FETCH_MODE;
350 $mode = $ADODB_FETCH_MODE;
352 $this->fetchMode = $mode;
353 return parent::__construct($id,$mode);
357 // returns the field object
358 function FetchField($fieldOffset = -1) {
359 $off=$fieldOffset+1; // offsets begin at 1
361 $o= new ADOFieldObject();
362 $rs = $this->_queryID;
363 $f = $rs->Fields($fieldOffset);
364 $o->name = $f->Name;
365 $t = $f->Type;
366 $o->type = $this->MetaType($t);
367 $o->max_length = $f->DefinedSize;
368 $o->ado_type = $t;
370 //print "off=$off name=$o->name type=$o->type len=$o->max_length<br>";
371 return $o;
374 /* Use associative array to get fields array */
375 function Fields($colname)
377 if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname];
378 if (!$this->bind) {
379 $this->bind = array();
380 for ($i=0; $i < $this->_numOfFields; $i++) {
381 $o = $this->FetchField($i);
382 $this->bind[strtoupper($o->name)] = $i;
386 return $this->fields[$this->bind[strtoupper($colname)]];
390 function _initrs()
392 $rs = $this->_queryID;
393 $this->_numOfRows = $rs->RecordCount;
395 $f = $rs->Fields;
396 $this->_numOfFields = $f->Count;
400 // should only be used to move forward as we normally use forward-only cursors
401 function _seek($row)
403 $rs = $this->_queryID;
404 // absoluteposition doesn't work -- my maths is wrong ?
405 // $rs->AbsolutePosition->$row-2;
406 // return true;
407 if ($this->_currentRow > $row) return false;
408 @$rs->Move((integer)$row - $this->_currentRow-1); //adBookmarkFirst
409 return true;
413 OLEDB types
415 enum DBTYPEENUM
416 { DBTYPE_EMPTY = 0,
417 DBTYPE_NULL = 1,
418 DBTYPE_I2 = 2,
419 DBTYPE_I4 = 3,
420 DBTYPE_R4 = 4,
421 DBTYPE_R8 = 5,
422 DBTYPE_CY = 6,
423 DBTYPE_DATE = 7,
424 DBTYPE_BSTR = 8,
425 DBTYPE_IDISPATCH = 9,
426 DBTYPE_ERROR = 10,
427 DBTYPE_BOOL = 11,
428 DBTYPE_VARIANT = 12,
429 DBTYPE_IUNKNOWN = 13,
430 DBTYPE_DECIMAL = 14,
431 DBTYPE_UI1 = 17,
432 DBTYPE_ARRAY = 0x2000,
433 DBTYPE_BYREF = 0x4000,
434 DBTYPE_I1 = 16,
435 DBTYPE_UI2 = 18,
436 DBTYPE_UI4 = 19,
437 DBTYPE_I8 = 20,
438 DBTYPE_UI8 = 21,
439 DBTYPE_GUID = 72,
440 DBTYPE_VECTOR = 0x1000,
441 DBTYPE_RESERVED = 0x8000,
442 DBTYPE_BYTES = 128,
443 DBTYPE_STR = 129,
444 DBTYPE_WSTR = 130,
445 DBTYPE_NUMERIC = 131,
446 DBTYPE_UDT = 132,
447 DBTYPE_DBDATE = 133,
448 DBTYPE_DBTIME = 134,
449 DBTYPE_DBTIMESTAMP = 135
451 ADO Types
453 adEmpty = 0,
454 adTinyInt = 16,
455 adSmallInt = 2,
456 adInteger = 3,
457 adBigInt = 20,
458 adUnsignedTinyInt = 17,
459 adUnsignedSmallInt = 18,
460 adUnsignedInt = 19,
461 adUnsignedBigInt = 21,
462 adSingle = 4,
463 adDouble = 5,
464 adCurrency = 6,
465 adDecimal = 14,
466 adNumeric = 131,
467 adBoolean = 11,
468 adError = 10,
469 adUserDefined = 132,
470 adVariant = 12,
471 adIDispatch = 9,
472 adIUnknown = 13,
473 adGUID = 72,
474 adDate = 7,
475 adDBDate = 133,
476 adDBTime = 134,
477 adDBTimeStamp = 135,
478 adBSTR = 8,
479 adChar = 129,
480 adVarChar = 200,
481 adLongVarChar = 201,
482 adWChar = 130,
483 adVarWChar = 202,
484 adLongVarWChar = 203,
485 adBinary = 128,
486 adVarBinary = 204,
487 adLongVarBinary = 205,
488 adChapter = 136,
489 adFileTime = 64,
490 adDBFileTime = 137,
491 adPropVariant = 138,
492 adVarNumeric = 139
494 function MetaType($t,$len=-1,$fieldobj=false)
496 if (is_object($t)) {
497 $fieldobj = $t;
498 $t = $fieldobj->type;
499 $len = $fieldobj->max_length;
502 if (!is_numeric($t)) return $t;
504 switch ($t) {
505 case 0:
506 case 12: // variant
507 case 8: // bstr
508 case 129: //char
509 case 130: //wc
510 case 200: // varc
511 case 202:// varWC
512 case 128: // bin
513 case 204: // varBin
514 case 72: // guid
515 if ($len <= $this->blobSize) return 'C';
517 case 201:
518 case 203:
519 return 'X';
520 case 128:
521 case 204:
522 case 205:
523 return 'B';
524 case 7:
525 case 133: return 'D';
527 case 134:
528 case 135: return 'T';
530 case 11: return 'L';
532 case 16:// adTinyInt = 16,
533 case 2://adSmallInt = 2,
534 case 3://adInteger = 3,
535 case 4://adBigInt = 20,
536 case 17://adUnsignedTinyInt = 17,
537 case 18://adUnsignedSmallInt = 18,
538 case 19://adUnsignedInt = 19,
539 case 20://adUnsignedBigInt = 21,
540 return 'I';
541 default: return 'N';
545 // time stamp not supported yet
546 function _fetch()
548 $rs = $this->_queryID;
549 if (!$rs or $rs->EOF) {
550 $this->fields = false;
551 return false;
553 $this->fields = array();
555 if (!$this->_tarr) {
556 $tarr = array();
557 $flds = array();
558 for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) {
559 $f = $rs->Fields($i);
560 $flds[] = $f;
561 $tarr[] = $f->Type;
563 // bind types and flds only once
564 $this->_tarr = $tarr;
565 $this->_flds = $flds;
567 $t = reset($this->_tarr);
568 $f = reset($this->_flds);
570 if ($this->hideErrors) $olde = error_reporting(E_ERROR|E_CORE_ERROR);// sometimes $f->value be null
571 for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) {
572 //echo "<p>",$t,' ';var_dump($f->value); echo '</p>';
573 switch($t) {
574 case 135: // timestamp
575 if (!strlen((string)$f->value)) $this->fields[] = false;
576 else {
577 if (!is_numeric($f->value)) # $val = variant_date_to_timestamp($f->value);
578 // VT_DATE stores dates as (float) fractional days since 1899/12/30 00:00:00
579 $val=(float) variant_cast($f->value,VT_R8)*3600*24-2209161600;
580 else
581 $val = $f->value;
582 $this->fields[] = adodb_date('Y-m-d H:i:s',$val);
584 break;
585 case 133:// A date value (yyyymmdd)
586 if ($val = $f->value) {
587 $this->fields[] = substr($val,0,4).'-'.substr($val,4,2).'-'.substr($val,6,2);
588 } else
589 $this->fields[] = false;
590 break;
591 case 7: // adDate
592 if (!strlen((string)$f->value)) $this->fields[] = false;
593 else {
594 if (!is_numeric($f->value)) $val = variant_date_to_timestamp($f->value);
595 else $val = $f->value;
597 if (($val % 86400) == 0) $this->fields[] = adodb_date('Y-m-d',$val);
598 else $this->fields[] = adodb_date('Y-m-d H:i:s',$val);
600 break;
601 case 1: // null
602 $this->fields[] = false;
603 break;
604 case 6: // currency is not supported properly;
605 ADOConnection::outp( '<b>'.$f->Name.': currency type not supported by PHP</b>');
606 $this->fields[] = (float) $f->value;
607 break;
608 case 11: //BIT;
609 $val = "";
610 if(is_bool($f->value)) {
611 if($f->value==true) $val = 1;
612 else $val = 0;
614 if(is_null($f->value)) $val = null;
616 $this->fields[] = $val;
617 break;
618 default:
619 $this->fields[] = $f->value;
620 break;
622 //print " $f->value $t, ";
623 $f = next($this->_flds);
624 $t = next($this->_tarr);
625 } // for
626 if ($this->hideErrors) error_reporting($olde);
627 @$rs->MoveNext(); // @ needed for some versions of PHP!
629 if ($this->fetchMode & ADODB_FETCH_ASSOC) {
630 $this->fields = $this->GetRowAssoc();
632 return true;
635 function NextRecordSet()
637 $rs = $this->_queryID;
638 $this->_queryID = $rs->NextRecordSet();
639 //$this->_queryID = $this->_QueryId->NextRecordSet();
640 if ($this->_queryID == null) return false;
642 $this->_currentRow = -1;
643 $this->_currentPage = -1;
644 $this->bind = false;
645 $this->fields = false;
646 $this->_flds = false;
647 $this->_tarr = false;
649 $this->_inited = false;
650 $this->Init();
651 return true;
654 function _close() {
655 $this->_flds = false;
656 @$this->_queryID->Close();// by Pete Dishman (peterd@telephonetics.co.uk)
657 $this->_queryID = false;