adodb.inc.php 133 KB
Newer Older
1
<?php
Penny Leach's avatar
Penny Leach committed
2
3
/*
 * Set tabs to 4 for best viewing.
4
 *
5
 * Latest version is available at http://adodb.org/
6
 *
Penny Leach's avatar
Penny Leach committed
7
8
9
10
11
12
13
14
 * This is the main include file for ADOdb.
 * Database specific drivers are stored in the adodb/drivers/adodb-*.inc.php
 *
 * The ADOdb files are formatted so that doxygen can be used to generate documentation.
 * Doxygen is a documentation generation tool and can be downloaded from http://doxygen.org/
 */

/**
15
	\mainpage
16

17
	@version   v5.20.14  06-Jan-2019
18
19
	@copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
	@copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
Penny Leach's avatar
Penny Leach committed
20
21
22

	Released under both BSD license and Lesser GPL library license. You can choose which license
	you prefer.
23
24
25

	PHP's database access functions are not standardised. This creates a need for a database
	class library to hide the differences between the different database API's (encapsulate
Penny Leach's avatar
Penny Leach committed
26
27
28
29
30
31
32
	the differences) so we can easily switch databases.

	We currently support MySQL, Oracle, Microsoft SQL Server, Sybase, Sybase SQL Anywhere, DB2,
	Informix, PostgreSQL, FrontBase, Interbase (Firebird and Borland variants), Foxpro, Access,
	ADO, SAP DB, SQLite and ODBC. We have had successful reports of connecting to Progress and
	other databases via ODBC.
 */
33
34
35
36

