1<?php
2/*
3  v4.992 10 Nov 2009  (c) 2000-2009 John Lim (jlim#natsoft.com). 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. See License.txt.
7  Set tabs to 4 for best viewing.
8  Latest version is available at http://adodb.sourceforge.net
9*/
10// Code contributed by "stefan bogdan" <sbogdan#rsb.ro>
11
12// security - hide paths
13if (!defined('ADODB_DIR')) die();
14
15define("_ADODB_ODBTP_LAYER", 2 );
16
17class ADODB_odbtp extends ADOConnection{
18	var $databaseType = "odbtp";
19	var $dataProvider = "odbtp";
20	var $fmtDate = "'Y-m-d'";
21	var $fmtTimeStamp = "'Y-m-d, h:i:sA'";
22	var $replaceQuote = "''"; // string to use to replace quotes
23	var $odbc_driver = 0;
24	var $hasAffectedRows = true;
25	var $hasInsertID = false;
26	var $hasGenID = true;
27	var $hasMoveFirst = true;
28
29	var $_genSeqSQL = "create table %s (seq_name char(30) not null unique , seq_value integer not null)";
30	var $_dropSeqSQL = "delete from adodb_seq where seq_name = '%s'";
31	var $_bindInputArray = false;
32	var $_useUnicodeSQL = false;
33	var $_canPrepareSP = false;
34	var $_dontPoolDBC = true;
35
36	function ADODB_odbtp()
37	{
38	}
39
40	function ServerInfo()
41	{
42		return array('description' => @odbtp_get_attr( ODB_ATTR_DBMSNAME, $this->_connectionID),
43		             'version' => @odbtp_get_attr( ODB_ATTR_DBMSVER, $this->_connectionID));
44	}
45
46	function ErrorMsg()
47	{
48		if (empty($this->_connectionID)) return @odbtp_last_error();
49		return @odbtp_last_error($this->_connectionID);
50	}
51
52	function ErrorNo()
53	{
54		if (empty($this->_connectionID)) return @odbtp_last_error_state();
55			return @odbtp_last_error_state($this->_connectionID);
56	}
57
58	function _insertid()
59	{
60	// SCOPE_IDENTITY()
61	// Returns the last IDENTITY value inserted into an IDENTITY column in
62	// the same scope. A scope is a module -- a stored procedure, trigger,
63	// function, or batch. Thus, two statements are in the same scope if
64	// they are in the same stored procedure, function, or batch.
65			return $this->GetOne($this->identitySQL);
66	}
67
68	function _affectedrows()
69	{
70		if ($this->_queryID) {
71			return @odbtp_affected_rows ($this->_queryID);
72	   } else
73		return 0;
74	}
75
76	function CreateSequence($seqname='adodbseq',$start=1)
77	{
78		//verify existence
79		$num = $this->GetOne("select seq_value from adodb_seq");
80		$seqtab='adodb_seq';
81		if( $this->odbc_driver == ODB_DRIVER_FOXPRO ) {
82			$path = @odbtp_get_attr( ODB_ATTR_DATABASENAME, $this->_connectionID );
83			//if using vfp dbc file
84			if( !strcasecmp(strrchr($path, '.'), '.dbc') )
85                $path = substr($path,0,strrpos($path,'\/'));
86           	$seqtab = $path . '/' . $seqtab;
87        }
88		if($num == false) {
89			if (empty($this->_genSeqSQL)) return false;
90			$ok = $this->Execute(sprintf($this->_genSeqSQL ,$seqtab));
91		}
92		$num = $this->GetOne("select seq_value from adodb_seq where seq_name='$seqname'");
93		if ($num) {
94			return false;
95		}
96		$start -= 1;
97		return $this->Execute("insert into adodb_seq values('$seqname',$start)");
98	}
99
100	function DropSequence($seqname)
101	{
102		if (empty($this->_dropSeqSQL)) return false;
103		return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
104	}
105
106	function GenID($seq='adodbseq',$start=1)
107	{
108		$seqtab='adodb_seq';
109		if( $this->odbc_driver == ODB_DRIVER_FOXPRO) {
110			$path = @odbtp_get_attr( ODB_ATTR_DATABASENAME, $this->_connectionID );
111			//if using vfp dbc file
112			if( !strcasecmp(strrchr($path, '.'), '.dbc') )
113                $path = substr($path,0,strrpos($path,'\/'));
114           	$seqtab = $path . '/' . $seqtab;
115        }
116		$MAXLOOPS = 100;
117		while (--$MAXLOOPS>=0) {
118			$num = $this->GetOne("select seq_value from adodb_seq where seq_name='$seq'");
119			if ($num === false) {
120				//verify if abodb_seq table exist
121				$ok = $this->GetOne("select seq_value from adodb_seq ");
122				if(!$ok) {
123					//creating the sequence table adodb_seq
124					$this->Execute(sprintf($this->_genSeqSQL ,$seqtab));
125				}
126				$start -= 1;
127				$num = '0';
128				$ok = $this->Execute("insert into adodb_seq values('$seq',$start)");
129				if (!$ok) return false;
130			}
131			$ok = $this->Execute("update adodb_seq set seq_value=seq_value+1 where seq_name='$seq'");
132			if($ok) {
133				$num += 1;
134				$this->genID = $num;
135				return $num;
136			}
137		}
138	if ($fn = $this->raiseErrorFn) {
139		$fn($this->databaseType,'GENID',-32000,"Unable to generate unique id after $MAXLOOPS attempts",$seq,$num);
140	}
141		return false;
142	}
143
144	//example for $UserOrDSN
145	//for visual fox : DRIVER={Microsoft Visual FoxPro Driver};SOURCETYPE=DBF;SOURCEDB=c:\YourDbfFileDir;EXCLUSIVE=NO;
146	//for visual fox dbc: DRIVER={Microsoft Visual FoxPro Driver};SOURCETYPE=DBC;SOURCEDB=c:\YourDbcFileDir\mydb.dbc;EXCLUSIVE=NO;
147	//for access : DRIVER={Microsoft Access Driver (*.mdb)};DBQ=c:\path_to_access_db\base_test.mdb;UID=root;PWD=;
148	//for mssql : DRIVER={SQL Server};SERVER=myserver;UID=myuid;PWD=mypwd;DATABASE=OdbtpTest;
149	//if uid & pwd can be separate
150    function _connect($HostOrInterface, $UserOrDSN='', $argPassword='', $argDatabase='')
151	{
152		$this->_connectionID = odbtp_connect($HostOrInterface,$UserOrDSN,$argPassword,$argDatabase);
153		if ($this->_connectionID === false) {
154			$this->_errorMsg = $this->ErrorMsg() ;
155			return false;
156		}
157
158		odbtp_convert_datetime($this->_connectionID,true);
159
160		if ($this->_dontPoolDBC) {
161			if (function_exists('odbtp_dont_pool_dbc'))
162				@odbtp_dont_pool_dbc($this->_connectionID);
163		}
164		else {
165			$this->_dontPoolDBC = true;
166		}
167		$this->odbc_driver = @odbtp_get_attr(ODB_ATTR_DRIVER, $this->_connectionID);
168		$dbms = strtolower(@odbtp_get_attr(ODB_ATTR_DBMSNAME, $this->_connectionID));
169		$this->odbc_name = $dbms;
170
171		// Account for inconsistent DBMS names
172		if( $this->odbc_driver == ODB_DRIVER_ORACLE )
173			$dbms = 'oracle';
174		else if( $this->odbc_driver == ODB_DRIVER_SYBASE )
175			$dbms = 'sybase';
176
177		// Set DBMS specific attributes
178		switch( $dbms ) {
179			case 'microsoft sql server':
180				$this->databaseType = 'odbtp_mssql';
181				$this->fmtDate = "'Y-m-d'";
182				$this->fmtTimeStamp = "'Y-m-d h:i:sA'";
183				$this->sysDate = 'convert(datetime,convert(char,GetDate(),102),102)';
184				$this->sysTimeStamp = 'GetDate()';
185				$this->ansiOuter = true;
186				$this->leftOuter = '*=';
187				$this->rightOuter = '=*';
188                $this->hasTop = 'top';
189				$this->hasInsertID = true;
190				$this->hasTransactions = true;
191				$this->_bindInputArray = true;
192				$this->_canSelectDb = true;
193				$this->substr = "substring";
194				$this->length = 'len';
195				$this->identitySQL = 'select SCOPE_IDENTITY()';
196				$this->metaDatabasesSQL = "select name from master..sysdatabases where name <> 'master'";
197				$this->_canPrepareSP = true;
198				break;
199			case 'access':
200				$this->databaseType = 'odbtp_access';
201				$this->fmtDate = "#Y-m-d#";
202				$this->fmtTimeStamp = "#Y-m-d h:i:sA#";
203				$this->sysDate = "FORMAT(NOW,'yyyy-mm-dd')";
204				$this->sysTimeStamp = 'NOW';
205                $this->hasTop = 'top';
206				$this->hasTransactions = false;
207				$this->_canPrepareSP = true;  // For MS Access only.
208				break;
209			case 'visual foxpro':
210				$this->databaseType = 'odbtp_vfp';
211				$this->fmtDate = "{^Y-m-d}";
212				$this->fmtTimeStamp = "{^Y-m-d, h:i:sA}";
213				$this->sysDate = 'date()';
214				$this->sysTimeStamp = 'datetime()';
215				$this->ansiOuter = true;
216                $this->hasTop = 'top';
217				$this->hasTransactions = false;
218				$this->replaceQuote = "'+chr(39)+'";
219				$this->true = '.T.';
220				$this->false = '.F.';
221
222				break;
223			case 'oracle':
224				$this->databaseType = 'odbtp_oci8';
225				$this->fmtDate = "'Y-m-d 00:00:00'";
226				$this->fmtTimeStamp = "'Y-m-d h:i:sA'";
227				$this->sysDate = 'TRUNC(SYSDATE)';
228				$this->sysTimeStamp = 'SYSDATE';
229				$this->hasTransactions = true;
230				$this->_bindInputArray = true;
231				$this->concat_operator = '||';
232				break;
233			case 'sybase':
234				$this->databaseType = 'odbtp_sybase';
235				$this->fmtDate = "'Y-m-d'";
236				$this->fmtTimeStamp = "'Y-m-d H:i:s'";
237				$this->sysDate = 'GetDate()';
238				$this->sysTimeStamp = 'GetDate()';
239				$this->leftOuter = '*=';
240				$this->rightOuter = '=*';
241				$this->hasInsertID = true;
242				$this->hasTransactions = true;
243				$this->identitySQL = 'select SCOPE_IDENTITY()';
244				break;
245			default:
246				$this->databaseType = 'odbtp';
247				if( @odbtp_get_attr(ODB_ATTR_TXNCAPABLE, $this->_connectionID) )
248					$this->hasTransactions = true;
249				else
250					$this->hasTransactions = false;
251		}
252        @odbtp_set_attr(ODB_ATTR_FULLCOLINFO, TRUE, $this->_connectionID );
253
254		if ($this->_useUnicodeSQL )
255			@odbtp_set_attr(ODB_ATTR_UNICODESQL, TRUE, $this->_connectionID);
256
257        return true;
258	}
259
260	function _pconnect($HostOrInterface, $UserOrDSN='', $argPassword='', $argDatabase='')
261	{
262		$this->_dontPoolDBC = false;
263  		return $this->_connect($HostOrInterface, $UserOrDSN, $argPassword, $argDatabase);
264	}
265
266	function SelectDB($dbName)
267	{
268		if (!@odbtp_select_db($dbName, $this->_connectionID)) {
269			return false;
270		}
271		$this->database = $dbName;
272		$this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
273		return true;
274	}
275
276	function &MetaTables($ttype='',$showSchema=false,$mask=false)
277	{
278	global $ADODB_FETCH_MODE;
279
280		$savem = $ADODB_FETCH_MODE;
281		$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
282		if ($this->fetchMode !== false) $savefm = $this->SetFetchMode(false);
283
284		$arr =& $this->GetArray("||SQLTables||||$ttype");
285
286		if (isset($savefm)) $this->SetFetchMode($savefm);
287		$ADODB_FETCH_MODE = $savem;
288
289		$arr2 = array();
290		for ($i=0; $i < sizeof($arr); $i++) {
291			if ($arr[$i][3] == 'SYSTEM TABLE' )	continue;
292			if ($arr[$i][2])
293				$arr2[] = $showSchema && $arr[$i][1]? $arr[$i][1].'.'.$arr[$i][2] : $arr[$i][2];
294		}
295		return $arr2;
296	}
297
298	function &MetaColumns($table,$upper=true)
299	{
300	global $ADODB_FETCH_MODE;
301
302		$schema = false;
303		$this->_findschema($table,$schema);
304		if ($upper) $table = strtoupper($table);
305
306		$savem = $ADODB_FETCH_MODE;
307		$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
308		if ($this->fetchMode !== false) $savefm = $this->SetFetchMode(false);
309
310		$rs = $this->Execute( "||SQLColumns||$schema|$table" );
311
312		if (isset($savefm)) $this->SetFetchMode($savefm);
313		$ADODB_FETCH_MODE = $savem;
314
315		if (!$rs || $rs->EOF) {
316			$false = false;
317			return $false;
318		}
319		$retarr = array();
320		while (!$rs->EOF) {
321			//print_r($rs->fields);
322			if (strtoupper($rs->fields[2]) == $table) {
323				$fld = new ADOFieldObject();
324				$fld->name = $rs->fields[3];
325				$fld->type = $rs->fields[5];
326				$fld->max_length = $rs->fields[6];
327    			$fld->not_null = !empty($rs->fields[9]);
328 				$fld->scale = $rs->fields[7];
329				if (isset($rs->fields[12])) // vfp does not have field 12
330	 				if (!is_null($rs->fields[12])) {
331	 					$fld->has_default = true;
332	 					$fld->default_value = $rs->fields[12];
333					}
334				$retarr[strtoupper($fld->name)] = $fld;
335			} else if (!empty($retarr))
336				break;
337			$rs->MoveNext();
338		}
339		$rs->Close();
340
341		return $retarr;
342	}
343
344	function &MetaPrimaryKeys($table, $owner='')
345	{
346	global $ADODB_FETCH_MODE;
347
348		$savem = $ADODB_FETCH_MODE;
349		$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
350		$arr =& $this->GetArray("||SQLPrimaryKeys||$owner|$table");
351		$ADODB_FETCH_MODE = $savem;
352
353		//print_r($arr);
354		$arr2 = array();
355		for ($i=0; $i < sizeof($arr); $i++) {
356			if ($arr[$i][3]) $arr2[] = $arr[$i][3];
357		}
358		return $arr2;
359	}
360
361	function &MetaForeignKeys($table, $owner='', $upper=false)
362	{
363	global $ADODB_FETCH_MODE;
364
365		$savem = $ADODB_FETCH_MODE;
366		$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
367		$constraints =& $this->GetArray("||SQLForeignKeys|||||$owner|$table");
368		$ADODB_FETCH_MODE = $savem;
369
370		$arr = false;
371		foreach($constraints as $constr) {
372			//print_r($constr);
373			$arr[$constr[11]][$constr[2]][] = $constr[7].'='.$constr[3];
374		}
375		if (!$arr) {
376			$false = false;
377			return $false;
378		}
379
380		$arr2 = array();
381
382		foreach($arr as $k => $v) {
383			foreach($v as $a => $b) {
384				if ($upper) $a = strtoupper($a);
385				$arr2[$a] = $b;
386			}
387		}
388		return $arr2;
389	}
390
391	function BeginTrans()
392	{
393		if (!$this->hasTransactions) return false;
394		if ($this->transOff) return true;
395		$this->transCnt += 1;
396		$this->autoCommit = false;
397		if (defined('ODB_TXN_DEFAULT'))
398			$txn = ODB_TXN_DEFAULT;
399		else
400			$txn = ODB_TXN_READUNCOMMITTED;
401		$rs = @odbtp_set_attr(ODB_ATTR_TRANSACTIONS,$txn,$this->_connectionID);
402		if(!$rs) return false;
403		return true;
404	}
405
406	function CommitTrans($ok=true)
407	{
408		if ($this->transOff) return true;
409		if (!$ok) return $this->RollbackTrans();
410		if ($this->transCnt) $this->transCnt -= 1;
411		$this->autoCommit = true;
412		if( ($ret = @odbtp_commit($this->_connectionID)) )
413			$ret = @odbtp_set_attr(ODB_ATTR_TRANSACTIONS, ODB_TXN_NONE, $this->_connectionID);//set transaction off
414		return $ret;
415	}
416
417	function RollbackTrans()
418	{
419		if ($this->transOff) return true;
420		if ($this->transCnt) $this->transCnt -= 1;
421		$this->autoCommit = true;
422		if( ($ret = @odbtp_rollback($this->_connectionID)) )
423			$ret = @odbtp_set_attr(ODB_ATTR_TRANSACTIONS, ODB_TXN_NONE, $this->_connectionID);//set transaction off
424		return $ret;
425	}
426
427	function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
428	{
429		// TOP requires ORDER BY for Visual FoxPro
430		if( $this->odbc_driver == ODB_DRIVER_FOXPRO ) {
431			if (!preg_match('/ORDER[ \t\r\n]+BY/is',$sql)) $sql .= ' ORDER BY 1';
432		}
433		$ret =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
434		return $ret;
435	}
436
437	function Prepare($sql)
438	{
439		if (! $this->_bindInputArray) return $sql; // no binding
440		$stmt = @odbtp_prepare($sql,$this->_connectionID);
441		if (!$stmt) {
442		//	print "Prepare Error for ($sql) ".$this->ErrorMsg()."<br>";
443			return $sql;
444		}
445		return array($sql,$stmt,false);
446	}
447
448	function PrepareSP($sql)
449	{
450		if (!$this->_canPrepareSP) return $sql; // Can't prepare procedures
451
452		$stmt = @odbtp_prepare_proc($sql,$this->_connectionID);
453		if (!$stmt) return false;
454		return array($sql,$stmt);
455	}
456
457	/*
458	Usage:
459		$stmt = $db->PrepareSP('SP_RUNSOMETHING'); -- takes 2 params, @myid and @group
460
461		# note that the parameter does not have @ in front!
462		$db->Parameter($stmt,$id,'myid');
463		$db->Parameter($stmt,$group,'group',false,64);
464		$db->Parameter($stmt,$group,'photo',false,100000,ODB_BINARY);
465		$db->Execute($stmt);
466
467		@param $stmt Statement returned by Prepare() or PrepareSP().
468		@param $var PHP variable to bind to. Can set to null (for isNull support).
469		@param $name Name of stored procedure variable name to bind to.
470		@param [$isOutput] Indicates direction of parameter 0/false=IN  1=OUT  2= IN/OUT. This is ignored in odbtp.
471		@param [$maxLen] Holds an maximum length of the variable.
472		@param [$type] The data type of $var. Legal values depend on driver.
473
474		See odbtp_attach_param documentation at http://odbtp.sourceforge.net.
475	*/
476	function Parameter(&$stmt, &$var, $name, $isOutput=false, $maxLen=0, $type=0)
477	{
478		if ( $this->odbc_driver == ODB_DRIVER_JET ) {
479			$name = '['.$name.']';
480			if( !$type && $this->_useUnicodeSQL
481				&& @odbtp_param_bindtype($stmt[1], $name) == ODB_CHAR )
482			{
483				$type = ODB_WCHAR;
484			}
485		}
486		else {
487			$name = '@'.$name;
488		}
489		return @odbtp_attach_param($stmt[1], $name, $var, $type, $maxLen);
490	}
491
492	/*
493		Insert a null into the blob field of the table first.
494		Then use UpdateBlob to store the blob.
495
496		Usage:
497
498		$conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
499		$conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
500	*/
501
502	function UpdateBlob($table,$column,$val,$where,$blobtype='image')
503	{
504		$sql = "UPDATE $table SET $column = ? WHERE $where";
505		if( !($stmt = @odbtp_prepare($sql, $this->_connectionID)) )
506			return false;
507		if( !@odbtp_input( $stmt, 1, ODB_BINARY, 1000000, $blobtype ) )
508			return false;
509		if( !@odbtp_set( $stmt, 1, $val ) )
510			return false;
511		return @odbtp_execute( $stmt ) != false;
512	}
513
514	function IfNull( $field, $ifNull )
515	{
516		switch( $this->odbc_driver ) {
517			case ODB_DRIVER_MSSQL:
518				return " ISNULL($field, $ifNull) ";
519			case ODB_DRIVER_JET:
520				return " IIF(IsNull($field), $ifNull, $field) ";
521		}
522		return " CASE WHEN $field is null THEN $ifNull ELSE $field END ";
523	}
524
525	function _query($sql,$inputarr=false)
526	{
527	global $php_errormsg;
528
529 		if ($inputarr) {
530			if (is_array($sql)) {
531				$stmtid = $sql[1];
532			} else {
533				$stmtid = @odbtp_prepare($sql,$this->_connectionID);
534				if ($stmtid == false) {
535					$this->_errorMsg = $php_errormsg;
536					return false;
537				}
538			}
539			$num_params = @odbtp_num_params( $stmtid );
540			for( $param = 1; $param <= $num_params; $param++ ) {
541				@odbtp_input( $stmtid, $param );
542				@odbtp_set( $stmtid, $param, $inputarr[$param-1] );
543			}
544			if (!@odbtp_execute($stmtid) ) {
545				return false;
546			}
547		} else if (is_array($sql)) {
548			$stmtid = $sql[1];
549			if (!@odbtp_execute($stmtid)) {
550				return false;
551			}
552		} else {
553			$stmtid = odbtp_query($sql,$this->_connectionID);
554   		}
555		$this->_lastAffectedRows = 0;
556		if ($stmtid) {
557				$this->_lastAffectedRows = @odbtp_affected_rows($stmtid);
558		}
559        return $stmtid;
560	}
561
562	function _close()
563	{
564		$ret = @odbtp_close($this->_connectionID);
565		$this->_connectionID = false;
566		return $ret;
567	}
568}
569
570class ADORecordSet_odbtp extends ADORecordSet {
571
572	var $databaseType = 'odbtp';
573	var $canSeek = true;
574
575	function ADORecordSet_odbtp($queryID,$mode=false)
576	{
577		if ($mode === false) {
578			global $ADODB_FETCH_MODE;
579			$mode = $ADODB_FETCH_MODE;
580		}
581		$this->fetchMode = $mode;
582		$this->ADORecordSet($queryID);
583	}
584
585	function _initrs()
586	{
587		$this->_numOfFields = @odbtp_num_fields($this->_queryID);
588		if (!($this->_numOfRows = @odbtp_num_rows($this->_queryID)))
589			$this->_numOfRows = -1;
590
591		if (!$this->connection->_useUnicodeSQL) return;
592
593		if ($this->connection->odbc_driver == ODB_DRIVER_JET) {
594			if (!@odbtp_get_attr(ODB_ATTR_MAPCHARTOWCHAR,
595			                     $this->connection->_connectionID))
596			{
597				for ($f = 0; $f < $this->_numOfFields; $f++) {
598					if (@odbtp_field_bindtype($this->_queryID, $f) == ODB_CHAR)
599						@odbtp_bind_field($this->_queryID, $f, ODB_WCHAR);
600				}
601			}
602		}
603	}
604
605	function &FetchField($fieldOffset = 0)
606	{
607		$off=$fieldOffset; // offsets begin at 0
608		$o= new ADOFieldObject();
609		$o->name = @odbtp_field_name($this->_queryID,$off);
610		$o->type = @odbtp_field_type($this->_queryID,$off);
611        $o->max_length = @odbtp_field_length($this->_queryID,$off);
612		if (ADODB_ASSOC_CASE == 0) $o->name = strtolower($o->name);
613		else if (ADODB_ASSOC_CASE == 1) $o->name = strtoupper($o->name);
614		return $o;
615	}
616
617	function _seek($row)
618	{
619		return @odbtp_data_seek($this->_queryID, $row);
620	}
621
622	function fields($colname)
623	{
624		if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname];
625
626		if (!$this->bind) {
627			$this->bind = array();
628			for ($i=0; $i < $this->_numOfFields; $i++) {
629				$name = @odbtp_field_name( $this->_queryID, $i );
630				$this->bind[strtoupper($name)] = $i;
631			}
632		}
633		return $this->fields[$this->bind[strtoupper($colname)]];
634	}
635
636	function _fetch_odbtp($type=0)
637	{
638		switch ($this->fetchMode) {
639			case ADODB_FETCH_NUM:
640				$this->fields = @odbtp_fetch_row($this->_queryID, $type);
641				break;
642			case ADODB_FETCH_ASSOC:
643				$this->fields = @odbtp_fetch_assoc($this->_queryID, $type);
644				break;
645            default:
646				$this->fields = @odbtp_fetch_array($this->_queryID, $type);
647		}
648		if ($this->databaseType = 'odbtp_vfp') {
649			if ($this->fields)
650			foreach($this->fields as $k => $v) {
651				if (strncmp($v,'1899-12-30',10) == 0) $this->fields[$k] = '';
652			}
653		}
654		return is_array($this->fields);
655	}
656
657	function _fetch()
658	{
659		return $this->_fetch_odbtp();
660	}
661
662	function MoveFirst()
663	{
664		if (!$this->_fetch_odbtp(ODB_FETCH_FIRST)) return false;
665		$this->EOF = false;
666		$this->_currentRow = 0;
667		return true;
668    }
669
670	function MoveLast()
671	{
672		if (!$this->_fetch_odbtp(ODB_FETCH_LAST)) return false;
673		$this->EOF = false;
674		$this->_currentRow = $this->_numOfRows - 1;
675		return true;
676	}
677
678	function NextRecordSet()
679	{
680		if (!@odbtp_next_result($this->_queryID)) return false;
681		$this->_inited = false;
682		$this->bind = false;
683		$this->_currentRow = -1;
684		$this->Init();
685		return true;
686	}
687
688	function _close()
689	{
690		return @odbtp_free_query($this->_queryID);
691	}
692}
693
694class ADORecordSet_odbtp_mssql extends ADORecordSet_odbtp {
695
696	var $databaseType = 'odbtp_mssql';
697
698	function ADORecordSet_odbtp_mssql($id,$mode=false)
699	{
700		return $this->ADORecordSet_odbtp($id,$mode);
701	}
702}
703
704class ADORecordSet_odbtp_access extends ADORecordSet_odbtp {
705
706	var $databaseType = 'odbtp_access';
707
708	function ADORecordSet_odbtp_access($id,$mode=false)
709	{
710		return $this->ADORecordSet_odbtp($id,$mode);
711	}
712}
713
714class ADORecordSet_odbtp_vfp extends ADORecordSet_odbtp {
715
716	var $databaseType = 'odbtp_vfp';
717
718	function ADORecordSet_odbtp_vfp($id,$mode=false)
719	{
720		return $this->ADORecordSet_odbtp($id,$mode);
721	}
722}
723
724class ADORecordSet_odbtp_oci8 extends ADORecordSet_odbtp {
725
726	var $databaseType = 'odbtp_oci8';
727
728	function ADORecordSet_odbtp_oci8($id,$mode=false)
729	{
730		return $this->ADORecordSet_odbtp($id,$mode);
731	}
732}
733
734class ADORecordSet_odbtp_sybase extends ADORecordSet_odbtp {
735
736	var $databaseType = 'odbtp_sybase';
737
738	function ADORecordSet_odbtp_sybase($id,$mode=false)
739	{
740		return $this->ADORecordSet_odbtp($id,$mode);
741	}
742}
743?>
744