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