Subversion Repositories svnkaklik

Rev

Details | Last modification | View Log

Rev Author Line No. Line
36 kaklik 1
<?php
2
/* 
3
V4.80 8 Mar 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
4
  Released under both BSD license and Lesser GPL library license. 
5
  Whenever there is any discrepancy between the two licenses, 
6
  the BSD license will take precedence. 
7
Set tabs to 4 for best viewing.
8
 
9
  Latest version is available at http://adodb.sourceforge.net
10
 
11
  Requires ODBC. Works on Windows and Unix.
12
*/
13
// security - hide paths
14
if (!defined('ADODB_DIR')) die();
15
 
16
  define("_ADODB_ODBC_LAYER", 2 );
17
 
18
/*--------------------------------------------------------------------------------------
19
--------------------------------------------------------------------------------------*/
20
 
21
 
22
class ADODB_odbc extends ADOConnection {
23
	var $databaseType = "odbc";	
24
	var $fmtDate = "'Y-m-d'";
25
	var $fmtTimeStamp = "'Y-m-d, h:i:sA'";
26
	var $replaceQuote = "''"; // string to use to replace quotes
27
	var $dataProvider = "odbc";
28
	var $hasAffectedRows = true;
29
	var $binmode = ODBC_BINMODE_RETURN;
30
	var $useFetchArray = false; // setting this to true will make array elements in FETCH_ASSOC mode case-sensitive
31
								// breaking backward-compat
32
	//var $longreadlen = 8000; // default number of chars to return for a Blob/Long field
33
	var $_bindInputArray = false;	
34
	var $curmode = SQL_CUR_USE_DRIVER; // See sqlext.h, SQL_CUR_DEFAULT == SQL_CUR_USE_DRIVER == 2L
35
	var $_genSeqSQL = "create table %s (id integer)";
36
	var $_autocommit = true;
37
	var $_haserrorfunctions = true;
38
	var $_has_stupid_odbc_fetch_api_change = true;
39
	var $_lastAffectedRows = 0;
40
	var $uCaseTables = true; // for meta* functions, uppercase table names
41
 
42
	function ADODB_odbc() 
43
	{ 	
44
		$this->_haserrorfunctions = ADODB_PHPVER >= 0x4050;
45
		$this->_has_stupid_odbc_fetch_api_change = ADODB_PHPVER >= 0x4200;
46
	}
47
 
48
		// returns true or false
49
	function _connect($argDSN, $argUsername, $argPassword, $argDatabasename)
50
	{
51
	global $php_errormsg;
52
 
53
		if (!function_exists('odbc_connect')) return null;
54
 
55
		if ($this->debug && $argDatabasename && $this->databaseType != 'vfp') {
56
			ADOConnection::outp("For odbc Connect(), $argDatabasename is not used. Place dsn in 1st parameter.");
57
		}
58
		if (isset($php_errormsg)) $php_errormsg = '';
59
		if ($this->curmode === false) $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword);
60
		else $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword,$this->curmode);
61
		$this->_errorMsg = isset($php_errormsg) ? $php_errormsg : '';
62
		if (isset($this->connectStmt)) $this->Execute($this->connectStmt);
63
 
64
		return $this->_connectionID != false;
65
	}
66
 
67
	// returns true or false
68
	function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename)
69
	{
70
	global $php_errormsg;
71
 
72
		if (!function_exists('odbc_connect')) return null;
73
 
74
		if (isset($php_errormsg)) $php_errormsg = '';
75
		$this->_errorMsg = isset($php_errormsg) ? $php_errormsg : '';
76
		if ($this->debug && $argDatabasename) {
77
			ADOConnection::outp("For odbc PConnect(), $argDatabasename is not used. Place dsn in 1st parameter.");
78
		}
79
	//	print "dsn=$argDSN u=$argUsername p=$argPassword<br>"; flush();
80
		if ($this->curmode === false) $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword);
81
		else $this->_connectionID = odbc_pconnect($argDSN,$argUsername,$argPassword,$this->curmode);
82
 
83
		$this->_errorMsg = isset($php_errormsg) ? $php_errormsg : '';
84
		if ($this->_connectionID && $this->autoRollback) @odbc_rollback($this->_connectionID);
85
		if (isset($this->connectStmt)) $this->Execute($this->connectStmt);
86
 
87
		return $this->_connectionID != false;
88
	}
89
 
90
 
91
	function ServerInfo()
