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