Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]

   1  <?php
   2  /*
   3    (c) 2000-2014 John Lim (jlim#natsoft.com.my). All rights reserved.
   4    Portions Copyright (c) 2007-2009, iAnywhere Solutions, Inc.
   5    All rights reserved. All unpublished rights reserved.
   6  
   7    Released under both BSD license and Lesser GPL library license.
   8    Whenever there is any discrepancy between the two licenses,
   9    the BSD license will take precedence.
  10  
  11  Set tabs to 4 for best viewing.
  12  
  13  
  14  NOTE: This driver requires the Advantage PHP client libraries, which
  15        can be downloaded for free via:
  16        http://devzone.advantagedatabase.com/dz/content.aspx?key=20
  17  
  18  DELPHI FOR PHP USERS:
  19        The following steps can be taken to utilize this driver from the
  20        CodeGear Delphi for PHP product:
  21          1 - See note above, download and install the Advantage PHP client.
  22          2 - Copy the following files to the Delphi for PHP\X.X\php\ext directory:
  23                ace32.dll
  24                axcws32.dll
  25                adsloc32.dll
  26                php_advantage.dll (rename the existing php_advantage.dll.5.x.x file)
  27          3 - Add the following line to the Delphi for PHP\X.X\php\php.ini.template file:
  28                extension=php_advantage.dll
  29          4 - To use: enter "ads" as the DriverName on a connection component, and set
  30              a Host property similar to "DataDirectory=c:\". See the Advantage PHP
  31              help file topic for ads_connect for details on connection path options
  32              and formatting.
  33          5 - (optional) - Modify the Delphi for PHP\X.X\vcl\packages\database.packages.php
  34              file and add ads to the list of strings returned when registering the
  35              Database object's DriverName property.
  36  
  37  */
  38  // security - hide paths
  39  if (!defined('ADODB_DIR')) {
  40  	 die();
  41  }
  42  
  43  define("_ADODB_ADS_LAYER", 2);
  44  
  45  /*--------------------------------------------------------------------------------------
  46  --------------------------------------------------------------------------------------*/
  47  
  48  
  49  class ADODB_ads extends ADOConnection
  50  {
  51  	 var $databaseType = "ads";
  52  	 var $fmt = "'m-d-Y'";
  53  	 var $fmtTimeStamp = "'Y-m-d H:i:s'";
  54  	 var $concat_operator = '';
  55  	 var $replaceQuote = "''"; // string to use to replace quotes
  56  	 var $dataProvider = "ads";
  57  	 var $hasAffectedRows = true;
  58  	 var $binmode = ODBC_BINMODE_RETURN;
  59  	 var $useFetchArray = false; // setting this to true will make array elements in FETCH_ASSOC mode case-sensitive
  60  	 // breaking backward-compat
  61  	 //var $longreadlen = 8000; // default number of chars to return for a Blob/Long field
  62  	 var $_bindInputArray = false;
  63  	 var $curmode = SQL_CUR_USE_DRIVER; // See sqlext.h, SQL_CUR_DEFAULT == SQL_CUR_USE_DRIVER == 2L
  64  	 var $_genSeqSQL = "create table %s (id integer)";
  65  	 var $_autocommit = true;
  66  	 var $_lastAffectedRows = 0;
  67  	 var $uCaseTables = true; // for meta* functions, uppercase table names
  68  
  69  	function __construct()
  70  	 {
  71  	 }
  72  
  73  	 // returns true or false
  74  	function _connect($argDSN, $argUsername, $argPassword, $argDatabasename)
  75  	 {
  76  	 	 if (!function_exists('ads_connect')) {
  77  	 	 	 return null;
  78  	 	 }
  79  
  80  	 	 if ($this->debug && $argDatabasename && $this->databaseType != 'vfp') {
  81  	 	 	 ADOConnection::outp("For Advantage Connect(), $argDatabasename is not used. Place dsn in 1st parameter.");
  82  	 	 }
  83  	 	 $last_php_error = $this->resetLastError();
  84  	 	 if ($this->curmode === false) {
  85  	 	 	 $this->_connectionID = ads_connect($argDSN, $argUsername, $argPassword);
  86  	 	 } else {
  87  	 	 	 $this->_connectionID = ads_connect($argDSN, $argUsername, $argPassword, $this->curmode);
  88  	 	 }
  89  	 	 $this->_errorMsg = $this->getChangedErrorMsg($last_php_error);
  90  	 	 if (isset($this->connectStmt)) {
  91  	 	 	 $this->Execute($this->connectStmt);
  92  	 	 }
  93  
  94  	 	 return $this->_connectionID != false;
  95  	 }
  96  
  97  	 // returns true or false
  98  	function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename)
  99  	 {
 100  	 	 if (!function_exists('ads_connect')) {
 101  	 	 	 return null;
 102  	 	 }
 103  
 104  	 	 $last_php_error = $this->resetLastError();
 105  	 	 $this->_errorMsg = '';
 106  	 	 if ($this->debug && $argDatabasename) {
 107  	 	 	 ADOConnection::outp("For PConnect(), $argDatabasename is not used. Place dsn in 1st parameter.");
 108  	 	 }
 109  	 	 //  print "dsn=$argDSN u=$argUsername p=$argPassword<br>"; flush();
 110  	 	 if ($this->curmode === false) {
 111  	 	 	 $this->_connectionID = ads_connect($argDSN, $argUsername, $argPassword);
 112  	 	 } else {
 113  	 	 	 $this->_connectionID = ads_pconnect($argDSN, $argUsername, $argPassword, $this->curmode);
 114  	 	 }
 115  
 116  	 	 $this->_errorMsg = $this->getChangedErrorMsg($last_php_error);
 117  	 	 if ($this->_connectionID && $this->autoRollback) {
 118  	 	 	 @ads_rollback($this->_connectionID);
 119  	 	 }
 120  	 	 if (isset($this->connectStmt)) {
 121  	 	 	 $this->Execute($this->connectStmt);
 122  	 	 }
 123  
 124  	 	 return $this->_connectionID != false;
 125  	 }
 126  
 127  	 // returns the Server version and Description
 128  	function ServerInfo()
 129  	 {
 130  
 131  	 	 if (!empty($this->host)) {
 132  	 	 	 $stmt = $this->Prepare('EXECUTE PROCEDURE sp_mgGetInstallInfo()');
 133  	 	 	 $res = $this->Execute($stmt);
 134  	 	 	 if (!$res) {
 135  	 	 	 	 print $this->ErrorMsg();
 136  	 	 	 } else {
 137  	 	 	 	 $ret["version"] = $res->fields[3];
 138  	 	 	 	 $ret["description"] = "Advantage Database Server";
 139  	 	 	 	 return $ret;
 140  	 	 	 }
 141  	 	 } else {
 142  	 	 	 return ADOConnection::ServerInfo();
 143  	 	 }
 144  	 }
 145  
 146  
 147  	 // returns true or false
 148  	function CreateSequence($seqname = 'adodbseq', $start = 1)
 149  	 {
 150  	 	 $res = $this->Execute("CREATE TABLE $seqname ( ID autoinc( 1 ) ) IN DATABASE");
 151  	 	 if (!$res) {
 152  	 	 	 print $this->ErrorMsg();
 153  	 	 	 return false;
 154  	 	 } else {
 155  	 	 	 return true;
 156  	 	 }
 157  
 158  	 }
 159  
 160  	 // returns true or false
 161  	function DropSequence($seqname = 'adodbseq')
 162  	 {
 163  	 	 $res = $this->Execute("DROP TABLE $seqname");
 164  	 	 if (!$res) {
 165  	 	 	 print $this->ErrorMsg();
 166  	 	 	 return false;
 167  	 	 } else {
 168  	 	 	 return true;
 169  	 	 }
 170  	 }
 171  
 172  
 173  	 // returns the generated ID or false
 174  	 // checks if the table already exists, else creates the table and inserts a record into the table
 175  	 // and gets the ID number of the last inserted record.
 176  	function GenID($seqname = 'adodbseq', $start = 1)
 177  	 {
 178  	 	 $go = $this->Execute("select * from $seqname");
 179  	 	 if (!$go) {
 180  	 	 	 $res = $this->Execute("CREATE TABLE $seqname ( ID autoinc( 1 ) ) IN DATABASE");
 181  	 	 	 if (!$res) {
 182  	 	 	 	 print $this->ErrorMsg();
 183  	 	 	 	 return false;
 184  	 	 	 }
 185  	 	 }
 186  	 	 $res = $this->Execute("INSERT INTO $seqname VALUES( DEFAULT )");
 187  	 	 if (!$res) {
 188  	 	 	 print $this->ErrorMsg();
 189  	 	 	 return false;
 190  	 	 } else {
 191  	 	 	 $gen = $this->Execute("SELECT LastAutoInc( STATEMENT ) FROM system.iota");
 192  	 	 	 $ret = $gen->fields[0];
 193  	 	 	 return $ret;
 194  	 	 }
 195  
 196  	 }
 197  
 198  
 199  	function ErrorMsg()
 200  	 {
 201  	 	 if ($this->_errorMsg !== false) {
 202  	 	 	 return $this->_errorMsg;
 203  	 	 }
 204  	 	 if (empty($this->_connectionID)) {
 205  	 	 	 return @ads_errormsg();
 206  	 	 }
 207  	 	 return @ads_errormsg($this->_connectionID);
 208  	 }
 209  
 210  
 211  	function ErrorNo()
 212  	 {
 213  	 	 if ($this->_errorCode !== false) {
 214  	 	 	 // bug in 4.0.6, error number can be corrupted string (should be 6 digits)
 215  	 	 	 return (strlen($this->_errorCode) <= 2) ? 0 : $this->_errorCode;
 216  	 	 }
 217  
 218  	 	 if (empty($this->_connectionID)) {
 219  	 	 	 $e = @ads_error();
 220  	 	 } else {
 221  	 	 	 $e = @ads_error($this->_connectionID);
 222  	 	 }
 223  
 224  	 	 // bug in 4.0.6, error number can be corrupted string (should be 6 digits)
 225  	 	 // so we check and patch
 226  	 	 if (strlen($e) <= 2) {
 227  	 	 	 return 0;
 228  	 	 }
 229  	 	 return $e;
 230  	 }
 231  
 232  
 233  	function BeginTrans()
 234  	 {
 235  	 	 if (!$this->hasTransactions) {
 236  	 	 	 return false;
 237  	 	 }
 238  	 	 if ($this->transOff) {
 239  	 	 	 return true;
 240  	 	 }
 241  	 	 $this->transCnt += 1;
 242  	 	 $this->_autocommit = false;
 243  	 	 return ads_autocommit($this->_connectionID, false);
 244  	 }
 245  
 246  	function CommitTrans($ok = true)
 247  	 {
 248  	 	 if ($this->transOff) {
 249  	 	 	 return true;
 250  	 	 }
 251  	 	 if (!$ok) {
 252  	 	 	 return $this->RollbackTrans();
 253  	 	 }
 254  	 	 if ($this->transCnt) {
 255  	 	 	 $this->transCnt -= 1;
 256  	 	 }
 257  	 	 $this->_autocommit = true;
 258  	 	 $ret = ads_commit($this->_connectionID);
 259  	 	 ads_autocommit($this->_connectionID, true);
 260  	 	 return $ret;
 261  	 }
 262  
 263  	function RollbackTrans()
 264  	 {
 265  	 	 if ($this->transOff) {
 266  	 	 	 return true;
 267  	 	 }
 268  	 	 if ($this->transCnt) {
 269  	 	 	 $this->transCnt -= 1;
 270  	 	 }
 271  	 	 $this->_autocommit = true;
 272  	 	 $ret = ads_rollback($this->_connectionID);
 273  	 	 ads_autocommit($this->_connectionID, true);
 274  	 	 return $ret;
 275  	 }
 276  
 277  
 278  	 // Returns tables,Views or both on successful execution. Returns
 279  	 // tables by default on successful execution.
 280  	 function &MetaTables($ttype = false, $showSchema = false, $mask = false)
 281  	 {
 282  	 	 $recordSet1 = $this->Execute("select * from system.tables");
 283  	 	 if (!$recordSet1) {
 284  	 	 	 print $this->ErrorMsg();
 285  	 	 	 return false;
 286  	 	 }
 287  	 	 $recordSet2 = $this->Execute("select * from system.views");
 288  	 	 if (!$recordSet2) {
 289  	 	 	 print $this->ErrorMsg();
 290  	 	 	 return false;
 291  	 	 }
 292  	 	 $i = 0;
 293  	 	 while (!$recordSet1->EOF) {
 294  	 	 	 $arr["$i"] = $recordSet1->fields[0];
 295  	 	 	 $recordSet1->MoveNext();
 296  	 	 	 $i = $i + 1;
 297  	 	 }
 298  	 	 if ($ttype == 'FALSE') {
 299  	 	 	 while (!$recordSet2->EOF) {
 300  	 	 	 	 $arr["$i"] = $recordSet2->fields[0];
 301  	 	 	 	 $recordSet2->MoveNext();
 302  	 	 	 	 $i = $i + 1;
 303  	 	 	 }
 304  	 	 	 return $arr;
 305  	 	 } elseif ($ttype == 'VIEWS') {
 306  	 	 	 while (!$recordSet2->EOF) {
 307  	 	 	 	 $arrV["$i"] = $recordSet2->fields[0];
 308  	 	 	 	 $recordSet2->MoveNext();
 309  	 	 	 	 $i = $i + 1;
 310  	 	 	 }
 311  	 	 	 return $arrV;
 312  	 	 } else {
 313  	 	 	 return $arr;
 314  	 	 }
 315  
 316  	 }
 317  
 318  	 function &MetaPrimaryKeys($table, $owner = false)
 319  	 {
 320  	 	 $recordSet = $this->Execute("select table_primary_key from system.tables where name='$table'");
 321  	 	 if (!$recordSet) {
 322  	 	 	 print $this->ErrorMsg();
 323  	 	 	 return false;
 324  	 	 }
 325  	 	 $i = 0;
 326  	 	 while (!$recordSet->EOF) {
 327  	 	 	 $arr["$i"] = $recordSet->fields[0];
 328  	 	 	 $recordSet->MoveNext();
 329  	 	 	 $i = $i + 1;
 330  	 	 }
 331  	 	 return $arr;
 332  	 }
 333  
 334  	 /*
 335  	 See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcdatetime_data_type_changes.asp
 336  	 / SQL data type codes /
 337  	 #define SQL_UNKNOWN_TYPE  0
 338  	 #define SQL_CHAR      1
 339  	 #define SQL_NUMERIC    2
 340  	 #define SQL_DECIMAL    3
 341  	 #define SQL_INTEGER    4
 342  	 #define SQL_SMALLINT    5
 343  	 #define SQL_FLOAT      6
 344  	 #define SQL_REAL      7
 345  	 #define SQL_DOUBLE      8
 346  	 #if (ODBCVER >= 0x0300)
 347  	 #define SQL_DATETIME    9
 348  	 #endif
 349  	 #define SQL_VARCHAR   12
 350  
 351  
 352  	 / One-parameter shortcuts for date/time data types /
 353  	 #if (ODBCVER >= 0x0300)
 354  	 #define SQL_TYPE_DATE   91
 355  	 #define SQL_TYPE_TIME   92
 356  	 #define SQL_TYPE_TIMESTAMP 93
 357  
 358  	 #define SQL_UNICODE                             (-95)
 359  	 #define SQL_UNICODE_VARCHAR                     (-96)
 360  	 #define SQL_UNICODE_LONGVARCHAR                 (-97)
 361  	 */
 362  	function ODBCTypes($t)
 363  	 {
 364  	 	 switch ((integer)$t) {
 365  	 	 	 case 1:
 366  	 	 	 case 12:
 367  	 	 	 case 0:
 368  	 	 	 case -95:
 369  	 	 	 case -96:
 370  	 	 	 	 return 'C';
 371  	 	 	 case -97:
 372  	 	 	 case -1: //text
 373  	 	 	 	 return 'X';
 374  	 	 	 case -4: //image
 375  	 	 	 	 return 'B';
 376  
 377  	 	 	 case 9:
 378  	 	 	 case 91:
 379  	 	 	 	 return 'D';
 380  
 381  	 	 	 case 10:
 382  	 	 	 case 11:
 383  	 	 	 case 92:
 384  	 	 	 case 93:
 385  	 	 	 	 return 'T';
 386  
 387  	 	 	 case 4:
 388  	 	 	 case 5:
 389  	 	 	 case -6:
 390  	 	 	 	 return 'I';
 391  
 392  	 	 	 case -11: // uniqidentifier
 393  	 	 	 	 return 'R';
 394  	 	 	 case -7: //bit
 395  	 	 	 	 return 'L';
 396  
 397  	 	 	 default:
 398  	 	 	 	 return 'N';
 399  	 	 }
 400  	 }
 401  
 402  	 function &MetaColumns($table, $normalize = true)
 403  	 {
 404  	 	 global $ADODB_FETCH_MODE;
 405  
 406  	 	 $false = false;
 407  	 	 if ($this->uCaseTables) {
 408  	 	 	 $table = strtoupper($table);
 409  	 	 }
 410  	 	 $schema = '';
 411  	 	 $this->_findschema($table, $schema);
 412  
 413  	 	 $savem = $ADODB_FETCH_MODE;
 414  	 	 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
 415  
 416  	 	 /*if (false) { // after testing, confirmed that the following does not work because of a bug
 417  	 	   $qid2 = ads_tables($this->_connectionID);
 418  	 	   $rs = new ADORecordSet_ads($qid2);
 419  	 	   $ADODB_FETCH_MODE = $savem;
 420  	 	   if (!$rs) return false;
 421  	 	   $rs->_fetch();
 422  
 423  	 	   while (!$rs->EOF) {
 424  	 	 	 if ($table == strtoupper($rs->fields[2])) {
 425  	 	 	   $q = $rs->fields[0];
 426  	 	 	   $o = $rs->fields[1];
 427  	 	 	   break;
 428  	 	 	 }
 429  	 	 	 $rs->MoveNext();
 430  	 	   }
 431  	 	   $rs->Close();
 432  
 433  	 	   $qid = ads_columns($this->_connectionID,$q,$o,strtoupper($table),'%');
 434  	 	 } */
 435  
 436  	 	 switch ($this->databaseType) {
 437  	 	 	 case 'access':
 438  	 	 	 case 'vfp':
 439  	 	 	 	 $qid = ads_columns($this->_connectionID);#,'%','',strtoupper($table),'%');
 440  	 	 	 	 break;
 441  
 442  
 443  	 	 	 case 'db2':
 444  	 	 	 	 $colname = "%";
 445  	 	 	 	 $qid = ads_columns($this->_connectionID, "", $schema, $table, $colname);
 446  	 	 	 	 break;
 447  
 448  	 	 	 default:
 449  	 	 	 	 $qid = @ads_columns($this->_connectionID, '%', '%', strtoupper($table), '%');
 450  	 	 	 	 if (empty($qid)) {
 451  	 	 	 	 	 $qid = ads_columns($this->_connectionID);
 452  	 	 	 	 }
 453  	 	 	 	 break;
 454  	 	 }
 455  	 	 if (empty($qid)) {
 456  	 	 	 return $false;
 457  	 	 }
 458  
 459  	 	 $rs = new ADORecordSet_ads($qid);
 460  	 	 $ADODB_FETCH_MODE = $savem;
 461  
 462  	 	 if (!$rs) {
 463  	 	 	 return $false;
 464  	 	 }
 465  	 	 $rs->_fetch();
 466  
 467  	 	 $retarr = array();
 468  
 469  	 	 /*
 470  	 	 $rs->fields indices
 471  	 	 0 TABLE_QUALIFIER
 472  	 	 1 TABLE_SCHEM
 473  	 	 2 TABLE_NAME
 474  	 	 3 COLUMN_NAME
 475  	 	 4 DATA_TYPE
 476  	 	 5 TYPE_NAME
 477  	 	 6 PRECISION
 478  	 	 7 LENGTH
 479  	 	 8 SCALE
 480  	 	 9 RADIX
 481  	 	 10 NULLABLE
 482  	 	 11 REMARKS
 483  	 	 */
 484  	 	 while (!$rs->EOF) {
 485  	 	 	 //  adodb_pr($rs->fields);
 486  	 	 	 if (strtoupper(trim($rs->fields[2])) == $table && (!$schema || strtoupper($rs->fields[1]) == $schema)) {
 487  	 	 	 	 $fld = new ADOFieldObject();
 488  	 	 	 	 $fld->name = $rs->fields[3];
 489  	 	 	 	 $fld->type = $this->ODBCTypes($rs->fields[4]);
 490  
 491  	 	 	 	 // ref: http://msdn.microsoft.com/library/default.asp?url=/archive/en-us/dnaraccgen/html/msdn_odk.asp
 492  	 	 	 	 // access uses precision to store length for char/varchar
 493  	 	 	 	 if ($fld->type == 'C' or $fld->type == 'X') {
 494  	 	 	 	 	 if ($this->databaseType == 'access') {
 495  	 	 	 	 	 	 $fld->max_length = $rs->fields[6];
 496  	 	 	 	 	 } else {
 497  	 	 	 	 	 	 if ($rs->fields[4] <= -95) // UNICODE
 498  	 	 	 	 	 	 {
 499  	 	 	 	 	 	 	 $fld->max_length = $rs->fields[7] / 2;
 500  	 	 	 	 	 	 } else {
 501  	 	 	 	 	 	 	 $fld->max_length = $rs->fields[7];
 502  	 	 	 	 	 	 }
 503  	 	 	 	 	 }
 504  	 	 	 	 } else {
 505  	 	 	 	 	 $fld->max_length = $rs->fields[7];
 506  	 	 	 	 }
 507  	 	 	 	 $fld->not_null = !empty($rs->fields[10]);
 508  	 	 	 	 $fld->scale = $rs->fields[8];
 509  	 	 	 	 $retarr[strtoupper($fld->name)] = $fld;
 510  	 	 	 } else {
 511  	 	 	 	 if (sizeof($retarr) > 0) {
 512  	 	 	 	 	 break;
 513  	 	 	 	 }
 514  	 	 	 }
 515  	 	 	 $rs->MoveNext();
 516  	 	 }
 517  	 	 $rs->Close(); //-- crashes 4.03pl1 -- why?
 518  
 519  	 	 if (empty($retarr)) {
 520  	 	 	 $retarr = false;
 521  	 	 }
 522  	 	 return $retarr;
 523  	 }
 524  
 525  	 // Returns an array of columns names for a given table
 526  	 function &MetaColumnNames($table, $numIndexes = false, $useattnum = false)
 527  	 {
 528  	 	 $recordSet = $this->Execute("select name from system.columns where parent='$table'");
 529  	 	 if (!$recordSet) {
 530  	 	 	 print $this->ErrorMsg();
 531  	 	 	 return false;
 532  	 	 } else {
 533  	 	 	 $i = 0;
 534  	 	 	 while (!$recordSet->EOF) {
 535  	 	 	 	 $arr["FIELD$i"] = $recordSet->fields[0];
 536  	 	 	 	 $recordSet->MoveNext();
 537  	 	 	 	 $i = $i + 1;
 538  	 	 	 }
 539  	 	 	 return $arr;
 540  	 	 }
 541  	 }
 542  
 543  
 544  	function Prepare($sql)
 545  	 {
 546  	 	 if (!$this->_bindInputArray) {
 547  	 	 	 return $sql;
 548  	 	 } // no binding
 549  	 	 $stmt = ads_prepare($this->_connectionID, $sql);
 550  	 	 if (!$stmt) {
 551  	 	 	 // we don't know whether odbc driver is parsing prepared stmts, so just return sql
 552  	 	 	 return $sql;
 553  	 	 }
 554  	 	 return array($sql, $stmt, false);
 555  	 }
 556  
 557  	 /* returns queryID or false */
 558  	function _query($sql, $inputarr = false)
 559  	 {
 560  	 	 $last_php_error = $this->resetLastError();
 561  	 	 $this->_errorMsg = '';
 562  
 563  	 	 if ($inputarr) {
 564  	 	 	 if (is_array($sql)) {
 565  	 	 	 	 $stmtid = $sql[1];
 566  	 	 	 } else {
 567  	 	 	 	 $stmtid = ads_prepare($this->_connectionID, $sql);
 568  
 569  	 	 	 	 if ($stmtid == false) {
 570  	 	 	 	 	 $this->_errorMsg = $this->getChangedErrorMsg($last_php_error);
 571  	 	 	 	 	 return false;
 572  	 	 	 	 }
 573  	 	 	 }
 574  
 575  	 	 	 if (!ads_execute($stmtid, $inputarr)) {
 576  	 	 	 	 //@ads_free_result($stmtid);
 577  	 	 	 	 $this->_errorMsg = ads_errormsg();
 578  	 	 	 	 $this->_errorCode = ads_error();
 579  	 	 	 	 return false;
 580  	 	 	 }
 581  
 582  	 	 } else {
 583  	 	 	 if (is_array($sql)) {
 584  	 	 	 	 $stmtid = $sql[1];
 585  	 	 	 	 if (!ads_execute($stmtid)) {
 586  	 	 	 	 	 //@ads_free_result($stmtid);
 587  	 	 	 	 	 $this->_errorMsg = ads_errormsg();
 588  	 	 	 	 	 $this->_errorCode = ads_error();
 589  	 	 	 	 	 return false;
 590  	 	 	 	 }
 591  	 	 	 } else {
 592  
 593  	 	 	 	 $stmtid = ads_exec($this->_connectionID, $sql);
 594  
 595  	 	 	 }
 596  	 	 }
 597  
 598  	 	 $this->_lastAffectedRows = 0;
 599  
 600  	 	 if ($stmtid) {
 601  
 602  	 	 	 if (@ads_num_fields($stmtid) == 0) {
 603  	 	 	 	 $this->_lastAffectedRows = ads_num_rows($stmtid);
 604  	 	 	 	 $stmtid = true;
 605  
 606  	 	 	 } else {
 607  
 608  	 	 	 	 $this->_lastAffectedRows = 0;
 609  	 	 	 	 ads_binmode($stmtid, $this->binmode);
 610  	 	 	 	 ads_longreadlen($stmtid, $this->maxblobsize);
 611  
 612  	 	 	 }
 613  
 614  	 	 	 $this->_errorMsg = '';
 615  	 	 	 $this->_errorCode = 0;
 616  	 	 } else {
 617  	 	 	 $this->_errorMsg = ads_errormsg();
 618  	 	 	 $this->_errorCode = ads_error();
 619  	 	 }
 620  
 621  	 	 return $stmtid;
 622  
 623  	 }
 624  
 625  	 /*
 626  	   Insert a null into the blob field of the table first.
 627  	   Then use UpdateBlob to store the blob.
 628  
 629  	   Usage:
 630  
 631  	   $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
 632  	   $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
 633  	  */
 634  	function UpdateBlob($table, $column, $val, $where, $blobtype = 'BLOB')
 635  	 {
 636  	 	 $last_php_error = $this->resetLastError();
 637  	 	 $sql = "UPDATE $table SET $column=? WHERE $where";
 638  	 	 $stmtid = ads_prepare($this->_connectionID, $sql);
 639  	 	 if ($stmtid == false) {
 640  	 	 	 $this->_errorMsg = $this->getChangedErrorMsg($last_php_error);
 641  	 	 	 return false;
 642  	 	 }
 643  	 	 if (!ads_execute($stmtid, array($val), array(SQL_BINARY))) {
 644  	 	 	 $this->_errorMsg = ads_errormsg();
 645  	 	 	 $this->_errorCode = ads_error();
 646  	 	 	 return false;
 647  	 	 }
 648  	 	 return true;
 649  	 }
 650  
 651  	 // returns true or false
 652  	function _close()
 653  	 {
 654  	 	 $ret = @ads_close($this->_connectionID);
 655  	 	 $this->_connectionID = false;
 656  	 	 return $ret;
 657  	 }
 658  
 659  	function _affectedrows()
 660  	 {
 661  	 	 return $this->_lastAffectedRows;
 662  	 }
 663  
 664  }
 665  
 666  /*--------------------------------------------------------------------------------------
 667     Class Name: Recordset
 668  --------------------------------------------------------------------------------------*/
 669  
 670  class ADORecordSet_ads extends ADORecordSet
 671  {
 672  
 673  	 var $bind = false;
 674  	 var $databaseType = "ads";
 675  	 var $dataProvider = "ads";
 676  	 var $useFetchArray;
 677  
 678  	function __construct($id, $mode = false)
 679  	 {
 680  	 	 if ($mode === false) {
 681  	 	 	 global $ADODB_FETCH_MODE;
 682  	 	 	 $mode = $ADODB_FETCH_MODE;
 683  	 	 }
 684  	 	 $this->fetchMode = $mode;
 685  
 686  	 	 $this->_queryID = $id;
 687  
 688  	 	 // the following is required for mysql odbc driver in 4.3.1 -- why?
 689  	 	 $this->EOF = false;
 690  	 	 $this->_currentRow = -1;
 691  	 	 //parent::__construct($id);
 692  	 }
 693  
 694  
 695  	 // returns the field object
 696  	 function &FetchField($fieldOffset = -1)
 697  	 {
 698  
 699  	 	 $off = $fieldOffset + 1; // offsets begin at 1
 700  
 701  	 	 $o = new ADOFieldObject();
 702  	 	 $o->name = @ads_field_name($this->_queryID, $off);
 703  	 	 $o->type = @ads_field_type($this->_queryID, $off);
 704  	 	 $o->max_length = @ads_field_len($this->_queryID, $off);
 705  	 	 if (ADODB_ASSOC_CASE == 0) {
 706  	 	 	 $o->name = strtolower($o->name);
 707  	 	 } else {
 708  	 	 	 if (ADODB_ASSOC_CASE == 1) {
 709  	 	 	 	 $o->name = strtoupper($o->name);
 710  	 	 	 }
 711  	 	 }
 712  	 	 return $o;
 713  	 }
 714  
 715  	 /* Use associative array to get fields array */
 716  	function Fields($colname)
 717  	 {
 718  	 	 if ($this->fetchMode & ADODB_FETCH_ASSOC) {
 719  	 	 	 return $this->fields[$colname];
 720  	 	 }
 721  	 	 if (!$this->bind) {
 722  	 	 	 $this->bind = array();
 723  	 	 	 for ($i = 0; $i < $this->_numOfFields; $i++) {
 724  	 	 	 	 $o = $this->FetchField($i);
 725  	 	 	 	 $this->bind[strtoupper($o->name)] = $i;
 726  	 	 	 }
 727  	 	 }
 728  
 729  	 	 return $this->fields[$this->bind[strtoupper($colname)]];
 730  	 }
 731  
 732  
 733  	function _initrs()
 734  	 {
 735  	 	 global $ADODB_COUNTRECS;
 736  	 	 $this->_numOfRows = ($ADODB_COUNTRECS) ? @ads_num_rows($this->_queryID) : -1;
 737  	 	 $this->_numOfFields = @ads_num_fields($this->_queryID);
 738  	 	 // some silly drivers such as db2 as/400 and intersystems cache return _numOfRows = 0
 739  	 	 if ($this->_numOfRows == 0) {
 740  	 	 	 $this->_numOfRows = -1;
 741  	 	 }
 742  	 	 //$this->useFetchArray = $this->connection->useFetchArray;
 743  	 }
 744  
 745  	function _seek($row)
 746  	 {
 747  	 	 return false;
 748  	 }
 749  
 750  	 // speed up SelectLimit() by switching to ADODB_FETCH_NUM as ADODB_FETCH_ASSOC is emulated
 751  	 function &GetArrayLimit($nrows, $offset = -1)
 752  	 {
 753  	 	 if ($offset <= 0) {
 754  	 	 	 $rs =& $this->GetArray($nrows);
 755  	 	 	 return $rs;
 756  	 	 }
 757  	 	 $savem = $this->fetchMode;
 758  	 	 $this->fetchMode = ADODB_FETCH_NUM;
 759  	 	 $this->Move($offset);
 760  	 	 $this->fetchMode = $savem;
 761  
 762  	 	 if ($this->fetchMode & ADODB_FETCH_ASSOC) {
 763  	 	 	 $this->fields =& $this->GetRowAssoc();
 764  	 	 }
 765  
 766  	 	 $results = array();
 767  	 	 $cnt = 0;
 768  	 	 while (!$this->EOF && $nrows != $cnt) {
 769  	 	 	 $results[$cnt++] = $this->fields;
 770  	 	 	 $this->MoveNext();
 771  	 	 }
 772  
 773  	 	 return $results;
 774  	 }
 775  
 776  
 777  	function MoveNext()
 778  	 {
 779  	 	 if ($this->_numOfRows != 0 && !$this->EOF) {
 780  	 	 	 $this->_currentRow++;
 781  	 	 	 if ($this->_fetch()) {
 782  	 	 	 	 return true;
 783  	 	 	 }
 784  	 	 }
 785  	 	 $this->fields = false;
 786  	 	 $this->EOF = true;
 787  	 	 return false;
 788  	 }
 789  
 790  	function _fetch()
 791  	 {
 792  	 	 $this->fields = false;
 793  	 	 $rez = @ads_fetch_into($this->_queryID, $this->fields);
 794  	 	 if ($rez) {
 795  	 	 	 if ($this->fetchMode & ADODB_FETCH_ASSOC) {
 796  	 	 	 	 $this->fields =& $this->GetRowAssoc();
 797  	 	 	 }
 798  	 	 	 return true;
 799  	 	 }
 800  	 	 return false;
 801  	 }
 802  
 803  	function _close()
 804  	 {
 805  	 	 return @ads_free_result($this->_queryID);
 806  	 }
 807  
 808  }