Редакция 2 | Только различия | Учитывать пробелы | Содержимое файла | Авторство | Последнее изменение | Открыть журнал | RSS
Редакция 2 | Редакция 94 | ||
---|---|---|---|
1 | <?php
|
1 | <?php
|
2 | 2 | ||
3 | /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 | /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
4 | 4 | ||
5 | /**
|
5 | /**
|
6 | * The PEAR DB driver for PHP's sqlite extension
|
6 | * The PEAR DB driver for PHP's sqlite extension
|
7 | * for interacting with SQLite databases
|
7 | * for interacting with SQLite databases
|
8 | *
|
8 | *
|
9 | * PHP versions 4 and 5
|
9 | * PHP versions 4 and 5
|
10 | *
|
10 | *
|
11 | * LICENSE: This source file is subject to version 3.0 of the PHP license
|
11 | * LICENSE: This source file is subject to version 3.0 of the PHP license
|
12 | * that is available through the world-wide-web at the following URI:
|
12 | * that is available through the world-wide-web at the following URI:
|
13 | * http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
13 | * http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
14 | * the PHP License and are unable to obtain it through the web, please
|
14 | * the PHP License and are unable to obtain it through the web, please
|
15 | * send a note to license@php.net so we can mail you a copy immediately.
|
15 | * send a note to license@php.net so we can mail you a copy immediately.
|
16 | *
|
16 | *
|
17 | * @category Database
|
17 | * @category Database
|
18 | * @package DB
|
18 | * @package DB
|
19 | * @author Urs Gehrig <urs@circle.ch>
|
19 | * @author Urs Gehrig <urs@circle.ch>
|
20 | * @author Mika Tuupola <tuupola@appelsiini.net>
|
20 | * @author Mika Tuupola <tuupola@appelsiini.net>
|
21 | * @author Daniel Convissor <danielc@php.net>
|
21 | * @author Daniel Convissor <danielc@php.net>
|
22 | * @copyright 1997-2007 The PHP Group
|
22 | * @copyright 1997-2007 The PHP Group
|
23 | * @license http://www.php.net/license/3_0.txt PHP License 3.0 3.0
|
23 | * @license http://www.php.net/license/3_0.txt PHP License 3.0 3.0
|
24 | * @version CVS: $Id: sqlite.php,v 1.117 2007/09/21 14:23:28 aharvey Exp $
|
24 | * @version CVS: $Id: sqlite.php,v 1.117 2007/09/21 14:23:28 aharvey Exp $
|
25 | * @link http://pear.php.net/package/DB
|
25 | * @link http://pear.php.net/package/DB
|
26 | */
|
26 | */
|
27 | 27 | ||
28 | /**
|
28 | /**
|
29 | * Obtain the DB_common class so it can be extended from
|
29 | * Obtain the DB_common class so it can be extended from
|
30 | */
|
30 | */
|
31 | require_once 'DB/common.php'; |
31 | require_once 'DB/common.php'; |
32 | 32 | ||
33 | /**
|
33 | /**
|
34 | * The methods PEAR DB uses to interact with PHP's sqlite extension
|
34 | * The methods PEAR DB uses to interact with PHP's sqlite extension
|
35 | * for interacting with SQLite databases
|
35 | * for interacting with SQLite databases
|
36 | *
|
36 | *
|
37 | * These methods overload the ones declared in DB_common.
|
37 | * These methods overload the ones declared in DB_common.
|
38 | *
|
38 | *
|
39 | * NOTICE: This driver needs PHP's track_errors ini setting to be on.
|
39 | * NOTICE: This driver needs PHP's track_errors ini setting to be on.
|
40 | * It is automatically turned on when connecting to the database.
|
40 | * It is automatically turned on when connecting to the database.
|
41 | * Make sure your scripts don't turn it off.
|
41 | * Make sure your scripts don't turn it off.
|
42 | *
|
42 | *
|
43 | * @category Database
|
43 | * @category Database
|
44 | * @package DB
|
44 | * @package DB
|
45 | * @author Urs Gehrig <urs@circle.ch>
|
45 | * @author Urs Gehrig <urs@circle.ch>
|
46 | * @author Mika Tuupola <tuupola@appelsiini.net>
|
46 | * @author Mika Tuupola <tuupola@appelsiini.net>
|
47 | * @author Daniel Convissor <danielc@php.net>
|
47 | * @author Daniel Convissor <danielc@php.net>
|
48 | * @copyright 1997-2007 The PHP Group
|
48 | * @copyright 1997-2007 The PHP Group
|
49 | * @license http://www.php.net/license/3_0.txt PHP License 3.0 3.0
|
49 | * @license http://www.php.net/license/3_0.txt PHP License 3.0 3.0
|
50 | * @version Release: 1.7.13
|
50 | * @version Release: 1.7.13
|
51 | * @link http://pear.php.net/package/DB
|
51 | * @link http://pear.php.net/package/DB
|
52 | */
|
52 | */
|
53 | class DB_sqlite extends DB_common |
53 | class DB_sqlite extends DB_common |
54 | {
|
54 | {
|
55 | // {{{ properties
|
55 | // {{{ properties
|
56 | 56 | ||
57 | /**
|
57 | /**
|
58 | * The DB driver type (mysql, oci8, odbc, etc.)
|
58 | * The DB driver type (mysql, oci8, odbc, etc.)
|
59 | * @var string
|
59 | * @var string
|
60 | */
|
60 | */
|
61 | var $phptype = 'sqlite'; |
61 | var $phptype = 'sqlite'; |
62 | 62 | ||
63 | /**
|
63 | /**
|
64 | * The database syntax variant to be used (db2, access, etc.), if any
|
64 | * The database syntax variant to be used (db2, access, etc.), if any
|
65 | * @var string
|
65 | * @var string
|
66 | */
|
66 | */
|
67 | var $dbsyntax = 'sqlite'; |
67 | var $dbsyntax = 'sqlite'; |
68 | 68 | ||
69 | /**
|
69 | /**
|
70 | * The capabilities of this DB implementation
|
70 | * The capabilities of this DB implementation
|
71 | *
|
71 | *
|
72 | * The 'new_link' element contains the PHP version that first provided
|
72 | * The 'new_link' element contains the PHP version that first provided
|
73 | * new_link support for this DBMS. Contains false if it's unsupported.
|
73 | * new_link support for this DBMS. Contains false if it's unsupported.
|
74 | *
|
74 | *
|
75 | * Meaning of the 'limit' element:
|
75 | * Meaning of the 'limit' element:
|
76 | * + 'emulate' = emulate with fetch row by number
|
76 | * + 'emulate' = emulate with fetch row by number
|
77 | * + 'alter' = alter the query
|
77 | * + 'alter' = alter the query
|
78 | * + false = skip rows
|
78 | * + false = skip rows
|
79 | *
|
79 | *
|
80 | * @var array
|
80 | * @var array
|
81 | */
|
81 | */
|
82 | var $features = array( |
82 | var $features = array( |
83 | 'limit' => 'alter', |
83 | 'limit' => 'alter', |
84 | 'new_link' => false, |
84 | 'new_link' => false, |
85 | 'numrows' => true, |
85 | 'numrows' => true, |
86 | 'pconnect' => true, |
86 | 'pconnect' => true, |
87 | 'prepare' => false, |
87 | 'prepare' => false, |
88 | 'ssl' => false, |
88 | 'ssl' => false, |
89 | 'transactions' => false, |
89 | 'transactions' => false, |
90 | ); |
90 | ); |
91 | 91 | ||
92 | /**
|
92 | /**
|
93 | * A mapping of native error codes to DB error codes
|
93 | * A mapping of native error codes to DB error codes
|
94 | *
|
94 | *
|
95 | * {@internal Error codes according to sqlite_exec. See the online
|
95 | * {@internal Error codes according to sqlite_exec. See the online
|
96 | * manual at http://sqlite.org/c_interface.html for info.
|
96 | * manual at http://sqlite.org/c_interface.html for info.
|
97 | * This error handling based on sqlite_exec is not yet implemented.}}
|
97 | * This error handling based on sqlite_exec is not yet implemented.}}
|
98 | *
|
98 | *
|
99 | * @var array
|
99 | * @var array
|
100 | */
|
100 | */
|
101 | var $errorcode_map = array( |
101 | var $errorcode_map = array( |
102 | ); |
102 | ); |
103 | 103 | ||
104 | /**
|
104 | /**
|
105 | * The raw database connection created by PHP
|
105 | * The raw database connection created by PHP
|
106 | * @var resource
|
106 | * @var resource
|
107 | */
|
107 | */
|
108 | var $connection; |
108 | var $connection; |
109 | 109 | ||
110 | /**
|
110 | /**
|
111 | * The DSN information for connecting to a database
|
111 | * The DSN information for connecting to a database
|
112 | * @var array
|
112 | * @var array
|
113 | */
|
113 | */
|
114 | var $dsn = array(); |
114 | var $dsn = array(); |
115 | 115 | ||
116 | 116 | ||
117 | /**
|
117 | /**
|
118 | * SQLite data types
|
118 | * SQLite data types
|
119 | *
|
119 | *
|
120 | * @link http://www.sqlite.org/datatypes.html
|
120 | * @link http://www.sqlite.org/datatypes.html
|
121 | *
|
121 | *
|
122 | * @var array
|
122 | * @var array
|
123 | */
|
123 | */
|
124 | var $keywords = array ( |
124 | var $keywords = array ( |
125 | 'BLOB' => '', |
125 | 'BLOB' => '', |
126 | 'BOOLEAN' => '', |
126 | 'BOOLEAN' => '', |
127 | 'CHARACTER' => '', |
127 | 'CHARACTER' => '', |
128 | 'CLOB' => '', |
128 | 'CLOB' => '', |
129 | 'FLOAT' => '', |
129 | 'FLOAT' => '', |
130 | 'INTEGER' => '', |
130 | 'INTEGER' => '', |
131 | 'KEY' => '', |
131 | 'KEY' => '', |
132 | 'NATIONAL' => '', |
132 | 'NATIONAL' => '', |
133 | 'NUMERIC' => '', |
133 | 'NUMERIC' => '', |
134 | 'NVARCHAR' => '', |
134 | 'NVARCHAR' => '', |
135 | 'PRIMARY' => '', |
135 | 'PRIMARY' => '', |
136 | 'TEXT' => '', |
136 | 'TEXT' => '', |
137 | 'TIMESTAMP' => '', |
137 | 'TIMESTAMP' => '', |
138 | 'UNIQUE' => '', |
138 | 'UNIQUE' => '', |
139 | 'VARCHAR' => '', |
139 | 'VARCHAR' => '', |
140 | 'VARYING' => '', |
140 | 'VARYING' => '', |
141 | ); |
141 | ); |
142 | 142 | ||
143 | /**
|
143 | /**
|
144 | * The most recent error message from $php_errormsg
|
144 | * The most recent error message from $php_errormsg
|
145 | * @var string
|
145 | * @var string
|
146 | * @access private
|
146 | * @access private
|
147 | */
|
147 | */
|
148 | var $_lasterror = ''; |
148 | var $_lasterror = ''; |
149 | 149 | ||
150 | 150 | ||
151 | // }}}
|
151 | // }}}
|
152 | // {{{ constructor
|
152 | // {{{ constructor
|
153 | 153 | ||
154 | /**
|
154 | /**
|
155 | * This constructor calls <kbd>$this->DB_common()</kbd>
|
155 | * This constructor calls <kbd>$this->DB_common()</kbd>
|
156 | *
|
156 | *
|
157 | * @return void
|
157 | * @return void
|
158 | */
|
158 | */
|
159 | function DB_sqlite() |
159 | function DB_sqlite() |
160 | {
|
160 | {
|
161 | $this->DB_common(); |
161 | $this->DB_common(); |
162 | }
|
162 | }
|
163 | 163 | ||
164 | // }}}
|
164 | // }}}
|
165 | // {{{ connect()
|
165 | // {{{ connect()
|
166 | 166 | ||
167 | /**
|
167 | /**
|
168 | * Connect to the database server, log in and open the database
|
168 | * Connect to the database server, log in and open the database
|
169 | *
|
169 | *
|
170 | * Don't call this method directly. Use DB::connect() instead.
|
170 | * Don't call this method directly. Use DB::connect() instead.
|
171 | *
|
171 | *
|
172 | * PEAR DB's sqlite driver supports the following extra DSN options:
|
172 | * PEAR DB's sqlite driver supports the following extra DSN options:
|
173 | * + mode The permissions for the database file, in four digit
|
173 | * + mode The permissions for the database file, in four digit
|
174 | * chmod octal format (eg "0600").
|
174 | * chmod octal format (eg "0600").
|
175 | *
|
175 | *
|
176 | * Example of connecting to a database in read-only mode:
|
176 | * Example of connecting to a database in read-only mode:
|
177 | * <code>
|
177 | * <code>
|
178 | * require_once 'DB.php';
|
178 | * require_once 'DB.php';
|
179 | *
|
179 | *
|
180 | * $dsn = 'sqlite:///path/and/name/of/db/file?mode=0400';
|
180 | * $dsn = 'sqlite:///path/and/name/of/db/file?mode=0400';
|
181 | * $options = array(
|
181 | * $options = array(
|
182 | * 'portability' => DB_PORTABILITY_ALL,
|
182 | * 'portability' => DB_PORTABILITY_ALL,
|
183 | * );
|
183 | * );
|
184 | *
|
184 | *
|
185 | * $db = DB::connect($dsn, $options);
|
185 | * $db = DB::connect($dsn, $options);
|
186 | * if (PEAR::isError($db)) {
|
186 | * if (PEAR::isError($db)) {
|
187 | * die($db->getMessage());
|
187 | * die($db->getMessage());
|
188 | * }
|
188 | * }
|
189 | * </code>
|
189 | * </code>
|
190 | *
|
190 | *
|
191 | * @param array $dsn the data source name
|
191 | * @param array $dsn the data source name
|
192 | * @param bool $persistent should the connection be persistent?
|
192 | * @param bool $persistent should the connection be persistent?
|
193 | *
|
193 | *
|
194 | * @return int DB_OK on success. A DB_Error object on failure.
|
194 | * @return int DB_OK on success. A DB_Error object on failure.
|
195 | */
|
195 | */
|
196 | function connect($dsn, $persistent = false) |
196 | function connect($dsn, $persistent = false) |
197 | {
|
197 | {
|
198 | if (!PEAR::loadExtension('sqlite')) { |
198 | if (!PEAR::loadExtension('sqlite')) { |
199 | return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); |
199 | return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); |
200 | }
|
200 | }
|
201 | 201 | ||
202 | $this->dsn = $dsn; |
202 | $this->dsn = $dsn; |
203 | if ($dsn['dbsyntax']) { |
203 | if ($dsn['dbsyntax']) { |
204 | $this->dbsyntax = $dsn['dbsyntax']; |
204 | $this->dbsyntax = $dsn['dbsyntax']; |
205 | }
|
205 | }
|
206 | 206 | ||
207 | if (!$dsn['database']) { |
207 | if (!$dsn['database']) { |
208 | return $this->sqliteRaiseError(DB_ERROR_ACCESS_VIOLATION); |
208 | return $this->sqliteRaiseError(DB_ERROR_ACCESS_VIOLATION); |
209 | }
|
209 | }
|
210 | 210 | ||
211 | if ($dsn['database'] !== ':memory:') { |
211 | if ($dsn['database'] !== ':memory:') { |
212 | if (!file_exists($dsn['database'])) { |
212 | if (!file_exists($dsn['database'])) { |
213 | if (!touch($dsn['database'])) { |
213 | if (!touch($dsn['database'])) { |
214 | return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND); |
214 | return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND); |
215 | }
|
215 | }
|
216 | if (!isset($dsn['mode']) || |
216 | if (!isset($dsn['mode']) || |
217 | !is_numeric($dsn['mode'])) |
217 | !is_numeric($dsn['mode'])) |
218 | {
|
218 | {
|
219 | $mode = 0644; |
219 | $mode = 0644; |
220 | } else { |
220 | } else { |
221 | $mode = octdec($dsn['mode']); |
221 | $mode = octdec($dsn['mode']); |
222 | }
|
222 | }
|
223 | if (!chmod($dsn['database'], $mode)) { |
223 | if (!chmod($dsn['database'], $mode)) { |
224 | return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND); |
224 | return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND); |
225 | }
|
225 | }
|
226 | if (!file_exists($dsn['database'])) { |
226 | if (!file_exists($dsn['database'])) { |
227 | return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND); |
227 | return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND); |
228 | }
|
228 | }
|
229 | }
|
229 | }
|
230 | if (!is_file($dsn['database'])) { |
230 | if (!is_file($dsn['database'])) { |
231 | return $this->sqliteRaiseError(DB_ERROR_INVALID); |
231 | return $this->sqliteRaiseError(DB_ERROR_INVALID); |
232 | }
|
232 | }
|
233 | if (!is_readable($dsn['database'])) { |
233 | if (!is_readable($dsn['database'])) { |
234 | return $this->sqliteRaiseError(DB_ERROR_ACCESS_VIOLATION); |
234 | return $this->sqliteRaiseError(DB_ERROR_ACCESS_VIOLATION); |
235 | }
|
235 | }
|
236 | }
|
236 | }
|
237 | 237 | ||
238 | $connect_function = $persistent ? 'sqlite_popen' : 'sqlite_open'; |
238 | $connect_function = $persistent ? 'sqlite_popen' : 'sqlite_open'; |
239 | 239 | ||
240 | // track_errors must remain on for simpleQuery()
|
240 | // track_errors must remain on for simpleQuery()
|
241 | @ini_set('track_errors', 1); |
241 | @ini_set('track_errors', 1); |
242 | $php_errormsg = ''; |
242 | $php_errormsg = ''; |
243 | 243 | ||
244 | if (!$this->connection = @$connect_function($dsn['database'])) { |
244 | if (!$this->connection = @$connect_function($dsn['database'])) { |
245 | return $this->raiseError(DB_ERROR_NODBSELECTED, |
245 | return $this->raiseError(DB_ERROR_NODBSELECTED, |
246 | null, null, null, |
246 | null, null, null, |
247 | $php_errormsg); |
247 | $php_errormsg); |
248 | }
|
248 | }
|
249 | return DB_OK; |
249 | return DB_OK; |
250 | }
|
250 | }
|
251 | 251 | ||
252 | // }}}
|
252 | // }}}
|
253 | // {{{ disconnect()
|
253 | // {{{ disconnect()
|
254 | 254 | ||
255 | /**
|
255 | /**
|
256 | * Disconnects from the database server
|
256 | * Disconnects from the database server
|
257 | *
|
257 | *
|
258 | * @return bool TRUE on success, FALSE on failure
|
258 | * @return bool TRUE on success, FALSE on failure
|
259 | */
|
259 | */
|
260 | function disconnect() |
260 | function disconnect() |
261 | {
|
261 | {
|
262 | $ret = @sqlite_close($this->connection); |
262 | $ret = @sqlite_close($this->connection); |
263 | $this->connection = null; |
263 | $this->connection = null; |
264 | return $ret; |
264 | return $ret; |
265 | }
|
265 | }
|
266 | 266 | ||
267 | // }}}
|
267 | // }}}
|
268 | // {{{ simpleQuery()
|
268 | // {{{ simpleQuery()
|
269 | 269 | ||
270 | /**
|
270 | /**
|
271 | * Sends a query to the database server
|
271 | * Sends a query to the database server
|
272 | *
|
272 | *
|
273 | * NOTICE: This method needs PHP's track_errors ini setting to be on.
|
273 | * NOTICE: This method needs PHP's track_errors ini setting to be on.
|
274 | * It is automatically turned on when connecting to the database.
|
274 | * It is automatically turned on when connecting to the database.
|
275 | * Make sure your scripts don't turn it off.
|
275 | * Make sure your scripts don't turn it off.
|
276 | *
|
276 | *
|
277 | * @param string the SQL query string
|
277 | * @param string the SQL query string
|
278 | *
|
278 | *
|
279 | * @return mixed + a PHP result resrouce for successful SELECT queries
|
279 | * @return mixed + a PHP result resrouce for successful SELECT queries
|
280 | * + the DB_OK constant for other successful queries
|
280 | * + the DB_OK constant for other successful queries
|
281 | * + a DB_Error object on failure
|
281 | * + a DB_Error object on failure
|
282 | */
|
282 | */
|
283 | function simpleQuery($query) |
283 | function simpleQuery($query) |
284 | {
|
284 | {
|
285 | $ismanip = $this->_checkManip($query); |
285 | $ismanip = $this->_checkManip($query); |
286 | $this->last_query = $query; |
286 | $this->last_query = $query; |
287 | $query = $this->modifyQuery($query); |
287 | $query = $this->modifyQuery($query); |
288 | 288 | ||
289 | $php_errormsg = ''; |
289 | $php_errormsg = ''; |
290 | 290 | ||
291 | $result = @sqlite_query($query, $this->connection); |
291 | $result = @sqlite_query($query, $this->connection); |
292 | $this->_lasterror = $php_errormsg ? $php_errormsg : ''; |
292 | $this->_lasterror = $php_errormsg ? $php_errormsg : ''; |
293 | 293 | ||
294 | $this->result = $result; |
294 | $this->result = $result; |
295 | if (!$this->result) { |
295 | if (!$this->result) { |
296 | return $this->sqliteRaiseError(null); |
296 | return $this->sqliteRaiseError(null); |
297 | }
|
297 | }
|
298 | 298 | ||
299 | // sqlite_query() seems to allways return a resource
|
299 | // sqlite_query() seems to allways return a resource
|
300 | // so cant use that. Using $ismanip instead
|
300 | // so cant use that. Using $ismanip instead
|
301 | if (!$ismanip) { |
301 | if (!$ismanip) { |
302 | $numRows = $this->numRows($result); |
302 | $numRows = $this->numRows($result); |
303 | if (is_object($numRows)) { |
303 | if (is_object($numRows)) { |
304 | // we've got PEAR_Error
|
304 | // we've got PEAR_Error
|
305 | return $numRows; |
305 | return $numRows; |
306 | }
|
306 | }
|
307 | return $result; |
307 | return $result; |
308 | }
|
308 | }
|
309 | return DB_OK; |
309 | return DB_OK; |
310 | }
|
310 | }
|
311 | 311 | ||
312 | // }}}
|
312 | // }}}
|
313 | // {{{ nextResult()
|
313 | // {{{ nextResult()
|
314 | 314 | ||
315 | /**
|
315 | /**
|
316 | * Move the internal sqlite result pointer to the next available result
|
316 | * Move the internal sqlite result pointer to the next available result
|
317 | *
|
317 | *
|
318 | * @param resource $result the valid sqlite result resource
|
318 | * @param resource $result the valid sqlite result resource
|
319 | *
|
319 | *
|
320 | * @return bool true if a result is available otherwise return false
|
320 | * @return bool true if a result is available otherwise return false
|
321 | */
|
321 | */
|
322 | function nextResult($result) |
322 | function nextResult($result) |
323 | {
|
323 | {
|
324 | return false; |
324 | return false; |
325 | }
|
325 | }
|
326 | 326 | ||
327 | // }}}
|
327 | // }}}
|
328 | // {{{ fetchInto()
|
328 | // {{{ fetchInto()
|
329 | 329 | ||
330 | /**
|
330 | /**
|
331 | * Places a row from the result set into the given array
|
331 | * Places a row from the result set into the given array
|
332 | *
|
332 | *
|
333 | * Formating of the array and the data therein are configurable.
|
333 | * Formating of the array and the data therein are configurable.
|
334 | * See DB_result::fetchInto() for more information.
|
334 | * See DB_result::fetchInto() for more information.
|
335 | *
|
335 | *
|
336 | * This method is not meant to be called directly. Use
|
336 | * This method is not meant to be called directly. Use
|
337 | * DB_result::fetchInto() instead. It can't be declared "protected"
|
337 | * DB_result::fetchInto() instead. It can't be declared "protected"
|
338 | * because DB_result is a separate object.
|
338 | * because DB_result is a separate object.
|
339 | *
|
339 | *
|
340 | * @param resource $result the query result resource
|
340 | * @param resource $result the query result resource
|
341 | * @param array $arr the referenced array to put the data in
|
341 | * @param array $arr the referenced array to put the data in
|
342 | * @param int $fetchmode how the resulting array should be indexed
|
342 | * @param int $fetchmode how the resulting array should be indexed
|
343 | * @param int $rownum the row number to fetch (0 = first row)
|
343 | * @param int $rownum the row number to fetch (0 = first row)
|
344 | *
|
344 | *
|
345 | * @return mixed DB_OK on success, NULL when the end of a result set is
|
345 | * @return mixed DB_OK on success, NULL when the end of a result set is
|
346 | * reached or on failure
|
346 | * reached or on failure
|
347 | *
|
347 | *
|
348 | * @see DB_result::fetchInto()
|
348 | * @see DB_result::fetchInto()
|
349 | */
|
349 | */
|
350 | function fetchInto($result, &$arr, $fetchmode, $rownum = null) |
350 | function fetchInto($result, &$arr, $fetchmode, $rownum = null) |
351 | {
|
351 | {
|
352 | if ($rownum !== null) { |
352 | if ($rownum !== null) { |
353 | if (!@sqlite_seek($this->result, $rownum)) { |
353 | if (!@sqlite_seek($this->result, $rownum)) { |
354 | return null; |
354 | return null; |
355 | }
|
355 | }
|
356 | }
|
356 | }
|
357 | if ($fetchmode & DB_FETCHMODE_ASSOC) { |
357 | if ($fetchmode & DB_FETCHMODE_ASSOC) { |
358 | $arr = @sqlite_fetch_array($result, SQLITE_ASSOC); |
358 | $arr = @sqlite_fetch_array($result, SQLITE_ASSOC); |
359 | if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { |
359 | if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { |
360 | $arr = array_change_key_case($arr, CASE_LOWER); |
360 | $arr = array_change_key_case($arr, CASE_LOWER); |
361 | }
|
361 | }
|
362 | 362 | ||
363 | /* Remove extraneous " characters from the fields in the result.
|
363 | /* Remove extraneous " characters from the fields in the result.
|
364 | * Fixes bug #11716. */
|
364 | * Fixes bug #11716. */
|
365 | if (is_array($arr) && count($arr) > 0) { |
365 | if (is_array($arr) && count($arr) > 0) { |
366 | $strippedArr = array(); |
366 | $strippedArr = array(); |
367 | foreach ($arr as $field => $value) { |
367 | foreach ($arr as $field => $value) { |
368 | $strippedArr[trim($field, '"')] = $value; |
368 | $strippedArr[trim($field, '"')] = $value; |
369 | }
|
369 | }
|
370 | $arr = $strippedArr; |
370 | $arr = $strippedArr; |
371 | }
|
371 | }
|
372 | } else { |
372 | } else { |
373 | $arr = @sqlite_fetch_array($result, SQLITE_NUM); |
373 | $arr = @sqlite_fetch_array($result, SQLITE_NUM); |
374 | }
|
374 | }
|
375 | if (!$arr) { |
375 | if (!$arr) { |
376 | return null; |
376 | return null; |
377 | }
|
377 | }
|
378 | if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { |
378 | if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { |
379 | /*
|
379 | /*
|
380 | * Even though this DBMS already trims output, we do this because
|
380 | * Even though this DBMS already trims output, we do this because
|
381 | * a field might have intentional whitespace at the end that
|
381 | * a field might have intentional whitespace at the end that
|
382 | * gets removed by DB_PORTABILITY_RTRIM under another driver.
|
382 | * gets removed by DB_PORTABILITY_RTRIM under another driver.
|
383 | */
|
383 | */
|
384 | $this->_rtrimArrayValues($arr); |
384 | $this->_rtrimArrayValues($arr); |
385 | }
|
385 | }
|
386 | if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { |
386 | if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { |
387 | $this->_convertNullArrayValuesToEmpty($arr); |
387 | $this->_convertNullArrayValuesToEmpty($arr); |
388 | }
|
388 | }
|
389 | return DB_OK; |
389 | return DB_OK; |
390 | }
|
390 | }
|
391 | 391 | ||
392 | // }}}
|
392 | // }}}
|
393 | // {{{ freeResult()
|
393 | // {{{ freeResult()
|
394 | 394 | ||
395 | /**
|
395 | /**
|
396 | * Deletes the result set and frees the memory occupied by the result set
|
396 | * Deletes the result set and frees the memory occupied by the result set
|
397 | *
|
397 | *
|
398 | * This method is not meant to be called directly. Use
|
398 | * This method is not meant to be called directly. Use
|
399 | * DB_result::free() instead. It can't be declared "protected"
|
399 | * DB_result::free() instead. It can't be declared "protected"
|
400 | * because DB_result is a separate object.
|
400 | * because DB_result is a separate object.
|
401 | *
|
401 | *
|
402 | * @param resource $result PHP's query result resource
|
402 | * @param resource $result PHP's query result resource
|
403 | *
|
403 | *
|
404 | * @return bool TRUE on success, FALSE if $result is invalid
|
404 | * @return bool TRUE on success, FALSE if $result is invalid
|
405 | *
|
405 | *
|
406 | * @see DB_result::free()
|
406 | * @see DB_result::free()
|
407 | */
|
407 | */
|
408 | function freeResult(&$result) |
408 | function freeResult(&$result) |
409 | {
|
409 | {
|
410 | // XXX No native free?
|
410 | // XXX No native free?
|
411 | if (!is_resource($result)) { |
411 | if (!is_resource($result)) { |
412 | return false; |
412 | return false; |
413 | }
|
413 | }
|
414 | $result = null; |
414 | $result = null; |
415 | return true; |
415 | return true; |
416 | }
|
416 | }
|
417 | 417 | ||
418 | // }}}
|
418 | // }}}
|
419 | // {{{ numCols()
|
419 | // {{{ numCols()
|
420 | 420 | ||
421 | /**
|
421 | /**
|
422 | * Gets the number of columns in a result set
|
422 | * Gets the number of columns in a result set
|
423 | *
|
423 | *
|
424 | * This method is not meant to be called directly. Use
|
424 | * This method is not meant to be called directly. Use
|
425 | * DB_result::numCols() instead. It can't be declared "protected"
|
425 | * DB_result::numCols() instead. It can't be declared "protected"
|
426 | * because DB_result is a separate object.
|
426 | * because DB_result is a separate object.
|
427 | *
|
427 | *
|
428 | * @param resource $result PHP's query result resource
|
428 | * @param resource $result PHP's query result resource
|
429 | *
|
429 | *
|
430 | * @return int the number of columns. A DB_Error object on failure.
|
430 | * @return int the number of columns. A DB_Error object on failure.
|
431 | *
|
431 | *
|
432 | * @see DB_result::numCols()
|
432 | * @see DB_result::numCols()
|
433 | */
|
433 | */
|
434 | function numCols($result) |
434 | function numCols($result) |
435 | {
|
435 | {
|
436 | $cols = @sqlite_num_fields($result); |
436 | $cols = @sqlite_num_fields($result); |
437 | if (!$cols) { |
437 | if (!$cols) { |
438 | return $this->sqliteRaiseError(); |
438 | return $this->sqliteRaiseError(); |
439 | }
|
439 | }
|
440 | return $cols; |
440 | return $cols; |
441 | }
|
441 | }
|
442 | 442 | ||
443 | // }}}
|
443 | // }}}
|
444 | // {{{ numRows()
|
444 | // {{{ numRows()
|
445 | 445 | ||
446 | /**
|
446 | /**
|
447 | * Gets the number of rows in a result set
|
447 | * Gets the number of rows in a result set
|
448 | *
|
448 | *
|
449 | * This method is not meant to be called directly. Use
|
449 | * This method is not meant to be called directly. Use
|
450 | * DB_result::numRows() instead. It can't be declared "protected"
|
450 | * DB_result::numRows() instead. It can't be declared "protected"
|
451 | * because DB_result is a separate object.
|
451 | * because DB_result is a separate object.
|
452 | *
|
452 | *
|
453 | * @param resource $result PHP's query result resource
|
453 | * @param resource $result PHP's query result resource
|
454 | *
|
454 | *
|
455 | * @return int the number of rows. A DB_Error object on failure.
|
455 | * @return int the number of rows. A DB_Error object on failure.
|
456 | *
|
456 | *
|
457 | * @see DB_result::numRows()
|
457 | * @see DB_result::numRows()
|
458 | */
|
458 | */
|
459 | function numRows($result) |
459 | function numRows($result) |
460 | {
|
460 | {
|
461 | $rows = @sqlite_num_rows($result); |
461 | $rows = @sqlite_num_rows($result); |
462 | if ($rows === null) { |
462 | if ($rows === null) { |
463 | return $this->sqliteRaiseError(); |
463 | return $this->sqliteRaiseError(); |
464 | }
|
464 | }
|
465 | return $rows; |
465 | return $rows; |
466 | }
|
466 | }
|
467 | 467 | ||
468 | // }}}
|
468 | // }}}
|
469 | // {{{ affected()
|
469 | // {{{ affected()
|
470 | 470 | ||
471 | /**
|
471 | /**
|
472 | * Determines the number of rows affected by a data maniuplation query
|
472 | * Determines the number of rows affected by a data maniuplation query
|
473 | *
|
473 | *
|
474 | * 0 is returned for queries that don't manipulate data.
|
474 | * 0 is returned for queries that don't manipulate data.
|
475 | *
|
475 | *
|
476 | * @return int the number of rows. A DB_Error object on failure.
|
476 | * @return int the number of rows. A DB_Error object on failure.
|
477 | */
|
477 | */
|
478 | function affectedRows() |
478 | function affectedRows() |
479 | {
|
479 | {
|
480 | return @sqlite_changes($this->connection); |
480 | return @sqlite_changes($this->connection); |
481 | }
|
481 | }
|
482 | 482 | ||
483 | // }}}
|
483 | // }}}
|
484 | // {{{ dropSequence()
|
484 | // {{{ dropSequence()
|
485 | 485 | ||
486 | /**
|
486 | /**
|
487 | * Deletes a sequence
|
487 | * Deletes a sequence
|
488 | *
|
488 | *
|
489 | * @param string $seq_name name of the sequence to be deleted
|
489 | * @param string $seq_name name of the sequence to be deleted
|
490 | *
|
490 | *
|
491 | * @return int DB_OK on success. A DB_Error object on failure.
|
491 | * @return int DB_OK on success. A DB_Error object on failure.
|
492 | *
|
492 | *
|
493 | * @see DB_common::dropSequence(), DB_common::getSequenceName(),
|
493 | * @see DB_common::dropSequence(), DB_common::getSequenceName(),
|
494 | * DB_sqlite::nextID(), DB_sqlite::createSequence()
|
494 | * DB_sqlite::nextID(), DB_sqlite::createSequence()
|
495 | */
|
495 | */
|
496 | function dropSequence($seq_name) |
496 | function dropSequence($seq_name) |
497 | {
|
497 | {
|
498 | return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); |
498 | return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); |
499 | }
|
499 | }
|
500 | 500 | ||
501 | /**
|
501 | /**
|
502 | * Creates a new sequence
|
502 | * Creates a new sequence
|
503 | *
|
503 | *
|
504 | * @param string $seq_name name of the new sequence
|
504 | * @param string $seq_name name of the new sequence
|
505 | *
|
505 | *
|
506 | * @return int DB_OK on success. A DB_Error object on failure.
|
506 | * @return int DB_OK on success. A DB_Error object on failure.
|
507 | *
|
507 | *
|
508 | * @see DB_common::createSequence(), DB_common::getSequenceName(),
|
508 | * @see DB_common::createSequence(), DB_common::getSequenceName(),
|
509 | * DB_sqlite::nextID(), DB_sqlite::dropSequence()
|
509 | * DB_sqlite::nextID(), DB_sqlite::dropSequence()
|
510 | */
|
510 | */
|
511 | function createSequence($seq_name) |
511 | function createSequence($seq_name) |
512 | {
|
512 | {
|
513 | $seqname = $this->getSequenceName($seq_name); |
513 | $seqname = $this->getSequenceName($seq_name); |
514 | $query = 'CREATE TABLE ' . $seqname . |
514 | $query = 'CREATE TABLE ' . $seqname . |
515 | ' (id INTEGER UNSIGNED PRIMARY KEY) '; |
515 | ' (id INTEGER UNSIGNED PRIMARY KEY) '; |
516 | $result = $this->query($query); |
516 | $result = $this->query($query); |
517 | if (DB::isError($result)) { |
517 | if (DB::isError($result)) { |
518 | return($result); |
518 | return($result); |
519 | }
|
519 | }
|
520 | $query = "CREATE TRIGGER ${seqname}_cleanup AFTER INSERT ON $seqname |
520 | $query = "CREATE TRIGGER ${seqname}_cleanup AFTER INSERT ON $seqname |
521 | BEGIN
|
521 | BEGIN
|
522 | DELETE FROM $seqname WHERE id<LAST_INSERT_ROWID();
|
522 | DELETE FROM $seqname WHERE id<LAST_INSERT_ROWID();
|
523 | END "; |
523 | END "; |
524 | $result = $this->query($query); |
524 | $result = $this->query($query); |
525 | if (DB::isError($result)) { |
525 | if (DB::isError($result)) { |
526 | return($result); |
526 | return($result); |
527 | }
|
527 | }
|
528 | }
|
528 | }
|
529 | 529 | ||
530 | // }}}
|
530 | // }}}
|
531 | // {{{ nextId()
|
531 | // {{{ nextId()
|
532 | 532 | ||
533 | /**
|
533 | /**
|
534 | * Returns the next free id in a sequence
|
534 | * Returns the next free id in a sequence
|
535 | *
|
535 | *
|
536 | * @param string $seq_name name of the sequence
|
536 | * @param string $seq_name name of the sequence
|
537 | * @param boolean $ondemand when true, the seqence is automatically
|
537 | * @param boolean $ondemand when true, the seqence is automatically
|
538 | * created if it does not exist
|
538 | * created if it does not exist
|
539 | *
|
539 | *
|
540 | * @return int the next id number in the sequence.
|
540 | * @return int the next id number in the sequence.
|
541 | * A DB_Error object on failure.
|
541 | * A DB_Error object on failure.
|
542 | *
|
542 | *
|
543 | * @see DB_common::nextID(), DB_common::getSequenceName(),
|
543 | * @see DB_common::nextID(), DB_common::getSequenceName(),
|
544 | * DB_sqlite::createSequence(), DB_sqlite::dropSequence()
|
544 | * DB_sqlite::createSequence(), DB_sqlite::dropSequence()
|
545 | */
|
545 | */
|
546 | function nextId($seq_name, $ondemand = true) |
546 | function nextId($seq_name, $ondemand = true) |
547 | {
|
547 | {
|
548 | $seqname = $this->getSequenceName($seq_name); |
548 | $seqname = $this->getSequenceName($seq_name); |
549 | 549 | ||
550 | do { |
550 | do { |
551 | $repeat = 0; |
551 | $repeat = 0; |
552 | $this->pushErrorHandling(PEAR_ERROR_RETURN); |
552 | $this->pushErrorHandling(PEAR_ERROR_RETURN); |
553 | $result = $this->query("INSERT INTO $seqname (id) VALUES (NULL)"); |
553 | $result = $this->query("INSERT INTO $seqname (id) VALUES (NULL)"); |
554 | $this->popErrorHandling(); |
554 | $this->popErrorHandling(); |
555 | if ($result === DB_OK) { |
555 | if ($result === DB_OK) { |
556 | $id = @sqlite_last_insert_rowid($this->connection); |
556 | $id = @sqlite_last_insert_rowid($this->connection); |
557 | if ($id != 0) { |
557 | if ($id != 0) { |
558 | return $id; |
558 | return $id; |
559 | }
|
559 | }
|
560 | } elseif ($ondemand && DB::isError($result) && |
560 | } elseif ($ondemand && DB::isError($result) && |
561 | $result->getCode() == DB_ERROR_NOSUCHTABLE) |
561 | $result->getCode() == DB_ERROR_NOSUCHTABLE) |
562 | {
|
562 | {
|
563 | $result = $this->createSequence($seq_name); |
563 | $result = $this->createSequence($seq_name); |
564 | if (DB::isError($result)) { |
564 | if (DB::isError($result)) { |
565 | return $this->raiseError($result); |
565 | return $this->raiseError($result); |
566 | } else { |
566 | } else { |
567 | $repeat = 1; |
567 | $repeat = 1; |
568 | }
|
568 | }
|
569 | }
|
569 | }
|
570 | } while ($repeat); |
570 | } while ($repeat); |
571 | 571 | ||
572 | return $this->raiseError($result); |
572 | return $this->raiseError($result); |
573 | }
|
573 | }
|
574 | 574 | ||
575 | // }}}
|
575 | // }}}
|
576 | // {{{ getDbFileStats()
|
576 | // {{{ getDbFileStats()
|
577 | 577 | ||
578 | /**
|
578 | /**
|
579 | * Get the file stats for the current database
|
579 | * Get the file stats for the current database
|
580 | *
|
580 | *
|
581 | * Possible arguments are dev, ino, mode, nlink, uid, gid, rdev, size,
|
581 | * Possible arguments are dev, ino, mode, nlink, uid, gid, rdev, size,
|
582 | * atime, mtime, ctime, blksize, blocks or a numeric key between
|
582 | * atime, mtime, ctime, blksize, blocks or a numeric key between
|
583 | * 0 and 12.
|
583 | * 0 and 12.
|
584 | *
|
584 | *
|
585 | * @param string $arg the array key for stats()
|
585 | * @param string $arg the array key for stats()
|
586 | *
|
586 | *
|
587 | * @return mixed an array on an unspecified key, integer on a passed
|
587 | * @return mixed an array on an unspecified key, integer on a passed
|
588 | * arg and false at a stats error
|
588 | * arg and false at a stats error
|
589 | */
|
589 | */
|
590 | function getDbFileStats($arg = '') |
590 | function getDbFileStats($arg = '') |
591 | {
|
591 | {
|
592 | $stats = stat($this->dsn['database']); |
592 | $stats = stat($this->dsn['database']); |
593 | if ($stats == false) { |
593 | if ($stats == false) { |
594 | return false; |
594 | return false; |
595 | }
|
595 | }
|
596 | if (is_array($stats)) { |
596 | if (is_array($stats)) { |
597 | if (is_numeric($arg)) { |
597 | if (is_numeric($arg)) { |
598 | if (((int)$arg <= 12) & ((int)$arg >= 0)) { |
598 | if (((int)$arg <= 12) & ((int)$arg >= 0)) { |
599 | return false; |
599 | return false; |
600 | }
|
600 | }
|
601 | return $stats[$arg ]; |
601 | return $stats[$arg ]; |
602 | }
|
602 | }
|
603 | if (array_key_exists(trim($arg), $stats)) { |
603 | if (array_key_exists(trim($arg), $stats)) { |
604 | return $stats[$arg ]; |
604 | return $stats[$arg ]; |
605 | }
|
605 | }
|
606 | }
|
606 | }
|
607 | return $stats; |
607 | return $stats; |
608 | }
|
608 | }
|
609 | 609 | ||
610 | // }}}
|
610 | // }}}
|
611 | // {{{ escapeSimple()
|
611 | // {{{ escapeSimple()
|
612 | 612 | ||
613 | /**
|
613 | /**
|
614 | * Escapes a string according to the current DBMS's standards
|
614 | * Escapes a string according to the current DBMS's standards
|
615 | *
|
615 | *
|
616 | * In SQLite, this makes things safe for inserts/updates, but may
|
616 | * In SQLite, this makes things safe for inserts/updates, but may
|
617 | * cause problems when performing text comparisons against columns
|
617 | * cause problems when performing text comparisons against columns
|
618 | * containing binary data. See the
|
618 | * containing binary data. See the
|
619 | * {@link http://php.net/sqlite_escape_string PHP manual} for more info.
|
619 | * {@link http://php.net/sqlite_escape_string PHP manual} for more info.
|
620 | *
|
620 | *
|
621 | * @param string $str the string to be escaped
|
621 | * @param string $str the string to be escaped
|
622 | *
|
622 | *
|
623 | * @return string the escaped string
|
623 | * @return string the escaped string
|
624 | *
|
624 | *
|
625 | * @since Method available since Release 1.6.1
|
625 | * @since Method available since Release 1.6.1
|
626 | * @see DB_common::escapeSimple()
|
626 | * @see DB_common::escapeSimple()
|
627 | */
|
627 | */
|
628 | function escapeSimple($str) |
628 | function escapeSimple($str) |
629 | {
|
629 | {
|
630 | return @sqlite_escape_string($str); |
630 | return @sqlite_escape_string($str); |
631 | }
|
631 | }
|
632 | 632 | ||
633 | // }}}
|
633 | // }}}
|
634 | // {{{ modifyLimitQuery()
|
634 | // {{{ modifyLimitQuery()
|
635 | 635 | ||
636 | /**
|
636 | /**
|
637 | * Adds LIMIT clauses to a query string according to current DBMS standards
|
637 | * Adds LIMIT clauses to a query string according to current DBMS standards
|
638 | *
|
638 | *
|
639 | * @param string $query the query to modify
|
639 | * @param string $query the query to modify
|
640 | * @param int $from the row to start to fetching (0 = the first row)
|
640 | * @param int $from the row to start to fetching (0 = the first row)
|
641 | * @param int $count the numbers of rows to fetch
|
641 | * @param int $count the numbers of rows to fetch
|
642 | * @param mixed $params array, string or numeric data to be used in
|
642 | * @param mixed $params array, string or numeric data to be used in
|
643 | * execution of the statement. Quantity of items
|
643 | * execution of the statement. Quantity of items
|
644 | * passed must match quantity of placeholders in
|
644 | * passed must match quantity of placeholders in
|
645 | * query: meaning 1 placeholder for non-array
|
645 | * query: meaning 1 placeholder for non-array
|
646 | * parameters or 1 placeholder per array element.
|
646 | * parameters or 1 placeholder per array element.
|
647 | *
|
647 | *
|
648 | * @return string the query string with LIMIT clauses added
|
648 | * @return string the query string with LIMIT clauses added
|
649 | *
|
649 | *
|
650 | * @access protected
|
650 | * @access protected
|
651 | */
|
651 | */
|
652 | function modifyLimitQuery($query, $from, $count, $params = array()) |
652 | function modifyLimitQuery($query, $from, $count, $params = array()) |
653 | {
|
653 | {
|
654 | return "$query LIMIT $count OFFSET $from"; |
654 | return "$query LIMIT $count OFFSET $from"; |
655 | }
|
655 | }
|
656 | 656 | ||
657 | // }}}
|
657 | // }}}
|
658 | // {{{ modifyQuery()
|
658 | // {{{ modifyQuery()
|
659 | 659 | ||
660 | /**
|
660 | /**
|
661 | * Changes a query string for various DBMS specific reasons
|
661 | * Changes a query string for various DBMS specific reasons
|
662 | *
|
662 | *
|
663 | * This little hack lets you know how many rows were deleted
|
663 | * This little hack lets you know how many rows were deleted
|
664 | * when running a "DELETE FROM table" query. Only implemented
|
664 | * when running a "DELETE FROM table" query. Only implemented
|
665 | * if the DB_PORTABILITY_DELETE_COUNT portability option is on.
|
665 | * if the DB_PORTABILITY_DELETE_COUNT portability option is on.
|
666 | *
|
666 | *
|
667 | * @param string $query the query string to modify
|
667 | * @param string $query the query string to modify
|
668 | *
|
668 | *
|
669 | * @return string the modified query string
|
669 | * @return string the modified query string
|
670 | *
|
670 | *
|
671 | * @access protected
|
671 | * @access protected
|
672 | * @see DB_common::setOption()
|
672 | * @see DB_common::setOption()
|
673 | */
|
673 | */
|
674 | function modifyQuery($query) |
674 | function modifyQuery($query) |
675 | {
|
675 | {
|
676 | if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) { |
676 | if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) { |
677 | if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) { |
677 | if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) { |
678 | $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/', |
678 | $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/', |
679 | 'DELETE FROM \1 WHERE 1=1', $query); |
679 | 'DELETE FROM \1 WHERE 1=1', $query); |
680 | }
|
680 | }
|
681 | }
|
681 | }
|
682 | return $query; |
682 | return $query; |
683 | }
|
683 | }
|
684 | 684 | ||
685 | // }}}
|
685 | // }}}
|
686 | // {{{ sqliteRaiseError()
|
686 | // {{{ sqliteRaiseError()
|
687 | 687 | ||
688 | /**
|
688 | /**
|
689 | * Produces a DB_Error object regarding the current problem
|
689 | * Produces a DB_Error object regarding the current problem
|
690 | *
|
690 | *
|
691 | * @param int $errno if the error is being manually raised pass a
|
691 | * @param int $errno if the error is being manually raised pass a
|
692 | * DB_ERROR* constant here. If this isn't passed
|
692 | * DB_ERROR* constant here. If this isn't passed
|
693 | * the error information gathered from the DBMS.
|
693 | * the error information gathered from the DBMS.
|
694 | *
|
694 | *
|
695 | * @return object the DB_Error object
|
695 | * @return object the DB_Error object
|
696 | *
|
696 | *
|
697 | * @see DB_common::raiseError(),
|
697 | * @see DB_common::raiseError(),
|
698 | * DB_sqlite::errorNative(), DB_sqlite::errorCode()
|
698 | * DB_sqlite::errorNative(), DB_sqlite::errorCode()
|
699 | */
|
699 | */
|
700 | function sqliteRaiseError($errno = null) |
700 | function sqliteRaiseError($errno = null) |
701 | {
|
701 | {
|
702 | $native = $this->errorNative(); |
702 | $native = $this->errorNative(); |
703 | if ($errno === null) { |
703 | if ($errno === null) { |
704 | $errno = $this->errorCode($native); |
704 | $errno = $this->errorCode($native); |
705 | }
|
705 | }
|
706 | 706 | ||
707 | $errorcode = @sqlite_last_error($this->connection); |
707 | $errorcode = @sqlite_last_error($this->connection); |
708 | $userinfo = "$errorcode ** $this->last_query"; |
708 | $userinfo = "$errorcode ** $this->last_query"; |
709 | 709 | ||
710 | return $this->raiseError($errno, null, null, $userinfo, $native); |
710 | return $this->raiseError($errno, null, null, $userinfo, $native); |
711 | }
|
711 | }
|
712 | 712 | ||
713 | // }}}
|
713 | // }}}
|
714 | // {{{ errorNative()
|
714 | // {{{ errorNative()
|
715 | 715 | ||
716 | /**
|
716 | /**
|
717 | * Gets the DBMS' native error message produced by the last query
|
717 | * Gets the DBMS' native error message produced by the last query
|
718 | *
|
718 | *
|
719 | * {@internal This is used to retrieve more meaningfull error messages
|
719 | * {@internal This is used to retrieve more meaningfull error messages
|
720 | * because sqlite_last_error() does not provide adequate info.}}
|
720 | * because sqlite_last_error() does not provide adequate info.}}
|
721 | *
|
721 | *
|
722 | * @return string the DBMS' error message
|
722 | * @return string the DBMS' error message
|
723 | */
|
723 | */
|
724 | function errorNative() |
724 | function errorNative() |
725 | {
|
725 | {
|
726 | return $this->_lasterror; |
726 | return $this->_lasterror; |
727 | }
|
727 | }
|
728 | 728 | ||
729 | // }}}
|
729 | // }}}
|
730 | // {{{ errorCode()
|
730 | // {{{ errorCode()
|
731 | 731 | ||
732 | /**
|
732 | /**
|
733 | * Determines PEAR::DB error code from the database's text error message
|
733 | * Determines PEAR::DB error code from the database's text error message
|
734 | *
|
734 | *
|
735 | * @param string $errormsg the error message returned from the database
|
735 | * @param string $errormsg the error message returned from the database
|
736 | *
|
736 | *
|
737 | * @return integer the DB error number
|
737 | * @return integer the DB error number
|
738 | */
|
738 | */
|
739 | function errorCode($errormsg) |
739 | function errorCode($errormsg) |
740 | {
|
740 | {
|
741 | static $error_regexps; |
741 | static $error_regexps; |
742 | 742 | ||
743 | // PHP 5.2+ prepends the function name to $php_errormsg, so we need
|
743 | // PHP 5.2+ prepends the function name to $php_errormsg, so we need
|
744 | // this hack to work around it, per bug #9599.
|
744 | // this hack to work around it, per bug #9599.
|
745 | $errormsg = preg_replace('/^sqlite[a-z_]+\(\): /', '', $errormsg); |
745 | $errormsg = preg_replace('/^sqlite[a-z_]+\(\): /', '', $errormsg); |
746 | 746 | ||
747 | if (!isset($error_regexps)) { |
747 | if (!isset($error_regexps)) { |
748 | $error_regexps = array( |
748 | $error_regexps = array( |
749 | '/^no such table:/' => DB_ERROR_NOSUCHTABLE, |
749 | '/^no such table:/' => DB_ERROR_NOSUCHTABLE, |
750 | '/^no such index:/' => DB_ERROR_NOT_FOUND, |
750 | '/^no such index:/' => DB_ERROR_NOT_FOUND, |
751 | '/^(table|index) .* already exists$/' => DB_ERROR_ALREADY_EXISTS, |
751 | '/^(table|index) .* already exists$/' => DB_ERROR_ALREADY_EXISTS, |
752 | '/PRIMARY KEY must be unique/i' => DB_ERROR_CONSTRAINT, |
752 | '/PRIMARY KEY must be unique/i' => DB_ERROR_CONSTRAINT, |
753 | '/is not unique/' => DB_ERROR_CONSTRAINT, |
753 | '/is not unique/' => DB_ERROR_CONSTRAINT, |
754 | '/columns .* are not unique/i' => DB_ERROR_CONSTRAINT, |
754 | '/columns .* are not unique/i' => DB_ERROR_CONSTRAINT, |
755 | '/uniqueness constraint failed/' => DB_ERROR_CONSTRAINT, |
755 | '/uniqueness constraint failed/' => DB_ERROR_CONSTRAINT, |
756 | '/may not be NULL/' => DB_ERROR_CONSTRAINT_NOT_NULL, |
756 | '/may not be NULL/' => DB_ERROR_CONSTRAINT_NOT_NULL, |
757 | '/^no such column:/' => DB_ERROR_NOSUCHFIELD, |
757 | '/^no such column:/' => DB_ERROR_NOSUCHFIELD, |
758 | '/column not present in both tables/i' => DB_ERROR_NOSUCHFIELD, |
758 | '/column not present in both tables/i' => DB_ERROR_NOSUCHFIELD, |
759 | '/^near ".*": syntax error$/' => DB_ERROR_SYNTAX, |
759 | '/^near ".*": syntax error$/' => DB_ERROR_SYNTAX, |
760 | '/[0-9]+ values for [0-9]+ columns/i' => DB_ERROR_VALUE_COUNT_ON_ROW, |
760 | '/[0-9]+ values for [0-9]+ columns/i' => DB_ERROR_VALUE_COUNT_ON_ROW, |
761 | ); |
761 | ); |
762 | }
|
762 | }
|
763 | foreach ($error_regexps as $regexp => $code) { |
763 | foreach ($error_regexps as $regexp => $code) { |
764 | if (preg_match($regexp, $errormsg)) { |
764 | if (preg_match($regexp, $errormsg)) { |
765 | return $code; |
765 | return $code; |
766 | }
|
766 | }
|
767 | }
|
767 | }
|
768 | // Fall back to DB_ERROR if there was no mapping.
|
768 | // Fall back to DB_ERROR if there was no mapping.
|
769 | return DB_ERROR; |
769 | return DB_ERROR; |
770 | }
|
770 | }
|
771 | 771 | ||
772 | // }}}
|
772 | // }}}
|
773 | // {{{ tableInfo()
|
773 | // {{{ tableInfo()
|
774 | 774 | ||
775 | /**
|
775 | /**
|
776 | * Returns information about a table
|
776 | * Returns information about a table
|
777 | *
|
777 | *
|
778 | * @param string $result a string containing the name of a table
|
778 | * @param string $result a string containing the name of a table
|
779 | * @param int $mode a valid tableInfo mode
|
779 | * @param int $mode a valid tableInfo mode
|
780 | *
|
780 | *
|
781 | * @return array an associative array with the information requested.
|
781 | * @return array an associative array with the information requested.
|
782 | * A DB_Error object on failure.
|
782 | * A DB_Error object on failure.
|
783 | *
|
783 | *
|
784 | * @see DB_common::tableInfo()
|
784 | * @see DB_common::tableInfo()
|
785 | * @since Method available since Release 1.7.0
|
785 | * @since Method available since Release 1.7.0
|
786 | */
|
786 | */
|
787 | function tableInfo($result, $mode = null) |
787 | function tableInfo($result, $mode = null) |
788 | {
|
788 | {
|
789 | if (is_string($result)) { |
789 | if (is_string($result)) { |
790 | /*
|
790 | /*
|
791 | * Probably received a table name.
|
791 | * Probably received a table name.
|
792 | * Create a result resource identifier.
|
792 | * Create a result resource identifier.
|
793 | */
|
793 | */
|
794 | $id = @sqlite_array_query($this->connection, |
794 | $id = @sqlite_array_query($this->connection, |
795 | "PRAGMA table_info('$result');", |
795 | "PRAGMA table_info('$result');", |
796 | SQLITE_ASSOC); |
796 | SQLITE_ASSOC); |
797 | $got_string = true; |
797 | $got_string = true; |
798 | } else { |
798 | } else { |
799 | $this->last_query = ''; |
799 | $this->last_query = ''; |
800 | return $this->raiseError(DB_ERROR_NOT_CAPABLE, null, null, null, |
800 | return $this->raiseError(DB_ERROR_NOT_CAPABLE, null, null, null, |
801 | 'This DBMS can not obtain tableInfo' . |
801 | 'This DBMS can not obtain tableInfo' . |
802 | ' from result sets'); |
802 | ' from result sets'); |
803 | }
|
803 | }
|
804 | 804 | ||
805 | if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { |
805 | if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { |
806 | $case_func = 'strtolower'; |
806 | $case_func = 'strtolower'; |
807 | } else { |
807 | } else { |
808 | $case_func = 'strval'; |
808 | $case_func = 'strval'; |
809 | }
|
809 | }
|
810 | 810 | ||
811 | $count = count($id); |
811 | $count = count($id); |
812 | $res = array(); |
812 | $res = array(); |
813 | 813 | ||
814 | if ($mode) { |
814 | if ($mode) { |
815 | $res['num_fields'] = $count; |
815 | $res['num_fields'] = $count; |
816 | }
|
816 | }
|
817 | 817 | ||
818 | for ($i = 0; $i < $count; $i++) { |
818 | for ($i = 0; $i < $count; $i++) { |
819 | if (strpos($id[$i]['type'], '(') !== false) { |
819 | if (strpos($id[$i]['type'], '(') !== false) { |
820 | $bits = explode('(', $id[$i]['type']); |
820 | $bits = explode('(', $id[$i]['type']); |
821 | $type = $bits[0]; |
821 | $type = $bits[0]; |
822 | $len = rtrim($bits[1],')'); |
822 | $len = rtrim($bits[1],')'); |
823 | } else { |
823 | } else { |
824 | $type = $id[$i]['type']; |
824 | $type = $id[$i]['type']; |
825 | $len = 0; |
825 | $len = 0; |
826 | }
|
826 | }
|
827 | 827 | ||
828 | $flags = ''; |
828 | $flags = ''; |
829 | if ($id[$i]['pk']) { |
829 | if ($id[$i]['pk']) { |
830 | $flags .= 'primary_key '; |
830 | $flags .= 'primary_key '; |
831 | }
|
831 | }
|
832 | if ($id[$i]['notnull']) { |
832 | if ($id[$i]['notnull']) { |
833 | $flags .= 'not_null '; |
833 | $flags .= 'not_null '; |
834 | }
|
834 | }
|
835 | if ($id[$i]['dflt_value'] !== null) { |
835 | if ($id[$i]['dflt_value'] !== null) { |
836 | $flags .= 'default_' . rawurlencode($id[$i]['dflt_value']); |
836 | $flags .= 'default_' . rawurlencode($id[$i]['dflt_value']); |
837 | }
|
837 | }
|
838 | $flags = trim($flags); |
838 | $flags = trim($flags); |
839 | 839 | ||
840 | $res[$i] = array( |
840 | $res[$i] = array( |
841 | 'table' => $case_func($result), |
841 | 'table' => $case_func($result), |
842 | 'name' => $case_func($id[$i]['name']), |
842 | 'name' => $case_func($id[$i]['name']), |
843 | 'type' => $type, |
843 | 'type' => $type, |
844 | 'len' => $len, |
844 | 'len' => $len, |
845 | 'flags' => $flags, |
845 | 'flags' => $flags, |
846 | ); |
846 | ); |
847 | 847 | ||
848 | if ($mode & DB_TABLEINFO_ORDER) { |
848 | if ($mode & DB_TABLEINFO_ORDER) { |
849 | $res['order'][$res[$i]['name']] = $i; |
849 | $res['order'][$res[$i]['name']] = $i; |
850 | }
|
850 | }
|
851 | if ($mode & DB_TABLEINFO_ORDERTABLE) { |
851 | if ($mode & DB_TABLEINFO_ORDERTABLE) { |
852 | $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; |
852 | $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; |
853 | }
|
853 | }
|
854 | }
|
854 | }
|
855 | 855 | ||
856 | return $res; |
856 | return $res; |
857 | }
|
857 | }
|
858 | 858 | ||
859 | // }}}
|
859 | // }}}
|
860 | // {{{ getSpecialQuery()
|
860 | // {{{ getSpecialQuery()
|
861 | 861 | ||
862 | /**
|
862 | /**
|
863 | * Obtains the query string needed for listing a given type of objects
|
863 | * Obtains the query string needed for listing a given type of objects
|
864 | *
|
864 | *
|
865 | * @param string $type the kind of objects you want to retrieve
|
865 | * @param string $type the kind of objects you want to retrieve
|
866 | * @param array $args SQLITE DRIVER ONLY: a private array of arguments
|
866 | * @param array $args SQLITE DRIVER ONLY: a private array of arguments
|
867 | * used by the getSpecialQuery(). Do not use
|
867 | * used by the getSpecialQuery(). Do not use
|
868 | * this directly.
|
868 | * this directly.
|
869 | *
|
869 | *
|
870 | * @return string the SQL query string or null if the driver doesn't
|
870 | * @return string the SQL query string or null if the driver doesn't
|
871 | * support the object type requested
|
871 | * support the object type requested
|
872 | *
|
872 | *
|
873 | * @access protected
|
873 | * @access protected
|
874 | * @see DB_common::getListOf()
|
874 | * @see DB_common::getListOf()
|
875 | */
|
875 | */
|
876 | function getSpecialQuery($type, $args = array()) |
876 | function getSpecialQuery($type, $args = array()) |
877 | {
|
877 | {
|
878 | if (!is_array($args)) { |
878 | if (!is_array($args)) { |
879 | return $this->raiseError('no key specified', null, null, null, |
879 | return $this->raiseError('no key specified', null, null, null, |
880 | 'Argument has to be an array.'); |
880 | 'Argument has to be an array.'); |
881 | }
|
881 | }
|
882 | 882 | ||
883 | switch ($type) { |
883 | switch ($type) { |
884 | case 'master': |
884 | case 'master': |
885 | return 'SELECT * FROM sqlite_master;'; |
885 | return 'SELECT * FROM sqlite_master;'; |
886 | case 'tables': |
886 | case 'tables': |
887 | return "SELECT name FROM sqlite_master WHERE type='table' " |
887 | return "SELECT name FROM sqlite_master WHERE type='table' " |
888 | . 'UNION ALL SELECT name FROM sqlite_temp_master ' |
888 | . 'UNION ALL SELECT name FROM sqlite_temp_master ' |
889 | . "WHERE type='table' ORDER BY name;"; |
889 | . "WHERE type='table' ORDER BY name;"; |
890 | case 'schema': |
890 | case 'schema': |
891 | return 'SELECT sql FROM (SELECT * FROM sqlite_master ' |
891 | return 'SELECT sql FROM (SELECT * FROM sqlite_master ' |
892 | . 'UNION ALL SELECT * FROM sqlite_temp_master) ' |
892 | . 'UNION ALL SELECT * FROM sqlite_temp_master) ' |
893 | . "WHERE type!='meta' " |
893 | . "WHERE type!='meta' " |
894 | . 'ORDER BY tbl_name, type DESC, name;'; |
894 | . 'ORDER BY tbl_name, type DESC, name;'; |
895 | case 'schemax': |
895 | case 'schemax': |
896 | case 'schema_x': |
896 | case 'schema_x': |
897 | /*
|
897 | /*
|
898 | * Use like:
|
898 | * Use like:
|
899 | * $res = $db->query($db->getSpecialQuery('schema_x',
|
899 | * $res = $db->query($db->getSpecialQuery('schema_x',
|
900 | * array('table' => 'table3')));
|
900 | * array('table' => 'table3')));
|
901 | */
|
901 | */
|
902 | return 'SELECT sql FROM (SELECT * FROM sqlite_master ' |
902 | return 'SELECT sql FROM (SELECT * FROM sqlite_master ' |
903 | . 'UNION ALL SELECT * FROM sqlite_temp_master) ' |
903 | . 'UNION ALL SELECT * FROM sqlite_temp_master) ' |
904 | . "WHERE tbl_name LIKE '{$args['table']}' " |
904 | . "WHERE tbl_name LIKE '{$args['table']}' " |
905 | . "AND type!='meta' " |
905 | . "AND type!='meta' " |
906 | . 'ORDER BY type DESC, name;'; |
906 | . 'ORDER BY type DESC, name;'; |
907 | case 'alter': |
907 | case 'alter': |
908 | /*
|
908 | /*
|
909 | * SQLite does not support ALTER TABLE; this is a helper query
|
909 | * SQLite does not support ALTER TABLE; this is a helper query
|
910 | * to handle this. 'table' represents the table name, 'rows'
|
910 | * to handle this. 'table' represents the table name, 'rows'
|
911 | * the news rows to create, 'save' the row(s) to keep _with_
|
911 | * the news rows to create, 'save' the row(s) to keep _with_
|
912 | * the data.
|
912 | * the data.
|
913 | *
|
913 | *
|
914 | * Use like:
|
914 | * Use like:
|
915 | * $args = array(
|
915 | * $args = array(
|
916 | * 'table' => $table,
|
916 | * 'table' => $table,
|
917 | * 'rows' => "id INTEGER PRIMARY KEY, firstname TEXT, surname TEXT, datetime TEXT",
|
917 | * 'rows' => "id INTEGER PRIMARY KEY, firstname TEXT, surname TEXT, datetime TEXT",
|
918 | * 'save' => "NULL, titel, content, datetime"
|
918 | * 'save' => "NULL, titel, content, datetime"
|
919 | * );
|
919 | * );
|
920 | * $res = $db->query( $db->getSpecialQuery('alter', $args));
|
920 | * $res = $db->query( $db->getSpecialQuery('alter', $args));
|
921 | */
|
921 | */
|
922 | $rows = strtr($args['rows'], $this->keywords); |
922 | $rows = strtr($args['rows'], $this->keywords); |
923 | 923 | ||
924 | $q = array( |
924 | $q = array( |
925 | 'BEGIN TRANSACTION', |
925 | 'BEGIN TRANSACTION', |
926 | "CREATE TEMPORARY TABLE {$args['table']}_backup ({$args['rows']})", |
926 | "CREATE TEMPORARY TABLE {$args['table']}_backup ({$args['rows']})", |
927 | "INSERT INTO {$args['table']}_backup SELECT {$args['save']} FROM {$args['table']}", |
927 | "INSERT INTO {$args['table']}_backup SELECT {$args['save']} FROM {$args['table']}", |
928 | "DROP TABLE {$args['table']}", |
928 | "DROP TABLE {$args['table']}", |
929 | "CREATE TABLE {$args['table']} ({$args['rows']})", |
929 | "CREATE TABLE {$args['table']} ({$args['rows']})", |
930 | "INSERT INTO {$args['table']} SELECT {$rows} FROM {$args['table']}_backup", |
930 | "INSERT INTO {$args['table']} SELECT {$rows} FROM {$args['table']}_backup", |
931 | "DROP TABLE {$args['table']}_backup", |
931 | "DROP TABLE {$args['table']}_backup", |
932 | 'COMMIT', |
932 | 'COMMIT', |
933 | ); |
933 | ); |
934 | 934 | ||
935 | /*
|
935 | /*
|
936 | * This is a dirty hack, since the above query will not get
|
936 | * This is a dirty hack, since the above query will not get
|
937 | * executed with a single query call so here the query method
|
937 | * executed with a single query call so here the query method
|
938 | * will be called directly and return a select instead.
|
938 | * will be called directly and return a select instead.
|
939 | */
|
939 | */
|
940 | foreach ($q as $query) { |
940 | foreach ($q as $query) { |
941 | $this->query($query); |
941 | $this->query($query); |
942 | }
|
942 | }
|
943 | return "SELECT * FROM {$args['table']};"; |
943 | return "SELECT * FROM {$args['table']};"; |
944 | default: |
944 | default: |
945 | return null; |
945 | return null; |
946 | }
|
946 | }
|
947 | }
|
947 | }
|
948 | 948 | ||
949 | // }}}
|
949 | // }}}
|
950 | }
|
950 | }
|
951 | 951 | ||
952 | /*
|
952 | /*
|
953 | * Local variables:
|
953 | * Local variables:
|
954 | * tab-width: 4
|
954 | * tab-width: 4
|
955 | * c-basic-offset: 4
|
955 | * c-basic-offset: 4
|
956 | * End:
|
956 | * End:
|
957 | */
|
957 | */
|
958 | 958 | ||
959 | ?>
|
959 | ?>
|
960 | 960 |