if (!defined('_ADODB_LAYER')) {
	define('_ADODB_LAYER',1);

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
	// The ADOdb extension is no longer maintained and effectively unsupported
	// since v5.04. The library will not function properly if it is present.
	if(defined('ADODB_EXTENSION')) {
		$msg = "Unsupported ADOdb Extension (v" . ADODB_EXTENSION . ") detected! "
			. "Disable it to use ADOdb";

		$errorfn = defined('ADODB_ERROR_HANDLER') ? ADODB_ERROR_HANDLER : false;
		if ($errorfn) {
			$conn = false;
			$errorfn('ADOdb', basename(__FILE__), -9999, $msg, null, null, $conn);
		} else {
			die($msg . PHP_EOL);
		}
	}

52
	//==============================================================================================
Penny Leach's avatar
Penny Leach committed
53
	// CONSTANT DEFINITIONS
54
	//==============================================================================================
Penny Leach's avatar
Penny Leach committed
55
56


57
	/**
Penny Leach's avatar
Penny Leach committed
58
59
60
	 * Set ADODB_DIR to the directory where this file resides...
	 * This constant was formerly called $ADODB_RootPath
	 */
61
62
63
	if (!defined('ADODB_DIR')) {
		define('ADODB_DIR',dirname(__FILE__));
	}
64
65

	//==============================================================================================
Penny Leach's avatar
Penny Leach committed
66
	// GLOBAL VARIABLES
67
	//==============================================================================================
Penny Leach's avatar
Penny Leach committed
68

69
	GLOBAL
70
		$ADODB_vers,		// database version
Penny Leach's avatar
Penny Leach committed
71
72
		$ADODB_COUNTRECS,	// count number of records returned - slows down query
		$ADODB_CACHE_DIR,	// directory to cache recordsets
73
74
		$ADODB_CACHE,
		$ADODB_CACHE_CLASS,
Penny Leach's avatar
Penny Leach committed
75
76
		$ADODB_EXTENSION,   // ADODB extension installed
		$ADODB_COMPAT_FETCH, // If $ADODB_COUNTRECS and this is true, $rs->fields is available on EOF
77
		$ADODB_FETCH_MODE,	// DEFAULT, NUM, ASSOC or BOTH. Default follows native driver default...
78
		$ADODB_GETONE_EOF,
79
80
81
		$ADODB_QUOTE_FIELDNAMES; // Allows you to force quotes (backticks) around field names in queries generated by getinsertsql and getupdatesql.

	//==============================================================================================
Penny Leach's avatar
Penny Leach committed
82
	// GLOBAL SETUP
83
84
	//==============================================================================================

Penny Leach's avatar
Penny Leach committed
85
86
	$ADODB_EXTENSION = defined('ADODB_EXTENSION');

87
88
89
90
91
92
93
94
95
96
97
98
99
100
	// ********************************************************
	// Controls $ADODB_FORCE_TYPE mode. Default is ADODB_FORCE_VALUE (3).
	// Used in GetUpdateSql and GetInsertSql functions. Thx to Niko, nuko#mbnet.fi
	//
	// 0 = ignore empty fields. All empty fields in array are ignored.
	// 1 = force null. All empty, php null and string 'null' fields are changed to sql NULL values.
	// 2 = force empty. All empty, php null and string 'null' fields are changed to sql empty '' or 0 values.
	// 3 = force value. Value is left as it is. Php null and string 'null' are set to sql NULL values and empty fields '' are set to empty '' sql values.

		define('ADODB_FORCE_IGNORE',0);
		define('ADODB_FORCE_NULL',1);
		define('ADODB_FORCE_EMPTY',2);
		define('ADODB_FORCE_VALUE',3);
	// ********************************************************
Penny Leach's avatar
Penny Leach committed
101

102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
	/**
	 * Associative array case constants
	 *
	 * By defining the ADODB_ASSOC_CASE constant to one of these values, it is
	 * possible to control the case of field names (associative array's keys)
	 * when operating in ADODB_FETCH_ASSOC fetch mode.
	 *   - LOWER:  $rs->fields['orderid']
	 *   - UPPER:  $rs->fields['ORDERID']
	 *   - NATIVE: $rs->fields['OrderID'] (or whatever the RDBMS will return)
	 *
	 * The default is to use native case-names.
	 *
	 * NOTE: This functionality is not implemented everywhere, it currently
	 * works only with: mssql, odbc, oci8 and ibase derived drivers
	 */
		define('ADODB_ASSOC_CASE_LOWER', 0);
		define('ADODB_ASSOC_CASE_UPPER', 1);
		define('ADODB_ASSOC_CASE_NATIVE', 2);
Penny Leach's avatar
Penny Leach committed
120
121

	if (!$ADODB_EXTENSION || ADODB_EXTENSION < 4.0) {
122

Penny Leach's avatar
Penny Leach committed
123
		define('ADODB_BAD_RS','<p>Bad $rs in %s. Connection or SQL invalid. Try using $connection->debug=true;</p>');
124

Penny Leach's avatar
Penny Leach committed
125
126
	// allow [ ] @ ` " and . in table names
		define('ADODB_TABLE_REGEX','([]0-9a-z_\:\"\`\.\@\[-]*)');
127

Penny Leach's avatar
Penny Leach committed
128
	// prefetching used by oracle
129
130
131
		if (!defined('ADODB_PREFETCH_ROWS')) {
			define('ADODB_PREFETCH_ROWS',10);
		}
132
133


134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
	/**
	 * Fetch mode
	 *
	 * Set global variable $ADODB_FETCH_MODE to one of these constants or use
	 * the SetFetchMode() method to control how recordset fields are returned
	 * when fetching data.
	 *
	 *   - NUM:     array()
	 *   - ASSOC:   array('id' => 456, 'name' => 'john')
	 *   - BOTH:    array(0 => 456, 'id' => 456, 1 => 'john', 'name' => 'john')
	 *   - DEFAULT: driver-dependent
	 */
		define('ADODB_FETCH_DEFAULT', 0);
		define('ADODB_FETCH_NUM', 1);
		define('ADODB_FETCH_ASSOC', 2);
		define('ADODB_FETCH_BOTH', 3);
150
151


152
153
154
155
156
157
158
159
160
161
162
		if (!defined('TIMESTAMP_FIRST_YEAR')) {
			define('TIMESTAMP_FIRST_YEAR',100);
		}

		/**
		 * AutoExecute constants
		 * (moved from adodb-pear.inc.php since they are only used in here)
		 */
		define('DB_AUTOQUERY_INSERT', 1);
		define('DB_AUTOQUERY_UPDATE', 2);

163

Penny Leach's avatar
Penny Leach committed
164
165
		// PHP's version scheme makes converting to numbers difficult - workaround
		$_adodb_ver = (float) PHP_VERSION;
166
167
168
		if ($_adodb_ver >= 5.2) {
			define('ADODB_PHPVER',0x5200);
		} else if ($_adodb_ver >= 5.0) {
Penny Leach's avatar
Penny Leach committed
169
			define('ADODB_PHPVER',0x5000);
170
		} else {
171
			die("PHP5 or later required. You are running ".PHP_VERSION);
172
173
		}
		unset($_adodb_ver);
Penny Leach's avatar
Penny Leach committed
174
	}
175
176


Penny Leach's avatar
Penny Leach committed
177
	/**
178
		Accepts $src and $dest arrays, replacing string $data
Penny Leach's avatar
Penny Leach committed
179
	*/
180
181
182
183
	function ADODB_str_replace($src, $dest, $data) {
		if (ADODB_PHPVER >= 0x4050) {
			return str_replace($src,$dest,$data);
		}
184

Penny Leach's avatar
Penny Leach committed
185
186
187
188
189
190
191
192
193
		$s = reset($src);
		$d = reset($dest);
		while ($s !== false) {
			$data = str_replace($s,$d,$data);
			$s = next($src);
			$d = next($dest);
		}
		return $data;
	}
194

195
	function ADODB_Setup() {
196
	GLOBAL
197
		$ADODB_vers,		// database version
Penny Leach's avatar
Penny Leach committed
198
199
		$ADODB_COUNTRECS,	// count number of records returned - slows down query
		$ADODB_CACHE_DIR,	// directory to cache recordsets
200
		$ADODB_FETCH_MODE,
201
202
203
204
205
		$ADODB_CACHE,
		$ADODB_CACHE_CLASS,
		$ADODB_FORCE_TYPE,
		$ADODB_GETONE_EOF,
		$ADODB_QUOTE_FIELDNAMES;
206

207
208
209
		if (empty($ADODB_CACHE_CLASS)) {
			$ADODB_CACHE_CLASS =  'ADODB_Cache_File' ;
		}
Penny Leach's avatar
Penny Leach committed
210
211
		$ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT;
		$ADODB_FORCE_TYPE = ADODB_FORCE_VALUE;
212
		$ADODB_GETONE_EOF = null;
Penny Leach's avatar
Penny Leach committed
213
214
215
216
217

		if (!isset($ADODB_CACHE_DIR)) {
			$ADODB_CACHE_DIR = '/tmp'; //(isset($_ENV['TMP'])) ? $_ENV['TMP'] : '/tmp';
		} else {
			// do not accept url based paths, eg. http:/ or ftp:/
218
			if (strpos($ADODB_CACHE_DIR,'://') !== false) {
Penny Leach's avatar
Penny Leach committed
219
				die("Illegal path http:// or ftp://");
220
			}
Penny Leach's avatar
Penny Leach committed
221
		}
222
223


Penny Leach's avatar
Penny Leach committed
224
		// Initialize random number generator for randomizing cache flushes
225
		// -- note Since PHP 4.2.0, the seed  becomes optional and defaults to a random value if omitted.
226
		srand(((double)microtime())*1000000);
227

Penny Leach's avatar
Penny Leach committed
228
229
230
		/**
		 * ADODB version as a string.
		 */
231
		$ADODB_vers = 'v5.20.14  06-Jan-2019';
232

Penny Leach's avatar
Penny Leach committed
233
		/**
234
		 * Determines whether recordset->RecordCount() is used.
Penny Leach's avatar
Penny Leach committed
235
236
237
		 * Set to false for highest performance -- RecordCount() will always return -1 then
		 * for databases that provide "virtual" recordcounts...
		 */
238
239
240
		if (!isset($ADODB_COUNTRECS)) {
			$ADODB_COUNTRECS = true;
		}
Penny Leach's avatar
Penny Leach committed
241
	}
242
243
244


	//==============================================================================================
Penny Leach's avatar
Penny Leach committed
245
	// CHANGE NOTHING BELOW UNLESS YOU ARE DESIGNING ADODB
246
247
	//==============================================================================================

Penny Leach's avatar
Penny Leach committed
248
249
	ADODB_Setup();

250
	//==============================================================================================
Penny Leach's avatar
Penny Leach committed
251
	// CLASS ADOFieldObject
252
	//==============================================================================================
Penny Leach's avatar
Penny Leach committed
253
254
255
	/**
	 * Helper class for FetchFields -- holds info on a column
	 */
256
	class ADOFieldObject {
Penny Leach's avatar
Penny Leach committed
257
258
259
260
261
		var $name = '';
		var $max_length=0;
		var $type="";
/*
		// additional fields by dannym... (danny_milo@yahoo.com)
262
		var $not_null = false;
Penny Leach's avatar
Penny Leach committed
263
264
265
		// actually, this has already been built-in in the postgres, fbsql AND mysql module? ^-^
		// so we can as well make not_null standard (leaving it at "false" does not harm anyways)

266
		var $has_default = false; // this one I have done only in mysql and postgres for now ...
Penny Leach's avatar
Penny Leach committed
267
268
269
270
			// others to come (dannym)
		var $default_value; // default, if any, and supported. Check has_default first.
*/
	}
271
272


273
	function _adodb_safedate($s) {
274
275
276
277
278
		return str_replace(array("'", '\\'), '', $s);
	}

	// parse date string to prevent injection attack
	// date string will have one quote at beginning e.g. '3434343'
279
	function _adodb_safedateq($s) {
280
		$len = strlen($s);
281
282
283
284
285
		if ($s[0] !== "'") {
			$s2 = "'".$s[0];
		} else {
			$s2 = "'";
		}
286
287
288
289
290
291
292
293
294
		for($i=1; $i<$len; $i++) {
			$ch = $s[$i];
			if ($ch === '\\') {
				$s2 .= "'";
				break;
			} elseif ($ch === "'") {
				$s2 .= $ch;
				break;
			}
295

296
297
			$s2 .= $ch;
		}
298

299
300
301
		return strlen($s2) == 0 ? 'null' : $s2;
	}

302

303
	// for transaction handling
304

305
	function ADODB_TransMonitor($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection) {
Penny Leach's avatar
Penny Leach committed
306
307
308
309
310
311
312
		//print "Errorno ($fn errno=$errno m=$errmsg) ";
		$thisConnection->_transOK = false;
		if ($thisConnection->_oldRaiseFn) {
			$fn = $thisConnection->_oldRaiseFn;
			$fn($dbms, $fn, $errno, $errmsg, $p1, $p2,$thisConnection);
		}
	}
313

314
315
316
	//------------------
	// class for caching
	class ADODB_Cache_File {
317

318
		var $createdir = true; // requires creation of temp dirs
319

320
321
322
323
324
		function __construct() {
			global $ADODB_INCLUDED_CSV;
			if (empty($ADODB_INCLUDED_CSV)) {
				include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
			}
325
		}
326

327
		// write serialised recordset to cache item/file
328
		function writecache($filename, $contents,  $debug, $secs2cache) {
329
330
			return adodb_write_file($filename, $contents,$debug);
		}
331

332
		// load serialised recordset and unserialise it
333
		function &readcache($filename, &$err, $secs2cache, $rsClass) {
334
335
336
			$rs = csv2rs($filename,$err,$secs2cache,$rsClass);
			return $rs;
		}
337

338
		// flush all items in cache
339
340
		function flushall($debug=false) {
			global $ADODB_CACHE_DIR;
341

342
			$rez = false;
343

344
345
			if (strlen($ADODB_CACHE_DIR) > 1) {
				$rez = $this->_dirFlush($ADODB_CACHE_DIR);
346
347
348
349
				if ($debug) {
					ADOConnection::outp( "flushall: $ADODB_CACHE_DIR<br><pre>\n". $rez."</pre>");
				}
			}
350
351
			return $rez;
		}
352

353
		// flush one file in cache
354
		function flushcache($f, $debug=false) {
355
			if (!@unlink($f)) {
356
357
358
				if ($debug) {
					ADOConnection::outp( "flushcache: failed for $f");
				}
359
360
			}
		}
361

362
363
364
365
366
		function getdirname($hash) {
			global $ADODB_CACHE_DIR;
			if (!isset($this->notSafeMode)) {
				$this->notSafeMode = !ini_get('safe_mode');
			}
367
368
			return ($this->notSafeMode) ? $ADODB_CACHE_DIR.'/'.substr($hash,0,2) : $ADODB_CACHE_DIR;
		}
369

370
		// create temp directories
371
372
		function createdir($hash, $debug) {
			global $ADODB_CACHE_PERMS;
373

374
375
376
			$dir = $this->getdirname($hash);
			if ($this->notSafeMode && !file_exists($dir)) {
				$oldu = umask(0);
377
378
379
380
381
				if (!@mkdir($dir, empty($ADODB_CACHE_PERMS) ? 0771 : $ADODB_CACHE_PERMS)) {
					if(!is_dir($dir) && $debug) {
						ADOConnection::outp("Cannot create $dir");
					}
				}
382
383
				umask($oldu);
			}
384

385
386
			return $dir;
		}
387

388
389
390
391
392
393
		/**
		* Private function to erase all of the files and subdirectories in a directory.
		*
		* Just specify the directory, and tell it if you want to delete the directory or just clear it out.
		* Note: $kill_top_level is used internally in the function to flush subdirectories.
		*/
394
395
		function _dirFlush($dir, $kill_top_level = false) {
			if(!$dh = @opendir($dir)) return;
396

397
398
			while (($obj = readdir($dh))) {
				if($obj=='.' || $obj=='..') continue;
399
				$f = $dir.'/'.$obj;
400

401
402
403
404
405
406
407
408
409
410
411
				if (strpos($obj,'.cache')) {
					@unlink($f);
				}
				if (is_dir($f)) {
					$this->_dirFlush($f, true);
				}
			}
			if ($kill_top_level === true) {
				@rmdir($dir);
			}
			return true;
412
413
		}
	}
414
415

	//==============================================================================================
Penny Leach's avatar
Penny Leach committed
416
	// CLASS ADOConnection
417
418
	//==============================================================================================

Penny Leach's avatar
Penny Leach committed
419
420
	/**
	 * Connection object. For connecting to databases, and executing queries.
421
422
	 */
	abstract class ADOConnection {
Penny Leach's avatar
Penny Leach committed
423
	//
424
	// PUBLIC VARS
Penny Leach's avatar
Penny Leach committed
425
426
	//
	var $dataProvider = 'native';
427
428
	var $databaseType = '';		/// RDBMS currently in use, eg. odbc, mysql, mssql
	var $database = '';			/// Name of database to be used.
429
430
431
432
433
434
	var $host = '';				/// The hostname of the database server
	var $port = '';				/// The port of the database server
	var $user = '';				/// The username which is used to connect to the database server.
  private $password = '';			/// Password for the username. This is required for __wakeup
	var $debug = false;			/// if set to true will output sql statements
	var $maxblobsize = 262144;	/// maximum size of blobs or large text fields (262144 = 256K)-- some db's die otherwise like foxpro
435
	var $concat_operator = '+'; /// default concat operator -- change to || for Oracle/Interbase
Penny Leach's avatar
Penny Leach committed
436
437
438
439
440
441
	var $substr = 'substr';		/// substring operator
	var $length = 'length';		/// string length ofperator
	var $random = 'rand()';		/// random function
	var $upperCase = 'upper';		/// uppercase function
	var $fmtDate = "'Y-m-d'";	/// used by DBDate() as the default date format used by the database
	var $fmtTimeStamp = "'Y-m-d, h:i:s A'"; /// used by DBTimeStamp as the default timestamp fmt.
442
443
444
	var $true = '1';			/// string that represents TRUE for a database
	var $false = '0';			/// string that represents FALSE for a database
	var $replaceQuote = "\\'";	/// string to use to replace quotes
Penny Leach's avatar
Penny Leach committed
445
	var $nameQuote = '"';		/// string to use to quote identifiers and names
446
	var $charSet=false;			/// character set to use - only for interbase, postgres and oci8
Penny Leach's avatar
Penny Leach committed
447
448
449
450
451
452
453
	var $metaDatabasesSQL = '';
	var $metaTablesSQL = '';
	var $uniqueOrderBy = false; /// All order by columns have to be unique
	var $emptyDate = '&nbsp;';
	var $emptyTimeStamp = '&nbsp;';
	var $lastInsID = false;
	//--
454
455
	var $hasInsertID = false;		/// supports autoincrement ID?
	var $hasAffectedRows = false;	/// supports affected rows for update/delete?
Penny Leach's avatar
Penny Leach committed
456
457
	var $hasTop = false;			/// support mssql/access SELECT TOP 10 * FROM TABLE
	var $hasLimit = false;			/// support pgsql/mysql SELECT * FROM TABLE LIMIT 10
458
459
460
461
	var $readOnly = false;			/// this is a readonly database - used by phpLens
	var $hasMoveFirst = false;		/// has ability to run MoveFirst(), scrolling backwards
	var $hasGenID = false;			/// can generate sequences using GenID();
	var $hasTransactions = true;	/// has transactions
Penny Leach's avatar
Penny Leach committed
462
	//--
463
464
465
466
	var $genID = 0;					/// sequence id used by GenID();
	var $raiseErrorFn = false;		/// error function to call
	var $isoDates = false;			/// accepts dates in ISO format
	var $cacheSecs = 3600;			/// cache for 1 hour
Penny Leach's avatar
Penny Leach committed
467
468
469
470
471
472
473
474
475

	// memcache
	var $memCache = false; /// should we use memCache instead of caching in files
	var $memCacheHost; /// memCache host
	var $memCachePort = 11211; /// memCache port
	var $memCacheCompress = false; /// Use 'true' to store the item compressed (uses zlib)

	var $sysDate = false; /// name of function that returns the current date
	var $sysTimeStamp = false; /// name of function that returns the current timestamp
476
	var $sysUTimeStamp = false; // name of function that returns the current timestamp accurate to the microsecond or nearest fraction
Penny Leach's avatar
Penny Leach committed
477
	var $arrayClass = 'ADORecordSet_array'; /// name of class used to generate array recordsets, which are pre-downloaded recordsets
478

Penny Leach's avatar
Penny Leach committed
479
	var $noNullStrings = false; /// oracle specific stuff - if true ensures that '' is converted to ' '
480
	var $numCacheHits = 0;
Penny Leach's avatar
Penny Leach committed
481
482
483
484
485
486
487
488
	var $numCacheMisses = 0;
	var $pageExecuteCountRows = true;
	var $uniqueSort = false; /// indicates that all fields in order by must be unique
	var $leftOuter = false; /// operator to use for left outer join in WHERE clause
	var $rightOuter = false; /// operator to use for right outer join in WHERE clause
	var $ansiOuter = false; /// whether ansi outer join syntax supported
	var $autoRollback = false; // autoRollback on PConnect().
	var $poorAffectedRows = false; // affectedRows not working or unreliable
489

Penny Leach's avatar
Penny Leach committed
490
491
492
493
	var $fnExecute = false;
	var $fnCacheExecute = false;
	var $blobEncodeType = false; // false=not required, 'I'=encode to integer, 'C'=encode to char
	var $rsPrefix = "ADORecordSet_";
494

495
496
497
	var $autoCommit = true;		/// do not modify this yourself - actually private
	var $transOff = 0;			/// temporarily disable transactions
	var $transCnt = 0;			/// count of nested transactions
498

Penny Leach's avatar
Penny Leach committed
499
	var $fetchMode=false;
500

501
502
	var $null2null = 'null'; // in autoexecute/getinsertsql/getupdatesql, this value will be converted to a null
	var $bulkBind = false; // enable 2D Execute array
503
504
505
	//
	// PRIVATE VARS
	//
Penny Leach's avatar
Penny Leach committed
506
507
	var $_oldRaiseFn =  false;
	var $_transOK = null;
508
	var $_connectionID	= false;	/// The returned link identifier whenever a successful database connection is made.
Penny Leach's avatar
Penny Leach committed
509
	var $_errorMsg = false;		/// A variable which was used to keep the returned last error message.  The value will
510
511
								/// then returned by the errorMsg() function
	var $_errorCode = false;	/// Last error code, not guaranteed to be used - only by oci8
Penny Leach's avatar
Penny Leach committed
512
	var $_queryID = false;		/// This variable keeps the last created result link identifier
513

Penny Leach's avatar
Penny Leach committed
514
515
516
517
518
519
	var $_isPersistentConnection = false;	/// A boolean variable to state whether its a persistent connection or normal connection.	*/
	var $_bindInputArray = false; /// set to true if ADOConnection.Execute() permits binding of array parameters.
	var $_evalAll = false;
	var $_affected = false;
	var $_logsql = false;
	var $_transmode = ''; // transaction mode
520

521
522
523
524
525
	/*
	 * Additional parameters that may be passed to drivers in the connect string
	 * Driver must be coded to accept the parameters
	 */
	protected $connectionParameters = array();
526

527
528
529
530
531
532
533
534
535
536
537
538
539
540
	/**
	* Adds a parameter to the connection string.
	*
	* These parameters are added to the connection string when connecting,
	* if the driver is coded to use it.
	*
	* @param	string	$parameter	The name of the parameter to set
	* @param	string	$value		The value of the parameter
	*
	* @return null
	*
	* @example, for mssqlnative driver ('CharacterSet','UTF-8')
	*/
	final public function setConnectionParameter($parameter,$value)
Penny Leach's avatar
Penny Leach committed
541
	{
542

543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
		$this->connectionParameters[$parameter] = $value;

	}

	static function Version() {
		global $ADODB_vers;

		// Semantic Version number matching regex
		$regex = '^[vV]?(\d+\.\d+\.\d+'         // Version number (X.Y.Z) with optional 'V'
			. '(?:-(?:'                         // Optional preprod version: a '-'
			. 'dev|'                            // followed by 'dev'
			. '(?:(?:alpha|beta|rc)(?:\.\d+))'  // or a preprod suffix and version number
			. '))?)(?:\s|$)';                   // Whitespace or end of string

		if (!preg_match("/$regex/", $ADODB_vers, $matches)) {
			// This should normally not happen... Return whatever is between the start
			// of the string and the first whitespace (or the end of the string).
			self::outp("Invalid version number: '$ADODB_vers'", 'Version');
			$regex = '^[vV]?(.*?)(?:\s|$)';
			preg_match("/$regex/", $ADODB_vers, $matches);
		}
		return $matches[1];
Penny Leach's avatar
Penny Leach committed
565
	}
566

Penny Leach's avatar
Penny Leach committed
567
568
	/**
		Get server version info...
569
570

		@returns An array with 2 elements: $arr['string'] is the description string,
Penny Leach's avatar
Penny Leach committed
571
572
			and $arr[version] is the version (also a string).
	*/
573
	function ServerInfo() {
Penny Leach's avatar
Penny Leach committed
574
575
		return array('description' => '', 'version' => '');
	}
576

577
	function IsConnected() {
578
		return !empty($this->_connectionID);
Penny Leach's avatar
Penny Leach committed
579
	}
580

581
582
583
584
585
586
	function _findvers($str) {
		if (preg_match('/([0-9]+\.([0-9\.])+)/',$str, $arr)) {
			return $arr[1];
		} else {
			return '';
		}
Penny Leach's avatar
Penny Leach committed
587
	}
588

Penny Leach's avatar
Penny Leach committed
589
590
591
592
	/**
	* All error messages go through this bottleneck function.
	* You can define your own handler by defining the function name in ADODB_OUTP.
	*/
593
594
	static function outp($msg,$newline=true) {
		global $ADODB_FLUSH,$ADODB_OUTP;
595

Penny Leach's avatar
Penny Leach committed
596
597
598
599
600
601
602
603
604
		if (defined('ADODB_OUTP')) {
			$fn = ADODB_OUTP;
			$fn($msg,$newline);
			return;
		} else if (isset($ADODB_OUTP)) {
			$fn = $ADODB_OUTP;
			$fn($msg,$newline);
			return;
		}
605

606
607
608
		if ($newline) {
			$msg .= "<br>\n";
		}
609

610
611
612
613
614
		if (isset($_SERVER['HTTP_USER_AGENT']) || !$newline) {
			echo $msg;
		} else {
			echo strip_tags($msg);
		}
615
616


617
618
619
		if (!empty($ADODB_FLUSH) && ob_get_length() !== false) {
			flush(); //  do not flush if output buffering enabled - useless - thx to Jesse Mullan
		}
620

Penny Leach's avatar
Penny Leach committed
621
	}
622

623
	function Time() {
624
		$rs = $this->_Execute("select $this->sysTimeStamp");
625
626
627
		if ($rs && !$rs->EOF) {
			return $this->UnixTimeStamp(reset($rs->fields));
		}
628

Penny Leach's avatar
Penny Leach committed
629
630
		return false;
	}
631

632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
	/**
	 * Parses the hostname to extract the port.
	 * Overwrites $this->host and $this->port, only if a port is specified.
	 * The Hostname can be fully or partially qualified,
	 * ie: "db.mydomain.com:5432" or "ldaps://ldap.mydomain.com:636"
	 * Any specified scheme such as ldap:// or ldaps:// is maintained.
	 */
	protected function parseHostNameAndPort() {
		$parsed_url = parse_url($this->host);
		if (is_array($parsed_url) && isset($parsed_url['host']) && isset($parsed_url['port'])) {
			if ( isset($parsed_url['scheme']) ) {
				// If scheme is specified (ie: ldap:// or ldaps://, make sure we retain that.
				$this->host = $parsed_url['scheme'] . "://" . $parsed_url['host'];
			} else {
				$this->host = $parsed_url['host'];
			}
			$this->port = $parsed_url['port'];
		}
	}

Penny Leach's avatar
Penny Leach committed
652
653
654
655
656
657
658
659
660
661
	/**
	 * Connect to database
	 *
	 * @param [argHostname]		Host to connect to
	 * @param [argUsername]		Userid to login
	 * @param [argPassword]		Associated password
	 * @param [argDatabaseName]	database
	 * @param [forceNew]		force new connection
	 *
	 * @return true or false
662
	 */
663
664
665
666
	function Connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "", $forceNew = false) {
		if ($argHostname != "") {
			$this->host = $argHostname;
		}
667
668
669
		// Overwrites $this->host and $this->port if a port is specified.
		$this->parseHostNameAndPort();

670
671
672
673
		if ($argUsername != "") {
			$this->user = $argUsername;
		}
		if ($argPassword != "") {
674
			$this->password = $argPassword;
675
676
677
678
		}
		if ($argDatabaseName != "") {
			$this->database = $argDatabaseName;
		}
679
680
681

		$this->_isPersistentConnection = false;

Penny Leach's avatar
Penny Leach committed
682
		if ($forceNew) {
683
684
685
			if ($rez=$this->_nconnect($this->host, $this->user, $argPassword, $this->database)) {
				return true;
			}
Penny Leach's avatar
Penny Leach committed
686
		} else {
687
688
689
			if ($rez=$this->_connect($this->host, $this->user, $argPassword, $this->database)) {
				return true;
			}
Penny Leach's avatar
Penny Leach committed
690
691
692
		}
		if (isset($rez)) {
			$err = $this->ErrorMsg();
693
694
695
696
			$errno = $this->ErrorNo();
			if (empty($err)) {
				$err = "Connection error to server '$argHostname' with user '$argUsername'";
			}
Penny Leach's avatar
Penny Leach committed
697
698
		} else {
			$err = "Missing extension for ".$this->dataProvider;
699
700
701
702
			$errno = 0;
		}
		if ($fn = $this->raiseErrorFn) {
			$fn($this->databaseType, 'CONNECT', $errno, $err, $this->host, $this->database, $this);
Penny Leach's avatar
Penny Leach committed
703
		}
704

Penny Leach's avatar
Penny Leach committed
705
		$this->_connectionID = false;
706
707
708
709
		if ($this->debug) {
			ADOConnection::outp( $this->host.': '.$err);
		}
		return false;
710
711
	}

712
	function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName) {
Penny Leach's avatar
Penny Leach committed
713
714
		return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName);
	}
