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