3 @version v5.20.3 01-Jan-2016
4 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
5 @copyright (c) 2014 Damien Regad, Mark Newnham and the ADOdb community
6 Released under both BSD license and Lesser GPL library license.
7 Whenever there is any discrepancy between the two licenses,
8 the BSD license will take precedence.
9 Set tabs to 4 for best viewing.
11 Latest version is available at http://adodb.sourceforge.net
13 Microsoft ADO data driver. Requires ADO. Works only on MS Windows. PHP5 compat version.
16 // security - hide paths
17 if (!defined('ADODB_DIR')) die();
19 define("_ADODB_ADO_LAYER", 1 );
20 /*--------------------------------------------------------------------------------------
21 --------------------------------------------------------------------------------------*/
24 class ADODB_ado
extends ADOConnection
{
25 var $databaseType = "ado";
26 var $_bindInputArray = false
;
27 var $fmtDate = "'Y-m-d'";
28 var $fmtTimeStamp = "'Y-m-d, h:i:sA'";
29 var $replaceQuote = "''"; // string to use to replace quotes
30 var $dataProvider = "ado";
31 var $hasAffectedRows = true
;
32 var $adoParameterType = 201; // 201 = long varchar, 203=long wide varchar, 205 = long varbinary
33 var $_affectedRows = false
;
34 var $_thisTransactions;
35 var $_cursor_type = 3; // 3=adOpenStatic,0=adOpenForwardOnly,1=adOpenKeyset,2=adOpenDynamic
36 var $_cursor_location = 3; // 2=adUseServer, 3 = adUseClient;
38 var $_execute_option = -1;
39 var $poorAffectedRows = true
;
42 function __construct()
44 $this->_affectedRows
= new VARIANT
;
49 if (!empty($this->_connectionID
)) $desc = $this->_connectionID
->provider
;
50 return array('description' => $desc, 'version' => '');
53 function _affectedrows()
55 if (PHP_VERSION
>= 5) return $this->_affectedRows
;
57 return $this->_affectedRows
->value
;
60 // you can also pass a connection string like this:
62 // $DB->Connect('USER ID=sa;PASSWORD=pwd;SERVER=mangrove;DATABASE=ai',false,false,'SQLOLEDB');
63 function _connect($argHostname, $argUsername, $argPassword,$argDBorProvider, $argProvider= '')
66 // - if $argProvider is empty, we assume that $argDBorProvider holds provider -- this is for backward compat
67 // - if $argProvider is not empty, then $argDBorProvider holds db
71 $argDatabasename = $argDBorProvider;
73 $argDatabasename = '';
74 if ($argDBorProvider) $argProvider = $argDBorProvider;
75 else if (stripos($argHostname,'PROVIDER') === false
) /* full conn string is not in $argHostname */
76 $argProvider = 'MSDASQL';
84 if (!empty($this->charPage
))
85 $dbc = new COM('ADODB.Connection',null
,$this->charPage
);
87 $dbc = new COM('ADODB.Connection');
89 if (! $dbc) return false
;
91 /* special support if provider is mssql or access */
92 if ($argProvider=='mssql') {
93 $u = 'User Id'; //User parameter name for OLEDB
95 $argProvider = "SQLOLEDB"; // SQL Server Provider
98 //if ($argDatabasename) $argHostname .= ";Initial Catalog=$argDatabasename";
100 //use trusted conection for SQL if username not specified
101 if (!$argUsername) $argHostname .= ";Trusted_Connection=Yes";
102 } else if ($argProvider=='access')
103 $argProvider = "Microsoft.Jet.OLEDB.4.0"; // Microsoft Jet Provider
105 if ($argProvider) $dbc->Provider
= $argProvider;
107 if ($argProvider) $argHostname = "PROVIDER=$argProvider;DRIVER={SQL Server};SERVER=$argHostname";
110 if ($argDatabasename) $argHostname .= ";DATABASE=$argDatabasename";
111 if ($argUsername) $argHostname .= ";$u=$argUsername";
112 if ($argPassword)$argHostname .= ";$p=$argPassword";
114 if ($this->debug
) ADOConnection
::outp( "Host=".$argHostname."<BR>\n version=$dbc->version");
115 // @ added below for php 4.0.1 and earlier
116 @$dbc->Open((string) $argHostname);
118 $this->_connectionID
= $dbc;
120 $dbc->CursorLocation
= $this->_cursor_location
;
121 return $dbc->State
> 0;
122 } catch (exception
$e) {
123 if ($this->debug
) echo "<pre>",$argHostname,"\n",$e,"</pre>\n";
129 // returns true or false
130 function _pconnect($argHostname, $argUsername, $argPassword, $argProvider='MSDASQL')
132 return $this->_connect($argHostname,$argUsername,$argPassword,$argProvider);
136 adSchemaCatalogs = 1,
137 adSchemaCharacterSets = 2,
138 adSchemaCollations = 3,
140 adSchemaCheckConstraints = 5,
141 adSchemaConstraintColumnUsage = 6,
142 adSchemaConstraintTableUsage = 7,
143 adSchemaKeyColumnUsage = 8,
144 adSchemaReferentialContraints = 9,
145 adSchemaTableConstraints = 10,
146 adSchemaColumnsDomainUsage = 11,
147 adSchemaIndexes = 12,
148 adSchemaColumnPrivileges = 13,
149 adSchemaTablePrivileges = 14,
150 adSchemaUsagePrivileges = 15,
151 adSchemaProcedures = 16,
152 adSchemaSchemata = 17,
153 adSchemaSQLLanguages = 18,
154 adSchemaStatistics = 19,
156 adSchemaTranslations = 21,
157 adSchemaProviderTypes = 22,
159 adSchemaViewColumnUsage = 24,
160 adSchemaViewTableUsage = 25,
161 adSchemaProcedureParameters = 26,
162 adSchemaForeignKeys = 27,
163 adSchemaPrimaryKeys = 28,
164 adSchemaProcedureColumns = 29,
165 adSchemaDBInfoKeywords = 30,
166 adSchemaDBInfoLiterals = 31,
168 adSchemaDimensions = 33,
169 adSchemaHierarchies = 34,
171 adSchemaMeasures = 36,
172 adSchemaProperties = 37,
177 function MetaTables($ttype = false
, $showSchema = false
, $mask = false
)
180 $dbc = $this->_connectionID
;
182 $adors=@$dbc->OpenSchema(20);//tables
184 $f = $adors->Fields(2);//table/view name
185 $t = $adors->Fields(3);//table type
186 while (!$adors->EOF
){
187 $tt=substr($t->value
,0,6);
188 if ($tt!='SYSTEM' && $tt !='ACCESS')
190 //print $f->value . ' ' . $t->value.'<br>';
199 function MetaColumns($table, $normalize=true
)
201 $table = strtoupper($table);
203 $dbc = $this->_connectionID
;
205 $adors=@$dbc->OpenSchema(4);//tables
208 $t = $adors->Fields(2);//table/view name
209 while (!$adors->EOF
){
212 if (strtoupper($t->Value
) == $table) {
214 $fld = new ADOFieldObject();
215 $c = $adors->Fields(3);
216 $fld->name
= $c->Value
;
217 $fld->type
= 'CHAR'; // cannot discover type in ADO!
218 $fld->max_length
= -1;
219 $arr[strtoupper($fld->name
)]=$fld;
230 /* returns queryID or false */
231 function _query($sql,$inputarr=false
)
233 try { // In PHP5, all COM errors are exceptions, so to maintain old behaviour...
235 $dbc = $this->_connectionID
;
243 if (!empty($this->charPage
))
244 $oCmd = new COM('ADODB.Command',null
,$this->charPage
);
246 $oCmd = new COM('ADODB.Command');
247 $oCmd->ActiveConnection
= $dbc;
248 $oCmd->CommandText
= $sql;
249 $oCmd->CommandType
= 1;
251 while(list(, $val) = each($inputarr)) {
252 $type = gettype($val);
254 if ($type == 'boolean')
255 $this->adoParameterType
= 11;
256 else if ($type == 'integer')
257 $this->adoParameterType
= 3;
258 else if ($type == 'double')
259 $this->adoParameterType
= 5;
260 elseif ($type == 'string')
261 $this->adoParameterType
= 202;
262 else if (($val === null
) ||
(!defined($val)))
265 $this->adoParameterType
= 130;
267 // name, type, direction 1 = input, len,
268 $p = $oCmd->CreateParameter('name',$this->adoParameterType
,1,$len,$val);
270 $oCmd->Parameters
->Append($p);
274 $rs = $oCmd->Execute();
276 if ($dbc->Errors
->Count
> 0) return $false;
280 $rs = @$dbc->Execute($sql,$this->_affectedRows
, $this->_execute_option
);
282 if ($dbc->Errors
->Count
> 0) return $false;
283 if (! $rs) return $false;
285 if ($rs->State
== 0) {
287 return $true; // 0 = adStateClosed means no records returned
291 } catch (exception
$e) {
298 function BeginTrans()
300 if ($this->transOff
) return true
;
302 if (isset($this->_thisTransactions
))
303 if (!$this->_thisTransactions
) return false
;
305 $o = $this->_connectionID
->Properties("Transaction DDL");
306 $this->_thisTransactions
= $o ? true
: false
;
307 if (!$o) return false
;
309 @$this->_connectionID
->BeginTrans();
310 $this->transCnt +
= 1;
313 function CommitTrans($ok=true
)
315 if (!$ok) return $this->RollbackTrans();
316 if ($this->transOff
) return true
;
318 @$this->_connectionID
->CommitTrans();
319 if ($this->transCnt
) @$this->transCnt
-= 1;
322 function RollbackTrans() {
323 if ($this->transOff
) return true
;
324 @$this->_connectionID
->RollbackTrans();
325 if ($this->transCnt
) @$this->transCnt
-= 1;
329 /* Returns: the last error message from previous database operation */
333 if (!$this->_connectionID
) return "No connection established";
337 $errc = $this->_connectionID
->Errors
;
338 if (!$errc) return "No Errors object found";
339 if ($errc->Count
== 0) return '';
340 $err = $errc->Item($errc->Count
-1);
341 $errmsg = $err->Description
;
342 }catch(exception
$e) {
349 $errc = $this->_connectionID
->Errors
;
350 if ($errc->Count
== 0) return 0;
351 $err = $errc->Item($errc->Count
-1);
352 return $err->NativeError
;
355 // returns true or false
358 if ($this->_connectionID
) $this->_connectionID
->Close();
359 $this->_connectionID
= false
;
366 /*--------------------------------------------------------------------------------------
367 Class Name: Recordset
368 --------------------------------------------------------------------------------------*/
370 class ADORecordSet_ado
extends ADORecordSet
{
373 var $databaseType = "ado";
374 var $dataProvider = "ado";
375 var $_tarr = false
; // caches the types
376 var $_flds; // and field objects
378 var $hideErrors = true
;
380 function __construct($id,$mode=false
)
382 if ($mode === false
) {
383 global $ADODB_FETCH_MODE;
384 $mode = $ADODB_FETCH_MODE;
386 $this->fetchMode
= $mode;
387 return parent
::__construct($id,$mode);
391 // returns the field object
392 function FetchField($fieldOffset = -1) {
393 $off=$fieldOffset+
1; // offsets begin at 1
395 $o= new ADOFieldObject();
396 $rs = $this->_queryID
;
397 if (!$rs) return false
;
399 $f = $rs->Fields($fieldOffset);
402 $o->type
= $this->MetaType($t);
403 $o->max_length
= $f->DefinedSize
;
407 //print "off=$off name=$o->name type=$o->type len=$o->max_length<br>";
411 /* Use associative array to get fields array */
412 function Fields($colname)
414 if ($this->fetchMode
& ADODB_FETCH_ASSOC
) return $this->fields
[$colname];
416 $this->bind
= array();
417 for ($i=0; $i < $this->_numOfFields
; $i++
) {
418 $o = $this->FetchField($i);
419 $this->bind
[strtoupper($o->name
)] = $i;
423 return $this->fields
[$this->bind
[strtoupper($colname)]];
429 $rs = $this->_queryID
;
432 $this->_numOfRows
= $rs->RecordCount
;
433 } catch (Exception
$e) {
434 $this->_numOfRows
= -1;
437 $this->_numOfFields
= $f->Count
;
441 // should only be used to move forward as we normally use forward-only cursors
444 $rs = $this->_queryID
;
445 // absoluteposition doesn't work -- my maths is wrong ?
446 // $rs->AbsolutePosition->$row-2;
448 if ($this->_currentRow
> $row) return false
;
449 @$rs->Move((integer)$row - $this->_currentRow
-1); //adBookmarkFirst
466 DBTYPE_IDISPATCH = 9,
470 DBTYPE_IUNKNOWN = 13,
473 DBTYPE_ARRAY = 0x2000,
474 DBTYPE_BYREF = 0x4000,
481 DBTYPE_VECTOR = 0x1000,
482 DBTYPE_RESERVED = 0x8000,
486 DBTYPE_NUMERIC = 131,
490 DBTYPE_DBTIMESTAMP = 135
499 adUnsignedTinyInt = 17,
500 adUnsignedSmallInt = 18,
502 adUnsignedBigInt = 21,
525 adLongVarWChar = 203,
528 adLongVarBinary = 205,
535 function MetaType($t,$len=-1,$fieldobj=false
)
539 $t = $fieldobj->type
;
540 $len = $fieldobj->max_length
;
543 if (!is_numeric($t)) return $t;
556 if ($len <= $this->blobSize
) return 'C';
566 case 133: return 'D';
569 case 135: return 'T';
573 case 16:// adTinyInt = 16,
574 case 2://adSmallInt = 2,
575 case 3://adInteger = 3,
576 case 4://adBigInt = 20,
577 case 17://adUnsignedTinyInt = 17,
578 case 18://adUnsignedSmallInt = 18,
579 case 19://adUnsignedInt = 19,
580 case 20://adUnsignedBigInt = 21,
586 // time stamp not supported yet
589 $rs = $this->_queryID
;
590 if (!$rs or $rs->EOF
) {
591 $this->fields
= false
;
594 $this->fields
= array();
599 for ($i=0,$max = $this->_numOfFields
; $i < $max; $i++
) {
600 $f = $rs->Fields($i);
604 // bind types and flds only once
605 $this->_tarr
= $tarr;
606 $this->_flds
= $flds;
608 $t = reset($this->_tarr
);
609 $f = reset($this->_flds
);
611 if ($this->hideErrors
) $olde = error_reporting(E_ERROR|E_CORE_ERROR
);// sometimes $f->value be null
612 for ($i=0,$max = $this->_numOfFields
; $i < $max; $i++
) {
613 //echo "<p>",$t,' ';var_dump($f->value); echo '</p>';
615 case 135: // timestamp
616 if (!strlen((string)$f->value
)) $this->fields
[] = false
;
618 if (!is_numeric($f->value
)) # $val = variant_date_to_timestamp($f->value);
619 // VT_DATE stores dates as (float) fractional days since 1899/12/30 00:00:00
620 $val= (float) variant_cast($f->value
,VT_R8
)*3600*24-2209161600;
623 $this->fields
[] = adodb_date('Y-m-d H:i:s',$val);
626 case 133:// A date value (yyyymmdd)
627 if ($val = $f->value
) {
628 $this->fields
[] = substr($val,0,4).'-'.substr($val,4,2).'-'.substr($val,6,2);
630 $this->fields
[] = false
;
633 if (!strlen((string)$f->value
)) $this->fields
[] = false
;
635 if (!is_numeric($f->value
)) $val = variant_date_to_timestamp($f->value
);
636 else $val = $f->value
;
638 if (($val %
86400) == 0) $this->fields
[] = adodb_date('Y-m-d',$val);
639 else $this->fields
[] = adodb_date('Y-m-d H:i:s',$val);
643 $this->fields
[] = false
;
646 case 21: // bigint (64 bit)
647 $this->fields
[] = (float) $f->value
; // if 64 bit PHP, could use (int)
649 case 6: // currency is not supported properly;
650 ADOConnection
::outp( '<b>'.$f->Name
.': currency type not supported by PHP</b>');
651 $this->fields
[] = (float) $f->value
;
655 if(is_bool($f->value
)) {
656 if($f->value
==true
) $val = 1;
659 if(is_null($f->value
)) $val = null
;
661 $this->fields
[] = $val;
664 $this->fields
[] = $f->value
;
667 //print " $f->value $t, ";
668 $f = next($this->_flds
);
669 $t = next($this->_tarr
);
671 if ($this->hideErrors
) error_reporting($olde);
672 @$rs->MoveNext(); // @ needed for some versions of PHP!
674 if ($this->fetchMode
& ADODB_FETCH_ASSOC
) {
675 $this->fields
= $this->GetRowAssoc();
680 function NextRecordSet()
682 $rs = $this->_queryID
;
683 $this->_queryID
= $rs->NextRecordSet();
684 //$this->_queryID = $this->_QueryId->NextRecordSet();
685 if ($this->_queryID
== null
) return false
;
687 $this->_currentRow
= -1;
688 $this->_currentPage
= -1;
690 $this->fields
= false
;
691 $this->_flds
= false
;
692 $this->_tarr
= false
;
694 $this->_inited
= false
;
700 $this->_flds
= false
;
702 @$this->_queryID
->Close();// by Pete Dishman (peterd@telephonetics.co.uk)
703 } catch (Exception
$e) {
705 $this->_queryID
= false
;