715
716


Penny Leach's avatar
Penny Leach committed
717
718
719
720
721
722
723
724
725
	/**
	 * Always force a new connection to database - currently only works with oracle
	 *
	 * @param [argHostname]		Host to connect to
	 * @param [argUsername]		Userid to login
	 * @param [argPassword]		Associated password
	 * @param [argDatabaseName]	database
	 *
	 * @return true or false
726
	 */
727
	function NConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") {
Penny Leach's avatar
Penny Leach committed
728
729
		return $this->Connect($argHostname, $argUsername, $argPassword, $argDatabaseName, true);
	}
730

Penny Leach's avatar
Penny Leach committed
731
732
733
734
735
736
737
738
739
	/**
	 * Establish persistent connect to database
	 *
	 * @param [argHostname]		Host to connect to
	 * @param [argUsername]		Userid to login
	 * @param [argPassword]		Associated password
	 * @param [argDatabaseName]	database
	 *
	 * @return return true or false
740
	 */
741
	function PConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") {
742

743
		if (defined('ADODB_NEVER_PERSIST')) {
Penny Leach's avatar
Penny Leach committed
744
			return $this->Connect($argHostname,$argUsername,$argPassword,$argDatabaseName);
745
		}
746

747
748
749
		if ($argHostname != "") {
			$this->host = $argHostname;
		}
