1<?php
2/*
3V4.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.
7Set 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
14if (!defined('ADODB_DIR')) die();
15
16  define("_ADODB_ODBC_LAYER", 2 );
17
18/*--------------------------------------------------------------------------------------
19--------------------------------------------------------------------------------------*/
20
21
22class 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/*
306See 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		0 TABLE_QUALIFIER
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
591class 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?>