upgrade to codeigniter 1.7.2 for f12
[www-register-wizard.git] / database / DB_active_rec.php
1 <?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
2 /**
3  * CodeIgniter
4  *
5  * An open source application development framework for PHP 4.3.2 or newer
6  *
7  * @package             CodeIgniter
8  * @author              ExpressionEngine Dev Team
9  * @copyright   Copyright (c) 2008 - 2009, EllisLab, Inc.
10  * @license             http://codeigniter.com/user_guide/license.html
11  * @link                http://codeigniter.com
12  * @since               Version 1.0
13  * @filesource
14  */
15
16 // ------------------------------------------------------------------------
17
18 /**
19  * Active Record Class
20  *
21  * This is the platform-independent base Active Record implementation class.
22  *
23  * @package             CodeIgniter
24  * @subpackage  Drivers
25  * @category    Database
26  * @author              ExpressionEngine Dev Team
27  * @link                http://codeigniter.com/user_guide/database/
28  */
29 class CI_DB_active_record extends CI_DB_driver {
30
31         var $ar_select                          = array();
32         var $ar_distinct                        = FALSE;
33         var $ar_from                            = array();
34         var $ar_join                            = array();
35         var $ar_where                           = array();
36         var $ar_like                            = array();
37         var $ar_groupby                         = array();
38         var $ar_having                          = array();
39         var $ar_limit                           = FALSE;
40         var $ar_offset                          = FALSE;
41         var $ar_order                           = FALSE;
42         var $ar_orderby                         = array();
43         var $ar_set                                     = array();      
44         var $ar_wherein                         = array();
45         var $ar_aliased_tables          = array();
46         var $ar_store_array                     = array();
47         
48         // Active Record Caching variables
49         var $ar_caching                         = FALSE;
50         var $ar_cache_exists            = array();
51         var $ar_cache_select            = array();
52         var $ar_cache_from                      = array();
53         var $ar_cache_join                      = array();
54         var $ar_cache_where                     = array();
55         var $ar_cache_like                      = array();
56         var $ar_cache_groupby           = array();
57         var $ar_cache_having            = array();
58         var $ar_cache_orderby           = array();
59         var $ar_cache_set                       = array();      
60
61
62         // --------------------------------------------------------------------
63
64         /**
65          * Select
66          *
67          * Generates the SELECT portion of the query
68          *
69          * @access      public
70          * @param       string
71          * @return      object
72          */
73         function select($select = '*', $escape = NULL)
74         {
75                 // Set the global value if this was sepecified  
76                 if (is_bool($escape))
77                 {
78                         $this->_protect_identifiers = $escape;
79                 }
80                 
81                 if (is_string($select))
82                 {
83                         $select = explode(',', $select);
84                 }
85
86                 foreach ($select as $val)
87                 {
88                         $val = trim($val);
89
90                         if ($val != '')
91                         {
92                                 $this->ar_select[] = $val;
93
94                                 if ($this->ar_caching === TRUE)
95                                 {
96                                         $this->ar_cache_select[] = $val;
97                                         $this->ar_cache_exists[] = 'select';
98                                 }
99                         }
100                 }
101                 return $this;
102         }
103
104         // --------------------------------------------------------------------
105
106         /**
107          * Select Max
108          *
109          * Generates a SELECT MAX(field) portion of a query
110          *
111          * @access      public
112          * @param       string  the field
113          * @param       string  an alias
114          * @return      object
115          */
116         function select_max($select = '', $alias = '')
117         {
118                 return $this->_max_min_avg_sum($select, $alias, 'MAX');
119         }
120                 
121         // --------------------------------------------------------------------
122
123         /**
124          * Select Min
125          *
126          * Generates a SELECT MIN(field) portion of a query
127          *
128          * @access      public
129          * @param       string  the field
130          * @param       string  an alias
131          * @return      object
132          */
133         function select_min($select = '', $alias = '')
134         {
135                 return $this->_max_min_avg_sum($select, $alias, 'MIN');
136         }
137
138         // --------------------------------------------------------------------
139
140         /**
141          * Select Average
142          *
143          * Generates a SELECT AVG(field) portion of a query
144          *
145          * @access      public
146          * @param       string  the field
147          * @param       string  an alias
148          * @return      object
149          */
150         function select_avg($select = '', $alias = '')
151         {
152                 return $this->_max_min_avg_sum($select, $alias, 'AVG');
153         }
154
155         // --------------------------------------------------------------------
156
157         /**
158          * Select Sum
159          *
160          * Generates a SELECT SUM(field) portion of a query
161          *
162          * @access      public
163          * @param       string  the field
164          * @param       string  an alias
165          * @return      object
166          */
167         function select_sum($select = '', $alias = '')
168         {
169                 return $this->_max_min_avg_sum($select, $alias, 'SUM');
170         }
171
172         // --------------------------------------------------------------------
173
174         /**
175          * Processing Function for the four functions above:
176          *
177          *      select_max()
178          *      select_min()
179          *      select_avg()
180          *  select_sum()
181          *      
182          * @access      public
183          * @param       string  the field
184          * @param       string  an alias
185          * @return      object
186          */
187         function _max_min_avg_sum($select = '', $alias = '', $type = 'MAX')
188         {
189                 if ( ! is_string($select) OR $select == '')
190                 {
191                         $this->display_error('db_invalid_query');
192                 }
193         
194                 $type = strtoupper($type);
195         
196                 if ( ! in_array($type, array('MAX', 'MIN', 'AVG', 'SUM')))
197                 {
198                         show_error('Invalid function type: '.$type);
199                 }
200         
201                 if ($alias == '')
202                 {
203                         $alias = $this->_create_alias_from_table(trim($select));
204                 }
205         
206                 $sql = $type.'('.$this->_protect_identifiers(trim($select)).') AS '.$alias;
207
208                 $this->ar_select[] = $sql;
209                 
210                 if ($this->ar_caching === TRUE)
211                 {
212                         $this->ar_cache_select[] = $sql;
213                         $this->ar_cache_exists[] = 'select';
214                 }
215                 
216                 return $this;
217         }
218
219         // --------------------------------------------------------------------
220
221         /**
222          * Determines the alias name based on the table
223          *
224          * @access      private
225          * @param       string
226          * @return      string
227          */
228         function _create_alias_from_table($item)
229         {
230                 if (strpos($item, '.') !== FALSE)
231                 {
232                         return end(explode('.', $item));
233                 }
234                 
235                 return $item;
236         }
237
238         // --------------------------------------------------------------------
239
240         /**
241          * DISTINCT
242          *
243          * Sets a flag which tells the query string compiler to add DISTINCT
244          *
245          * @access      public
246          * @param       bool
247          * @return      object
248          */
249         function distinct($val = TRUE)
250         {
251                 $this->ar_distinct = (is_bool($val)) ? $val : TRUE;
252                 return $this;
253         }
254         
255         // --------------------------------------------------------------------
256
257         /**
258          * From
259          *
260          * Generates the FROM portion of the query
261          *
262          * @access      public
263          * @param       mixed   can be a string or array
264          * @return      object
265          */
266         function from($from)
267         {
268                 foreach ((array)$from as $val)
269                 {
270                         if (strpos($val, ',') !== FALSE)
271                         {
272                                 foreach (explode(',', $val) as $v)
273                                 {
274                                         $v = trim($v);
275                                         $this->_track_aliases($v);
276
277                                         $this->ar_from[] = $this->_protect_identifiers($v, TRUE, NULL, FALSE);
278                                         
279                                         if ($this->ar_caching === TRUE)
280                                         {
281                                                 $this->ar_cache_from[] = $this->_protect_identifiers($v, TRUE, NULL, FALSE);
282                                                 $this->ar_cache_exists[] = 'from';
283                                         }                               
284                                 }
285
286                         }
287                         else
288                         {
289                                 $val = trim($val);
290
291                                 // Extract any aliases that might exist.  We use this information
292                                 // in the _protect_identifiers to know whether to add a table prefix 
293                                 $this->_track_aliases($val);
294         
295                                 $this->ar_from[] = $this->_protect_identifiers($val, TRUE, NULL, FALSE);
296                                 
297                                 if ($this->ar_caching === TRUE)
298                                 {
299                                         $this->ar_cache_from[] = $this->_protect_identifiers($val, TRUE, NULL, FALSE);
300                                         $this->ar_cache_exists[] = 'from';
301                                 }
302                         }
303                 }
304
305                 return $this;
306         }
307
308         // --------------------------------------------------------------------
309
310         /**
311          * Join
312          *
313          * Generates the JOIN portion of the query
314          *
315          * @access      public
316          * @param       string
317          * @param       string  the join condition
318          * @param       string  the type of join
319          * @return      object
320          */
321         function join($table, $cond, $type = '')
322         {               
323                 if ($type != '')
324                 {
325                         $type = strtoupper(trim($type));
326
327                         if ( ! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER')))
328                         {
329                                 $type = '';
330                         }
331                         else
332                         {
333                                 $type .= ' ';
334                         }
335                 }
336
337                 // Extract any aliases that might exist.  We use this information
338                 // in the _protect_identifiers to know whether to add a table prefix 
339                 $this->_track_aliases($table);
340
341                 // Strip apart the condition and protect the identifiers
342                 if (preg_match('/([\w\.]+)([\W\s]+)(.+)/', $cond, $match))
343                 {
344                         $match[1] = $this->_protect_identifiers($match[1]);
345                         $match[3] = $this->_protect_identifiers($match[3]);
346                 
347                         $cond = $match[1].$match[2].$match[3];          
348                 }
349                 
350                 // Assemble the JOIN statement
351                 $join = $type.'JOIN '.$this->_protect_identifiers($table, TRUE, NULL, FALSE).' ON '.$cond;
352
353                 $this->ar_join[] = $join;
354                 if ($this->ar_caching === TRUE)
355                 {
356                         $this->ar_cache_join[] = $join;
357                         $this->ar_cache_exists[] = 'join';
358                 }
359
360                 return $this;
361         }
362
363         // --------------------------------------------------------------------
364
365         /**
366          * Where
367          *
368          * Generates the WHERE portion of the query. Separates
369          * multiple calls with AND
370          *
371          * @access      public
372          * @param       mixed
373          * @param       mixed
374          * @return      object
375          */
376         function where($key, $value = NULL, $escape = TRUE)
377         {
378                 return $this->_where($key, $value, 'AND ', $escape);
379         }
380         
381         // --------------------------------------------------------------------
382
383         /**
384          * OR Where
385          *
386          * Generates the WHERE portion of the query. Separates
387          * multiple calls with OR
388          *
389          * @access      public
390          * @param       mixed
391          * @param       mixed
392          * @return      object
393          */
394         function or_where($key, $value = NULL, $escape = TRUE)
395         {
396                 return $this->_where($key, $value, 'OR ', $escape);
397         }
398
399         // --------------------------------------------------------------------
400
401         /**
402          * orwhere() is an alias of or_where()
403          * this function is here for backwards compatibility, as
404          * orwhere() has been deprecated
405          */
406         function orwhere($key, $value = NULL, $escape = TRUE)
407         {
408                 return $this->or_where($key, $value, $escape);
409         }
410
411         // --------------------------------------------------------------------
412
413         /**
414          * Where
415          *
416          * Called by where() or orwhere()
417          *
418          * @access      private
419          * @param       mixed
420          * @param       mixed
421          * @param       string
422          * @return      object
423          */
424         function _where($key, $value = NULL, $type = 'AND ', $escape = NULL)
425         {
426                 if ( ! is_array($key))
427                 {
428                         $key = array($key => $value);
429                 }
430                 
431                 // If the escape value was not set will will base it on the global setting
432                 if ( ! is_bool($escape))
433                 {
434                         $escape = $this->_protect_identifiers;
435                 }
436
437                 foreach ($key as $k => $v)
438                 {
439                         $prefix = (count($this->ar_where) == 0 AND count($this->ar_cache_where) == 0) ? '' : $type;
440
441                         if (is_null($v) && ! $this->_has_operator($k))
442                         {
443                                 // value appears not to have been set, assign the test to IS NULL
444                                 $k .= ' IS NULL';
445                         }
446                         
447                         if ( ! is_null($v))
448                         {
449                                 if ($escape === TRUE)
450                                 {
451                                         $k = $this->_protect_identifiers($k, FALSE, $escape);
452                                         
453                                         $v = ' '.$this->escape($v);
454                                 }
455
456                                 if ( ! $this->_has_operator($k))
457                                 {
458                                         $k .= ' =';
459                                 }
460                         }
461                         else
462                         {
463                                 $k = $this->_protect_identifiers($k, FALSE, $escape);                   
464                         }
465
466                         $this->ar_where[] = $prefix.$k.$v;
467                         
468                         if ($this->ar_caching === TRUE)
469                         {
470                                 $this->ar_cache_where[] = $prefix.$k.$v;
471                                 $this->ar_cache_exists[] = 'where';
472                         }
473                         
474                 }
475                 
476                 return $this;
477         }
478
479         // --------------------------------------------------------------------
480
481         /**
482          * Where_in
483          *
484          * Generates a WHERE field IN ('item', 'item') SQL query joined with
485          * AND if appropriate
486          *
487          * @access      public
488          * @param       string  The field to search
489          * @param       array   The values searched on
490          * @return      object
491          */
492         function where_in($key = NULL, $values = NULL)
493         {
494                 return $this->_where_in($key, $values);
495         }
496         
497         // --------------------------------------------------------------------
498
499         /**
500          * Where_in_or
501          *
502          * Generates a WHERE field IN ('item', 'item') SQL query joined with
503          * OR if appropriate
504          *
505          * @access      public
506          * @param       string  The field to search
507          * @param       array   The values searched on
508          * @return      object
509          */
510         function or_where_in($key = NULL, $values = NULL)
511         {
512                 return $this->_where_in($key, $values, FALSE, 'OR ');
513         }
514
515         // --------------------------------------------------------------------
516
517         /**
518          * Where_not_in
519          *
520          * Generates a WHERE field NOT IN ('item', 'item') SQL query joined
521          * with AND if appropriate
522          *
523          * @access      public
524          * @param       string  The field to search
525          * @param       array   The values searched on
526          * @return      object
527          */
528         function where_not_in($key = NULL, $values = NULL)
529         {
530                 return $this->_where_in($key, $values, TRUE);
531         }
532         
533         // --------------------------------------------------------------------
534
535         /**
536          * Where_not_in_or
537          *
538          * Generates a WHERE field NOT IN ('item', 'item') SQL query joined
539          * with OR if appropriate
540          *
541          * @access      public
542          * @param       string  The field to search
543          * @param       array   The values searched on
544          * @return      object
545          */
546         function or_where_not_in($key = NULL, $values = NULL)
547         {
548                 return $this->_where_in($key, $values, TRUE, 'OR ');
549         }
550
551         // --------------------------------------------------------------------
552
553         /**
554          * Where_in
555          *
556          * Called by where_in, where_in_or, where_not_in, where_not_in_or
557          *
558          * @access      public
559          * @param       string  The field to search
560          * @param       array   The values searched on
561          * @param       boolean If the statement would be IN or NOT IN
562          * @param       string  
563          * @return      object
564          */
565         function _where_in($key = NULL, $values = NULL, $not = FALSE, $type = 'AND ')
566         {
567                 if ($key === NULL OR $values === NULL)
568                 {
569                         return;
570                 }
571                 
572                 if ( ! is_array($values))
573                 {
574                         $values = array($values);
575                 }
576                 
577                 $not = ($not) ? ' NOT' : '';
578
579                 foreach ($values as $value)
580                 {
581                         $this->ar_wherein[] = $this->escape($value);
582                 }
583
584                 $prefix = (count($this->ar_where) == 0) ? '' : $type;
585  
586                 $where_in = $prefix . $this->_protect_identifiers($key) . $not . " IN (" . implode(", ", $this->ar_wherein) . ") ";
587
588                 $this->ar_where[] = $where_in;
589                 if ($this->ar_caching === TRUE)
590                 {
591                         $this->ar_cache_where[] = $where_in;
592                         $this->ar_cache_exists[] = 'where';
593                 }
594
595                 // reset the array for multiple calls
596                 $this->ar_wherein = array();
597                 return $this;
598         }
599                 
600         // --------------------------------------------------------------------
601
602         /**
603          * Like
604          *
605          * Generates a %LIKE% portion of the query. Separates
606          * multiple calls with AND
607          *
608          * @access      public
609          * @param       mixed
610          * @param       mixed
611          * @return      object
612          */
613         function like($field, $match = '', $side = 'both')
614         {
615                 return $this->_like($field, $match, 'AND ', $side);
616         }
617
618         // --------------------------------------------------------------------
619
620         /**
621          * Not Like
622          *
623          * Generates a NOT LIKE portion of the query. Separates
624          * multiple calls with AND
625          *
626          * @access      public
627          * @param       mixed
628          * @param       mixed
629          * @return      object
630          */
631         function not_like($field, $match = '', $side = 'both')
632         {
633                 return $this->_like($field, $match, 'AND ', $side, 'NOT');
634         }
635                 
636         // --------------------------------------------------------------------
637
638         /**
639          * OR Like
640          *
641          * Generates a %LIKE% portion of the query. Separates
642          * multiple calls with OR
643          *
644          * @access      public
645          * @param       mixed
646          * @param       mixed
647          * @return      object
648          */
649         function or_like($field, $match = '', $side = 'both')
650         {
651                 return $this->_like($field, $match, 'OR ', $side);
652         }
653
654         // --------------------------------------------------------------------
655
656         /**
657          * OR Not Like
658          *
659          * Generates a NOT LIKE portion of the query. Separates
660          * multiple calls with OR
661          *
662          * @access      public
663          * @param       mixed
664          * @param       mixed
665          * @return      object
666          */
667         function or_not_like($field, $match = '', $side = 'both')
668         {
669                 return $this->_like($field, $match, 'OR ', $side, 'NOT');
670         }
671         
672         // --------------------------------------------------------------------
673
674         /**
675          * orlike() is an alias of or_like()
676          * this function is here for backwards compatibility, as
677          * orlike() has been deprecated
678          */
679         function orlike($field, $match = '', $side = 'both')
680         {
681                 return $this->or_like($field, $match, $side);
682         }
683         
684         // --------------------------------------------------------------------
685
686         /**
687          * Like
688          *
689          * Called by like() or orlike()
690          *
691          * @access      private
692          * @param       mixed
693          * @param       mixed
694          * @param       string
695          * @return      object
696          */
697         function _like($field, $match = '', $type = 'AND ', $side = 'both', $not = '')
698         {
699                 if ( ! is_array($field))
700                 {
701                         $field = array($field => $match);
702                 }
703         
704                 foreach ($field as $k => $v)
705                 {
706                         $k = $this->_protect_identifiers($k);
707
708                         $prefix = (count($this->ar_like) == 0) ? '' : $type;
709
710                         $v = $this->escape_like_str($v);
711
712                         if ($side == 'before')
713                         {
714                                 $like_statement = $prefix." $k $not LIKE '%{$v}'";
715                         }
716                         elseif ($side == 'after')
717                         {
718                                 $like_statement = $prefix." $k $not LIKE '{$v}%'";
719                         }
720                         else
721                         {
722                                 $like_statement = $prefix." $k $not LIKE '%{$v}%'";
723                         }
724                         
725                         // some platforms require an escape sequence definition for LIKE wildcards
726                         if ($this->_like_escape_str != '')
727                         {
728                                 $like_statement = $like_statement.sprintf($this->_like_escape_str, $this->_like_escape_char);
729                         }
730                         
731                         $this->ar_like[] = $like_statement;
732                         if ($this->ar_caching === TRUE)
733                         {
734                                 $this->ar_cache_like[] = $like_statement;
735                                 $this->ar_cache_exists[] = 'like';
736                         }
737                         
738                 }
739                 return $this;
740         }
741         
742         // --------------------------------------------------------------------
743
744         /**
745          * GROUP BY
746          *
747          * @access      public
748          * @param       string
749          * @return      object
750          */
751         function group_by($by)
752         {
753                 if (is_string($by))
754                 {
755                         $by = explode(',', $by);
756                 }
757         
758                 foreach ($by as $val)
759                 {
760                         $val = trim($val);
761                 
762                         if ($val != '')
763                         {
764                                 $this->ar_groupby[] = $this->_protect_identifiers($val);
765                                 
766                                 if ($this->ar_caching === TRUE)
767                                 {
768                                         $this->ar_cache_groupby[] = $this->_protect_identifiers($val);
769                                         $this->ar_cache_exists[] = 'groupby';
770                                 }
771                         }
772                 }
773                 return $this;
774         }
775
776         // --------------------------------------------------------------------
777
778         /**
779          * groupby() is an alias of group_by()
780          * this function is here for backwards compatibility, as
781          * groupby() has been deprecated
782          */
783         function groupby($by)
784         {
785                 return $this->group_by($by);
786         }       
787
788         // --------------------------------------------------------------------
789
790         /**
791          * Sets the HAVING value
792          *
793          * Separates multiple calls with AND
794          *
795          * @access      public
796          * @param       string
797          * @param       string
798          * @return      object
799          */
800         function having($key, $value = '', $escape = TRUE)
801         {
802                 return $this->_having($key, $value, 'AND ', $escape);
803         }
804
805         // --------------------------------------------------------------------
806
807         /**
808          * orhaving() is an alias of or_having()
809          * this function is here for backwards compatibility, as
810          * orhaving() has been deprecated
811          */
812
813         function orhaving($key, $value = '', $escape = TRUE)
814         {
815                 return $this->or_having($key, $value, $escape);
816         }       
817         // --------------------------------------------------------------------
818
819         /**
820          * Sets the OR HAVING value
821          *
822          * Separates multiple calls with OR
823          *
824          * @access      public
825          * @param       string
826          * @param       string
827          * @return      object
828          */
829         function or_having($key, $value = '', $escape = TRUE)
830         {
831                 return $this->_having($key, $value, 'OR ', $escape);
832         }
833         
834         // --------------------------------------------------------------------
835
836         /**
837          * Sets the HAVING values
838          *
839          * Called by having() or or_having()
840          *
841          * @access      private
842          * @param       string
843          * @param       string
844          * @return      object
845          */
846         function _having($key, $value = '', $type = 'AND ', $escape = TRUE)
847         {
848                 if ( ! is_array($key))
849                 {
850                         $key = array($key => $value);
851                 }
852         
853                 foreach ($key as $k => $v)
854                 {
855                         $prefix = (count($this->ar_having) == 0) ? '' : $type;
856
857                         if ($escape === TRUE)
858                         {
859                                 $k = $this->_protect_identifiers($k);
860                         }
861
862                         if ( ! $this->_has_operator($k))
863                         {
864                                 $k .= ' = ';
865                         }
866
867                         if ($v != '')
868                         {
869                                 $v = ' '.$this->escape_str($v);
870                         }
871                         
872                         $this->ar_having[] = $prefix.$k.$v;
873                         if ($this->ar_caching === TRUE)
874                         {
875                                 $this->ar_cache_having[] = $prefix.$k.$v;
876                                 $this->ar_cache_exists[] = 'having';
877                         }
878                 }
879                 
880                 return $this;
881         }
882         
883         // --------------------------------------------------------------------
884
885         /**
886          * Sets the ORDER BY value
887          *
888          * @access      public
889          * @param       string
890          * @param       string  direction: asc or desc
891          * @return      object
892          */
893         function order_by($orderby, $direction = '')
894         {
895                 if (strtolower($direction) == 'random')
896                 {
897                         $orderby = ''; // Random results want or don't need a field name
898                         $direction = $this->_random_keyword;
899                 }
900                 elseif (trim($direction) != '')
901                 {
902                         $direction = (in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE)) ? ' '.$direction : ' ASC';
903                 }
904         
905         
906                 if (strpos($orderby, ',') !== FALSE)
907                 {
908                         $temp = array();
909                         foreach (explode(',', $orderby) as $part)
910                         {
911                                 $part = trim($part);
912                                 if ( ! in_array($part, $this->ar_aliased_tables))
913                                 {
914                                         $part = $this->_protect_identifiers(trim($part));
915                                 }
916                                 
917                                 $temp[] = $part;
918                         }
919                         
920                         $orderby = implode(', ', $temp);                        
921                 }
922                 else if ($direction != $this->_random_keyword)
923                 {
924                         $orderby = $this->_protect_identifiers($orderby);
925                 }
926         
927                 $orderby_statement = $orderby.$direction;
928                 
929                 $this->ar_orderby[] = $orderby_statement;
930                 if ($this->ar_caching === TRUE)
931                 {
932                         $this->ar_cache_orderby[] = $orderby_statement;
933                         $this->ar_cache_exists[] = 'orderby';
934                 }
935
936                 return $this;
937         }
938         
939         // --------------------------------------------------------------------
940
941         /**
942          * orderby() is an alias of order_by()
943          * this function is here for backwards compatibility, as
944          * orderby() has been deprecated
945          */
946         function orderby($orderby, $direction = '')
947         {
948                 return $this->order_by($orderby, $direction);
949         }
950         
951         // --------------------------------------------------------------------
952
953         /**
954          * Sets the LIMIT value
955          *
956          * @access      public
957          * @param       integer the limit value
958          * @param       integer the offset value
959          * @return      object
960          */
961         function limit($value, $offset = '')
962         {
963                 $this->ar_limit = $value;
964
965                 if ($offset != '')
966                 {
967                         $this->ar_offset = $offset;
968                 }
969                 
970                 return $this;
971         }
972         
973         // --------------------------------------------------------------------
974
975         /**
976          * Sets the OFFSET value
977          *
978          * @access      public
979          * @param       integer the offset value
980          * @return      object
981          */
982         function offset($offset)
983         {
984                 $this->ar_offset = $offset;
985                 return $this;
986         }
987         
988         // --------------------------------------------------------------------
989
990         /**
991          * The "set" function.  Allows key/value pairs to be set for inserting or updating
992          *
993          * @access      public
994          * @param       mixed
995          * @param       string
996          * @param       boolean
997          * @return      object
998          */
999         function set($key, $value = '', $escape = TRUE)
1000         {
1001                 $key = $this->_object_to_array($key);
1002         
1003                 if ( ! is_array($key))
1004                 {
1005                         $key = array($key => $value);
1006                 }       
1007
1008                 foreach ($key as $k => $v)
1009                 {
1010                         if ($escape === FALSE)
1011                         {
1012                                 $this->ar_set[$this->_protect_identifiers($k)] = $v;
1013                         }
1014                         else
1015                         {
1016                                 $this->ar_set[$this->_protect_identifiers($k)] = $this->escape($v);
1017                         }
1018                 }
1019                 
1020                 return $this;
1021         }
1022         
1023         // --------------------------------------------------------------------
1024
1025         /**
1026          * Get
1027          *
1028          * Compiles the select statement based on the other functions called
1029          * and runs the query
1030          *
1031          * @access      public
1032          * @param       string  the table
1033          * @param       string  the limit clause
1034          * @param       string  the offset clause
1035          * @return      object
1036          */
1037         function get($table = '', $limit = null, $offset = null)
1038         {
1039                 if ($table != '')
1040                 {
1041                         $this->_track_aliases($table);
1042                         $this->from($table);
1043                 }
1044                 
1045                 if ( ! is_null($limit))
1046                 {
1047                         $this->limit($limit, $offset);
1048                 }
1049                         
1050                 $sql = $this->_compile_select();
1051
1052                 $result = $this->query($sql);
1053                 $this->_reset_select();
1054                 return $result;
1055         }
1056
1057         /**
1058          * "Count All Results" query
1059          *
1060          * Generates a platform-specific query string that counts all records 
1061          * returned by an Active Record query.
1062          *
1063          * @access      public
1064          * @param       string
1065          * @return      string
1066          */
1067         function count_all_results($table = '')
1068         {
1069                 if ($table != '')
1070                 {
1071                         $this->_track_aliases($table);
1072                         $this->from($table);
1073                 }
1074                 
1075                 $sql = $this->_compile_select($this->_count_string . $this->_protect_identifiers('numrows'));
1076
1077                 $query = $this->query($sql);
1078                 $this->_reset_select();
1079         
1080                 if ($query->num_rows() == 0)
1081                 {
1082                         return '0';
1083                 }
1084
1085                 $row = $query->row();
1086                 return $row->numrows;
1087         }
1088
1089         // --------------------------------------------------------------------
1090
1091         /**
1092          * Get_Where
1093          *
1094          * Allows the where clause, limit and offset to be added directly
1095          *
1096          * @access      public
1097          * @param       string  the where clause
1098          * @param       string  the limit clause
1099          * @param       string  the offset clause
1100          * @return      object
1101          */
1102         function get_where($table = '', $where = null, $limit = null, $offset = null)
1103         {
1104                 if ($table != '')
1105                 {
1106                         $this->from($table);
1107                 }
1108
1109                 if ( ! is_null($where))
1110                 {
1111                         $this->where($where);
1112                 }
1113                 
1114                 if ( ! is_null($limit))
1115                 {
1116                         $this->limit($limit, $offset);
1117                 }
1118                         
1119                 $sql = $this->_compile_select();
1120
1121                 $result = $this->query($sql);
1122                 $this->_reset_select();
1123                 return $result;
1124         }
1125
1126         // --------------------------------------------------------------------
1127
1128         /**
1129          * getwhere() is an alias of get_where()
1130          * this function is here for backwards compatibility, as
1131          * getwhere() has been deprecated
1132          */
1133         function getwhere($table = '', $where = null, $limit = null, $offset = null)
1134         {
1135                 return $this->get_where($table, $where, $limit, $offset);
1136         }
1137         
1138         // --------------------------------------------------------------------
1139
1140         /**
1141          * Insert
1142          *
1143          * Compiles an insert string and runs the query
1144          *
1145          * @access      public
1146          * @param       string  the table to retrieve the results from
1147          * @param       array   an associative array of insert values
1148          * @return      object
1149          */
1150         function insert($table = '', $set = NULL)
1151         {       
1152                 if ( ! is_null($set))
1153                 {
1154                         $this->set($set);
1155                 }
1156         
1157                 if (count($this->ar_set) == 0)
1158                 {
1159                         if ($this->db_debug)
1160                         {
1161                                 return $this->display_error('db_must_use_set');
1162                         }
1163                         return FALSE;
1164                 }
1165
1166                 if ($table == '')
1167                 {
1168                         if ( ! isset($this->ar_from[0]))
1169                         {
1170                                 if ($this->db_debug)
1171                                 {
1172                                         return $this->display_error('db_must_set_table');
1173                                 }
1174                                 return FALSE;
1175                         }
1176                         
1177                         $table = $this->ar_from[0];
1178                 }
1179
1180                 $sql = $this->_insert($this->_protect_identifiers($table, TRUE, NULL, FALSE), array_keys($this->ar_set), array_values($this->ar_set));
1181                 
1182                 $this->_reset_write();
1183                 return $this->query($sql);              
1184         }
1185         
1186         // --------------------------------------------------------------------
1187
1188         /**
1189          * Update
1190          *
1191          * Compiles an update string and runs the query
1192          *
1193          * @access      public
1194          * @param       string  the table to retrieve the results from
1195          * @param       array   an associative array of update values
1196          * @param       mixed   the where clause
1197          * @return      object
1198          */
1199         function update($table = '', $set = NULL, $where = NULL, $limit = NULL)
1200         {
1201                 // Combine any cached components with the current statements
1202                 $this->_merge_cache();
1203
1204                 if ( ! is_null($set))
1205                 {
1206                         $this->set($set);
1207                 }
1208         
1209                 if (count($this->ar_set) == 0)
1210                 {
1211                         if ($this->db_debug)
1212                         {
1213                                 return $this->display_error('db_must_use_set');
1214                         }
1215                         return FALSE;
1216                 }
1217
1218                 if ($table == '')
1219                 {
1220                         if ( ! isset($this->ar_from[0]))
1221                         {
1222                                 if ($this->db_debug)
1223                                 {
1224                                         return $this->display_error('db_must_set_table');
1225                                 }
1226                                 return FALSE;
1227                         }
1228                         
1229                         $table = $this->ar_from[0];
1230                 }
1231                 
1232                 if ($where != NULL)
1233                 {
1234                         $this->where($where);
1235                 }
1236
1237                 if ($limit != NULL)
1238                 {
1239                         $this->limit($limit);
1240                 }
1241                 
1242                 $sql = $this->_update($this->_protect_identifiers($table, TRUE, NULL, FALSE), $this->ar_set, $this->ar_where, $this->ar_orderby, $this->ar_limit);
1243                 
1244                 $this->_reset_write();
1245                 return $this->query($sql);
1246         }
1247
1248         // --------------------------------------------------------------------
1249
1250         /**
1251          * Empty Table
1252          *
1253          * Compiles a delete string and runs "DELETE FROM table"
1254          *
1255          * @access      public
1256          * @param       string  the table to empty
1257          * @return      object
1258          */
1259         function empty_table($table = '')
1260         {
1261                 if ($table == '')
1262                 {
1263                         if ( ! isset($this->ar_from[0]))
1264                         {
1265                                 if ($this->db_debug)
1266                                 {
1267                                         return $this->display_error('db_must_set_table');
1268                                 }
1269                                 return FALSE;
1270                         }
1271
1272                         $table = $this->ar_from[0];
1273                 }
1274                 else
1275                 {
1276                         $table = $this->_protect_identifiers($table, TRUE, NULL, FALSE);
1277                 }
1278
1279                 $sql = $this->_delete($table);
1280
1281                 $this->_reset_write();
1282                 
1283                 return $this->query($sql);
1284         }
1285
1286         // --------------------------------------------------------------------
1287
1288         /**
1289          * Truncate
1290          *
1291          * Compiles a truncate string and runs the query
1292          * If the database does not support the truncate() command
1293          * This function maps to "DELETE FROM table"
1294          *
1295          * @access      public
1296          * @param       string  the table to truncate
1297          * @return      object
1298          */
1299         function truncate($table = '')
1300         {
1301                 if ($table == '')
1302                 {
1303                         if ( ! isset($this->ar_from[0]))
1304                         {
1305                                 if ($this->db_debug)
1306                                 {
1307                                         return $this->display_error('db_must_set_table');
1308                                 }
1309                                 return FALSE;
1310                         }
1311
1312                         $table = $this->ar_from[0];
1313                 }
1314                 else
1315                 {
1316                         $table = $this->_protect_identifiers($table, TRUE, NULL, FALSE);
1317                 }
1318
1319                 $sql = $this->_truncate($table);
1320
1321                 $this->_reset_write();
1322                 
1323                 return $this->query($sql);
1324         }
1325         
1326         // --------------------------------------------------------------------
1327
1328         /**
1329          * Delete
1330          *
1331          * Compiles a delete string and runs the query
1332          *
1333          * @access      public
1334          * @param       mixed   the table(s) to delete from. String or array
1335          * @param       mixed   the where clause
1336          * @param       mixed   the limit clause
1337          * @param       boolean
1338          * @return      object
1339          */
1340         function delete($table = '', $where = '', $limit = NULL, $reset_data = TRUE)
1341         {
1342                 // Combine any cached components with the current statements
1343                 $this->_merge_cache();
1344
1345                 if ($table == '')
1346                 {
1347                         if ( ! isset($this->ar_from[0]))
1348                         {
1349                                 if ($this->db_debug)
1350                                 {
1351                                         return $this->display_error('db_must_set_table');
1352                                 }
1353                                 return FALSE;
1354                         }
1355
1356                         $table = $this->ar_from[0];
1357                 }
1358                 elseif (is_array($table))
1359                 {
1360                         foreach($table as $single_table)
1361                         {
1362                                 $this->delete($single_table, $where, $limit, FALSE);
1363                         }
1364
1365                         $this->_reset_write();
1366                         return;
1367                 }
1368                 else
1369                 {
1370                         $table = $this->_protect_identifiers($table, TRUE, NULL, FALSE);
1371                 }
1372
1373                 if ($where != '')
1374                 {
1375                         $this->where($where);
1376                 }
1377
1378                 if ($limit != NULL)
1379                 {
1380                         $this->limit($limit);
1381                 }
1382
1383                 if (count($this->ar_where) == 0 && count($this->ar_wherein) == 0 && count($this->ar_like) == 0)
1384                 {
1385                         if ($this->db_debug)
1386                         {
1387                                 return $this->display_error('db_del_must_use_where');
1388                         }
1389
1390                         return FALSE;
1391                 }               
1392
1393                 $sql = $this->_delete($table, $this->ar_where, $this->ar_like, $this->ar_limit);
1394
1395                 if ($reset_data)
1396                 {
1397                         $this->_reset_write();
1398                 }
1399                 
1400                 return $this->query($sql);
1401         }
1402
1403         // --------------------------------------------------------------------
1404
1405         /**
1406          * DB Prefix
1407          *
1408          * Prepends a database prefix if one exists in configuration
1409          *
1410          * @access      public
1411          * @param       string  the table
1412          * @return      string
1413          */
1414         function dbprefix($table = '')
1415         {
1416                 if ($table == '')
1417                 {
1418                         $this->display_error('db_table_name_required');
1419                 }
1420
1421                 return $this->dbprefix.$table;
1422         }
1423
1424         // --------------------------------------------------------------------
1425
1426         /**
1427          * Track Aliases
1428          *
1429          * Used to track SQL statements written with aliased tables.
1430          *
1431          * @access      private
1432          * @param       string  The table to inspect
1433          * @return      string
1434          */     
1435         function _track_aliases($table)
1436         {
1437                 if (is_array($table))
1438                 {
1439                         foreach ($table as $t)
1440                         {
1441                                 $this->_track_aliases($t);
1442                         }
1443                         return;
1444                 }
1445                 
1446                 // Does the string contain a comma?  If so, we need to separate
1447                 // the string into discreet statements
1448                 if (strpos($table, ',') !== FALSE)
1449                 {
1450                         return $this->_track_aliases(explode(',', $table));
1451                 }
1452         
1453                 // if a table alias is used we can recognize it by a space
1454                 if (strpos($table, " ") !== FALSE)
1455                 {
1456                         // if the alias is written with the AS keyword, remove it
1457                         $table = preg_replace('/ AS /i', ' ', $table);
1458                         
1459                         // Grab the alias
1460                         $table = trim(strrchr($table, " "));
1461                         
1462                         // Store the alias, if it doesn't already exist
1463                         if ( ! in_array($table, $this->ar_aliased_tables))
1464                         {
1465                                 $this->ar_aliased_tables[] = $table;
1466                         }
1467                 }
1468         }
1469
1470         // --------------------------------------------------------------------
1471
1472         /**
1473          * Compile the SELECT statement
1474          *
1475          * Generates a query string based on which functions were used.
1476          * Should not be called directly.  The get() function calls it.
1477          *
1478          * @access      private
1479          * @return      string
1480          */
1481         function _compile_select($select_override = FALSE)
1482         {
1483                 // Combine any cached components with the current statements
1484                 $this->_merge_cache();
1485
1486                 // ----------------------------------------------------------------
1487                 
1488                 // Write the "select" portion of the query
1489
1490                 if ($select_override !== FALSE)
1491                 {
1492                         $sql = $select_override;
1493                 }
1494                 else
1495                 {
1496                         $sql = ( ! $this->ar_distinct) ? 'SELECT ' : 'SELECT DISTINCT ';
1497                 
1498                         if (count($this->ar_select) == 0)
1499                         {
1500                                 $sql .= '*';            
1501                         }
1502                         else
1503                         {                               
1504                                 // Cycle through the "select" portion of the query and prep each column name.
1505                                 // The reason we protect identifiers here rather then in the select() function
1506                                 // is because until the user calls the from() function we don't know if there are aliases
1507                                 foreach ($this->ar_select as $key => $val)
1508                                 {
1509                                         $this->ar_select[$key] = $this->_protect_identifiers($val);
1510                                 }
1511                                 
1512                                 $sql .= implode(', ', $this->ar_select);
1513                         }
1514                 }
1515
1516                 // ----------------------------------------------------------------
1517                 
1518                 // Write the "FROM" portion of the query
1519
1520                 if (count($this->ar_from) > 0)
1521                 {
1522                         $sql .= "\nFROM ";
1523
1524                         $sql .= $this->_from_tables($this->ar_from);
1525                 }
1526
1527                 // ----------------------------------------------------------------
1528                 
1529                 // Write the "JOIN" portion of the query
1530
1531                 if (count($this->ar_join) > 0)
1532                 {
1533                         $sql .= "\n";
1534
1535                         $sql .= implode("\n", $this->ar_join);
1536                 }
1537
1538                 // ----------------------------------------------------------------
1539                 
1540                 // Write the "WHERE" portion of the query
1541
1542                 if (count($this->ar_where) > 0 OR count($this->ar_like) > 0)
1543                 {
1544                         $sql .= "\n";
1545
1546                         $sql .= "WHERE ";
1547                 }
1548
1549                 $sql .= implode("\n", $this->ar_where);
1550
1551                 // ----------------------------------------------------------------
1552                 
1553                 // Write the "LIKE" portion of the query
1554         
1555                 if (count($this->ar_like) > 0)
1556                 {
1557                         if (count($this->ar_where) > 0)
1558                         {
1559                                 $sql .= "\nAND ";
1560                         }
1561
1562                         $sql .= implode("\n", $this->ar_like);
1563                 }
1564
1565                 // ----------------------------------------------------------------
1566                 
1567                 // Write the "GROUP BY" portion of the query
1568         
1569                 if (count($this->ar_groupby) > 0)
1570                 {
1571                         $sql .= "\nGROUP BY ";
1572                         
1573                         $sql .= implode(', ', $this->ar_groupby);
1574                 }
1575
1576                 // ----------------------------------------------------------------
1577                 
1578                 // Write the "HAVING" portion of the query
1579                 
1580                 if (count($this->ar_having) > 0)
1581                 {
1582                         $sql .= "\nHAVING ";
1583                         $sql .= implode("\n", $this->ar_having);
1584                 }
1585
1586                 // ----------------------------------------------------------------
1587                 
1588                 // Write the "ORDER BY" portion of the query
1589
1590                 if (count($this->ar_orderby) > 0)
1591                 {
1592                         $sql .= "\nORDER BY ";
1593                         $sql .= implode(', ', $this->ar_orderby);
1594                         
1595                         if ($this->ar_order !== FALSE)
1596                         {
1597                                 $sql .= ($this->ar_order == 'desc') ? ' DESC' : ' ASC';
1598                         }               
1599                 }
1600
1601                 // ----------------------------------------------------------------
1602                 
1603                 // Write the "LIMIT" portion of the query
1604                 
1605                 if (is_numeric($this->ar_limit))
1606                 {
1607                         $sql .= "\n";
1608                         $sql = $this->_limit($sql, $this->ar_limit, $this->ar_offset);
1609                 }
1610
1611                 return $sql;
1612         }
1613
1614         // --------------------------------------------------------------------
1615
1616         /**
1617          * Object to Array
1618          *
1619          * Takes an object as input and converts the class variables to array key/vals
1620          *
1621          * @access      public
1622          * @param       object
1623          * @return      array
1624          */
1625         function _object_to_array($object)
1626         {
1627                 if ( ! is_object($object))
1628                 {
1629                         return $object;
1630                 }
1631                 
1632                 $array = array();
1633                 foreach (get_object_vars($object) as $key => $val)
1634                 {
1635                         // There are some built in keys we need to ignore for this conversion
1636                         if ( ! is_object($val) && ! is_array($val) && $key != '_parent_name' && $key != '_ci_scaffolding' && $key != '_ci_scaff_table')
1637                         {
1638                                 $array[$key] = $val;
1639                         }
1640                 }
1641         
1642                 return $array;
1643         }
1644         
1645         // --------------------------------------------------------------------
1646
1647         /**
1648          * Start Cache
1649          *
1650          * Starts AR caching
1651          *
1652          * @access      public
1653          * @return      void
1654          */             
1655         function start_cache()
1656         {
1657                 $this->ar_caching = TRUE;
1658         }
1659
1660         // --------------------------------------------------------------------
1661
1662         /**
1663          * Stop Cache
1664          *
1665          * Stops AR caching
1666          *
1667          * @access      public
1668          * @return      void
1669          */             
1670         function stop_cache()
1671         {
1672                 $this->ar_caching = FALSE;
1673         }
1674
1675         // --------------------------------------------------------------------
1676
1677         /**
1678          * Flush Cache
1679          *
1680          * Empties the AR cache
1681          *
1682          * @access      public
1683          * @return      void
1684          */     
1685         function flush_cache()
1686         {       
1687                 $this->_reset_run(
1688                                                         array(
1689                                                                         'ar_cache_select'       => array(), 
1690                                                                         'ar_cache_from'         => array(), 
1691                                                                         'ar_cache_join'         => array(),
1692                                                                         'ar_cache_where'        => array(), 
1693                                                                         'ar_cache_like'         => array(), 
1694                                                                         'ar_cache_groupby'      => array(), 
1695                                                                         'ar_cache_having'       => array(), 
1696                                                                         'ar_cache_orderby'      => array(), 
1697                                                                         'ar_cache_set'          => array(),
1698                                                                         'ar_cache_exists'       => array()
1699                                                                 )
1700                                                         );      
1701         }
1702
1703         // --------------------------------------------------------------------
1704
1705         /**
1706          * Merge Cache
1707          *
1708          * When called, this function merges any cached AR arrays with 
1709          * locally called ones.
1710          *
1711          * @access      private
1712          * @return      void
1713          */
1714         function _merge_cache()
1715         {
1716                 if (count($this->ar_cache_exists) == 0)
1717                 {
1718                         return;
1719                 }
1720
1721                 foreach ($this->ar_cache_exists as $val)
1722                 {
1723                         $ar_variable    = 'ar_'.$val;
1724                         $ar_cache_var   = 'ar_cache_'.$val;
1725
1726                         if (count($this->$ar_cache_var) == 0)
1727                         {
1728                                 continue;
1729                         }
1730
1731                         $this->$ar_variable = array_unique(array_merge($this->$ar_cache_var, $this->$ar_variable));
1732                 }
1733
1734                 // If we are "protecting identifiers" we need to examine the "from"
1735                 // portion of the query to determine if there are any aliases
1736                 if ($this->_protect_identifiers === TRUE AND count($this->ar_cache_from) > 0)
1737                 {
1738                         $this->_track_aliases($this->ar_from);
1739                 }
1740         }
1741
1742         // --------------------------------------------------------------------
1743
1744         /**
1745          * Resets the active record values.  Called by the get() function
1746          *
1747          * @access      private
1748          * @param       array   An array of fields to reset
1749          * @return      void
1750          */
1751         function _reset_run($ar_reset_items)
1752         {
1753                 foreach ($ar_reset_items as $item => $default_value)
1754                 {
1755                         if ( ! in_array($item, $this->ar_store_array))
1756                         {
1757                                 $this->$item = $default_value;
1758                         }
1759                 }
1760         }
1761
1762         // --------------------------------------------------------------------
1763
1764         /**
1765          * Resets the active record values.  Called by the get() function
1766          *
1767          * @access      private
1768          * @return      void
1769          */
1770         function _reset_select()
1771         {
1772                 $ar_reset_items = array(
1773                                                                 'ar_select'                     => array(), 
1774                                                                 'ar_from'                       => array(), 
1775                                                                 'ar_join'                       => array(), 
1776                                                                 'ar_where'                      => array(), 
1777                                                                 'ar_like'                       => array(), 
1778                                                                 'ar_groupby'            => array(), 
1779                                                                 'ar_having'                     => array(), 
1780                                                                 'ar_orderby'            => array(), 
1781                                                                 'ar_wherein'            => array(), 
1782                                                                 'ar_aliased_tables'     => array(),
1783                                                                 'ar_distinct'           => FALSE, 
1784                                                                 'ar_limit'                      => FALSE, 
1785                                                                 'ar_offset'                     => FALSE, 
1786                                                                 'ar_order'                      => FALSE,
1787                                                         );
1788                 
1789                 $this->_reset_run($ar_reset_items);
1790         }
1791         
1792         // --------------------------------------------------------------------
1793
1794         /**
1795          * Resets the active record "write" values.
1796          *
1797          * Called by the insert() update() and delete() functions
1798          *
1799          * @access      private
1800          * @return      void
1801          */
1802         function _reset_write()
1803         {       
1804                 $ar_reset_items = array(
1805                                                                 'ar_set'                => array(), 
1806                                                                 'ar_from'               => array(), 
1807                                                                 'ar_where'              => array(), 
1808                                                                 'ar_like'               => array(),
1809                                                                 'ar_orderby'    => array(), 
1810                                                                 'ar_limit'              => FALSE, 
1811                                                                 'ar_order'              => FALSE
1812                                                                 );
1813
1814                 $this->_reset_run($ar_reset_items);
1815         }
1816         
1817 }
1818
1819 /* End of file DB_active_rec.php */
1820 /* Location: ./system/database/DB_active_rec.php */