750
751
752
		// Overwrites $this->host and $this->port if a port is specified.
		$this->parseHostNameAndPort();

753
754
755
756
757
758
759
760
761
		if ($argUsername != "") {
			$this->user = $argUsername;
		}
		if ($argPassword != "") {
			$this->password = 'not stored';
		}
		if ($argDatabaseName != "") {
			$this->database = $argDatabaseName;
		}
762
763
764

		$this->_isPersistentConnection = true;

765
766
767
		if ($rez = $this->_pconnect($this->host, $this->user, $argPassword, $this->database)) {
			return true;
		}
Penny Leach's avatar
Penny Leach committed
768
769
		if (isset($rez)) {
			$err = $this->ErrorMsg();
770
771
772
			if (empty($err)) {
				$err = "Connection error to server '$argHostname' with user '$argUsername'";
			}
Penny Leach's avatar
Penny Leach committed
773
774
775
776
777
778
779
780
			$ret = false;
		} else {
			$err = "Missing extension for ".$this->dataProvider;
			$ret = 0;
		}
		if ($fn = $this->raiseErrorFn) {
			$fn($this->databaseType,'PCONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
		}
781

Penny Leach's avatar
Penny Leach committed
782
		$this->_connectionID = false;
783
784
785
		if ($this->debug) {
			ADOConnection::outp( $this->host.': '.$err);
		}
Penny Leach's avatar
Penny Leach committed
786
787
788
		return $ret;
	}