92
	{
93
 
94
		if (!empty($this->host) && ADODB_PHPVER >= 0x4300) {
95
			$dsn = strtoupper($this->host);
96
			$first = true;
97
			$found = false;
98
 
99
			if (!function_exists('odbc_data_source')) return false;
100
 
101
			while(true) {
102
 
103
				$rez = @odbc_data_source($this->_connectionID,
104
					$first ? SQL_FETCH_FIRST : SQL_FETCH_NEXT);
105
				$first = false;
106
				if (!is_array($rez)) break;
107
				if (strtoupper($rez['server']) == $dsn) {
108
					$found = true;
109
					break;
110
				}
111
			} 
112
			if (!$found) return ADOConnection::ServerInfo();
113
			if (!isset($rez['version'])) $rez['version'] = '';
114
			return $rez;
115
		} else {
116
			return ADOConnection::ServerInfo();
117
		}
118
	}
119
 
120
 
121
	function CreateSequence($seqname='adodbseq',$start=1)
122
	{
123
		if (empty($this->_genSeqSQL)) return false;
124
		$ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname));
125
		if (!$ok) return false;
126
		$start -= 1;
127
		return $this->Execute("insert into $seqname values($start)");
128
	}
129
 
130
	var $_dropSeqSQL = 'drop table %s';
131
	function DropSequence($seqname)
132
	{
133
		if (empty($this->_dropSeqSQL)) return false;
134
		return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
135
	}
136
 
137
	/*
138
		This algorithm is not very efficient, but works even if table locking
139
		is not available.
140
 
141
		Will return false if unable to generate an ID after $MAXLOOPS attempts.
142
	*/
143
	function GenID($seq='adodbseq',$start=1)
144
	{	
145
		// if you have to modify the parameter below, your database is overloaded,
146
		// or you need to implement generation of id's yourself!
147
		$MAXLOOPS = 100;
148
		//$this->debug=1;
149
		while (--$MAXLOOPS>=0) {
150
			$num = $this->GetOne("select id from $seq");
151
			if ($num === false) {
152
				$this->Execute(sprintf($this->_genSeqSQL ,$seq));	
153
				$start -= 1;
154
				$num = '0';
155
				$ok = $this->Execute("insert into $seq values($start)");
156
				if (!$ok) return false;
157
			} 
158
			$this->Execute("update $seq set id=id+1 where id=$num");
159
 
160
			if ($this->affected_rows() > 0) {
161
				$num += 1;
162
				$this->genID = $num;
163
				return $num;
164
			}
165
		}
166
		if ($fn = $this->raiseErrorFn) {
167
			$fn($this->databaseType,'GENID',-32000,"Unable to generate unique id after $MAXLOOPS attempts",$seq,$num);
168
		}
169
		return false;
170
	}
171
 
172
 
173
	function ErrorMsg()
174
	{
175
		if ($this->_haserrorfunctions) {
176
			if ($this->_errorMsg !== false) return $this->_errorMsg;
177
			if (empty($this->_connectionID)) return @odbc_errormsg();
178
			return @odbc_errormsg($this->_connectionID);
179
		} else return ADOConnection::ErrorMsg();
180
	}
181
 
182
	function ErrorNo()
183
	{
184
 
185
		if ($this->_haserrorfunctions) {
186
			if ($this->_errorCode !== false) {
187
				// bug in 4.0.6, error number can be corrupted string (should be 6 digits)
188
				return (strlen($this->_errorCode)<=2) ? 0 : $this->_errorCode;
189
			}
190
 
191
			if (empty($this->_connectionID)) $e = @odbc_error(); 
192
			else $e = @odbc_error($this->_connectionID);
193
 
194
			 // bug in 4.0.6, error number can be corrupted string (should be 6 digits)
195
			 // so we check and patch
196
			if (strlen($e)<=2) return 0;
197
			return $e;
198
		} else return ADOConnection::ErrorNo();
199
	}
200
 
201
 
202
 
203
	function BeginTrans()
204
	{	
205
		if (!$this->hasTransactions) return false;
206
		if ($this->transOff) return true; 
207
		$this->transCnt += 1;
208
		$this->_autocommit = false;
209
		return odbc_autocommit($this->_connectionID,false);
210
	}
211
 
212
	function CommitTrans($ok=true) 
213
	{ 
214
		if ($this->transOff) return true; 
215
		if (!$ok) return $this->RollbackTrans();
216
		if ($this->transCnt) $this->transCnt -= 1;
217
		$this->_autocommit = true;
218
		$ret = odbc_commit($this->_connectionID);
219
		odbc_autocommit($this->_connectionID,true);
220
		return $ret;
221
	}
