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