3 V5.14 8 Sept 2011 (c) 2000-2011 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.
9 Latest version is available at http://adodb.sourceforge.net
11 Microsoft ADO data driver. Requires ADO. Works only on MS Windows.
14 // security - hide paths
15 if (!defined('ADODB_DIR')) die();
17 define("_ADODB_ADO_LAYER", 1 );
18 /*--------------------------------------------------------------------------------------
19 --------------------------------------------------------------------------------------*/
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;
36 var $_execute_option = -1;
37 var $poorAffectedRows = true;
42 $this->_affectedRows
= new VARIANT
;
47 if (!empty($this->_connectionID
)) $desc = $this->_connectionID
->provider
;
48 return array('description' => $desc, 'version' => '');
51 function _affectedrows()
53 if (PHP_VERSION
>= 5) return $this->_affectedRows
;
55 return $this->_affectedRows
->value
;
58 // you can also pass a connection string like this:
60 // $DB->Connect('USER ID=sa;PASSWORD=pwd;SERVER=mangrove;DATABASE=ai',false,false,'SQLOLEDB');
61 function _connect($argHostname, $argUsername, $argPassword, $argProvider= 'MSDASQL')
66 if (!empty($this->charPage
))
67 $dbc = new COM('ADODB.Connection',null,$this->charPage
);
69 $dbc = new COM('ADODB.Connection');
71 if (! $dbc) return false;
73 /* special support if provider is mssql or access */
74 if ($argProvider=='mssql') {
75 $u = 'User Id'; //User parameter name for OLEDB
77 $argProvider = "SQLOLEDB"; // SQL Server Provider
80 //if ($argDatabasename) $argHostname .= ";Initial Catalog=$argDatabasename";
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
87 if ($argProvider) $dbc->Provider
= $argProvider;
89 if ($argUsername) $argHostname .= ";$u=$argUsername";
90 if ($argPassword)$argHostname .= ";$p=$argPassword";
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);
96 $this->_connectionID
= $dbc;
98 $dbc->CursorLocation
= $this->_cursor_location
;
99 return $dbc->State
> 0;
102 // returns true or false
103 function _pconnect($argHostname, $argUsername, $argPassword, $argProvider='MSDASQL')
105 return $this->_connect($argHostname,$argUsername,$argPassword,$argProvider);
109 adSchemaCatalogs = 1,
110 adSchemaCharacterSets = 2,
111 adSchemaCollations = 3,
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,
129 adSchemaTranslations = 21,
130 adSchemaProviderTypes = 22,
132 adSchemaViewColumnUsage = 24,
133 adSchemaViewTableUsage = 25,
134 adSchemaProcedureParameters = 26,
135 adSchemaForeignKeys = 27,
136 adSchemaPrimaryKeys = 28,
137 adSchemaProcedureColumns = 29,
138 adSchemaDBInfoKeywords = 30,
139 adSchemaDBInfoLiterals = 31,
141 adSchemaDimensions = 33,
142 adSchemaHierarchies = 34,
144 adSchemaMeasures = 36,
145 adSchemaProperties = 37,
150 function MetaTables()
153 $dbc = $this->_connectionID
;
155 $adors=@$dbc->OpenSchema(20);//tables
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')
163 //print $f->value . ' ' . $t->value.'<br>';
172 function MetaColumns($table, $normalize=true)
174 $table = strtoupper($table);
176 $dbc = $this->_connectionID
;
178 $adors=@$dbc->OpenSchema(4);//tables
181 $t = $adors->Fields(2);//table/view name
182 while (!$adors->EOF
){
185 if (strtoupper($t->Value
) == $table) {
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;
200 return empty($arr) ?
$false : $arr;
206 /* returns queryID or false */
207 function _query($sql,$inputarr=false)
210 $dbc = $this->_connectionID
;
216 if (!empty($this->charPage
))
217 $oCmd = new COM('ADODB.Command',null,$this->charPage
);
219 $oCmd = new COM('ADODB.Command');
220 $oCmd->ActiveConnection
= $dbc;
221 $oCmd->CommandText
= $sql;
222 $oCmd->CommandType
= 1;
224 // Map by http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ado270/htm/mdmthcreateparam.asp
225 // Check issue http://bugs.php.net/bug.php?id=40664 !!!
226 while(list(, $val) = each($inputarr)) {
227 $type = gettype($val);
229 if ($type == 'boolean')
230 $this->adoParameterType
= 11;
231 else if ($type == 'integer')
232 $this->adoParameterType
= 3;
233 else if ($type == 'double')
234 $this->adoParameterType
= 5;
235 elseif ($type == 'string')
236 $this->adoParameterType
= 202;
237 else if (($val === null) ||
(!defined($val)))
240 $this->adoParameterType
= 130;
242 // name, type, direction 1 = input, len,
243 $p = $oCmd->CreateParameter('name',$this->adoParameterType
,1,$len,$val);
245 $oCmd->Parameters
->Append($p);
248 $rs = $oCmd->Execute();
250 if ($dbc->Errors
->Count
> 0) return $false;
254 $rs = @$dbc->Execute($sql,$this->_affectedRows
, $this->_execute_option
);
256 if ($dbc->Errors
->Count
> 0) return $false;
257 if (! $rs) return $false;
259 if ($rs->State
== 0) {
261 return $true; // 0 = adStateClosed means no records returned
267 function BeginTrans()
269 if ($this->transOff
) return true;
271 if (isset($this->_thisTransactions
))
272 if (!$this->_thisTransactions
) return false;
274 $o = $this->_connectionID
->Properties("Transaction DDL");
275 $this->_thisTransactions
= $o ?
true : false;
276 if (!$o) return false;
278 @$this->_connectionID
->BeginTrans();
279 $this->transCnt +
= 1;
283 function CommitTrans($ok=true)
285 if (!$ok) return $this->RollbackTrans();
286 if ($this->transOff
) return true;
288 @$this->_connectionID
->CommitTrans();
289 if ($this->transCnt
) @$this->transCnt
-= 1;
292 function RollbackTrans() {
293 if ($this->transOff
) return true;
294 @$this->_connectionID
->RollbackTrans();
295 if ($this->transCnt
) @$this->transCnt
-= 1;
299 /* Returns: the last error message from previous database operation */
303 if (!$this->_connectionID
) return "No connection established";
304 $errc = $this->_connectionID
->Errors
;
305 if (!$errc) return "No Errors object found";
306 if ($errc->Count
== 0) return '';
307 $err = $errc->Item($errc->Count
-1);
308 return $err->Description
;
313 $errc = $this->_connectionID
->Errors
;
314 if ($errc->Count
== 0) return 0;
315 $err = $errc->Item($errc->Count
-1);
316 return $err->NativeError
;
319 // returns true or false
322 if ($this->_connectionID
) $this->_connectionID
->Close();
323 $this->_connectionID
= false;
330 /*--------------------------------------------------------------------------------------
331 Class Name: Recordset
332 --------------------------------------------------------------------------------------*/
334 class ADORecordSet_ado
extends ADORecordSet
{
337 var $databaseType = "ado";
338 var $dataProvider = "ado";
339 var $_tarr = false; // caches the types
340 var $_flds; // and field objects
342 var $hideErrors = true;
344 function ADORecordSet_ado($id,$mode=false)
346 if ($mode === false) {
347 global $ADODB_FETCH_MODE;
348 $mode = $ADODB_FETCH_MODE;
350 $this->fetchMode
= $mode;
351 return $this->ADORecordSet($id,$mode);
355 // returns the field object
356 function FetchField($fieldOffset = -1) {
357 $off=$fieldOffset+
1; // offsets begin at 1
359 $o= new ADOFieldObject();
360 $rs = $this->_queryID
;
361 $f = $rs->Fields($fieldOffset);
364 $o->type
= $this->MetaType($t);
365 $o->max_length
= $f->DefinedSize
;
368 //print "off=$off name=$o->name type=$o->type len=$o->max_length<br>";
372 /* Use associative array to get fields array */
373 function Fields($colname)
375 if ($this->fetchMode
& ADODB_FETCH_ASSOC
) return $this->fields
[$colname];
377 $this->bind
= array();
378 for ($i=0; $i < $this->_numOfFields
; $i++
) {
379 $o = $this->FetchField($i);
380 $this->bind
[strtoupper($o->name
)] = $i;
384 return $this->fields
[$this->bind
[strtoupper($colname)]];
390 $rs = $this->_queryID
;
391 $this->_numOfRows
= $rs->RecordCount
;
394 $this->_numOfFields
= $f->Count
;
398 // should only be used to move forward as we normally use forward-only cursors
401 $rs = $this->_queryID
;
402 // absoluteposition doesn't work -- my maths is wrong ?
403 // $rs->AbsolutePosition->$row-2;
405 if ($this->_currentRow
> $row) return false;
406 @$rs->Move((integer)$row - $this->_currentRow
-1); //adBookmarkFirst
423 DBTYPE_IDISPATCH = 9,
427 DBTYPE_IUNKNOWN = 13,
430 DBTYPE_ARRAY = 0x2000,
431 DBTYPE_BYREF = 0x4000,
438 DBTYPE_VECTOR = 0x1000,
439 DBTYPE_RESERVED = 0x8000,
443 DBTYPE_NUMERIC = 131,
447 DBTYPE_DBTIMESTAMP = 135
456 adUnsignedTinyInt = 17,
457 adUnsignedSmallInt = 18,
459 adUnsignedBigInt = 21,
482 adLongVarWChar = 203,
485 adLongVarBinary = 205,
492 function MetaType($t,$len=-1,$fieldobj=false)
496 $t = $fieldobj->type
;
497 $len = $fieldobj->max_length
;
500 if (!is_numeric($t)) return $t;
513 if ($len <= $this->blobSize
) return 'C';
523 case 133: return 'D';
526 case 135: return 'T';
530 case 16:// adTinyInt = 16,
531 case 2://adSmallInt = 2,
532 case 3://adInteger = 3,
533 case 4://adBigInt = 20,
534 case 17://adUnsignedTinyInt = 17,
535 case 18://adUnsignedSmallInt = 18,
536 case 19://adUnsignedInt = 19,
537 case 20://adUnsignedBigInt = 21,
543 // time stamp not supported yet
546 $rs = $this->_queryID
;
547 if (!$rs or $rs->EOF
) {
548 $this->fields
= false;
551 $this->fields
= array();
556 for ($i=0,$max = $this->_numOfFields
; $i < $max; $i++
) {
557 $f = $rs->Fields($i);
561 // bind types and flds only once
562 $this->_tarr
= $tarr;
563 $this->_flds
= $flds;
565 $t = reset($this->_tarr
);
566 $f = reset($this->_flds
);
568 if ($this->hideErrors
) $olde = error_reporting(E_ERROR|E_CORE_ERROR
);// sometimes $f->value be null
569 for ($i=0,$max = $this->_numOfFields
; $i < $max; $i++
) {
570 //echo "<p>",$t,' ';var_dump($f->value); echo '</p>';
572 case 135: // timestamp
573 if (!strlen((string)$f->value
)) $this->fields
[] = false;
575 if (!is_numeric($f->value
)) # $val = variant_date_to_timestamp($f->value);
576 // VT_DATE stores dates as (float) fractional days since 1899/12/30 00:00:00
577 $val=(float) variant_cast($f->value
,VT_R8
)*3600*24-2209161600;
580 $this->fields
[] = adodb_date('Y-m-d H:i:s',$val);
583 case 133:// A date value (yyyymmdd)
584 if ($val = $f->value
) {
585 $this->fields
[] = substr($val,0,4).'-'.substr($val,4,2).'-'.substr($val,6,2);
587 $this->fields
[] = false;
590 if (!strlen((string)$f->value
)) $this->fields
[] = false;
592 if (!is_numeric($f->value
)) $val = variant_date_to_timestamp($f->value
);
593 else $val = $f->value
;
595 if (($val %
86400) == 0) $this->fields
[] = adodb_date('Y-m-d',$val);
596 else $this->fields
[] = adodb_date('Y-m-d H:i:s',$val);
600 $this->fields
[] = false;
602 case 6: // currency is not supported properly;
603 ADOConnection
::outp( '<b>'.$f->Name
.': currency type not supported by PHP</b>');
604 $this->fields
[] = (float) $f->value
;
608 if(is_bool($f->value
)) {
609 if($f->value
==true) $val = 1;
612 if(is_null($f->value
)) $val = null;
614 $this->fields
[] = $val;
617 $this->fields
[] = $f->value
;
620 //print " $f->value $t, ";
621 $f = next($this->_flds
);
622 $t = next($this->_tarr
);
624 if ($this->hideErrors
) error_reporting($olde);
625 @$rs->MoveNext(); // @ needed for some versions of PHP!
627 if ($this->fetchMode
& ADODB_FETCH_ASSOC
) {
628 $this->fields
= $this->GetRowAssoc(ADODB_ASSOC_CASE
);
633 function NextRecordSet()
635 $rs = $this->_queryID
;
636 $this->_queryID
= $rs->NextRecordSet();
637 //$this->_queryID = $this->_QueryId->NextRecordSet();
638 if ($this->_queryID
== null) return false;
640 $this->_currentRow
= -1;
641 $this->_currentPage
= -1;
643 $this->fields
= false;
644 $this->_flds
= false;
645 $this->_tarr
= false;
647 $this->_inited
= false;
653 $this->_flds
= false;
654 @$this->_queryID
->Close();// by Pete Dishman (peterd@telephonetics.co.uk)
655 $this->_queryID
= false;