222
 
223
	function RollbackTrans()
224
	{
225
		if ($this->transOff) return true; 
226
		if ($this->transCnt) $this->transCnt -= 1;
227
		$this->_autocommit = true;
228
		$ret = odbc_rollback($this->_connectionID);
229
		odbc_autocommit($this->_connectionID,true);
230
		return $ret;
231
	}
232
 
233
	function MetaPrimaryKeys($table)
234
	{
235
	global $ADODB_FETCH_MODE;
236
 
237
		if ($this->uCaseTables) $table = strtoupper($table);
238
		$schema = '';
239
		$this->_findschema($table,$schema);
240
 
241
		$savem = $ADODB_FETCH_MODE;
242
		$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
243
		$qid = @odbc_primarykeys($this->_connectionID,'',$schema,$table);
244
 
245
		if (!$qid) {
246
			$ADODB_FETCH_MODE = $savem;
247
			return false;
248
		}
249
		$rs = new ADORecordSet_odbc($qid);
250
		$ADODB_FETCH_MODE = $savem;
251
 
252
		if (!$rs) return false;
253
		$rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
254
 
255
		$arr =& $rs->GetArray();
256
		$rs->Close();
257
		//print_r($arr);
258
		$arr2 = array();
259
		for ($i=0; $i < sizeof($arr); $i++) {
260
			if ($arr[$i][3]) $arr2[] = $arr[$i][3];
261
		}
262
		return $arr2;
263
	}
264
 
265
 
266
 
267
	function &MetaTables($ttype=false)
268
	{
269
	global $ADODB_FETCH_MODE;
270
 
271
		$savem = $ADODB_FETCH_MODE;
272
		$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
273
		$qid = odbc_tables($this->_connectionID);
274
 
275
		$rs = new ADORecordSet_odbc($qid);
276
 
277
		$ADODB_FETCH_MODE = $savem;
278
		if (!$rs) {
279
			$false = false;
280
			return $false;
281
		}
282
		$rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
283
 
284
		$arr =& $rs->GetArray();
285
		//print_r($arr);
286
 
287
		$rs->Close();
288
		$arr2 = array();
289
 
290
		if ($ttype) {
291
			$isview = strncmp($ttype,'V',1) === 0;
292
		}
293
		for ($i=0; $i < sizeof($arr); $i++) {
294
			if (!$arr[$i][2]) continue;
295
			$type = $arr[$i][3];
296
			if ($ttype) { 
297
				if ($isview) {
298
					if (strncmp($type,'V',1) === 0) $arr2[] = $arr[$i][2];
299
				} else if (strncmp($type,'SYS',3) !== 0) $arr2[] = $arr[$i][2];
300
			} else if (strncmp($type,'SYS',3) !== 0) $arr2[] = $arr[$i][2];
301
		}
302
		return $arr2;
303
	}
304
 
305
/*
306
See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcdatetime_data_type_changes.asp
307
/ SQL data type codes /
308
#define	SQL_UNKNOWN_TYPE	0
309
#define SQL_CHAR			1
310
#define SQL_NUMERIC		 2
311
#define SQL_DECIMAL		 3
312
#define SQL_INTEGER		 4
313
#define SQL_SMALLINT		5
314
#define SQL_FLOAT		   6
315
#define SQL_REAL			7
316
#define SQL_DOUBLE		  8
317
#if (ODBCVER >= 0x0300)
318
#define SQL_DATETIME		9
319
#endif
320
#define SQL_VARCHAR		12
321
 
322
 
323
/ One-parameter shortcuts for date/time data types /
324
#if (ODBCVER >= 0x0300)
325
#define SQL_TYPE_DATE	  91
326
#define SQL_TYPE_TIME	  92
327
#define SQL_TYPE_TIMESTAMP 93
328
 
329
#define SQL_UNICODE                             (-95)
330
#define SQL_UNICODE_VARCHAR                     (-96)
331
#define SQL_UNICODE_LONGVARCHAR                 (-97)
332
*/
333
	function ODBCTypes($t)
334
	{
335
		switch ((integer)$t) {
336
		case 1:	
337
		case 12:
338
		case 0:
339
		case -95:
340
		case -96:
341
			return 'C';
342
		case -97:
343
		case -1: //text
344
			return 'X';
345
		case -4: //image
346
			return 'B';
347
 
348
		case 9:	
349
		case 91:
350
			return 'D';
351
 
352
		case 10:
353
		case 11:
354
		case 92:
355
		case 93:
356
			return 'T';
357
 
358
		case 4:
359
		case 5:
360
		case -6:
361
			return 'I';
362
 
363
		case -11: // uniqidentifier
364
			return 'R';
365
		case -7: //bit
366
			return 'L';
367
 
368
		default:
369
			return 'N';
370
		}
371
	}