789
	function outp_throw($msg,$src='WARN',$sql='') {
790
791
792
		if (defined('ADODB_ERROR_HANDLER') &&  ADODB_ERROR_HANDLER == 'adodb_throw') {
			adodb_throw($this->databaseType,$src,-9999,$msg,$sql,false,$this);
			return;
793
		}
794
795
		ADOConnection::outp($msg);
	}
796

797
	// create cache class. Code is backward compat with old memcache implementation
798
799
	function _CreateCache() {
		global $ADODB_CACHE, $ADODB_CACHE_CLASS;
800

801
		if ($this->memCache) {
802
			global $ADODB_INCLUDED_MEMCACHE;
803

804
805
806
807
808
809
810
			if (empty($ADODB_INCLUDED_MEMCACHE)) {
				include_once(ADODB_DIR.'/adodb-memcache.lib.inc.php');
			}
			$ADODB_CACHE = new ADODB_Cache_MemCache($this);
		} else {
			$ADODB_CACHE = new $ADODB_CACHE_CLASS($this);
		}
811
	}
812

Penny Leach's avatar
Penny Leach committed
813
	// Format date column in sql string given an input format that understands Y M D
814
815
816
817
	function SQLDate($fmt, $col=false) {
		if (!$col) {
			$col = $this->sysDate;
		}
Penny Leach's avatar
Penny Leach committed
818
819
		return $col; // child class implement
	}
