]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/WikiDB/adodb/drivers/adodb-ibase.inc.php
Reformat code
[SourceForge/phpwiki.git] / lib / WikiDB / adodb / drivers / adodb-ibase.inc.php
1 <?php
2 /*
3 V4.22 15 Apr 2004  (c) 2000-2004 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
8   Latest version is available at http://php.weblogs.com/
9
10   Interbase data driver. Requires interbase client. Works on Windows and Unix.
11
12   3 Jan 2002 -- suggestions by Hans-Peter Oeri <kampfcaspar75@oeri.ch>
13       changed transaction handling and added experimental blob stuff
14
15   Docs to interbase at the website
16    http://www.synectics.co.za/php3/tutorial/IB_PHP3_API.html
17
18   To use gen_id(), see
19    http://www.volny.cz/iprenosil/interbase/ip_ib_code.htm#_code_creategen
20
21    $rs = $conn->Execute('select gen_id(adodb,1) from rdb$database');
22    $id = $rs->fields[0];
23    $conn->Execute("insert into table (id, col1,...) values ($id, $val1,...)");
24 */
25
26 class ADODB_ibase extends ADOConnection
27 {
28     var $databaseType = "ibase";
29     var $dataProvider = "ibase";
30     var $replaceQuote = "''"; // string to use to replace quotes
31     var $ibase_timefmt = '%Y-%m-%d'; // For hours,mins,secs change to '%Y-%m-%d %H:%M:%S';
32     var $fmtDate = "'Y-m-d'";
33     var $fmtTimeStamp = "'Y-m-d, H:i:s'";
34     var $concat_operator = '||';
35     var $_transactionID;
36     var $metaTablesSQL = "select rdb\$relation_name from rdb\$relations where rdb\$relation_name not like 'RDB\$%'";
37     //OPN STUFF start
38     var $metaColumnsSQL = "select a.rdb\$field_name, a.rdb\$null_flag, a.rdb\$default_source, b.rdb\$field_length, b.rdb\$field_scale, b.rdb\$field_sub_type, b.rdb\$field_precision, b.rdb\$field_type from rdb\$relation_fields a, rdb\$fields b where a.rdb\$field_source = b.rdb\$field_name and a.rdb\$relation_name = '%s' order by a.rdb\$field_position asc";
39     //OPN STUFF end
40     var $ibasetrans;
41     var $hasGenID = true;
42     var $_bindInputArray = true;
43     var $buffers = 0;
44     var $dialect = 1;
45     var $sysDate = "cast('TODAY' as date)";
46     var $sysTimeStamp = "cast('NOW' as timestamp)";
47     var $ansiOuter = true;
48     var $hasAffectedRows = false;
49     var $poorAffectedRows = true;
50     var $blobEncodeType = 'C';
51
52     function ADODB_ibase()
53     {
54         if (defined('IBASE_DEFAULT')) $this->ibasetrans = IBASE_DEFAULT;
55     }
56
57     function MetaPrimaryKeys($table, $owner_notused = false, $internalKey = false)
58     {
59         if ($internalKey) return array('RDB$DB_KEY');
60
61         $table = strtoupper($table);
62
63         $sql = 'SELECT S.RDB$FIELD_NAME AFIELDNAME
64     FROM RDB$INDICES I JOIN RDB$INDEX_SEGMENTS S ON I.RDB$INDEX_NAME=S.RDB$INDEX_NAME
65     WHERE I.RDB$RELATION_NAME=\'' . $table . '\' and I.RDB$INDEX_NAME like \'RDB$PRIMARY%\'
66     ORDER BY I.RDB$INDEX_NAME,S.RDB$FIELD_POSITION';
67
68         $a = $this->GetCol($sql, false, true);
69         if ($a && sizeof($a) > 0) return $a;
70         return false;
71     }
72
73     function ServerInfo()
74     {
75         $arr['dialect'] = $this->dialect;
76         switch ($arr['dialect']) {
77             case '':
78             case '1':
79                 $s = 'Interbase 5.5 or earlier';
80                 break;
81             case '2':
82                 $s = 'Interbase 5.6';
83                 break;
84             default:
85             case '3':
86                 $s = 'Interbase 6.0';
87                 break;
88         }
89         $arr['version'] = ADOConnection::_findvers($s);
90         $arr['description'] = $s;
91         return $arr;
92     }
93
94     function BeginTrans()
95     {
96         if ($this->transOff) return true;
97         $this->transCnt += 1;
98         $this->autoCommit = false;
99         $this->_transactionID = $this->_connectionID; //ibase_trans($this->ibasetrans, $this->_connectionID);
100         return $this->_transactionID;
101     }
102
103     function CommitTrans($ok = true)
104     {
105         if (!$ok) return $this->RollbackTrans();
106         if ($this->transOff) return true;
107         if ($this->transCnt) $this->transCnt -= 1;
108         $ret = false;
109         $this->autoCommit = true;
110         if ($this->_transactionID) {
111             //print ' commit ';
112             $ret = ibase_commit($this->_transactionID);
113         }
114         $this->_transactionID = false;
115         return $ret;
116     }
117
118     function RollbackTrans()
119     {
120         if ($this->transOff) return true;
121         if ($this->transCnt) $this->transCnt -= 1;
122         $ret = false;
123         $this->autoCommit = true;
124         if ($this->_transactionID)
125             $ret = ibase_rollback($this->_transactionID);
126         $this->_transactionID = false;
127
128         return $ret;
129     }
130
131     function &MetaIndexes($table, $primary = FALSE, $owner = false)
132     {
133         // save old fetch mode
134         global $ADODB_FETCH_MODE;
135
136         $save = $ADODB_FETCH_MODE;
137         $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
138         if ($this->fetchMode !== FALSE) {
139             $savem = $this->SetFetchMode(FALSE);
140         }
141         $table = strtoupper($table);
142         $sql = "SELECT * FROM RDB\$INDICES WHERE RDB\$RELATION_NAME = '" . $table . "'";
143         if (!$primary) {
144             $sql .= " AND RDB\$INDEX_NAME NOT LIKE 'RDB\$%'";
145         } else {
146             $sql .= " AND RDB\$INDEX_NAME NOT LIKE 'RDB\$FOREIGN%'";
147         }
148         // get index details
149         $rs = $this->Execute($sql);
150         if (!is_object($rs)) {
151             // restore fetchmode
152             if (isset($savem)) {
153                 $this->SetFetchMode($savem);
154             }
155             $ADODB_FETCH_MODE = $save;
156             return FALSE;
157         }
158
159         $indexes = array();
160         while ($row = $rs->FetchRow()) {
161             $index = $row[0];
162             if (!isset($indexes[$index])) {
163                 if (is_null($row[3])) {
164                     $row[3] = 0;
165                 }
166                 $indexes[$index] = array(
167                     'unique' => ($row[3] == 1),
168                     'columns' => array()
169                 );
170             }
171             $sql = "SELECT * FROM RDB\$INDEX_SEGMENTS WHERE RDB\$INDEX_NAME = '" . $name . "' ORDER BY RDB\$FIELD_POSITION ASC";
172             $rs1 = $this->Execute($sql);
173             while ($row1 = $rs1->FetchRow()) {
174                 $indexes[$index]['columns'][$row1[2]] = $row1[1];
175             }
176         }
177         // restore fetchmode
178         if (isset($savem)) {
179             $this->SetFetchMode($savem);
180         }
181         $ADODB_FETCH_MODE = $save;
182
183         return $indexes;
184     }
185
186     // See http://community.borland.com/article/0,1410,25844,00.html
187     function RowLock($tables, $where, $col)
188     {
189         if ($this->autoCommit) $this->BeginTrans();
190         $this->Execute("UPDATE $table SET $col=$col WHERE $where "); // is this correct - jlim?
191         return 1;
192     }
193
194     function CreateSequence($seqname, $startID = 1)
195     {
196         $ok = $this->Execute(("INSERT INTO RDB\$GENERATORS (RDB\$GENERATOR_NAME) VALUES (UPPER('$seqname'))"));
197         if (!$ok) return false;
198         return $this->Execute("SET GENERATOR $seqname TO " . ($startID - 1) . ';');
199     }
200
201     function DropSequence($seqname)
202     {
203         $seqname = strtoupper($seqname);
204         $this->Execute("delete from RDB\$GENERATORS where RDB\$GENERATOR_NAME='$seqname'");
205     }
206
207     function GenID($seqname = 'adodbseq', $startID = 1)
208     {
209         $getnext = ("SELECT Gen_ID($seqname,1) FROM RDB\$DATABASE");
210         $rs = @$this->Execute($getnext);
211         if (!$rs) {
212             $this->Execute(("INSERT INTO RDB\$GENERATORS (RDB\$GENERATOR_NAME) VALUES (UPPER('$seqname'))"));
213             $this->Execute("SET GENERATOR $seqname TO " . ($startID - 1) . ';');
214             $rs = $this->Execute($getnext);
215         }
216         if ($rs && !$rs->EOF) $this->genID = (integer)reset($rs->fields);
217         else $this->genID = 0; // false
218
219         if ($rs) $rs->Close();
220
221         return $this->genID;
222     }
223
224     function SelectDB($dbName)
225     {
226         return false;
227     }
228
229     function _handleerror()
230     {
231         $this->_errorMsg = ibase_errmsg();
232     }
233
234     function ErrorNo()
235     {
236         if (preg_match('/error code = ([\-0-9]*)/i', $this->_errorMsg, $arr)) return (integer)$arr[1];
237         else return 0;
238     }
239
240     function ErrorMsg()
241     {
242         return $this->_errorMsg;
243     }
244
245     // returns true or false
246     function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
247     {
248         if (!function_exists('ibase_pconnect')) return false;
249         if ($argDatabasename) $argHostname .= ':' . $argDatabasename;
250         $this->_connectionID = ibase_connect($argHostname, $argUsername, $argPassword, $this->charSet, $this->buffers, $this->dialect);
251         if ($this->dialect != 1) { // http://www.ibphoenix.com/ibp_60_del_id_ds.html
252             $this->replaceQuote = "''";
253         }
254         if ($this->_connectionID === false) {
255             $this->_handleerror();
256             return false;
257         }
258
259         ibase_timefmt($this->ibase_timefmt);
260         return true;
261     }
262
263     // returns true or false
264     function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
265     {
266         if (!function_exists('ibase_pconnect')) return false;
267         if ($argDatabasename) $argHostname .= ':' . $argDatabasename;
268         $this->_connectionID = ibase_pconnect($argHostname, $argUsername, $argPassword, $this->charSet, $this->buffers, $this->dialect);
269         if ($this->dialect != 1) { // http://www.ibphoenix.com/ibp_60_del_id_ds.html
270             $this->replaceQuote = "''";
271         }
272         if ($this->_connectionID === false) {
273             $this->_handleerror();
274             return false;
275         }
276
277         ibase_timefmt($this->ibase_timefmt);
278         return true;
279     }
280
281     function Prepare($sql)
282     {
283         $stmt = ibase_prepare($this->_connectionID, $sql);
284         if (!$stmt) return false;
285         return array($sql, $stmt);
286     }
287
288     // returns query ID if successful, otherwise false
289     // there have been reports of problems with nested queries - the code is probably not re-entrant?
290     function _query($sql, $iarr = false)
291     {
292
293         if (!$this->autoCommit && $this->_transactionID) {
294             $conn = $this->_transactionID;
295             $docommit = false;
296         } else {
297             $conn = $this->_connectionID;
298             $docommit = true;
299         }
300         if (is_array($sql)) {
301             $fn = 'ibase_execute';
302             $sql = $sql[1];
303
304             if (is_array($iarr)) {
305                 if (ADODB_PHPVER >= 0x4050) { // actually 4.0.4
306                     if (!isset($iarr[0])) $iarr[0] = ''; // PHP5 compat hack
307                     $fnarr =& array_merge(array($sql), $iarr);
308                     $ret = call_user_func_array($fn, $fnarr);
309                 } else {
310                     switch (sizeof($iarr)) {
311                         case 1:
312                             $ret = $fn($sql, $iarr[0]);
313                             break;
314                         case 2:
315                             $ret = $fn($sql, $iarr[0], $iarr[1]);
316                             break;
317                         case 3:
318                             $ret = $fn($sql, $iarr[0], $iarr[1], $iarr[2]);
319                             break;
320                         case 4:
321                             $ret = $fn($sql, $iarr[0], $iarr[1], $iarr[2], $iarr[3]);
322                             break;
323                         case 5:
324                             $ret = $fn($sql, $iarr[0], $iarr[1], $iarr[2], $iarr[3], $iarr[4]);
325                             break;
326                         case 6:
327                             $ret = $fn($sql, $iarr[0], $iarr[1], $iarr[2], $iarr[3], $iarr[4], $iarr[5]);
328                             break;
329                         case 7:
330                             $ret = $fn($sql, $iarr[0], $iarr[1], $iarr[2], $iarr[3], $iarr[4], $iarr[5], $iarr[6]);
331                             break;
332                         default:
333                             ADOConnection::outp("Too many parameters to ibase query $sql");
334                         case 8:
335                             $ret = $fn($sql, $iarr[0], $iarr[1], $iarr[2], $iarr[3], $iarr[4], $iarr[5], $iarr[6], $iarr[7]);
336                             break;
337                     }
338                 }
339             } else $ret = $fn($sql);
340         } else {
341             $fn = 'ibase_query';
342
343             if (is_array($iarr)) {
344                 if (ADODB_PHPVER >= 0x4050) { // actually 4.0.4
345                     if (!isset($iarr[0])) $iarr[0] = ''; // PHP5 compat hack
346                     $fnarr =& array_merge(array($conn, $sql), $iarr);
347                     $ret = call_user_func_array($fn, $fnarr);
348                 } else {
349                     switch (sizeof($iarr)) {
350                         case 1:
351                             $ret = $fn($conn, $sql, $iarr[0]);
352                             break;
353                         case 2:
354                             $ret = $fn($conn, $sql, $iarr[0], $iarr[1]);
355                             break;
356                         case 3:
357                             $ret = $fn($conn, $sql, $iarr[0], $iarr[1], $iarr[2]);
358                             break;
359                         case 4:
360                             $ret = $fn($conn, $sql, $iarr[0], $iarr[1], $iarr[2], $iarr[3]);
361                             break;
362                         case 5:
363                             $ret = $fn($conn, $sql, $iarr[0], $iarr[1], $iarr[2], $iarr[3], $iarr[4]);
364                             break;
365                         case 6:
366                             $ret = $fn($conn, $sql, $iarr[0], $iarr[1], $iarr[2], $iarr[3], $iarr[4], $iarr[5]);
367                             break;
368                         case 7:
369                             $ret = $fn($conn, $sql, $iarr[0], $iarr[1], $iarr[2], $iarr[3], $iarr[4], $iarr[5], $iarr[6]);
370                             break;
371                         default:
372                             ADOConnection::outp("Too many parameters to ibase query $sql");
373                         case 8:
374                             $ret = $fn($conn, $sql, $iarr[0], $iarr[1], $iarr[2], $iarr[3], $iarr[4], $iarr[5], $iarr[6], $iarr[7]);
375                             break;
376                     }
377                 }
378             } else $ret = $fn($conn, $sql);
379         }
380         if ($docommit && $ret === true) ibase_commit($this->_connectionID);
381
382         $this->_handleerror();
383         return $ret;
384     }
385
386     // returns true or false
387     function _close()
388     {
389         if (!$this->autoCommit) @ibase_rollback($this->_connectionID);
390         return @ibase_close($this->_connectionID);
391     }
392
393     //OPN STUFF start
394     function _ConvertFieldType(&$fld, $ftype, $flen, $fscale, $fsubtype, $fprecision, $isInterbase6)
395     {
396         $fscale = abs($fscale);
397         $fld->max_length = $flen;
398         $fld->scale = null;
399         switch ($ftype) {
400             case 7:
401             case 8:
402                 if ($isInterbase6) {
403                     switch ($fsubtype) {
404                         case 0:
405                             $fld->type = ($ftype == 7 ? 'smallint' : 'integer');
406                             break;
407                         case 1:
408                             $fld->type = 'numeric';
409                             $fld->max_length = $fprecision;
410                             $fld->scale = $fscale;
411                             break;
412                         case 2:
413                             $fld->type = 'decimal';
414                             $fld->max_length = $fprecision;
415                             $fld->scale = $fscale;
416                             break;
417                     } // switch
418                 } else {
419                     if ($fscale != 0) {
420                         $fld->type = 'decimal';
421                         $fld->scale = $fscale;
422                         $fld->max_length = ($ftype == 7 ? 4 : 9);
423                     } else {
424                         $fld->type = ($ftype == 7 ? 'smallint' : 'integer');
425                     }
426                 }
427                 break;
428             case 16:
429                 if ($isInterbase6) {
430                     switch ($fsubtype) {
431                         case 0:
432                             $fld->type = 'decimal';
433                             $fld->max_length = 18;
434                             $fld->scale = 0;
435                             break;
436                         case 1:
437                             $fld->type = 'numeric';
438                             $fld->max_length = $fprecision;
439                             $fld->scale = $fscale;
440                             break;
441                         case 2:
442                             $fld->type = 'decimal';
443                             $fld->max_length = $fprecision;
444                             $fld->scale = $fscale;
445                             break;
446                     } // switch
447                 }
448                 break;
449             case 10:
450                 $fld->type = 'float';
451                 break;
452             case 14:
453                 $fld->type = 'char';
454                 break;
455             case 27:
456                 if ($fscale != 0) {
457                     $fld->type = 'decimal';
458                     $fld->max_length = 15;
459                     $fld->scale = 5;
460                 } else {
461                     $fld->type = 'double';
462                 }
463                 break;
464             case 35:
465                 if ($isInterbase6) {
466                     $fld->type = 'timestamp';
467                 } else {
468                     $fld->type = 'date';
469                 }
470                 break;
471             case 12:
472             case 13:
473                 $fld->type = 'date';
474                 break;
475             case 37:
476                 $fld->type = 'varchar';
477                 break;
478             case 40:
479                 $fld->type = 'cstring';
480                 break;
481             case 261:
482                 $fld->type = 'blob';
483                 $fld->max_length = -1;
484                 break;
485         } // switch
486     }
487
488     //OPN STUFF end
489     // returns array of ADOFieldObjects for current table
490     function &MetaColumns($table)
491     {
492         global $ADODB_FETCH_MODE;
493
494         if ($this->metaColumnsSQL) {
495
496             $save = $ADODB_FETCH_MODE;
497             $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
498
499             $rs = $this->Execute(sprintf($this->metaColumnsSQL, strtoupper($table)));
500
501             $ADODB_FETCH_MODE = $save;
502             if ($rs === false) return false;
503
504             $retarr = array();
505             //OPN STUFF start
506             $isInterbase6 = ($this->dialect == 3 ? true : false);
507             //OPN STUFF end
508             while (!$rs->EOF) { //print_r($rs->fields);
509                 $fld = new ADOFieldObject();
510                 $fld->name = trim($rs->fields[0]);
511                 //OPN STUFF start
512                 $this->_ConvertFieldType($fld, $rs->fields[7], $rs->fields[3], $rs->fields[4], $rs->fields[5], $rs->fields[6], $isInterbase6);
513                 if (isset($rs->fields[1]) && $rs->fields[1]) {
514                     $fld->not_null = true;
515                 }
516                 if (isset($rs->fields[2])) {
517
518                     $fld->has_default = true;
519                     $d = substr($rs->fields[2], strlen('default '));
520                     switch ($fld->type) {
521                         case 'smallint':
522                         case 'integer':
523                             $fld->default_value = (int)$d;
524                             break;
525                         case 'char':
526                         case 'blob':
527                         case 'text':
528                         case 'varchar':
529                             $fld->default_value = (string)substr($d, 1, strlen($d) - 2);
530                             break;
531                         case 'double':
532                         case 'float':
533                             $fld->default_value = (float)$d;
534                             break;
535                         default:
536                             $fld->default_value = $d;
537                             break;
538                     }
539                     //  case 35:$tt = 'TIMESTAMP'; break;
540                 }
541                 if ((isset($rs->fields[5])) && ($fld->type == 'blob')) {
542                     $fld->sub_type = $rs->fields[5];
543                 } else {
544                     $fld->sub_type = null;
545                 }
546                 //OPN STUFF end
547                 if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;
548                 else $retarr[strtoupper($fld->name)] = $fld;
549
550                 $rs->MoveNext();
551             }
552             $rs->Close();
553             return $retarr;
554         }
555         return false;
556     }
557
558     function BlobEncode($blob)
559     {
560         $blobid = ibase_blob_create($this->_connectionID);
561         ibase_blob_add($blobid, $blob);
562         return ibase_blob_close($blobid);
563     }
564
565     // since we auto-decode all blob's since 2.42,
566     // BlobDecode should not do any transforms
567     function BlobDecode($blob)
568     {
569         return $blob;
570     }
571
572
573     // old blobdecode function
574     // still used to auto-decode all blob's
575     function _BlobDecode($blob)
576     {
577         $blobid = ibase_blob_open($blob);
578         $realblob = ibase_blob_get($blobid, $this->maxblobsize); // 2nd param is max size of blob -- Kevin Boillet <kevinboillet@yahoo.fr>
579         while ($string = ibase_blob_get($blobid, 8192)) {
580             $realblob .= $string;
581         }
582         ibase_blob_close($blobid);
583
584         return ($realblob);
585     }
586
587     function UpdateBlobFile($table, $column, $path, $where, $blobtype = 'BLOB')
588     {
589         $fd = fopen($path, 'rb');
590         if ($fd === false) return false;
591         $blob_id = ibase_blob_create($this->_connectionID);
592
593         /* fill with data */
594
595         while ($val = fread($fd, 32768)) {
596             ibase_blob_add($blob_id, $val);
597         }
598
599         /* close and get $blob_id_str for inserting into table */
600         $blob_id_str = ibase_blob_close($blob_id);
601
602         fclose($fd);
603         return $this->Execute("UPDATE $table SET $column=(?) WHERE $where", array($blob_id_str)) != false;
604     }
605
606     /*
607         Insert a null into the blob field of the table first.
608         Then use UpdateBlob to store the blob.
609
610         Usage:
611
612         $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
613         $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
614     */
615     function UpdateBlob($table, $column, $val, $where, $blobtype = 'BLOB')
616     {
617         $blob_id = ibase_blob_create($this->_connectionID);
618
619         // ibase_blob_add($blob_id, $val);
620
621         // replacement that solves the problem by which only the first modulus 64K /
622         // of $val are stored at the blob field ////////////////////////////////////
623         // Thx Abel Berenstein  aberenstein#afip.gov.ar
624         $len = strlen($val);
625         $chunk_size = 32768;
626         $tail_size = $len % $chunk_size;
627         $n_chunks = ($len - $tail_size) / $chunk_size;
628
629         for ($n = 0; $n < $n_chunks; $n++) {
630             $start = $n * $chunk_size;
631             $data = substr($val, $start, $chunk_size);
632             ibase_blob_add($blob_id, $data);
633         }
634
635         if ($tail_size) {
636             $start = $n_chunks * $chunk_size;
637             $data = substr($val, $start, $tail_size);
638             ibase_blob_add($blob_id, $data);
639         }
640         // end replacement /////////////////////////////////////////////////////////
641
642         $blob_id_str = ibase_blob_close($blob_id);
643
644         return $this->Execute("UPDATE $table SET $column=(?) WHERE $where", array($blob_id_str)) != false;
645
646     }
647
648     function OldUpdateBlob($table, $column, $val, $where, $blobtype = 'BLOB')
649     {
650         $blob_id = ibase_blob_create($this->_connectionID);
651         ibase_blob_add($blob_id, $val);
652         $blob_id_str = ibase_blob_close($blob_id);
653         return $this->Execute("UPDATE $table SET $column=(?) WHERE $where", array($blob_id_str)) != false;
654     }
655
656     // Format date column in sql string given an input format that understands Y M D
657     // Only since Interbase 6.0 - uses EXTRACT
658     // problem - does not zero-fill the day and month yet
659     function SQLDate($fmt, $col = false)
660     {
661         if (!$col) $col = $this->sysDate;
662         $s = '';
663
664         $len = strlen($fmt);
665         for ($i = 0; $i < $len; $i++) {
666             if ($s) $s .= '||';
667             $ch = $fmt[$i];
668             switch ($ch) {
669                 case 'Y':
670                 case 'y':
671                     $s .= "extract(year from $col)";
672                     break;
673                 case 'M':
674                 case 'm':
675                     $s .= "extract(month from $col)";
676                     break;
677                 case 'Q':
678                 case 'q':
679                     $s .= "cast(((extract(month from $col)+2) / 3) as integer)";
680                     break;
681                 case 'D':
682                 case 'd':
683                     $s .= "(extract(day from $col))";
684                     break;
685                 case 'H':
686                 case 'h':
687                     $s .= "(extract(hour from $col))";
688                     break;
689                 case 'I':
690                 case 'i':
691                     $s .= "(extract(minute from $col))";
692                     break;
693                 case 'S':
694                 case 's':
695                     $s .= "CAST((extract(second from $col)) AS INTEGER)";
696                     break;
697
698                 default:
699                     if ($ch == '\\') {
700                         $i++;
701                         $ch = substr($fmt, $i, 1);
702                     }
703                     $s .= $this->qstr($ch);
704                     break;
705             }
706         }
707         return $s;
708     }
709 }
710
711 /*--------------------------------------------------------------------------------------
712          Class Name: Recordset
713 --------------------------------------------------------------------------------------*/
714
715 class ADORecordset_ibase extends ADORecordSet
716 {
717
718     var $databaseType = "ibase";
719     var $bind = false;
720     var $_cacheType;
721
722     function ADORecordset_ibase($id, $mode = false)
723     {
724         global $ADODB_FETCH_MODE;
725
726         $this->fetchMode = ($mode === false) ? $ADODB_FETCH_MODE : $mode;
727         return $this->ADORecordSet($id);
728     }
729
730     /*          Returns: an object containing field information.
731             Get column information in the Recordset object. fetchField() can be used in order to obtain information about
732             fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
733             fetchField() is retrieved.          */
734
735     function &FetchField($fieldOffset = -1)
736     {
737         $fld = new ADOFieldObject;
738         $ibf = ibase_field_info($this->_queryID, $fieldOffset);
739         $fld->name = strtolower($ibf['alias']);
740         if (empty($fld->name)) $fld->name = strtolower($ibf['name']);
741         $fld->type = $ibf['type'];
742         $fld->max_length = $ibf['length'];
743         return $fld;
744     }
745
746     function _initrs()
747     {
748         $this->_numOfRows = -1;
749         $this->_numOfFields = @ibase_num_fields($this->_queryID);
750
751         // cache types for blob decode check
752         for ($i = 0, $max = $this->_numOfFields; $i < $max; $i++) {
753             $f1 = $this->FetchField($i);
754             $this->_cacheType[] = $f1->type;
755         }
756     }
757
758     function _seek($row)
759     {
760         return false;
761     }
762
763     function _fetch()
764     {
765         $f = @ibase_fetch_row($this->_queryID);
766         if ($f === false) {
767             $this->fields = false;
768             return false;
769         }
770         // OPN stuff start - optimized
771         // fix missing nulls and decode blobs automatically
772
773         global $ADODB_ANSI_PADDING_OFF;
774         //$ADODB_ANSI_PADDING_OFF=1;
775         $rtrim = !empty($ADODB_ANSI_PADDING_OFF);
776
777         for ($i = 0, $max = $this->_numOfFields; $i < $max; $i++) {
778             if ($this->_cacheType[$i] == "BLOB") {
779                 if (isset($f[$i])) {
780                     $f[$i] = $this->connection->_BlobDecode($f[$i]);
781                 } else {
782                     $f[$i] = null;
783                 }
784             } else {
785                 if (!isset($f[$i])) {
786                     $f[$i] = null;
787                 } elseif ($rtrim && is_string($f[$i])) {
788                     $f[$i] = rtrim($f[$i]);
789                 }
790             }
791         }
792         // OPN stuff end
793
794         $this->fields = $f;
795         if ($this->fetchMode == ADODB_FETCH_ASSOC) {
796             $this->fields = &$this->GetRowAssoc(ADODB_ASSOC_CASE);
797         } elseif ($this->fetchMode == ADODB_FETCH_BOTH) {
798             $this->fields =& array_merge($this->fields, $this->GetRowAssoc(ADODB_ASSOC_CASE));
799         }
800         return true;
801     }
802
803     /* Use associative array to get fields array */
804     function Fields($colname)
805     {
806         if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname];
807         if (!$this->bind) {
808             $this->bind = array();
809             for ($i = 0; $i < $this->_numOfFields; $i++) {
810                 $o = $this->FetchField($i);
811                 $this->bind[strtoupper($o->name)] = $i;
812             }
813         }
814
815         return $this->fields[$this->bind[strtoupper($colname)]];
816
817     }
818
819     function _close()
820     {
821         return @ibase_free_result($this->_queryID);
822     }
823
824     function MetaType($t, $len = -1, $fieldobj = false)
825     {
826         if (is_object($t)) {
827             $fieldobj = $t;
828             $t = $fieldobj->type;
829             $len = $fieldobj->max_length;
830         }
831         switch (strtoupper($t)) {
832             case 'CHAR':
833                 return 'C';
834
835             case 'TEXT':
836             case 'VARCHAR':
837             case 'VARYING':
838                 if ($len <= $this->blobSize) return 'C';
839                 return 'X';
840             case 'BLOB':
841                 return 'B';
842
843             case 'TIMESTAMP':
844             case 'DATE':
845                 return 'D';
846
847             //case 'T': return 'T';
848
849             //case 'L': return 'L';
850             case 'INT':
851             case 'SHORT':
852             case 'INTEGER':
853                 return 'I';
854             default:
855                 return 'N';
856         }
857     }
858
859 }