372
 
373
	function &MetaColumns($table)
374
	{
375
	global $ADODB_FETCH_MODE;
376
 
377
		$false = false;
378
		if ($this->uCaseTables) $table = strtoupper($table);
379
		$schema = '';
380
		$this->_findschema($table,$schema);
381
 
382
		$savem = $ADODB_FETCH_MODE;
383
		$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
384
 
385
		/*if (false) { // after testing, confirmed that the following does not work becoz of a bug
386
			$qid2 = odbc_tables($this->_connectionID);
387
			$rs = new ADORecordSet_odbc($qid2);		
388
			$ADODB_FETCH_MODE = $savem;
389
			if (!$rs) return false;
390
			$rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
391
			$rs->_fetch();
392
 
393
			while (!$rs->EOF) {
394
				if ($table == strtoupper($rs->fields[2])) {
395
					$q = $rs->fields[0];
396
					$o = $rs->fields[1];
397
					break;
398
				}
399
				$rs->MoveNext();
400
			}
401
			$rs->Close();
402
 
403
			$qid = odbc_columns($this->_connectionID,$q,$o,strtoupper($table),'%');
404
		} */
405
 
406
		switch ($this->databaseType) {
407
		case 'access':
408
		case 'vfp':
409
			$qid = odbc_columns($this->_connectionID);#,'%','',strtoupper($table),'%');
410
			break;
411
 
412
 
413
		case 'db2':
414
            $colname = "%";
415
            $qid = odbc_columns($this->_connectionID, "", $schema, $table, $colname);
416
            break;
417
 
418
		default:
419
			$qid = @odbc_columns($this->_connectionID,'%','%',strtoupper($table),'%');
420
			if (empty($qid)) $qid = odbc_columns($this->_connectionID);
421
			break;
422
		}
423
		if (empty($qid)) return $false;
424
 
425
		$rs =& new ADORecordSet_odbc($qid);
426
		$ADODB_FETCH_MODE = $savem;
427
 
428
		if (!$rs) return $false;
429
		$rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
430
		$rs->_fetch();
431
 
432
		$retarr = array();
433
 
434
		/*
435
		$rs->fields indices
436
 
437
		1 TABLE_SCHEM
438
		2 TABLE_NAME
439
		3 COLUMN_NAME
440
		4 DATA_TYPE
441
		5 TYPE_NAME
442
		6 PRECISION
443
		7 LENGTH
444
		8 SCALE
445
		9 RADIX
446
		10 NULLABLE
447
		11 REMARKS
448
		*/
449
		while (!$rs->EOF) {
450
		//	adodb_pr($rs->fields);
451
			if (strtoupper(trim($rs->fields[2])) == $table && (!$schema || strtoupper($rs->fields[1]) == $schema)) {
452
				$fld = new ADOFieldObject();
453
				$fld->name = $rs->fields[3];
454
				$fld->type = $this->ODBCTypes($rs->fields[4]);
455
 
456
				// ref: http://msdn.microsoft.com/library/default.asp?url=/archive/en-us/dnaraccgen/html/msdn_odk.asp
457
				// access uses precision to store length for char/varchar
458
				if ($fld->type == 'C' or $fld->type == 'X') {
459
					if ($this->databaseType == 'access') 
460
						$fld->max_length = $rs->fields[6];
461
					else if ($rs->fields[4] <= -95) // UNICODE
462
						$fld->max_length = $rs->fields[7]/2;
463
					else
464
						$fld->max_length = $rs->fields[7];
465
				} else 
466
					$fld->max_length = $rs->fields[7];
467
				$fld->not_null = !empty($rs->fields[10]);
468
				$fld->scale = $rs->fields[8];
469
				$retarr[strtoupper($fld->name)] = $fld;	
470
			} else if (sizeof($retarr)>0)
471
				break;
472
			$rs->MoveNext();
473
		}
474
		$rs->Close(); //-- crashes 4.03pl1 -- why?
475
 
476
		if (empty($retarr)) $retarr = false;
477
		return $retarr;
478
	}
479
 
480
	function Prepare($sql)