820

Penny Leach's avatar
Penny Leach committed
821
822
823
824
825
826
827
828
829
830
831
832
	/**
	 * Should prepare the sql statement and return the stmt resource.
	 * For databases that do not support this, we return the $sql. To ensure
	 * compatibility with databases that do not support prepare:
	 *
	 *   $stmt = $db->Prepare("insert into table (id, name) values (?,?)");
	 *   $db->Execute($stmt,array(1,'Jill')) or die('insert failed');
	 *   $db->Execute($stmt,array(2,'Joe')) or die('insert failed');
	 *
	 * @param sql	SQL to send to database
	 *
	 * @return return FALSE, or the prepared statement, or the original sql if
833
	 *         if the database does not support prepare.
Penny Leach's avatar
Penny Leach committed
834
	 *
835
	 */
836
	function Prepare($sql) {
Penny Leach's avatar
Penny Leach committed
837
838
		return $sql;
	}
839

Penny Leach's avatar
Penny Leach committed
840
841
842
843
844
845
846
847
848
849
850
	/**
	 * Some databases, eg. mssql require a different function for preparing
	 * stored procedures. So we cannot use Prepare().
	 *
	 * Should prepare the stored procedure  and return the stmt resource.
	 * For databases that do not support this, we return the $sql. To ensure
	 * compatibility with databases that do not support prepare:
	 *
	 * @param sql	SQL to send to database
	 *
	 * @return return FALSE, or the prepared statement, or the original sql if
851
	 *         if the database does not support prepare.
Penny Leach's avatar
Penny Leach committed
852
	 *
853
	 */
