You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
636 lines
16 KiB
636 lines
16 KiB
<?php
|
|
/*
|
|
V4.55 3 Jan 2005 (c) 2000-2005 John Lim (jlim@natsoft.com.my). All rights reserved.
|
|
Released under both BSD license and Lesser GPL library license.
|
|
Whenever there is any discrepancy between the two licenses,
|
|
the BSD license will take precedence.
|
|
Set tabs to 4 for best viewing.
|
|
|
|
Latest version is available at http://adodb.sourceforge.net
|
|
|
|
Microsoft ADO data driver. Requires ADO. Works only on MS Windows. PHP5 compat version.
|
|
*/
|
|
|
|
// security - hide paths
|
|
if (!defined('ADODB_DIR')) die();
|
|
|
|
define("_ADODB_ADO_LAYER", 1 );
|
|
/*--------------------------------------------------------------------------------------
|
|
--------------------------------------------------------------------------------------*/
|
|
|
|
|
|
class ADODB_ado extends ADOConnection {
|
|
var $databaseType = "ado";
|
|
var $_bindInputArray = false;
|
|
var $fmtDate = "'Y-m-d'";
|
|
var $fmtTimeStamp = "'Y-m-d, h:i:sA'";
|
|
var $replaceQuote = "''"; // string to use to replace quotes
|
|
var $dataProvider = "ado";
|
|
var $hasAffectedRows = true;
|
|
var $adoParameterType = 201; // 201 = long varchar, 203=long wide varchar, 205 = long varbinary
|
|
var $_affectedRows = false;
|
|
var $_thisTransactions;
|
|
var $_cursor_type = 3; // 3=adOpenStatic,0=adOpenForwardOnly,1=adOpenKeyset,2=adOpenDynamic
|
|
var $_cursor_location = 3; // 2=adUseServer, 3 = adUseClient;
|
|
var $_lock_type = -1;
|
|
var $_execute_option = -1;
|
|
var $poorAffectedRows = true;
|
|
var $charPage;
|
|
|
|
function ADODB_ado()
|
|
{
|
|
$this->_affectedRows = new VARIANT;
|
|
}
|
|
|
|
function ServerInfo()
|
|
{
|
|
if (!empty($this->_connectionID)) $desc = $this->_connectionID->provider;
|
|
return array('description' => $desc, 'version' => '');
|
|
}
|
|
|
|
function _affectedrows()
|
|
{
|
|
if (PHP_VERSION >= 5) return $this->_affectedRows;
|
|
|
|
return $this->_affectedRows->value;
|
|
}
|
|
|
|
// you can also pass a connection string like this:
|
|
//
|
|
// $DB->Connect('USER ID=sa;PASSWORD=pwd;SERVER=mangrove;DATABASE=ai',false,false,'SQLOLEDB');
|
|
function _connect($argHostname, $argUsername, $argPassword, $argProvider= 'MSDASQL')
|
|
{
|
|
try {
|
|
$u = 'UID';
|
|
$p = 'PWD';
|
|
|
|
if (!empty($this->charPage))
|
|
$dbc = new COM('ADODB.Connection',null,$this->charPage);
|
|
else
|
|
$dbc = new COM('ADODB.Connection');
|
|
|
|
if (! $dbc) return false;
|
|
|
|
/* special support if provider is mssql or access */
|
|
if ($argProvider=='mssql') {
|
|
$u = 'User Id'; //User parameter name for OLEDB
|
|
$p = 'Password';
|
|
$argProvider = "SQLOLEDB"; // SQL Server Provider
|
|
|
|
// not yet
|
|
//if ($argDatabasename) $argHostname .= ";Initial Catalog=$argDatabasename";
|
|
|
|
//use trusted conection for SQL if username not specified
|
|
if (!$argUsername) $argHostname .= ";Trusted_Connection=Yes";
|
|
} else if ($argProvider=='access')
|
|
$argProvider = "Microsoft.Jet.OLEDB.4.0"; // Microsoft Jet Provider
|
|
|
|
if ($argProvider) $dbc->Provider = $argProvider;
|
|
|
|
if ($argUsername) $argHostname .= ";$u=$argUsername";
|
|
if ($argPassword)$argHostname .= ";$p=$argPassword";
|
|
|
|
if ($this->debug) ADOConnection::outp( "Host=".$argHostname."<BR>\n version=$dbc->version");
|
|
// @ added below for php 4.0.1 and earlier
|
|
@$dbc->Open((string) $argHostname);
|
|
|
|
$this->_connectionID = $dbc;
|
|
|
|
$dbc->CursorLocation = $this->_cursor_location;
|
|
return $dbc->State > 0;
|
|
} catch (exception $e) {
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// returns true or false
|
|
function _pconnect($argHostname, $argUsername, $argPassword, $argProvider='MSDASQL')
|
|
{
|
|
return $this->_connect($argHostname,$argUsername,$argPassword,$argProvider);
|
|
}
|
|
|
|
/*
|
|
adSchemaCatalogs = 1,
|
|
adSchemaCharacterSets = 2,
|
|
adSchemaCollations = 3,
|
|
adSchemaColumns = 4,
|
|
adSchemaCheckConstraints = 5,
|
|
adSchemaConstraintColumnUsage = 6,
|
|
adSchemaConstraintTableUsage = 7,
|
|
adSchemaKeyColumnUsage = 8,
|
|
adSchemaReferentialContraints = 9,
|
|
adSchemaTableConstraints = 10,
|
|
adSchemaColumnsDomainUsage = 11,
|
|
adSchemaIndexes = 12,
|
|
adSchemaColumnPrivileges = 13,
|
|
adSchemaTablePrivileges = 14,
|
|
adSchemaUsagePrivileges = 15,
|
|
adSchemaProcedures = 16,
|
|
adSchemaSchemata = 17,
|
|
adSchemaSQLLanguages = 18,
|
|
adSchemaStatistics = 19,
|
|
adSchemaTables = 20,
|
|
adSchemaTranslations = 21,
|
|
adSchemaProviderTypes = 22,
|
|
adSchemaViews = 23,
|
|
adSchemaViewColumnUsage = 24,
|
|
adSchemaViewTableUsage = 25,
|
|
adSchemaProcedureParameters = 26,
|
|
adSchemaForeignKeys = 27,
|
|
adSchemaPrimaryKeys = 28,
|
|
adSchemaProcedureColumns = 29,
|
|
adSchemaDBInfoKeywords = 30,
|
|
adSchemaDBInfoLiterals = 31,
|
|
adSchemaCubes = 32,
|
|
adSchemaDimensions = 33,
|
|
adSchemaHierarchies = 34,
|
|
adSchemaLevels = 35,
|
|
adSchemaMeasures = 36,
|
|
adSchemaProperties = 37,
|
|
adSchemaMembers = 38
|
|
|
|
*/
|
|
|
|
function &MetaTables()
|
|
{
|
|
$arr= array();
|
|
$dbc = $this->_connectionID;
|
|
|
|
$adors=@$dbc->OpenSchema(20);//tables
|
|
if ($adors){
|
|
$f = $adors->Fields(2);//table/view name
|
|
$t = $adors->Fields(3);//table type
|
|
while (!$adors->EOF){
|
|
$tt=substr($t->value,0,6);
|
|
if ($tt!='SYSTEM' && $tt !='ACCESS')
|
|
$arr[]=$f->value;
|
|
//print $f->value . ' ' . $t->value.'<br>';
|
|
$adors->MoveNext();
|
|
}
|
|
$adors->Close();
|
|
}
|
|
|
|
return $arr;
|
|
}
|
|
|
|
function &MetaColumns($table)
|
|
{
|
|
$table = strtoupper($table);
|
|
$arr= array();
|
|
$dbc = $this->_connectionID;
|
|
|
|
$adors=@$dbc->OpenSchema(4);//tables
|
|
|
|
if ($adors){
|
|
$t = $adors->Fields(2);//table/view name
|
|
while (!$adors->EOF){
|
|
|
|
|
|
if (strtoupper($t->Value) == $table) {
|
|
|
|
$fld = new ADOFieldObject();
|
|
$c = $adors->Fields(3);
|
|
$fld->name = $c->Value;
|
|
$fld->type = 'CHAR'; // cannot discover type in ADO!
|
|
$fld->max_length = -1;
|
|
$arr[strtoupper($fld->name)]=$fld;
|
|
}
|
|
|
|
$adors->MoveNext();
|
|
}
|
|
$adors->Close();
|
|
}
|
|
|
|
return $arr;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* returns queryID or false */
|
|
function &_query($sql,$inputarr=false)
|
|
{
|
|
try { // In PHP5, all COM errors are exceptions, so to maintain old behaviour...
|
|
|
|
$dbc = $this->_connectionID;
|
|
|
|
// return rs
|
|
if ($inputarr) {
|
|
|
|
if (!empty($this->charPage))
|
|
$oCmd = new COM('ADODB.Command',null,$this->charPage);
|
|
else
|
|
$oCmd = new COM('ADODB.Command');
|
|
$oCmd->ActiveConnection = $dbc;
|
|
$oCmd->CommandText = $sql;
|
|
$oCmd->CommandType = 1;
|
|
|
|
foreach($inputarr as $val) {
|
|
// name, type, direction 1 = input, len,
|
|
$this->adoParameterType = 130;
|
|
$p = $oCmd->CreateParameter('name',$this->adoParameterType,1,strlen($val),$val);
|
|
//print $p->Type.' '.$p->value;
|
|
$oCmd->Parameters->Append($p);
|
|
}
|
|
$p = false;
|
|
$rs = $oCmd->Execute();
|
|
$e = $dbc->Errors;
|
|
if ($dbc->Errors->Count > 0) return false;
|
|
return $rs;
|
|
}
|
|
|
|
$rs = @$dbc->Execute($sql,$this->_affectedRows, $this->_execute_option);
|
|
|
|
if ($dbc->Errors->Count > 0) return false;
|
|
if (! $rs) return false;
|
|
|
|
if ($rs->State == 0) return true; // 0 = adStateClosed means no records returned
|
|
return $rs;
|
|
|
|
} catch (exception $e) {
|
|
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
function BeginTrans()
|
|
{
|
|
if ($this->transOff) return true;
|
|
|
|
if (isset($this->_thisTransactions))
|
|
if (!$this->_thisTransactions) return false;
|
|
else {
|
|
$o = $this->_connectionID->Properties("Transaction DDL");
|
|
$this->_thisTransactions = $o ? true : false;
|
|
if (!$o) return false;
|
|
}
|
|
@$this->_connectionID->BeginTrans();
|
|
$this->transCnt += 1;
|
|
return true;
|
|
}
|
|
function CommitTrans($ok=true)
|
|
{
|
|
if (!$ok) return $this->RollbackTrans();
|
|
if ($this->transOff) return true;
|
|
|
|
@$this->_connectionID->CommitTrans();
|
|
if ($this->transCnt) @$this->transCnt -= 1;
|
|
return true;
|
|
}
|
|
function RollbackTrans() {
|
|
if ($this->transOff) return true;
|
|
@$this->_connectionID->RollbackTrans();
|
|
if ($this->transCnt) @$this->transCnt -= 1;
|
|
return true;
|
|
}
|
|
|
|
/* Returns: the last error message from previous database operation */
|
|
|
|
function ErrorMsg()
|
|
{
|
|
$errc = $this->_connectionID->Errors;
|
|
if ($errc->Count == 0) return '';
|
|
$err = $errc->Item($errc->Count-1);
|
|
return $err->Description;
|
|
}
|
|
|
|
function ErrorNo()
|
|
{
|
|
$errc = $this->_connectionID->Errors;
|
|
if ($errc->Count == 0) return 0;
|
|
$err = $errc->Item($errc->Count-1);
|
|
return $err->NativeError;
|
|
}
|
|
|
|
// returns true or false
|
|
function _close()
|
|
{
|
|
if ($this->_connectionID) $this->_connectionID->Close();
|
|
$this->_connectionID = false;
|
|
return true;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------------------
|
|
Class Name: Recordset
|
|
--------------------------------------------------------------------------------------*/
|
|
|
|
class ADORecordSet_ado extends ADORecordSet {
|
|
|
|
var $bind = false;
|
|
var $databaseType = "ado";
|
|
var $dataProvider = "ado";
|
|
var $_tarr = false; // caches the types
|
|
var $_flds; // and field objects
|
|
var $canSeek = true;
|
|
var $hideErrors = true;
|
|
|
|
function ADORecordSet_ado($id,$mode=false)
|
|
{
|
|
if ($mode === false) {
|
|
global $ADODB_FETCH_MODE;
|
|
$mode = $ADODB_FETCH_MODE;
|
|
}
|
|
$this->fetchMode = $mode;
|
|
return $this->ADORecordSet($id,$mode);
|
|
}
|
|
|
|
|
|
// returns the field object
|
|
function FetchField($fieldOffset = -1) {
|
|
$off=$fieldOffset+1; // offsets begin at 1
|
|
|
|
$o= new ADOFieldObject();
|
|
$rs = $this->_queryID;
|
|
$f = $rs->Fields($fieldOffset);
|
|
$o->name = $f->Name;
|
|
$t = $f->Type;
|
|
$o->type = $this->MetaType($t);
|
|
$o->max_length = $f->DefinedSize;
|
|
$o->ado_type = $t;
|
|
|
|
|
|
//print "off=$off name=$o->name type=$o->type len=$o->max_length<br>";
|
|
return $o;
|
|
}
|
|
|
|
/* Use associative array to get fields array */
|
|
function Fields($colname)
|
|
{
|
|
if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname];
|
|
if (!$this->bind) {
|
|
$this->bind = array();
|
|
for ($i=0; $i < $this->_numOfFields; $i++) {
|
|
$o = $this->FetchField($i);
|
|
$this->bind[strtoupper($o->name)] = $i;
|
|
}
|
|
}
|
|
|
|
return $this->fields[$this->bind[strtoupper($colname)]];
|
|
}
|
|
|
|
|
|
function _initrs()
|
|
{
|
|
$rs = $this->_queryID;
|
|
$this->_numOfRows = $rs->RecordCount;
|
|
|
|
$f = $rs->Fields;
|
|
$this->_numOfFields = $f->Count;
|
|
}
|
|
|
|
|
|
// should only be used to move forward as we normally use forward-only cursors
|
|
function _seek($row)
|
|
{
|
|
$rs = $this->_queryID;
|
|
// absoluteposition doesn't work -- my maths is wrong ?
|
|
// $rs->AbsolutePosition->$row-2;
|
|
// return true;
|
|
if ($this->_currentRow > $row) return false;
|
|
@$rs->Move((integer)$row - $this->_currentRow-1); //adBookmarkFirst
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
OLEDB types
|
|
|
|
enum DBTYPEENUM
|
|
{ DBTYPE_EMPTY = 0,
|
|
DBTYPE_NULL = 1,
|
|
DBTYPE_I2 = 2,
|
|
DBTYPE_I4 = 3,
|
|
DBTYPE_R4 = 4,
|
|
DBTYPE_R8 = 5,
|
|
DBTYPE_CY = 6,
|
|
DBTYPE_DATE = 7,
|
|
DBTYPE_BSTR = 8,
|
|
DBTYPE_IDISPATCH = 9,
|
|
DBTYPE_ERROR = 10,
|
|
DBTYPE_BOOL = 11,
|
|
DBTYPE_VARIANT = 12,
|
|
DBTYPE_IUNKNOWN = 13,
|
|
DBTYPE_DECIMAL = 14,
|
|
DBTYPE_UI1 = 17,
|
|
DBTYPE_ARRAY = 0x2000,
|
|
DBTYPE_BYREF = 0x4000,
|
|
DBTYPE_I1 = 16,
|
|
DBTYPE_UI2 = 18,
|
|
DBTYPE_UI4 = 19,
|
|
DBTYPE_I8 = 20,
|
|
DBTYPE_UI8 = 21,
|
|
DBTYPE_GUID = 72,
|
|
DBTYPE_VECTOR = 0x1000,
|
|
DBTYPE_RESERVED = 0x8000,
|
|
DBTYPE_BYTES = 128,
|
|
DBTYPE_STR = 129,
|
|
DBTYPE_WSTR = 130,
|
|
DBTYPE_NUMERIC = 131,
|
|
DBTYPE_UDT = 132,
|
|
DBTYPE_DBDATE = 133,
|
|
DBTYPE_DBTIME = 134,
|
|
DBTYPE_DBTIMESTAMP = 135
|
|
|
|
ADO Types
|
|
|
|
adEmpty = 0,
|
|
adTinyInt = 16,
|
|
adSmallInt = 2,
|
|
adInteger = 3,
|
|
adBigInt = 20,
|
|
adUnsignedTinyInt = 17,
|
|
adUnsignedSmallInt = 18,
|
|
adUnsignedInt = 19,
|
|
adUnsignedBigInt = 21,
|
|
adSingle = 4,
|
|
adDouble = 5,
|
|
adCurrency = 6,
|
|
adDecimal = 14,
|
|
adNumeric = 131,
|
|
adBoolean = 11,
|
|
adError = 10,
|
|
adUserDefined = 132,
|
|
adVariant = 12,
|
|
adIDispatch = 9,
|
|
adIUnknown = 13,
|
|
adGUID = 72,
|
|
adDate = 7,
|
|
adDBDate = 133,
|
|
adDBTime = 134,
|
|
adDBTimeStamp = 135,
|
|
adBSTR = 8,
|
|
adChar = 129,
|
|
adVarChar = 200,
|
|
adLongVarChar = 201,
|
|
adWChar = 130,
|
|
adVarWChar = 202,
|
|
adLongVarWChar = 203,
|
|
adBinary = 128,
|
|
adVarBinary = 204,
|
|
adLongVarBinary = 205,
|
|
adChapter = 136,
|
|
adFileTime = 64,
|
|
adDBFileTime = 137,
|
|
adPropVariant = 138,
|
|
adVarNumeric = 139
|
|
*/
|
|
function MetaType($t,$len=-1,$fieldobj=false)
|
|
{
|
|
if (is_object($t)) {
|
|
$fieldobj = $t;
|
|
$t = $fieldobj->type;
|
|
$len = $fieldobj->max_length;
|
|
}
|
|
|
|
if (!is_numeric($t)) return $t;
|
|
|
|
switch ($t) {
|
|
case 0:
|
|
case 12: // variant
|
|
case 8: // bstr
|
|
case 129: //char
|
|
case 130: //wc
|
|
case 200: // varc
|
|
case 202:// varWC
|
|
case 128: // bin
|
|
case 204: // varBin
|
|
case 72: // guid
|
|
if ($len <= $this->blobSize) return 'C';
|
|
|
|
case 201:
|
|
case 203:
|
|
return 'X';
|
|
case 128:
|
|
case 204:
|
|
case 205:
|
|
return 'B';
|
|
case 7:
|
|
case 133: return 'D';
|
|
|
|
case 134:
|
|
case 135: return 'T';
|
|
|
|
case 11: return 'L';
|
|
|
|
case 16:// adTinyInt = 16,
|
|
case 2://adSmallInt = 2,
|
|
case 3://adInteger = 3,
|
|
case 4://adBigInt = 20,
|
|
case 17://adUnsignedTinyInt = 17,
|
|
case 18://adUnsignedSmallInt = 18,
|
|
case 19://adUnsignedInt = 19,
|
|
case 20://adUnsignedBigInt = 21,
|
|
return 'I';
|
|
default: return 'N';
|
|
}
|
|
}
|
|
|
|
// time stamp not supported yet
|
|
function _fetch()
|
|
{
|
|
$rs = $this->_queryID;
|
|
if (!$rs or $rs->EOF) {
|
|
$this->fields = false;
|
|
return false;
|
|
}
|
|
$this->fields = array();
|
|
|
|
if (!$this->_tarr) {
|
|
$tarr = array();
|
|
$flds = array();
|
|
for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) {
|
|
$f = $rs->Fields($i);
|
|
$flds[] = $f;
|
|
$tarr[] = $f->Type;
|
|
}
|
|
// bind types and flds only once
|
|
$this->_tarr = $tarr;
|
|
$this->_flds = $flds;
|
|
}
|
|
$t = reset($this->_tarr);
|
|
$f = reset($this->_flds);
|
|
|
|
if ($this->hideErrors) $olde = error_reporting(E_ERROR|E_CORE_ERROR);// sometimes $f->value be null
|
|
for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) {
|
|
//echo "<p>",$t,' ';var_dump($f->value); echo '</p>';
|
|
switch($t) {
|
|
case 135: // timestamp
|
|
if (!strlen((string)$f->value)) $this->fields[] = false;
|
|
else {
|
|
if (!is_numeric($f->value)) $val = variant_date_to_timestamp($f->value);
|
|
else $val = $f->value;
|
|
$this->fields[] = adodb_date('Y-m-d H:i:s',$val);
|
|
}
|
|
break;
|
|
case 133:// A date value (yyyymmdd)
|
|
if ($val = $f->value) {
|
|
$this->fields[] = substr($val,0,4).'-'.substr($val,4,2).'-'.substr($val,6,2);
|
|
} else
|
|
$this->fields[] = false;
|
|
break;
|
|
case 7: // adDate
|
|
if (!strlen((string)$f->value)) $this->fields[] = false;
|
|
else {
|
|
if (!is_numeric($f->value)) $val = variant_date_to_timestamp($f->value);
|
|
else $val = $f->value;
|
|
|
|
if (($val % 86400) == 0) $this->fields[] = adodb_date('Y-m-d',$val);
|
|
else $this->fields[] = adodb_date('Y-m-d H:i:s',$val);
|
|
}
|
|
break;
|
|
case 1: // null
|
|
$this->fields[] = false;
|
|
break;
|
|
case 6: // currency is not supported properly;
|
|
ADOConnection::outp( '<b>'.$f->Name.': currency type not supported by PHP</b>');
|
|
$this->fields[] = (float) $f->value;
|
|
break;
|
|
default:
|
|
$this->fields[] = $f->value;
|
|
break;
|
|
}
|
|
//print " $f->value $t, ";
|
|
$f = next($this->_flds);
|
|
$t = next($this->_tarr);
|
|
} // for
|
|
if ($this->hideErrors) error_reporting($olde);
|
|
@$rs->MoveNext(); // @ needed for some versions of PHP!
|
|
|
|
if ($this->fetchMode & ADODB_FETCH_ASSOC) {
|
|
$this->fields = &$this->GetRowAssoc(ADODB_ASSOC_CASE);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function NextRecordSet()
|
|
{
|
|
$rs = $this->_queryID;
|
|
$this->_queryID = $rs->NextRecordSet();
|
|
//$this->_queryID = $this->_QueryId->NextRecordSet();
|
|
if ($this->_queryID == null) return false;
|
|
|
|
$this->_currentRow = -1;
|
|
$this->_currentPage = -1;
|
|
$this->bind = false;
|
|
$this->fields = false;
|
|
$this->_flds = false;
|
|
$this->_tarr = false;
|
|
|
|
$this->_inited = false;
|
|
$this->Init();
|
|
return true;
|
|
}
|
|
|
|
function _close() {
|
|
$this->_flds = false;
|
|
@$this->_queryID->Close();// by Pete Dishman (peterd@telephonetics.co.uk)
|
|
$this->_queryID = false;
|
|
}
|
|
|
|
}
|
|
|
|
?>
|