481
	{
482
		if (! $this->_bindInputArray) return $sql; // no binding
483
		$stmt = odbc_prepare($this->_connectionID,$sql);
484
		if (!$stmt) {
485
			// we don't know whether odbc driver is parsing prepared stmts, so just return sql
486
			return $sql;
487
		}
488
		return array($sql,$stmt,false);
489
	}
490
 
491
	/* returns queryID or false */
492
	function _query($sql,$inputarr=false) 
493
	{
494
	GLOBAL $php_errormsg;
495
		if (isset($php_errormsg)) $php_errormsg = '';
496
		$this->_error = '';
497
 
498
		if ($inputarr) {
499
			if (is_array($sql)) {
500
				$stmtid = $sql[1];
501
			} else {
502
				$stmtid = odbc_prepare($this->_connectionID,$sql);
503
 
504
				if ($stmtid == false) {
505
					$this->_errorMsg = isset($php_errormsg) ? $php_errormsg : '';
506
					return false;
507
				}
508
			}
509
 
510
			if (! odbc_execute($stmtid,$inputarr)) {
511
				//@odbc_free_result($stmtid);
512
				if ($this->_haserrorfunctions) {
513
					$this->_errorMsg = odbc_errormsg();
514
					$this->_errorCode = odbc_error();
515
				}
516
				return false;
517
			}
518
 
519
		} else if (is_array($sql)) {
520
			$stmtid = $sql[1];
521
			if (!odbc_execute($stmtid)) {
522
				//@odbc_free_result($stmtid);
523
				if ($this->_haserrorfunctions) {
524
					$this->_errorMsg = odbc_errormsg();
525
					$this->_errorCode = odbc_error();
526
				}
527
				return false;
528
			}
529
		} else
530
			$stmtid = odbc_exec($this->_connectionID,$sql);
531
 
532
		$this->_lastAffectedRows = 0;
533
		if ($stmtid) {
534
			if (@odbc_num_fields($stmtid) == 0) {
535
				$this->_lastAffectedRows = odbc_num_rows($stmtid);
536
				$stmtid = true;
537
			} else {
538
				$this->_lastAffectedRows = 0;
539
				odbc_binmode($stmtid,$this->binmode);
540
				odbc_longreadlen($stmtid,$this->maxblobsize);
541
			}
542
 
543
			if ($this->_haserrorfunctions) {
544
				$this->_errorMsg = '';
545
				$this->_errorCode = 0;
546
			} else
547
				$this->_errorMsg = isset($php_errormsg) ? $php_errormsg : '';
548
		} else {
549
			if ($this->_haserrorfunctions) {
550
				$this->_errorMsg = odbc_errormsg();
551
				$this->_errorCode = odbc_error();
552
			} else
553
				$this->_errorMsg = isset($php_errormsg) ? $php_errormsg : '';
554
		}
555
		return $stmtid;
556
	}
557
 
558
	/*
559
		Insert a null into the blob field of the table first.
560
		Then use UpdateBlob to store the blob.
561
 
562
		Usage:
563
 
564
		$conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
565
		$conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
566
	*/
567
	function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
568
	{
569
		return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;
570
	}
571
 
572
	// returns true or false
573
	function _close()
574
	{
575
		$ret = @odbc_close($this->_connectionID);
576
		$this->_connectionID = false;
577
		return $ret;
578
	}
579
 
580
	function _affectedrows()
581
	{
582
		return $this->_lastAffectedRows;
583
	}
584
 
585
}
586
 
587
/*--------------------------------------------------------------------------------------
588
	 Class Name: Recordset
589
--------------------------------------------------------------------------------------*/
590
 
