blob: b91e76f8505dab3efd0e68db4d41f8981e6168ff [file] [log] [blame]
Andrey Andreev8ae24c52012-01-16 13:05:23 +02001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
2/**
3 * CodeIgniter
4 *
5 * An open source application development framework for PHP 5.1.6 or newer
6 *
7 * NOTICE OF LICENSE
8 *
9 * Licensed under the Open Software License version 3.0
10 *
11 * This source file is subject to the Open Software License (OSL 3.0) that is
Andrey Andreevf20fb982012-01-24 15:26:01 +020012 * bundled with this package in the files license.txt / license.rst. It is
Andrey Andreev8ae24c52012-01-16 13:05:23 +020013 * also available through the world wide web at this URL:
14 * http://opensource.org/licenses/OSL-3.0
15 * If you did not receive a copy of the license and are unable to obtain it
16 * through the world wide web, please send an email to
17 * licensing@ellislab.com so we can send you a copy immediately.
18 *
Andrey Andreevd947eba2012-04-09 14:58:28 +030019 * @package CodeIgniter
20 * @author EllisLab Dev Team
Andrey Andreev8ae24c52012-01-16 13:05:23 +020021 * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
Andrey Andreevd947eba2012-04-09 14:58:28 +030022 * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
23 * @link http://codeigniter.com
24 * @since Version 1.0
Andrey Andreev8ae24c52012-01-16 13:05:23 +020025 * @filesource
26 */
27
28/**
29 * SQLite Result Class
30 *
31 * This class extends the parent result class: CI_DB_result
32 *
33 * @category Database
34 * @author Andrey Andreev
35 * @link http://codeigniter.com/user_guide/database/
Andrey Andreev5ca05132012-07-05 12:06:34 +030036 * @since 3.0
Andrey Andreev8ae24c52012-01-16 13:05:23 +020037 */
38class CI_DB_sqlite3_result extends CI_DB_result {
39
Andrey Andreev8ae24c52012-01-16 13:05:23 +020040 // num_fields() might be called multiple times, so we'll use this one to cache it's result
41 protected $_num_fields;
42
43 /**
44 * Number of rows in the result set
45 *
46 * @return int
47 */
48 public function num_rows()
49 {
Andrey Andreev5cbecb32012-01-16 13:08:24 +020050 /* The SQLite3 driver doesn't have a graceful way to do this,
51 * so we'll have to do it on our own.
52 */
Andrey Andreev8ae24c52012-01-16 13:05:23 +020053 return is_int($this->num_rows)
54 ? $this->num_rows
55 : $this->num_rows = count($this->result_array());
56 }
57
58 // --------------------------------------------------------------------
59
60 /**
61 * Number of fields in the result set
62 *
63 * @return int
64 */
65 public function num_fields()
66 {
67 return ( ! is_int($this->_num_fields))
68 ? $this->_num_fields = $this->result_id->numColumns()
69 : $this->_num_fields;
70 }
71
72 // --------------------------------------------------------------------
73
74 /**
75 * Fetch Field Names
76 *
77 * Generates an array of column names
78 *
79 * @return array
80 */
81 public function list_fields()
82 {
83 $field_names = array();
Andrey Andreev53921ca2012-01-16 14:35:22 +020084 for ($i = 0, $c = $this->num_fields(); $i < $c; $i++)
Andrey Andreev8ae24c52012-01-16 13:05:23 +020085 {
86 $field_names[] = $this->result_id->columnName($i);
87 }
88
89 return $field_names;
90 }
91
92 // --------------------------------------------------------------------
93
94 /**
95 * Field data
96 *
97 * Generates an array of objects containing field meta-data
98 *
99 * @return array
100 */
101 public function field_data()
102 {
103 $retval = array();
104 for ($i = 0, $c = $this->num_fields(); $i < $this->num_fields(); $i++)
105 {
106 $retval[$i] = new stdClass();
107 $retval[$i]->name = $this->result_id->columnName($i);
108 $retval[$i]->type = 'varchar';
109 $retval[$i]->max_length = 0;
110 $retval[$i]->primary_key = 0;
111 $retval[$i]->default = '';
112 }
113
114 return $retval;
115 }
116
117 // --------------------------------------------------------------------
118
119 /**
120 * Free the result
121 *
122 * @return void
123 */
124 public function free_result()
125 {
126 if (is_object($this->result_id))
127 {
128 $this->result_id->finalize();
129 $this->result_id = NULL;
130 }
131 }
132
133 // --------------------------------------------------------------------
134
135 /**
136 * Result - associative array
137 *
138 * Returns the result set as an array
139 *
140 * @return array
141 */
142 protected function _fetch_assoc()
143 {
144 return $this->result_id->fetchArray(SQLITE3_ASSOC);
145 }
146
147 // --------------------------------------------------------------------
148
149 /**
150 * Result - object
151 *
152 * Returns the result set as an object
153 *
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200154 * @return object
155 */
156 protected function _fetch_object()
157 {
158 // No native support for fetching as an object
159 $row = $this->_fetch_assoc();
160 return ($row !== FALSE) ? (object) $row : FALSE;
161 }
162
163 // --------------------------------------------------------------------
164
165 /**
166 * Query result. "array" version.
167 *
168 * return array
169 */
170 public function result_array()
171 {
172 if (count($this->result_array) > 0)
173 {
174 return $this->result_array;
175 }
176 elseif (is_array($this->row_data))
177 {
178 if (count($this->row_data) === 0)
179 {
180 return $this->result_array;
181 }
182 else
183 {
184 $row_index = count($this->row_data);
185 }
186 }
187 else
188 {
189 $row_index = 0;
190 $this->row_data = array();
191 }
192
193 $row = NULL;
194 while ($row = $this->_fetch_assoc())
195 {
196 $this->row_data[$row_index++] = $row;
197 }
198
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200199 return $this->result_array = $this->row_data;
200 }
201
202 // --------------------------------------------------------------------
203
204 /**
205 * Query result. "object" version.
206 *
207 * @return array
208 */
209 public function result_object()
210 {
211 if (count($this->result_object) > 0)
212 {
213 return $this->result_object;
214 }
215 elseif (count($this->result_array) > 0)
216 {
217 for ($i = 0, $c = count($this->result_array); $i < $c; $i++)
218 {
219 $this->result_object[] = (object) $this->result_array[$i];
220 }
221
222 return $this->result_object;
223 }
224 elseif (is_array($this->row_data))
225 {
226 if (count($this->row_data) === 0)
227 {
228 return $this->result_object;
229 }
230 else
231 {
232 $row_index = count($this->row_data);
233 for ($i = 0; $i < $row_index; $i++)
234 {
235 $this->result_object[$i] = (object) $this->row_data[$i];
236 }
237 }
238 }
239 else
240 {
241 $row_index = 0;
242 $this->row_data = array();
243 }
244
245 $row = NULL;
246 while ($row = $this->_fetch_assoc())
247 {
248 $this->row_data[$row_index] = $row;
249 $this->result_object[$row_index++] = (object) $row;
250 }
251
252 $this->result_array = $this->row_data;
253
254 /* As described for the num_rows() method - there's no easy
255 * way to get the number of rows selected. Our work-around
256 * solution (as in here as well) first checks if result_array
257 * exists and returns its count. It doesn't however check for
258 * custom_object_result, so - do it here.
259 */
260 if ( ! is_int($this->num_rows))
261 {
262 $this->num_rows = count($this->result_object);
263 }
264
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200265 return $this->result_object;
266 }
267
268 // --------------------------------------------------------------------
269
270 /**
271 * Query result. Custom object version.
272 *
273 * @param string class name used to instantiate rows to
274 * @return array
275 */
276 public function custom_result_object($class_name)
277 {
278 if (array_key_exists($class_name, $this->custom_result_object))
279 {
280 return $this->custom_result_object[$class_name];
281 }
282
283 if ( ! class_exists($class_name) OR ! is_object($this->result_id) OR $this->num_rows() === 0)
284 {
285 return array();
286 }
287
288 /* Even if result_array hasn't been set prior to custom_result_object being called,
289 * num_rows() has done it.
290 */
291 $data = &$this->result_array;
292
293 $result_object = array();
294 for ($i = 0, $c = count($data); $i < $c; $i++)
295 {
296 $result_object[$i] = new $class_name();
297 foreach ($data[$i] as $key => $value)
298 {
299 $result_object[$i]->$key = $value;
300 }
301 }
302
303 /* As described for the num_rows() method - there's no easy
304 * way to get the number of rows selected. Our work-around
305 * solution (as in here as well) first checks if result_array
306 * exists and returns its count. It doesn't however check for
307 * custom_object_result, so - do it here.
308 */
309 if ( ! is_int($this->num_rows))
310 {
311 $this->num_rows = count($result_object);
312 }
313
314 // Cache and return the array
315 return $this->custom_result_object[$class_name] = $result_object;
316 }
317
318 // --------------------------------------------------------------------
319
320 /* Single row result.
321 *
322 * Acts as a wrapper for row_object(), row_array()
323 * and custom_row_object(). Also used by first_row(), next_row()
324 * and previous_row().
325 *
326 * @param int row index
327 * @param string ('object', 'array' or a custom class name)
328 * @return mixed whatever was passed to the second parameter
329 */
330 public function row($n = 0, $type = 'object')
331 {
332 if ($type === 'object')
333 {
334 return $this->row_object($n);
335 }
336 elseif ($type === 'array')
337 {
338 return $this->row_array($n);
339 }
340
341 return $this->custom_row_object($n, $type);
342 }
343
344 // --------------------------------------------------------------------
345
346 /* Single row result. Array version.
347 *
348 * @param int row index
349 * @return array
350 */
351 public function row_array($n = 0)
352 {
353 // Make sure $n is not a string
354 if ( ! is_int($n))
355 {
356 $n = (int) $n;
357 }
358
359 /* If row_data is initialized, it means that we've already tried
360 * (at least) to fetch some data, so ... check if we already have
361 * this row.
362 */
363 if (is_array($this->row_data))
364 {
365 /* If we already have row_data[$n] - return it.
366 *
367 * If we enter the elseif, there's a number of reasons to
368 * return an empty array:
369 *
370 * - count($this->row_data) === 0 means there are no results
371 * - num_rows being set or result_array having count() > 0 means
372 * that we've already fetched all data and $n is greater than
373 * our highest row index available
374 * - $n < $this->current_row means that if such row existed,
375 * we would've already returned it, therefore $n is an
376 * invalid index
377 */
378 if (isset($this->row_data[$n])) // We already have this row
379 {
380 $this->current_row = $n;
381 return $this->row_data[$n];
382 }
383 elseif (count($this->row_data) === 0 OR is_int($this->num_rows)
384 OR count($this->result_array) > 0 OR $n < $this->current_row)
385 {
386 // No such row exists
Andrey Andreev55d3ad42012-05-24 22:13:06 +0300387 return NULL;
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200388 }
389
390 // Get the next row index that would actually need to be fetched
391 $current_row = ($this->current_row < count($this->row_data)) ? count($this->row_data) : $this->current_row + 1;
392 }
393 else
394 {
395 $current_row = $this->current_row = 0;
396 $this->row_data = array();
397 }
398
399 /* Fetch more data, if available
400 *
401 * NOTE: Operator precedence is important here, if you change
402 * 'AND' with '&&' - it WILL BREAK the results, as
403 * $row will be assigned the scalar value of both
404 * expressions!
405 */
406 while ($row = $this->_fetch_assoc() AND $current_row <= $n)
407 {
408 $this->row_data[$current_row++] = $row;
409 }
410
411 // This would mean that there's no (more) data to fetch
412 if ( ! is_array($this->row_data) OR ! isset($this->row_data[$n]))
413 {
414 // Cache what we already have
415 if (is_array($this->row_data))
416 {
417 $this->num_rows = count($this->row_data);
418 /* Usually, row_data could have less elements than result_array,
419 * but at this point - they should be exactly the same.
420 */
421 $this->result_array = $this->row_data;
422 }
423 else
424 {
425 $this->num_rows = 0;
426 }
427
Andrey Andreev55d3ad42012-05-24 22:13:06 +0300428 return NULL;
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200429 }
430
431 $this->current_row = $n;
432 return $this->row_data[$n];
433 }
434
435 // --------------------------------------------------------------------
436
437 /* Single row result. Object version.
438 *
439 * @param int row index
440 * @return mixed object if row found; empty array if not
441 */
442 public function row_object($n = 0)
443 {
444 // Make sure $n is not a string
445 if ( ! is_int($n))
446 {
447 $n = (int) $n;
448 }
449
450 /* Logic here is exactly the same as in row_array,
451 * except we have to cast row_data[$n] to an object.
452 *
453 * If we already have result_object though - we can
454 * directly return from it.
455 */
456 if (isset($this->result_object[$n]))
457 {
458 $this->current_row = $n;
459 return $this->result_object[$n];
460 }
461
462 $row = $this->row_array($n);
463 // Cast only if the row exists
464 if (count($row) > 0)
465 {
466 $this->current_row = $n;
467 return (object) $row;
468 }
469
Andrey Andreev55d3ad42012-05-24 22:13:06 +0300470 return NULL;
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200471 }
472
473 // --------------------------------------------------------------------
474
475 /* Single row result. Custom object version.
476 *
477 * @param int row index
478 * @param string custom class name
479 * @return mixed custom object if row found; empty array otherwise
480 */
481 public function custom_row_object($n = 0, $class_name)
482 {
483 // Make sure $n is not a string
484 if ( ! is_int($n))
485 {
486 $n = (int) $n;
487 }
488
489 if (array_key_exists($class_name, $this->custom_result_object))
490 {
491 /* We already have a the whole result set with this class_name,
492 * return the specified row if it exists, and an empty array if
493 * it doesn't.
494 */
495 if (isset($this->custom_result_object[$class_name][$n]))
496 {
497 $this->current_row = $n;
498 return $this->custom_result_object[$class_name][$n];
499 }
500 else
501 {
Andrey Andreev55d3ad42012-05-24 22:13:06 +0300502 return NULL;
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200503 }
504 }
505 elseif ( ! class_exists($class_name)) // No such class exists
506 {
Andrey Andreev55d3ad42012-05-24 22:13:06 +0300507 return NULL;
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200508 }
509
510 $row = $this->row_array($n);
Andrey Andreev55d3ad42012-05-24 22:13:06 +0300511 // A non-array would mean that the row doesn't exist
512 if ( ! is_array($row))
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200513 {
Andrey Andreev55d3ad42012-05-24 22:13:06 +0300514 return NULL;
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200515 }
516
517 // Convert to the desired class and return
518 $row_object = new $class_name();
519 foreach ($row as $key => $value)
520 {
521 $row_object->$key = $value;
522 }
523
524 $this->current_row = $n;
525 return $row_object;
526 }
527
528 // --------------------------------------------------------------------
529
530 /* First row result.
531 *
532 * @param string ('object', 'array' or a custom class name)
533 * @return mixed whatever was passed to the second parameter
534 */
535 public function first_row($type = 'object')
536 {
537 return $this->row(0, $type);
538 }
539
540 // --------------------------------------------------------------------
541
542 /* Last row result.
543 *
544 * @param string ('object', 'array' or a custom class name)
545 * @return mixed whatever was passed to the second parameter
546 */
547 public function last_row($type = 'object')
548 {
549 $result = &$this->result($type);
550 if ( ! isset($this->num_rows))
551 {
552 $this->num_rows = count($result);
553 }
554 $this->current_row = $this->num_rows - 1;
555 return $result[$this->current_row];
556 }
557
558 // --------------------------------------------------------------------
559
560 /* Next row result.
561 *
562 * @param string ('object', 'array' or a custom class name)
563 * @return mixed whatever was passed to the second parameter
564 */
565 public function next_row($type = 'object')
566 {
567 if (is_array($this->row_data))
568 {
569 $count = count($this->row_data);
570 $n = ($this->current_row > $count OR ($this->current_row === 0 && $count === 0)) ? $count : $this->current_row + 1;
571 }
572 else
573 {
574 $n = 0;
575 }
576
577 return $this->row($n, $type);
578 }
579
580 // --------------------------------------------------------------------
581
582 /* Previous row result.
583 *
584 * @param string ('object', 'array' or a custom class name)
585 * @return mixed whatever was passed to the second parameter
586 */
587 public function previous_row($type = 'object')
588 {
589 $n = ($this->current_row !== 0) ? $this->current_row - 1 : 0;
590 return $this->row($n, $type);
591 }
592
593 // --------------------------------------------------------------------
594
595 /**
596 * Data Seek
597 *
598 * Moves the internal pointer to the desired offset. We call
599 * this internally before fetching results to make sure the
600 * result set starts at zero
601 *
602 * @return array
603 */
Andrey Andreevf944d3b2012-03-20 22:12:55 +0200604 protected function _data_seek($n = 0)
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200605 {
606 // Only resetting to the start of the result set is supported
607 return $this->result_id->reset();
608 }
609
610}
611
612/* End of file sqlite3_result.php */
Andrey Andreevf944d3b2012-03-20 22:12:55 +0200613/* Location: ./system/database/drivers/sqlite3/sqlite3_result.php */