Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

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

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