blob: acda28e6a15ea135ab186ef4545dd09c0368297e [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 *
19 * @package CodeIgniter
20 * @author EllisLab Dev Team
21 * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
22 * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
23 * @link http://codeigniter.com
24 * @since Version 1.0
25 * @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 *
156 * @access private
157 * @return object
158 */
159 protected function _fetch_object()
160 {
161 // No native support for fetching as an object
162 $row = $this->_fetch_assoc();
163 return ($row !== FALSE) ? (object) $row : FALSE;
164 }
165
166 // --------------------------------------------------------------------
167
168 /**
169 * Query result. "array" version.
170 *
171 * return array
172 */
173 public function result_array()
174 {
175 if (count($this->result_array) > 0)
176 {
177 return $this->result_array;
178 }
179 elseif (is_array($this->row_data))
180 {
181 if (count($this->row_data) === 0)
182 {
183 return $this->result_array;
184 }
185 else
186 {
187 $row_index = count($this->row_data);
188 }
189 }
190 else
191 {
192 $row_index = 0;
193 $this->row_data = array();
194 }
195
196 $row = NULL;
197 while ($row = $this->_fetch_assoc())
198 {
199 $this->row_data[$row_index++] = $row;
200 }
201
202 // Un-comment the following line, in case it becomes needed
203 // $this->_data_seek();
204 return $this->result_array = $this->row_data;
205 }
206
207 // --------------------------------------------------------------------
208
209 /**
210 * Query result. "object" version.
211 *
212 * @return array
213 */
214 public function result_object()
215 {
216 if (count($this->result_object) > 0)
217 {
218 return $this->result_object;
219 }
220 elseif (count($this->result_array) > 0)
221 {
222 for ($i = 0, $c = count($this->result_array); $i < $c; $i++)
223 {
224 $this->result_object[] = (object) $this->result_array[$i];
225 }
226
227 return $this->result_object;
228 }
229 elseif (is_array($this->row_data))
230 {
231 if (count($this->row_data) === 0)
232 {
233 return $this->result_object;
234 }
235 else
236 {
237 $row_index = count($this->row_data);
238 for ($i = 0; $i < $row_index; $i++)
239 {
240 $this->result_object[$i] = (object) $this->row_data[$i];
241 }
242 }
243 }
244 else
245 {
246 $row_index = 0;
247 $this->row_data = array();
248 }
249
250 $row = NULL;
251 while ($row = $this->_fetch_assoc())
252 {
253 $this->row_data[$row_index] = $row;
254 $this->result_object[$row_index++] = (object) $row;
255 }
256
257 $this->result_array = $this->row_data;
258
259 /* As described for the num_rows() method - there's no easy
260 * way to get the number of rows selected. Our work-around
261 * solution (as in here as well) first checks if result_array
262 * exists and returns its count. It doesn't however check for
263 * custom_object_result, so - do it here.
264 */
265 if ( ! is_int($this->num_rows))
266 {
267 $this->num_rows = count($this->result_object);
268 }
269
270 // Un-comment the following line, in case it becomes needed
271 // $this->_data_seek();
272 return $this->result_object;
273 }
274
275 // --------------------------------------------------------------------
276
277 /**
278 * Query result. Custom object version.
279 *
280 * @param string class name used to instantiate rows to
281 * @return array
282 */
283 public function custom_result_object($class_name)
284 {
285 if (array_key_exists($class_name, $this->custom_result_object))
286 {
287 return $this->custom_result_object[$class_name];
288 }
289
290 if ( ! class_exists($class_name) OR ! is_object($this->result_id) OR $this->num_rows() === 0)
291 {
292 return array();
293 }
294
295 /* Even if result_array hasn't been set prior to custom_result_object being called,
296 * num_rows() has done it.
297 */
298 $data = &$this->result_array;
299
300 $result_object = array();
301 for ($i = 0, $c = count($data); $i < $c; $i++)
302 {
303 $result_object[$i] = new $class_name();
304 foreach ($data[$i] as $key => $value)
305 {
306 $result_object[$i]->$key = $value;
307 }
308 }
309
310 /* As described for the num_rows() method - there's no easy
311 * way to get the number of rows selected. Our work-around
312 * solution (as in here as well) first checks if result_array
313 * exists and returns its count. It doesn't however check for
314 * custom_object_result, so - do it here.
315 */
316 if ( ! is_int($this->num_rows))
317 {
318 $this->num_rows = count($result_object);
319 }
320
321 // Cache and return the array
322 return $this->custom_result_object[$class_name] = $result_object;
323 }
324
325 // --------------------------------------------------------------------
326
327 /* Single row result.
328 *
329 * Acts as a wrapper for row_object(), row_array()
330 * and custom_row_object(). Also used by first_row(), next_row()
331 * and previous_row().
332 *
333 * @param int row index
334 * @param string ('object', 'array' or a custom class name)
335 * @return mixed whatever was passed to the second parameter
336 */
337 public function row($n = 0, $type = 'object')
338 {
339 if ($type === 'object')
340 {
341 return $this->row_object($n);
342 }
343 elseif ($type === 'array')
344 {
345 return $this->row_array($n);
346 }
347
348 return $this->custom_row_object($n, $type);
349 }
350
351 // --------------------------------------------------------------------
352
353 /* Single row result. Array version.
354 *
355 * @param int row index
356 * @return array
357 */
358 public function row_array($n = 0)
359 {
360 // Make sure $n is not a string
361 if ( ! is_int($n))
362 {
363 $n = (int) $n;
364 }
365
366 /* If row_data is initialized, it means that we've already tried
367 * (at least) to fetch some data, so ... check if we already have
368 * this row.
369 */
370 if (is_array($this->row_data))
371 {
372 /* If we already have row_data[$n] - return it.
373 *
374 * If we enter the elseif, there's a number of reasons to
375 * return an empty array:
376 *
377 * - count($this->row_data) === 0 means there are no results
378 * - num_rows being set or result_array having count() > 0 means
379 * that we've already fetched all data and $n is greater than
380 * our highest row index available
381 * - $n < $this->current_row means that if such row existed,
382 * we would've already returned it, therefore $n is an
383 * invalid index
384 */
385 if (isset($this->row_data[$n])) // We already have this row
386 {
387 $this->current_row = $n;
388 return $this->row_data[$n];
389 }
390 elseif (count($this->row_data) === 0 OR is_int($this->num_rows)
391 OR count($this->result_array) > 0 OR $n < $this->current_row)
392 {
393 // No such row exists
394 return array();
395 }
396
397 // Get the next row index that would actually need to be fetched
398 $current_row = ($this->current_row < count($this->row_data)) ? count($this->row_data) : $this->current_row + 1;
399 }
400 else
401 {
402 $current_row = $this->current_row = 0;
403 $this->row_data = array();
404 }
405
406 /* Fetch more data, if available
407 *
408 * NOTE: Operator precedence is important here, if you change
409 * 'AND' with '&&' - it WILL BREAK the results, as
410 * $row will be assigned the scalar value of both
411 * expressions!
412 */
413 while ($row = $this->_fetch_assoc() AND $current_row <= $n)
414 {
415 $this->row_data[$current_row++] = $row;
416 }
417
418 // This would mean that there's no (more) data to fetch
419 if ( ! is_array($this->row_data) OR ! isset($this->row_data[$n]))
420 {
421 // Cache what we already have
422 if (is_array($this->row_data))
423 {
424 $this->num_rows = count($this->row_data);
425 /* Usually, row_data could have less elements than result_array,
426 * but at this point - they should be exactly the same.
427 */
428 $this->result_array = $this->row_data;
429 }
430 else
431 {
432 $this->num_rows = 0;
433 }
434
435 return array();
436 }
437
438 $this->current_row = $n;
439 return $this->row_data[$n];
440 }
441
442 // --------------------------------------------------------------------
443
444 /* Single row result. Object version.
445 *
446 * @param int row index
447 * @return mixed object if row found; empty array if not
448 */
449 public function row_object($n = 0)
450 {
451 // Make sure $n is not a string
452 if ( ! is_int($n))
453 {
454 $n = (int) $n;
455 }
456
457 /* Logic here is exactly the same as in row_array,
458 * except we have to cast row_data[$n] to an object.
459 *
460 * If we already have result_object though - we can
461 * directly return from it.
462 */
463 if (isset($this->result_object[$n]))
464 {
465 $this->current_row = $n;
466 return $this->result_object[$n];
467 }
468
469 $row = $this->row_array($n);
470 // Cast only if the row exists
471 if (count($row) > 0)
472 {
473 $this->current_row = $n;
474 return (object) $row;
475 }
476
477 return array();
478 }
479
480 // --------------------------------------------------------------------
481
482 /* Single row result. Custom object version.
483 *
484 * @param int row index
485 * @param string custom class name
486 * @return mixed custom object if row found; empty array otherwise
487 */
488 public function custom_row_object($n = 0, $class_name)
489 {
490 // Make sure $n is not a string
491 if ( ! is_int($n))
492 {
493 $n = (int) $n;
494 }
495
496 if (array_key_exists($class_name, $this->custom_result_object))
497 {
498 /* We already have a the whole result set with this class_name,
499 * return the specified row if it exists, and an empty array if
500 * it doesn't.
501 */
502 if (isset($this->custom_result_object[$class_name][$n]))
503 {
504 $this->current_row = $n;
505 return $this->custom_result_object[$class_name][$n];
506 }
507 else
508 {
509 return array();
510 }
511 }
512 elseif ( ! class_exists($class_name)) // No such class exists
513 {
514 return array();
515 }
516
517 $row = $this->row_array($n);
518 // An array would mean that the row doesn't exist
519 if (is_array($row))
520 {
521 return $row;
522 }
523
524 // Convert to the desired class and return
525 $row_object = new $class_name();
526 foreach ($row as $key => $value)
527 {
528 $row_object->$key = $value;
529 }
530
531 $this->current_row = $n;
532 return $row_object;
533 }
534
535 // --------------------------------------------------------------------
536
537 /* First row result.
538 *
539 * @param string ('object', 'array' or a custom class name)
540 * @return mixed whatever was passed to the second parameter
541 */
542 public function first_row($type = 'object')
543 {
544 return $this->row(0, $type);
545 }
546
547 // --------------------------------------------------------------------
548
549 /* Last row result.
550 *
551 * @param string ('object', 'array' or a custom class name)
552 * @return mixed whatever was passed to the second parameter
553 */
554 public function last_row($type = 'object')
555 {
556 $result = &$this->result($type);
557 if ( ! isset($this->num_rows))
558 {
559 $this->num_rows = count($result);
560 }
561 $this->current_row = $this->num_rows - 1;
562 return $result[$this->current_row];
563 }
564
565 // --------------------------------------------------------------------
566
567 /* Next row result.
568 *
569 * @param string ('object', 'array' or a custom class name)
570 * @return mixed whatever was passed to the second parameter
571 */
572 public function next_row($type = 'object')
573 {
574 if (is_array($this->row_data))
575 {
576 $count = count($this->row_data);
577 $n = ($this->current_row > $count OR ($this->current_row === 0 && $count === 0)) ? $count : $this->current_row + 1;
578 }
579 else
580 {
581 $n = 0;
582 }
583
584 return $this->row($n, $type);
585 }
586
587 // --------------------------------------------------------------------
588
589 /* Previous row result.
590 *
591 * @param string ('object', 'array' or a custom class name)
592 * @return mixed whatever was passed to the second parameter
593 */
594 public function previous_row($type = 'object')
595 {
596 $n = ($this->current_row !== 0) ? $this->current_row - 1 : 0;
597 return $this->row($n, $type);
598 }
599
600 // --------------------------------------------------------------------
601
602 /**
603 * Data Seek
604 *
605 * Moves the internal pointer to the desired offset. We call
606 * this internally before fetching results to make sure the
607 * result set starts at zero
608 *
609 * @return array
610 */
611 public function _data_seek($n = 0)
612 {
613 // Only resetting to the start of the result set is supported
614 return $this->result_id->reset();
615 }
616
617}
618
619/* End of file sqlite3_result.php */
620/* Location: ./system/database/drivers/sqlite3/sqlite3_result.php */