source: aowow/includes/DbSimple/Ibase.php

Last change on this file was 170, checked in by maron, 16 years ago
  • Property svn:executable set to *
File size: 9.5 KB
Line 
1<?php
2/**
3 * DbSimple_Ibase: Interbase/Firebird database.
4 * (C) Dk Lab, http://en.dklab.ru
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 * See http://www.gnu.org/copyleft/lesser.html
11 *
12 * Placeholders are emulated because of logging purposes.
13 *
14 * @author Dmitry Koterov, http://forum.dklab.ru/users/DmitryKoterov/
15 * @author Konstantin Zhinko, http://forum.dklab.ru/users/KonstantinGinkoTit/
16 *
17 * @version 2.x $Id: Ibase.php 221 2007-07-27 23:24:35Z dk $
18 */
19require_once dirname(__FILE__) . '/Generic.php';
20
21/**
22 * Best transaction parameters for script queries.
23 * They never give us update conflicts (unlike others)!
24 * Used by default.
25 */
26define('IBASE_BEST_TRANSACTION', IBASE_COMMITTED + IBASE_WAIT + IBASE_REC_VERSION);
27define('IBASE_BEST_FETCH', IBASE_UNIXTIME);
28
29/**
30 * Database class for Interbase/Firebird.
31 */
32
33class DbSimple_Ibase extends DbSimple_Generic_Database
34{
35 var $DbSimple_Ibase_BEST_TRANSACTION = IBASE_BEST_TRANSACTION;
36 var $DbSimple_Ibase_USE_NATIVE_PHOLDERS = true;
37 var $fetchFlags = IBASE_BEST_FETCH;
38 var $link;
39 var $trans;
40 var $prepareCache = array();
41
42 /**
43 * constructor(string $dsn)
44 * Connect to Interbase/Firebird.
45 */
46 function DbSimple_Ibase($dsn)
47 {
48 $p = DbSimple_Generic::parseDSN($dsn);
49 if (!is_callable('ibase_connect')) {
50 return $this->_setLastError("-1", "Interbase/Firebird extension is not loaded", "ibase_connect");
51 }
52 $ok = $this->link = ibase_connect(
53 $p['host'] . (empty($p['port'])? "" : ":".$p['port']) .':'.preg_replace('{^/}s', '', $p['path']),
54 $p['user'],
55 $p['pass'],
56 isset($p['CHARSET']) ? $p['CHARSET'] : 'win1251',
57 isset($p['BUFFERS']) ? $p['BUFFERS'] : 0,
58 isset($p['DIALECT']) ? $p['DIALECT'] : 3,
59 isset($p['ROLE']) ? $p['ROLE'] : ''
60 );
61 if (isset($p['TRANSACTION'])) $this->DbSimple_Ibase_BEST_TRANSACTION = eval($p['TRANSACTION'].";");
62 $this->_resetLastError();
63 if (!$ok) return $this->_setDbError('ibase_connect()');
64 }
65
66 function _performEscape($s, $isIdent=false)
67 {
68 if (!$isIdent)
69 return "'" . str_replace("'", "''", $s) . "'";
70 else
71 return '"' . str_replace('"', '_', $s) . '"';
72 }
73
74 function _performTransaction($parameters=null)
75 {
76 if ($parameters === null) $parameters = $this->DbSimple_Ibase_BEST_TRANSACTION;
77 $this->trans = @ibase_trans($parameters, $this->link);
78 }
79
80 function& _performNewBlob($blobid=null)
81 {
82 $obj =& new DbSimple_Ibase_Blob($this, $blobid);
83 return $obj;
84 }
85
86 function _performGetBlobFieldNames($result)
87 {
88 $blobFields = array();
89 for ($i=ibase_num_fields($result)-1; $i>=0; $i--) {
90 $info = ibase_field_info($result, $i);
91 if ($info['type'] === "BLOB") $blobFields[] = $info['name'];
92 }
93 return $blobFields;
94 }
95
96 function _performGetPlaceholderIgnoreRe()
97 {
98 return '
99 " (?> [^"\\\\]+|\\\\"|\\\\)* " |
100 \' (?> [^\'\\\\]+|\\\\\'|\\\\)* \' |
101 ` (?> [^`]+ | ``)* ` | # backticks
102 /\* .*? \*/ # comments
103 ';
104 }
105
106 function _performCommit()
107 {
108 if (!is_resource($this->trans)) return false;
109 $result = @ibase_commit($this->trans);
110 if (true === $result) {
111 $this->trans = null;
112 }
113 return $result;
114 }
115
116
117 function _performRollback()
118 {
119 if (!is_resource($this->trans)) return false;
120 $result = @ibase_rollback($this->trans);
121 if (true === $result) {
122 $this->trans = null;
123 }
124 return $result;
125 }
126
127 function _performTransformQuery(&$queryMain, $how)
128 {
129 // If we also need to calculate total number of found rows...
130 switch ($how) {
131 // Prepare total calculation (if possible)
132 case 'CALC_TOTAL':
133 // Not possible
134 return true;
135
136 // Perform total calculation.
137 case 'GET_TOTAL':
138 // TODO: GROUP BY ... -> COUNT(DISTINCT ...)
139 $re = '/^
140 (?> -- [^\r\n]* | \s+)*
141 (\s* SELECT \s+) #1
142 ((?:FIRST \s+ \S+ \s+ (?:SKIP \s+ \S+ \s+)? )?) #2
143 (.*?) #3
144 (\s+ FROM \s+ .*?) #4
145 ((?:\s+ ORDER \s+ BY \s+ .*)?) #5
146 $/six';
147 $m = null;
148 if (preg_match($re, $queryMain[0], $m)) {
149 $queryMain[0] = $m[1] . $this->_fieldList2Count($m[3]) . " AS C" . $m[4];
150 $skipHead = substr_count($m[2], '?');
151 if ($skipHead) array_splice($queryMain, 1, $skipHead);
152 $skipTail = substr_count($m[5], '?');
153 if ($skipTail) array_splice($queryMain, -$skipTail);
154 }
155 return true;
156 }
157
158 return false;
159 }
160
161 function _performQuery($queryMain)
162 {
163 $this->_lastQuery = $queryMain;
164 $this->_expandPlaceholders($queryMain, $this->DbSimple_Ibase_USE_NATIVE_PHOLDERS);
165
166 $hash = $queryMain[0];
167
168 if (!isset($this->prepareCache[$hash])) {
169 $this->prepareCache[$hash] = @ibase_prepare((is_resource($this->trans) ? $this->trans : $this->link), $queryMain[0]);
170 } else {
171 // Prepare cache hit!
172 }
173
174 $prepared = $this->prepareCache[$hash];
175 if (!$prepared) return $this->_setDbError($queryMain[0]);
176 $queryMain[0] = $prepared;
177 $result = @call_user_func_array('ibase_execute', $queryMain);
178 // ATTENTION!!!
179 // WE MUST save prepared ID (stored in $prepared variable) somewhere
180 // before returning $result because of ibase destructor. Now it is done
181 // by $this->prepareCache. When variable $prepared goes out of scope, it
182 // is destroyed, and memory for result also freed by PHP. Totally we
183 // got "Invalud statement handle" error message.
184
185 if ($result === false) return $this->_setDbError($queryMain[0]);
186 if (!is_resource($result)) {
187 // Non-SELECT queries return number of affected rows, SELECT - resource.
188 return @ibase_affected_rows((is_resource($this->trans) ? $this->trans : $this->link));
189 }
190 return $result;
191 }
192
193 function _performFetch($result)
194 {
195 // Select fetch mode.
196 $flags = $this->fetchFlags;
197 if (empty($this->attributes['BLOB_OBJ'])) $flags = $flags | IBASE_TEXT;
198 else $flags = $flags & ~IBASE_TEXT;
199
200 $row = @ibase_fetch_assoc($result, $flags);
201 if (ibase_errmsg()) return $this->_setDbError($this->_lastQuery);
202 if ($row === false) return null;
203 return $row;
204 }
205
206
207 function _setDbError($query)
208 {
209 return $this->_setLastError(ibase_errcode(), ibase_errmsg(), $query);
210 }
211
212}
213
214class DbSimple_Ibase_Blob extends DbSimple_Generic_Blob
215{
216 var $blob; // resourse link
217 var $id;
218 var $database;
219
220 function DbSimple_Ibase_Blob(&$database, $id=null)
221 {
222 $this->database =& $database;
223 $this->id = $id;
224 $this->blob = null;
225 }
226
227 function read($len)
228 {
229 if ($this->id === false) return ''; // wr-only blob
230 if (!($e=$this->_firstUse())) return $e;
231 $data = @ibase_blob_get($this->blob, $len);
232 if ($data === false) return $this->_setDbError('read');
233 return $data;
234 }
235
236 function write($data)
237 {
238 if (!($e=$this->_firstUse())) return $e;
239 $ok = @ibase_blob_add($this->blob, $data);
240 if ($ok === false) return $this->_setDbError('add data to');
241 return true;
242 }
243
244 function close()
245 {
246 if (!($e=$this->_firstUse())) return $e;
247 if ($this->blob) {
248 $id = @ibase_blob_close($this->blob);
249 if ($id === false) return $this->_setDbError('close');
250 $this->blob = null;
251 } else {
252 $id = null;
253 }
254 return $this->id ? $this->id : $id;
255 }
256
257 function length()
258 {
259 if ($this->id === false) return 0; // wr-only blob
260 if (!($e=$this->_firstUse())) return $e;
261 $info = @ibase_blob_info($this->id);
262 if (!$info) return $this->_setDbError('get length of');
263 return $info[0];
264 }
265
266 function _setDbError($query)
267 {
268 $hId = $this->id === null ? "null" : ($this->id === false ? "false" : $this->id);
269 $query = "-- $query BLOB $hId";
270 $this->database->_setDbError($query);
271 }
272
273 // Called on each blob use (reading or writing).
274 function _firstUse()
275 {
276 // BLOB is opened - nothing to do.
277 if (is_resource($this->blob)) return true;
278 // Open or create blob.
279 if ($this->id !== null) {
280 $this->blob = @ibase_blob_open($this->id);
281 if ($this->blob === false) return $this->_setDbError('open');
282 } else {
283 $this->blob = @ibase_blob_create($this->database->link);
284 if ($this->blob === false) return $this->_setDbError('create');
285 }
286 return true;
287 }
288}
289
290?>
Note: See TracBrowser for help on using the repository browser.