591
class ADORecordSet_odbc extends ADORecordSet {	
592
 
593
	var $bind = false;
594
	var $databaseType = "odbc";		
595
	var $dataProvider = "odbc";
596
	var $useFetchArray;
597
	var $_has_stupid_odbc_fetch_api_change;
598
 
599
	function ADORecordSet_odbc($id,$mode=false)
600
	{
601
		if ($mode === false) {  
602
			global $ADODB_FETCH_MODE;
603
			$mode = $ADODB_FETCH_MODE;
604
		}
605
		$this->fetchMode = $mode;
606
 
607
		$this->_queryID = $id;
608
 
609
		// the following is required for mysql odbc driver in 4.3.1 -- why?
610
		$this->EOF = false;
611
		$this->_currentRow = -1;
612
		//$this->ADORecordSet($id);
613
	}
614
 
615
 
616
	// returns the field object
617
	function &FetchField($fieldOffset = -1) 
618
	{
619
 
620
		$off=$fieldOffset+1; // offsets begin at 1
621
 
622
		$o= new ADOFieldObject();
623
		$o->name = @odbc_field_name($this->_queryID,$off);
624
		$o->type = @odbc_field_type($this->_queryID,$off);
625
		$o->max_length = @odbc_field_len($this->_queryID,$off);
626
		if (ADODB_ASSOC_CASE == 0) $o->name = strtolower($o->name);
627
		else if (ADODB_ASSOC_CASE == 1) $o->name = strtoupper($o->name);
628
		return $o;
629
	}
630
 
631
	/* Use associative array to get fields array */
632
	function Fields($colname)
633
	{
634
		if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname];
635
		if (!$this->bind) {
636
			$this->bind = array();
637
			for ($i=0; $i < $this->_numOfFields; $i++) {
638
				$o = $this->FetchField($i);
639
				$this->bind[strtoupper($o->name)] = $i;
640
			}
641
		}
642
 
643
		 return $this->fields[$this->bind[strtoupper($colname)]];
644
	}
645
 
646
 
647
	function _initrs()
648
	{
649
	global $ADODB_COUNTRECS;
650
		$this->_numOfRows = ($ADODB_COUNTRECS) ? @odbc_num_rows($this->_queryID) : -1;
651
		$this->_numOfFields = @odbc_num_fields($this->_queryID);
652
		// some silly drivers such as db2 as/400 and intersystems cache return _numOfRows = 0
653
		if ($this->_numOfRows == 0) $this->_numOfRows = -1;
654
		//$this->useFetchArray = $this->connection->useFetchArray;
655
		$this->_has_stupid_odbc_fetch_api_change = ADODB_PHPVER >= 0x4200;
656
	}	
657
 
658
	function _seek($row)
659
	{
660
		return false;
661
	}
662
 
663
	// speed up SelectLimit() by switching to ADODB_FETCH_NUM as ADODB_FETCH_ASSOC is emulated
664
	function &GetArrayLimit($nrows,$offset=-1) 
665
	{
666
		if ($offset <= 0) {
667
			$rs =& $this->GetArray($nrows);
668
			return $rs;
669
		}
670
		$savem = $this->fetchMode;
671
		$this->fetchMode = ADODB_FETCH_NUM;
672
		$this->Move($offset);
673
		$this->fetchMode = $savem;
674
 
675
		if ($this->fetchMode & ADODB_FETCH_ASSOC) {
676
			$this->fields =& $this->GetRowAssoc(ADODB_ASSOC_CASE);
677
		}
678
 
679
		$results = array();
680
		$cnt = 0;
681
		while (!$this->EOF && $nrows != $cnt) {
682
			$results[$cnt++] = $this->fields;
683
			$this->MoveNext();
684
		}
685
 
686
		return $results;
687
	}
688
 
689
 
690
	function MoveNext() 
691
	{
692
		if ($this->_numOfRows != 0 && !$this->EOF) {		
693
			$this->_currentRow++;
694
 
695
			if ($this->_has_stupid_odbc_fetch_api_change)
696
				$rez = @odbc_fetch_into($this->_queryID,$this->fields);
697
			else {
698
				$row = 0;
699
				$rez = @odbc_fetch_into($this->_queryID,$row,$this->fields);
700
			}
701
			if ($rez) {
702
				if ($this->fetchMode & ADODB_FETCH_ASSOC) {
703
					$this->fields =& $this->GetRowAssoc(ADODB_ASSOC_CASE);
704
				}
705
				return true;
706
			}
707
		}
708
		$this->fields = false;
709
		$this->EOF = true;
710
		return false;
711
	}	
712
 
713
	function _fetch()
714
	{
715
 
716
		if ($this->_has_stupid_odbc_fetch_api_change)
717
			$rez = @odbc_fetch_into($this->_queryID,$this->fields);
718
		else {
719
			$row = 0;
720
			$rez = @odbc_fetch_into($this->_queryID,$row,$this->fields);
721
		}
722
		if ($rez) {
723
			if ($this->fetchMode & ADODB_FETCH_ASSOC) {
724
				$this->fields =& $this->GetRowAssoc(ADODB_ASSOC_CASE);
725
			}
726
			return true;
727
		}
728
		$this->fields = false;
729
		return false;
730
	}
731
 
732
	function _close() 
733
	{
734
		return @odbc_free_result($this->_queryID);		
735
	}
736
 
737
}
738
?>