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