854
	function PrepareSP($sql,$param=true) {
Penny Leach's avatar
Penny Leach committed
855
856
		return $this->Prepare($sql,$param);
	}
857

Penny Leach's avatar
Penny Leach committed
858
859
860
	/**
	* PEAR DB Compat
	*/
861
	function Quote($s) {
Penny Leach's avatar
Penny Leach committed
862
863
		return $this->qstr($s,false);
	}
864

Penny Leach's avatar
Penny Leach committed
865
	/**
866
867
868
	 * Requested by "Karsten Dambekalns" <k.dambekalns@fishfarm.de>
	 */
	function QMagic($s) {
Penny Leach's avatar
Penny Leach committed
869
870
871
		return $this->qstr($s,get_magic_quotes_gpc());
	}

872
873
874
875
	function q(&$s) {
		//if (!empty($this->qNull && $s == 'null') {
		//	return $s;
		//}
Penny Leach's avatar
Penny Leach committed
876
877
		$s = $this->qstr($s,false);
	}
878

Penny Leach's avatar
Penny Leach committed
879
	/**
880
	* PEAR DB Compat - do not use internally.
Penny Leach's avatar
Penny Leach committed
881
	*/
882
	function ErrorNative() {
Penny Leach's avatar
Penny Leach committed
883
884
885
		return $this->ErrorNo();
	}

886
887
888
889

	/**
	 * PEAR DB Compat - do not use internally.
	 */
890
	function nextId($seq_name) {
Penny Leach's avatar
Penny Leach committed
891
892
893
894
		return $this->GenID($seq_name);
	}

	/**
895
896
	 * Lock a row, will escalate and lock the table if row locking not supported
	 * will normally free the lock at the end of the transaction
897
	 *
898
899
	 * @param $table	name of table to lock
	 * @param $where	where clause to use, eg: "WHERE row=12". If left empty, will escalate to table lock
900
	 */
901
	function RowLock($table,$where,$col='1 as adodbignore') {
Penny Leach's avatar
Penny Leach committed
902
903
		return false;
	}
904

905
	function CommitLock($table) {
Penny Leach's avatar
Penny Leach committed
906
907
		return $this->CommitTrans();
	}
908

909
	function RollbackLock($table) {
Penny Leach's avatar
Penny Leach committed
910
911
		return $this->RollbackTrans();
	}
912

Penny Leach's avatar
Penny Leach committed
913
	/**
914
	* PEAR DB Compat - do not use internally.
Penny Leach's avatar
Penny Leach committed
915
916
	*
	* The fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB are identical
917
	* for easy porting :-)
Penny Leach's avatar
Penny Leach committed
918
919
920
921
	*
	* @param mode	The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM
	* @returns		The previous fetch mode
	*/
922
	function SetFetchMode($mode) {
Penny Leach's avatar
Penny Leach committed
923
924
		$old = $this->fetchMode;
		$this->fetchMode = $mode;
925

Penny Leach's avatar
Penny Leach committed
926
		if ($old === false) {
927
			global $ADODB_FETCH_MODE;
Penny Leach's avatar
Penny Leach committed
928
929
930
931
			return $ADODB_FETCH_MODE;
		}
		return $old;
	}
932

Penny Leach's avatar
Penny Leach committed
933
934

	/**
935
	* PEAR DB Compat - do not use internally.
Penny Leach's avatar
Penny Leach committed
936
	*/
937
	function Query($sql, $inputarr=false) {
938
		$rs = $this->Execute($sql, $inputarr);
939
940
941
		if (!$rs && defined('ADODB_PEAR')) {
			return ADODB_PEAR_Error();
		}
Penny Leach's avatar
Penny Leach committed
942
943
944
		return $rs;
	}

945

Penny Leach's avatar
Penny Leach committed
946
947
948
	/**
	* PEAR DB Compat - do not use internally
	*/
949
	function LimitQuery($sql, $offset, $count, $params=false) {
950
		$rs = $this->SelectLimit($sql, $count, $offset, $params);
951
952
953
		if (!$rs && defined('ADODB_PEAR')) {
			return ADODB_PEAR_Error();
		}
Penny Leach's avatar
Penny Leach committed
954
955
956
		return $rs;
	}

957

Penny Leach's avatar
Penny Leach committed
958
959
960
	/**
	* PEAR DB Compat - do not use internally
	*/
961
	function Disconnect() {
Penny Leach's avatar
Penny Leach committed
962
963
		return $this->Close();
	}
964
965
966
967
968
969
970
971
972
973
974
975
976
977

	/**
	 * Returns a placeholder for query parameters
	 * e.g. $DB->Param('a') will return
	 * - '?' for most databases
	 * - ':a' for Oracle
	 * - '$1', '$2', etc. for PostgreSQL
	 * @param string $name parameter's name, false to force a reset of the
	 *                     number to 1 (for databases that require positioned
	 *                     params such as PostgreSQL; note that ADOdb will
	 *                     automatically reset this when executing a query )
	 * @param string $type (unused)
	 * @return string query parameter placeholder
	 */
