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