blob: 7b1b4502ab542fe6a01502bdf45ad690e20fcc3f [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
12 * bundled with this package in the files license.txt / license.rst. It is
13 * 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 {
52 return is_int($this->num_rows)
53 ? $this->num_rows
54 : $this->num_rows = count($this->result_array());
55 }
56
57 // --------------------------------------------------------------------
58
59 /**
60 * Number of fields in the result set
61 *
62 * @return int
63 */
64 public function num_fields()
65 {
66 return ( ! is_int($this->_num_fields))
67 ? $this->_num_fields = $this->result_id->numColumns()
68 : $this->_num_fields;
69 }
70
71 // --------------------------------------------------------------------
72
73 /**
74 * Fetch Field Names
75 *
76 * Generates an array of column names
77 *
78 * @return array
79 */
80 public function list_fields()
81 {
82 $field_names = array();
83 for ($i = 0, $c = $this->num_fields(); $i < $this->num_fields(); $i++)
84 {
85 $field_names[] = $this->result_id->columnName($i);
86 }
87
88 return $field_names;
89 }
90
91 // --------------------------------------------------------------------
92
93 /**
94 * Field data
95 *
96 * Generates an array of objects containing field meta-data
97 *
98 * @return array
99 */
100 public function field_data()
101 {
102 $retval = array();
103 for ($i = 0, $c = $this->num_fields(); $i < $this->num_fields(); $i++)
104 {
105 $retval[$i] = new stdClass();
106 $retval[$i]->name = $this->result_id->columnName($i);
107 $retval[$i]->type = 'varchar';
108 $retval[$i]->max_length = 0;
109 $retval[$i]->primary_key = 0;
110 $retval[$i]->default = '';
111 }
112
113 return $retval;
114 }
115
116 // --------------------------------------------------------------------
117
118 /**
119 * Free the result
120 *
121 * @return void
122 */
123 public function free_result()
124 {
125 if (is_object($this->result_id))
126 {
127 $this->result_id->finalize();
128 $this->result_id = NULL;
129 }
130 }
131
132 // --------------------------------------------------------------------
133
134 /**
135 * Result - associative array
136 *
137 * Returns the result set as an array
138 *
139 * @return array
140 */
141 protected function _fetch_assoc()
142 {
143 return $this->result_id->fetchArray(SQLITE3_ASSOC);
144 }
145
146 // --------------------------------------------------------------------
147
148 /**
149 * Result - object
150 *
151 * Returns the result set as an object
152 *
153 * @access private
154 * @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
199 // Un-comment the following line, in case it becomes needed
200 // $this->_data_seek();
201 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
267 // Un-comment the following line, in case it becomes needed
268 // $this->_data_seek();
269 return $this->result_object;
270 }
271
272 // --------------------------------------------------------------------
273
274 /**
275 * Query result. Custom object version.
276 *
277 * @param string class name used to instantiate rows to
278 * @return array
279 */
280 public function custom_result_object($class_name)
281 {
282 if (array_key_exists($class_name, $this->custom_result_object))
283 {
284 return $this->custom_result_object[$class_name];
285 }
286
287 if ( ! class_exists($class_name) OR ! is_object($this->result_id) OR $this->num_rows() === 0)
288 {
289 return array();
290 }
291
292 /* Even if result_array hasn't been set prior to custom_result_object being called,
293 * num_rows() has done it.
294 */
295 $data = &$this->result_array;
296
297 $result_object = array();
298 for ($i = 0, $c = count($data); $i < $c; $i++)
299 {
300 $result_object[$i] = new $class_name();
301 foreach ($data[$i] as $key => $value)
302 {
303 $result_object[$i]->$key = $value;
304 }
305 }
306
307 /* As described for the num_rows() method - there's no easy
308 * way to get the number of rows selected. Our work-around
309 * solution (as in here as well) first checks if result_array
310 * exists and returns its count. It doesn't however check for
311 * custom_object_result, so - do it here.
312 */
313 if ( ! is_int($this->num_rows))
314 {
315 $this->num_rows = count($result_object);
316 }
317
318 // Cache and return the array
319 return $this->custom_result_object[$class_name] = $result_object;
320 }
321
322 // --------------------------------------------------------------------
323
324 /* Single row result.
325 *
326 * Acts as a wrapper for row_object(), row_array()
327 * and custom_row_object(). Also used by first_row(), next_row()
328 * and previous_row().
329 *
330 * @param int row index
331 * @param string ('object', 'array' or a custom class name)
332 * @return mixed whatever was passed to the second parameter
333 */
334 public function row($n = 0, $type = 'object')
335 {
336 if ($type === 'object')
337 {
338 return $this->row_object($n);
339 }
340 elseif ($type === 'array')
341 {
342 return $this->row_array($n);
343 }
344
345 return $this->custom_row_object($n, $type);
346 }
347
348 // --------------------------------------------------------------------
349
350 /* Single row result. Array version.
351 *
352 * @param int row index
353 * @return array
354 */
355 public function row_array($n = 0)
356 {
357 // Make sure $n is not a string
358 if ( ! is_int($n))
359 {
360 $n = (int) $n;
361 }
362
363 /* If row_data is initialized, it means that we've already tried
364 * (at least) to fetch some data, so ... check if we already have
365 * this row.
366 */
367 if (is_array($this->row_data))
368 {
369 /* If we already have row_data[$n] - return it.
370 *
371 * If we enter the elseif, there's a number of reasons to
372 * return an empty array:
373 *
374 * - count($this->row_data) === 0 means there are no results
375 * - num_rows being set or result_array having count() > 0 means
376 * that we've already fetched all data and $n is greater than
377 * our highest row index available
378 * - $n < $this->current_row means that if such row existed,
379 * we would've already returned it, therefore $n is an
380 * invalid index
381 */
382 if (isset($this->row_data[$n])) // We already have this row
383 {
384 $this->current_row = $n;
385 return $this->row_data[$n];
386 }
387 elseif (count($this->row_data) === 0 OR is_int($this->num_rows)
388 OR count($this->result_array) > 0 OR $n < $this->current_row)
389 {
390 // No such row exists
391 return array();
392 }
393
394 // Get the next row index that would actually need to be fetched
395 $current_row = ($this->current_row < count($this->row_data)) ? count($this->row_data) : $this->current_row + 1;
396 }
397 else
398 {
399 $current_row = $this->current_row = 0;
400 $this->row_data = array();
401 }
402
403 /* Fetch more data, if available
404 *
405 * NOTE: Operator precedence is important here, if you change
406 * 'AND' with '&&' - it WILL BREAK the results, as
407 * $row will be assigned the scalar value of both
408 * expressions!
409 */
410 while ($row = $this->_fetch_assoc() AND $current_row <= $n)
411 {
412 $this->row_data[$current_row++] = $row;
413 }
414
415 // This would mean that there's no (more) data to fetch
416 if ( ! is_array($this->row_data) OR ! isset($this->row_data[$n]))
417 {
418 // Cache what we already have
419 if (is_array($this->row_data))
420 {
421 $this->num_rows = count($this->row_data);
422 /* Usually, row_data could have less elements than result_array,
423 * but at this point - they should be exactly the same.
424 */
425 $this->result_array = $this->row_data;
426 }
427 else
428 {
429 $this->num_rows = 0;
430 }
431
432 return array();
433 }
434
435 $this->current_row = $n;
436 return $this->row_data[$n];
437 }
438
439 // --------------------------------------------------------------------
440
441 /* Single row result. Object version.
442 *
443 * @param int row index
444 * @return mixed object if row found; empty array if not
445 */
446 public function row_object($n = 0)
447 {
448 // Make sure $n is not a string
449 if ( ! is_int($n))
450 {
451 $n = (int) $n;
452 }
453
454 /* Logic here is exactly the same as in row_array,
455 * except we have to cast row_data[$n] to an object.
456 *
457 * If we already have result_object though - we can
458 * directly return from it.
459 */
460 if (isset($this->result_object[$n]))
461 {
462 $this->current_row = $n;
463 return $this->result_object[$n];
464 }
465
466 $row = $this->row_array($n);
467 // Cast only if the row exists
468 if (count($row) > 0)
469 {
470 $this->current_row = $n;
471 return (object) $row;
472 }
473
474 return array();
475 }
476
477 // --------------------------------------------------------------------
478
479 /* Single row result. Custom object version.
480 *
481 * @param int row index
482 * @param string custom class name
483 * @return mixed custom object if row found; empty array otherwise
484 */
485 public function custom_row_object($n = 0, $class_name)
486 {
487 // Make sure $n is not a string
488 if ( ! is_int($n))
489 {
490 $n = (int) $n;
491 }
492
493 if (array_key_exists($class_name, $this->custom_result_object))
494 {
495 /* We already have a the whole result set with this class_name,
496 * return the specified row if it exists, and an empty array if
497 * it doesn't.
498 */
499 if (isset($this->custom_result_object[$class_name][$n]))
500 {
501 $this->current_row = $n;
502 return $this->custom_result_object[$class_name][$n];
503 }
504 else
505 {
506 return array();
507 }
508 }
509 elseif ( ! class_exists($class_name)) // No such class exists
510 {
511 return array();
512 }
513
514 $row = $this->row_array($n);
515 // An array would mean that the row doesn't exist
516 if (is_array($row))
517 {
518 return $row;
519 }
520
521 // Convert to the desired class and return
522 $row_object = new $class_name();
523 foreach ($row as $key => $value)
524 {
525 $row_object->$key = $value;
526 }
527
528 $this->current_row = $n;
529 return $row_object;
530 }
531
532 // --------------------------------------------------------------------
533
534 /* First row result.
535 *
536 * @param string ('object', 'array' or a custom class name)
537 * @return mixed whatever was passed to the second parameter
538 */
539 public function first_row($type = 'object')
540 {
541 return $this->row(0, $type);
542 }
543
544 // --------------------------------------------------------------------
545
546 /* Last row result.
547 *
548 * @param string ('object', 'array' or a custom class name)
549 * @return mixed whatever was passed to the second parameter
550 */
551 public function last_row($type = 'object')
552 {
553 $result = &$this->result($type);
554 if ( ! isset($this->num_rows))
555 {
556 $this->num_rows = count($result);
557 }
558 $this->current_row = $this->num_rows - 1;
559 return $result[$this->current_row];
560 }
561
562 // --------------------------------------------------------------------
563
564 /* Next row result.
565 *
566 * @param string ('object', 'array' or a custom class name)
567 * @return mixed whatever was passed to the second parameter
568 */
569 public function next_row($type = 'object')
570 {
571 if (is_array($this->row_data))
572 {
573 $count = count($this->row_data);
574 $n = ($this->current_row > $count OR ($this->current_row === 0 && $count === 0)) ? $count : $this->current_row + 1;
575 }
576 else
577 {
578 $n = 0;
579 }
580
581 return $this->row($n, $type);
582 }
583
584 // --------------------------------------------------------------------
585
586 /* Previous row result.
587 *
588 * @param string ('object', 'array' or a custom class name)
589 * @return mixed whatever was passed to the second parameter
590 */
591 public function previous_row($type = 'object')
592 {
593 $n = ($this->current_row !== 0) ? $this->current_row - 1 : 0;
594 return $this->row($n, $type);
595 }
596
597 // --------------------------------------------------------------------
598
599 /**
600 * Data Seek
601 *
602 * Moves the internal pointer to the desired offset. We call
603 * this internally before fetching results to make sure the
604 * result set starts at zero
605 *
606 * @return array
607 */
608 public function _data_seek($n = 0)
609 {
610 // Only resetting to the start of the result set is supported
611 return $this->result_id->reset();
612 }
613
614}
615
616/* End of file sqlite3_result.php */
617/* Location: ./system/database/drivers/sqlite3/sqlite3_result.php */