978
	function Param($name,$type='C') {
Penny Leach's avatar
Penny Leach committed
979
980
		return '?';
	}
981

Penny Leach's avatar
Penny Leach committed
982
983
984
	/*
		InParameter and OutParameter are self-documenting versions of Parameter().
	*/
985
	function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) {
Penny Leach's avatar
Penny Leach committed
986
987
		return $this->Parameter($stmt,$var,$name,false,$maxLen,$type);
	}
988

Penny Leach's avatar
Penny Leach committed
989
990
	/*
	*/
991
	function OutParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) {
Penny Leach's avatar
Penny Leach committed
992
		return $this->Parameter($stmt,$var,$name,true,$maxLen,$type);
993

Penny Leach's avatar
Penny Leach committed
994
995
	}

996
997

	/*
Penny Leach's avatar
Penny Leach committed
998
999
1000
1001
1002
	Usage in oracle
		$stmt = $db->Prepare('select * from table where id =:myid and group=:group');
		$db->Parameter($stmt,$id,'myid');
		$db->Parameter($stmt,$group,'group',64);
		$db->Execute();
1003

Penny Leach's avatar
Penny Leach committed
1004
1005
1006
1007
1008
1009
1010
1011
		@param $stmt Statement returned by Prepare() or PrepareSP().
		@param $var PHP variable to bind to
		@param $name Name of stored procedure variable name to bind to.
		@param [$isOutput] Indicates direction of parameter 0/false=IN  1=OUT  2= IN/OUT. This is ignored in oci8.
		@param [$maxLen] Holds an maximum length of the variable.
		@param [$type] The data type of $var. Legal values depend on driver.

	*/
1012
	function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false) {
Penny Leach's avatar
Penny Leach committed
1013
1014
		return false;
	}
1015
1016


1017
	function IgnoreErrors($saveErrs=false) {
Penny Leach's avatar
Penny Leach committed
1018
1019
1020
1021
1022
1023
1024
1025
1026
		if (!$saveErrs) {
			$saveErrs = array($this->raiseErrorFn,$this->_transOK);
			$this->raiseErrorFn = false;
			return $saveErrs;
		} else {
			$this->raiseErrorFn = $saveErrs[0];
			$this->_transOK = $saveErrs[1];
		}
	}
1027

Penny Leach's avatar
Penny Leach committed
1028
	/**
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
	 * Improved method of initiating a transaction. Used together with CompleteTrans().
	 * Advantages include:
     *
	 * a. StartTrans/CompleteTrans is nestable, unlike BeginTrans/CommitTrans/RollbackTrans.
	 *    Only the outermost block is treated as a transaction.<br>
	 * b. CompleteTrans auto-detects SQL errors, and will rollback on errors, commit otherwise.<br>
	 * c. All BeginTrans/CommitTrans/RollbackTrans inside a StartTrans/CompleteTrans block
	 *    are disabled, making it backward compatible.
	 */
	function StartTrans($errfn = 'ADODB_TransMonitor') {
Penny Leach's avatar
Penny Leach committed
1039
1040
		if ($this->transOff > 0) {
			$this->transOff += 1;
1041
			return true;
Penny Leach's avatar
Penny Leach committed
1042
		}
1043

Penny Leach's avatar
Penny Leach committed
1044
1045
1046
		$this->_oldRaiseFn = $this->raiseErrorFn;
		$this->raiseErrorFn = $errfn;
		$this->_transOK = true;
1047

1048
1049
1050
		if ($this->debug && $this->transCnt > 0) {
			ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans");
		}
1051
		$ok = $this->BeginTrans();
Penny Leach's avatar
Penny Leach committed
1052
		$this->transOff = 1;
1053
		return $ok;
Penny Leach's avatar
Penny Leach committed
1054
	}
1055
1056


Penny Leach's avatar
Penny Leach committed
1057
1058
1059
	/**
		Used together with StartTrans() to end a transaction. Monitors connection
		for sql errors, and will commit or rollback as appropriate.
1060
1061

		@autoComplete if true, monitor sql errors and commit and rollback as appropriate,
Penny Leach's avatar
Penny Leach committed
1062
1063
1064
		and if set to false force rollback even if no SQL error detected.
		@returns true on commit, false on rollback.
	*/
1065
	function CompleteTrans($autoComplete = true) {
Penny Leach's avatar
Penny Leach committed
1066
1067
1068
1069
1070
		if ($this->transOff > 1) {
			$this->transOff -= 1;
			return true;
		}
		$this->raiseErrorFn = $this->_oldRaiseFn;
1071

Penny Leach's avatar
Penny Leach committed
1072
1073
1074
1075
		$this->transOff = 0;
		if ($this->_transOK && $autoComplete) {
			if (!$this->CommitTrans()) {
				$this->_transOK = false;
1076
1077
1078
1079
1080
1081
1082
1083
				if ($this->debug) {
					ADOConnection::outp("Smart Commit failed");
				}
			} else {
				if ($this->debug) {
					ADOConnection::outp("Smart Commit occurred");
				}
			}
Penny Leach's avatar
Penny Leach committed
1084
1085
1086
		} else {
			$this->_transOK = false;
			$this->RollbackTrans();
1087
1088
1089
			if ($this->debug) {
				ADOCOnnection::outp("Smart Rollback occurred");
			}
Penny Leach's avatar
Penny Leach committed
1090
		}
1091

Penny Leach's avatar
Penny Leach committed
1092
1093
		return $this->_transOK;
	}
1094

Penny Leach's avatar
Penny Leach committed
1095
1096
1097
	/*
		At the end of a StartTrans/CompleteTrans block, perform a rollback.
	*/
1098
	function FailTrans() {
1099
		if ($this->debug)
Penny Leach's avatar
Penny Leach committed
1100
1101
1102
1103
1104
1105
1106
1107
			if ($this->transOff == 0) {
				ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans");
			} else {
				ADOConnection::outp("FailTrans was called");
				adodb_backtrace();
			}
		$this->_transOK = false;
	}