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