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