/lenasys/trunk

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/lenasys/trunk

« back to all changes in this revision

Viewing changes to codeigniter/system/database/DB_driver.php

  • Committer: Gustav Hatvigsson
  • Date: 2013-04-11 09:20:09 UTC
  • mfrom: (19.1.5 lenasys)
  • Revision ID: gustav.hartvigsson@gmail.com-20130411092009-ylcqzqwcmjdglb17
merged in implemetaion group one's team bransh, it contains code-ignighter
and the new admin-panel.
20130411

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?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
 * @package             CodeIgniter
 
8
 * @author              ExpressionEngine Dev Team
 
9
 * @copyright   Copyright (c) 2008 - 2011, 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
 * Database Driver Class
 
20
 *
 
21
 * This is the platform-independent base DB implementation class.
 
22
 * This class will not be called directly. Rather, the adapter
 
23
 * class for the specific database will extend and instantiate it.
 
24
 *
 
25
 * @package             CodeIgniter
 
26
 * @subpackage  Drivers
 
27
 * @category    Database
 
28
 * @author              ExpressionEngine Dev Team
 
29
 * @link                http://codeigniter.com/user_guide/database/
 
30
 */
 
31
class CI_DB_driver {
 
32
 
 
33
        var $username;
 
34
        var $password;
 
35
        var $hostname;
 
36
        var $database;
 
37
        var $dbdriver           = 'mysql';
 
38
        var $dbprefix           = '';
 
39
        var $char_set           = 'utf8';
 
40
        var $dbcollat           = 'utf8_general_ci';
 
41
        var $autoinit           = TRUE; // Whether to automatically initialize the DB
 
42
        var $swap_pre           = '';
 
43
        var $port                       = '';
 
44
        var $pconnect           = FALSE;
 
45
        var $conn_id            = FALSE;
 
46
        var $result_id          = FALSE;
 
47
        var $db_debug           = FALSE;
 
48
        var $benchmark          = 0;
 
49
        var $query_count        = 0;
 
50
        var $bind_marker        = '?';
 
51
        var $save_queries       = TRUE;
 
52
        var $queries            = array();
 
53
        var $query_times        = array();
 
54
        var $data_cache         = array();
 
55
        var $trans_enabled      = TRUE;
 
56
        var $trans_strict       = TRUE;
 
57
        var $_trans_depth       = 0;
 
58
        var $_trans_status      = TRUE; // Used with transactions to determine if a rollback should occur
 
59
        var $cache_on           = FALSE;
 
60
        var $cachedir           = '';
 
61
        var $cache_autodel      = FALSE;
 
62
        var $CACHE; // The cache class object
 
63
 
 
64
        // Private variables
 
65
        var $_protect_identifiers       = TRUE;
 
66
        var $_reserved_identifiers      = array('*'); // Identifiers that should NOT be escaped
 
67
 
 
68
        // These are use with Oracle
 
69
        var $stmt_id;
 
70
        var $curs_id;
 
71
        var $limit_used;
 
72
 
 
73
 
 
74
 
 
75
        /**
 
76
         * Constructor.  Accepts one parameter containing the database
 
77
         * connection settings.
 
78
         *
 
79
         * @param array
 
80
         */
 
81
        function __construct($params)
 
82
        {
 
83
                if (is_array($params))
 
84
                {
 
85
                        foreach ($params as $key => $val)
 
86
                        {
 
87
                                $this->$key = $val;
 
88
                        }
 
89
                }
 
90
 
 
91
                log_message('debug', 'Database Driver Class Initialized');
 
92
        }
 
93
 
 
94
        // --------------------------------------------------------------------
 
95
 
 
96
        /**
 
97
         * Initialize Database Settings
 
98
         *
 
99
         * @access      private Called by the constructor
 
100
         * @param       mixed
 
101
         * @return      void
 
102
         */
 
103
        function initialize()
 
104
        {
 
105
                // If an existing connection resource is available
 
106
                // there is no need to connect and select the database
 
107
                if (is_resource($this->conn_id) OR is_object($this->conn_id))
 
108
                {
 
109
                        return TRUE;
 
110
                }
 
111
 
 
112
                // ----------------------------------------------------------------
 
113
 
 
114
                // Connect to the database and set the connection ID
 
115
                $this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect();
 
116
 
 
117
                // No connection resource?  Throw an error
 
118
                if ( ! $this->conn_id)
 
119
                {
 
120
                        log_message('error', 'Unable to connect to the database');
 
121
 
 
122
                        if ($this->db_debug)
 
123
                        {
 
124
                                $this->display_error('db_unable_to_connect');
 
125
                        }
 
126
                        return FALSE;
 
127
                }
 
128
 
 
129
                // ----------------------------------------------------------------
 
130
 
 
131
                // Select the DB... assuming a database name is specified in the config file
 
132
                if ($this->database != '')
 
133
                {
 
134
                        if ( ! $this->db_select())
 
135
                        {
 
136
                                log_message('error', 'Unable to select database: '.$this->database);
 
137
 
 
138
                                if ($this->db_debug)
 
139
                                {
 
140
                                        $this->display_error('db_unable_to_select', $this->database);
 
141
                                }
 
142
                                return FALSE;
 
143
                        }
 
144
                        else
 
145
                        {
 
146
                                // We've selected the DB. Now we set the character set
 
147
                                if ( ! $this->db_set_charset($this->char_set, $this->dbcollat))
 
148
                                {
 
149
                                        return FALSE;
 
150
                                }
 
151
 
 
152
                                return TRUE;
 
153
                        }
 
154
                }
 
155
 
 
156
                return TRUE;
 
157
        }
 
158
 
 
159
        // --------------------------------------------------------------------
 
160
 
 
161
        /**
 
162
         * Set client character set
 
163
         *
 
164
         * @access      public
 
165
         * @param       string
 
166
         * @param       string
 
167
         * @return      resource
 
168
         */
 
169
        function db_set_charset($charset, $collation)
 
170
        {
 
171
                if ( ! $this->_db_set_charset($this->char_set, $this->dbcollat))
 
172
                {
 
173
                        log_message('error', 'Unable to set database connection charset: '.$this->char_set);
 
174
 
 
175
                        if ($this->db_debug)
 
176
                        {
 
177
                                $this->display_error('db_unable_to_set_charset', $this->char_set);
 
178
                        }
 
179
 
 
180
                        return FALSE;
 
181
                }
 
182
 
 
183
                return TRUE;
 
184
        }
 
185
 
 
186
        // --------------------------------------------------------------------
 
187
 
 
188
        /**
 
189
         * The name of the platform in use (mysql, mssql, etc...)
 
190
         *
 
191
         * @access      public
 
192
         * @return      string
 
193
         */
 
194
        function platform()
 
195
        {
 
196
                return $this->dbdriver;
 
197
        }
 
198
 
 
199
        // --------------------------------------------------------------------
 
200
 
 
201
        /**
 
202
         * Database Version Number.  Returns a string containing the
 
203
         * version of the database being used
 
204
         *
 
205
         * @access      public
 
206
         * @return      string
 
207
         */
 
208
        function version()
 
209
        {
 
210
                if (FALSE === ($sql = $this->_version()))
 
211
                {
 
212
                        if ($this->db_debug)
 
213
                        {
 
214
                                return $this->display_error('db_unsupported_function');
 
215
                        }
 
216
                        return FALSE;
 
217
                }
 
218
 
 
219
                // Some DBs have functions that return the version, and don't run special
 
220
                // SQL queries per se. In these instances, just return the result.
 
221
                $driver_version_exceptions = array('oci8', 'sqlite', 'cubrid');
 
222
 
 
223
                if (in_array($this->dbdriver, $driver_version_exceptions))
 
224
                {
 
225
                        return $sql;
 
226
                }
 
227
                else
 
228
                {
 
229
                        $query = $this->query($sql);
 
230
                        return $query->row('ver');
 
231
                }
 
232
        }
 
233
 
 
234
        // --------------------------------------------------------------------
 
235
 
 
236
        /**
 
237
         * Execute the query
 
238
         *
 
239
         * Accepts an SQL string as input and returns a result object upon
 
240
         * successful execution of a "read" type query.  Returns boolean TRUE
 
241
         * upon successful execution of a "write" type query. Returns boolean
 
242
         * FALSE upon failure, and if the $db_debug variable is set to TRUE
 
243
         * will raise an error.
 
244
         *
 
245
         * @access      public
 
246
         * @param       string  An SQL query string
 
247
         * @param       array   An array of binding data
 
248
         * @return      mixed
 
249
         */
 
250
        function query($sql, $binds = FALSE, $return_object = TRUE)
 
251
        {
 
252
                if ($sql == '')
 
253
                {
 
254
                        if ($this->db_debug)
 
255
                        {
 
256
                                log_message('error', 'Invalid query: '.$sql);
 
257
                                return $this->display_error('db_invalid_query');
 
258
                        }
 
259
                        return FALSE;
 
260
                }
 
261
 
 
262
                // Verify table prefix and replace if necessary
 
263
                if ( ($this->dbprefix != '' AND $this->swap_pre != '') AND ($this->dbprefix != $this->swap_pre) )
 
264
                {
 
265
                        $sql = preg_replace("/(\W)".$this->swap_pre."(\S+?)/", "\\1".$this->dbprefix."\\2", $sql);
 
266
                }
 
267
 
 
268
                // Compile binds if needed
 
269
                if ($binds !== FALSE)
 
270
                {
 
271
                        $sql = $this->compile_binds($sql, $binds);
 
272
                }
 
273
 
 
274
                // Is query caching enabled?  If the query is a "read type"
 
275
                // we will load the caching class and return the previously
 
276
                // cached query if it exists
 
277
                if ($this->cache_on == TRUE AND stristr($sql, 'SELECT'))
 
278
                {
 
279
                        if ($this->_cache_init())
 
280
                        {
 
281
                                $this->load_rdriver();
 
282
                                if (FALSE !== ($cache = $this->CACHE->read($sql)))
 
283
                                {
 
284
                                        return $cache;
 
285
                                }
 
286
                        }
 
287
                }
 
288
 
 
289
                // Save the  query for debugging
 
290
                if ($this->save_queries == TRUE)
 
291
                {
 
292
                        $this->queries[] = $sql;
 
293
                }
 
294
 
 
295
                // Start the Query Timer
 
296
                $time_start = list($sm, $ss) = explode(' ', microtime());
 
297
 
 
298
                // Run the Query
 
299
                if (FALSE === ($this->result_id = $this->simple_query($sql)))
 
300
                {
 
301
                        if ($this->save_queries == TRUE)
 
302
                        {
 
303
                                $this->query_times[] = 0;
 
304
                        }
 
305
 
 
306
                        // This will trigger a rollback if transactions are being used
 
307
                        $this->_trans_status = FALSE;
 
308
 
 
309
                        if ($this->db_debug)
 
310
                        {
 
311
                                // grab the error number and message now, as we might run some
 
312
                                // additional queries before displaying the error
 
313
                                $error_no = $this->_error_number();
 
314
                                $error_msg = $this->_error_message();
 
315
 
 
316
                                // We call this function in order to roll-back queries
 
317
                                // if transactions are enabled.  If we don't call this here
 
318
                                // the error message will trigger an exit, causing the
 
319
                                // transactions to remain in limbo.
 
320
                                $this->trans_complete();
 
321
 
 
322
                                // Log and display errors
 
323
                                log_message('error', 'Query error: '.$error_msg);
 
324
                                return $this->display_error(
 
325
                                                                                array(
 
326
                                                                                                'Error Number: '.$error_no,
 
327
                                                                                                $error_msg,
 
328
                                                                                                $sql
 
329
                                                                                        )
 
330
                                                                                );
 
331
                        }
 
332
 
 
333
                        return FALSE;
 
334
                }
 
335
 
 
336
                // Stop and aggregate the query time results
 
337
                $time_end = list($em, $es) = explode(' ', microtime());
 
338
                $this->benchmark += ($em + $es) - ($sm + $ss);
 
339
 
 
340
                if ($this->save_queries == TRUE)
 
341
                {
 
342
                        $this->query_times[] = ($em + $es) - ($sm + $ss);
 
343
                }
 
344
 
 
345
                // Increment the query counter
 
346
                $this->query_count++;
 
347
 
 
348
                // Was the query a "write" type?
 
349
                // If so we'll simply return true
 
350
                if ($this->is_write_type($sql) === TRUE)
 
351
                {
 
352
                        // If caching is enabled we'll auto-cleanup any
 
353
                        // existing files related to this particular URI
 
354
                        if ($this->cache_on == TRUE AND $this->cache_autodel == TRUE AND $this->_cache_init())
 
355
                        {
 
356
                                $this->CACHE->delete();
 
357
                        }
 
358
 
 
359
                        return TRUE;
 
360
                }
 
361
 
 
362
                // Return TRUE if we don't need to create a result object
 
363
                // Currently only the Oracle driver uses this when stored
 
364
                // procedures are used
 
365
                if ($return_object !== TRUE)
 
366
                {
 
367
                        return TRUE;
 
368
                }
 
369
 
 
370
                // Load and instantiate the result driver
 
371
 
 
372
                $driver                 = $this->load_rdriver();
 
373
                $RES                    = new $driver();
 
374
                $RES->conn_id   = $this->conn_id;
 
375
                $RES->result_id = $this->result_id;
 
376
 
 
377
                if ($this->dbdriver == 'oci8')
 
378
                {
 
379
                        $RES->stmt_id           = $this->stmt_id;
 
380
                        $RES->curs_id           = NULL;
 
381
                        $RES->limit_used        = $this->limit_used;
 
382
                        $this->stmt_id          = FALSE;
 
383
                }
 
384
 
 
385
                // oci8 vars must be set before calling this
 
386
                $RES->num_rows  = $RES->num_rows();
 
387
 
 
388
                // Is query caching enabled?  If so, we'll serialize the
 
389
                // result object and save it to a cache file.
 
390
                if ($this->cache_on == TRUE AND $this->_cache_init())
 
391
                {
 
392
                        // We'll create a new instance of the result object
 
393
                        // only without the platform specific driver since
 
394
                        // we can't use it with cached data (the query result
 
395
                        // resource ID won't be any good once we've cached the
 
396
                        // result object, so we'll have to compile the data
 
397
                        // and save it)
 
398
                        $CR = new CI_DB_result();
 
399
                        $CR->num_rows           = $RES->num_rows();
 
400
                        $CR->result_object      = $RES->result_object();
 
401
                        $CR->result_array       = $RES->result_array();
 
402
 
 
403
                        // Reset these since cached objects can not utilize resource IDs.
 
404
                        $CR->conn_id            = NULL;
 
405
                        $CR->result_id          = NULL;
 
406
 
 
407
                        $this->CACHE->write($sql, $CR);
 
408
                }
 
409
 
 
410
                return $RES;
 
411
        }
 
412
 
 
413
        // --------------------------------------------------------------------
 
414
 
 
415
        /**
 
416
         * Load the result drivers
 
417
         *
 
418
         * @access      public
 
419
         * @return      string  the name of the result class
 
420
         */
 
421
        function load_rdriver()
 
422
        {
 
423
                $driver = 'CI_DB_'.$this->dbdriver.'_result';
 
424
 
 
425
                if ( ! class_exists($driver))
 
426
                {
 
427
                        include_once(BASEPATH.'database/DB_result.php');
 
428
                        include_once(BASEPATH.'database/drivers/'.$this->dbdriver.'/'.$this->dbdriver.'_result.php');
 
429
                }
 
430
 
 
431
                return $driver;
 
432
        }
 
433
 
 
434
        // --------------------------------------------------------------------
 
435
 
 
436
        /**
 
437
         * Simple Query
 
438
         * This is a simplified version of the query() function.  Internally
 
439
         * we only use it when running transaction commands since they do
 
440
         * not require all the features of the main query() function.
 
441
         *
 
442
         * @access      public
 
443
         * @param       string  the sql query
 
444
         * @return      mixed
 
445
         */
 
446
        function simple_query($sql)
 
447
        {
 
448
                if ( ! $this->conn_id)
 
449
                {
 
450
                        $this->initialize();
 
451
                }
 
452
 
 
453
                return $this->_execute($sql);
 
454
        }
 
455
 
 
456
        // --------------------------------------------------------------------
 
457
 
 
458
        /**
 
459
         * Disable Transactions
 
460
         * This permits transactions to be disabled at run-time.
 
461
         *
 
462
         * @access      public
 
463
         * @return      void
 
464
         */
 
465
        function trans_off()
 
466
        {
 
467
                $this->trans_enabled = FALSE;
 
468
        }
 
469
 
 
470
        // --------------------------------------------------------------------
 
471
 
 
472
        /**
 
473
         * Enable/disable Transaction Strict Mode
 
474
         * When strict mode is enabled, if you are running multiple groups of
 
475
         * transactions, if one group fails all groups will be rolled back.
 
476
         * If strict mode is disabled, each group is treated autonomously, meaning
 
477
         * a failure of one group will not affect any others
 
478
         *
 
479
         * @access      public
 
480
         * @return      void
 
481
         */
 
482
        function trans_strict($mode = TRUE)
 
483
        {
 
484
                $this->trans_strict = is_bool($mode) ? $mode : TRUE;
 
485
        }
 
486
 
 
487
        // --------------------------------------------------------------------
 
488
 
 
489
        /**
 
490
         * Start Transaction
 
491
         *
 
492
         * @access      public
 
493
         * @return      void
 
494
         */
 
495
        function trans_start($test_mode = FALSE)
 
496
        {
 
497
                if ( ! $this->trans_enabled)
 
498
                {
 
499
                        return FALSE;
 
500
                }
 
501
 
 
502
                // When transactions are nested we only begin/commit/rollback the outermost ones
 
503
                if ($this->_trans_depth > 0)
 
504
                {
 
505
                        $this->_trans_depth += 1;
 
506
                        return;
 
507
                }
 
508
 
 
509
                $this->trans_begin($test_mode);
 
510
        }
 
511
 
 
512
        // --------------------------------------------------------------------
 
513
 
 
514
        /**
 
515
         * Complete Transaction
 
516
         *
 
517
         * @access      public
 
518
         * @return      bool
 
519
         */
 
520
        function trans_complete()
 
521
        {
 
522
                if ( ! $this->trans_enabled)
 
523
                {
 
524
                        return FALSE;
 
525
                }
 
526
 
 
527
                // When transactions are nested we only begin/commit/rollback the outermost ones
 
528
                if ($this->_trans_depth > 1)
 
529
                {
 
530
                        $this->_trans_depth -= 1;
 
531
                        return TRUE;
 
532
                }
 
533
 
 
534
                // The query() function will set this flag to FALSE in the event that a query failed
 
535
                if ($this->_trans_status === FALSE)
 
536
                {
 
537
                        $this->trans_rollback();
 
538
 
 
539
                        // If we are NOT running in strict mode, we will reset
 
540
                        // the _trans_status flag so that subsequent groups of transactions
 
541
                        // will be permitted.
 
542
                        if ($this->trans_strict === FALSE)
 
543
                        {
 
544
                                $this->_trans_status = TRUE;
 
545
                        }
 
546
 
 
547
                        log_message('debug', 'DB Transaction Failure');
 
548
                        return FALSE;
 
549
                }
 
550
 
 
551
                $this->trans_commit();
 
552
                return TRUE;
 
553
        }
 
554
 
 
555
        // --------------------------------------------------------------------
 
556
 
 
557
        /**
 
558
         * Lets you retrieve the transaction flag to determine if it has failed
 
559
         *
 
560
         * @access      public
 
561
         * @return      bool
 
562
         */
 
563
        function trans_status()
 
564
        {
 
565
                return $this->_trans_status;
 
566
        }
 
567
 
 
568
        // --------------------------------------------------------------------
 
569
 
 
570
        /**
 
571
         * Compile Bindings
 
572
         *
 
573
         * @access      public
 
574
         * @param       string  the sql statement
 
575
         * @param       array   an array of bind data
 
576
         * @return      string
 
577
         */
 
578
        function compile_binds($sql, $binds)
 
579
        {
 
580
                if (strpos($sql, $this->bind_marker) === FALSE)
 
581
                {
 
582
                        return $sql;
 
583
                }
 
584
 
 
585
                if ( ! is_array($binds))
 
586
                {
 
587
                        $binds = array($binds);
 
588
                }
 
589
 
 
590
                // Get the sql segments around the bind markers
 
591
                $segments = explode($this->bind_marker, $sql);
 
592
 
 
593
                // The count of bind should be 1 less then the count of segments
 
594
                // If there are more bind arguments trim it down
 
595
                if (count($binds) >= count($segments)) {
 
596
                        $binds = array_slice($binds, 0, count($segments)-1);
 
597
                }
 
598
 
 
599
                // Construct the binded query
 
600
                $result = $segments[0];
 
601
                $i = 0;
 
602
                foreach ($binds as $bind)
 
603
                {
 
604
                        $result .= $this->escape($bind);
 
605
                        $result .= $segments[++$i];
 
606
                }
 
607
 
 
608
                return $result;
 
609
        }
 
610
 
 
611
        // --------------------------------------------------------------------
 
612
 
 
613
        /**
 
614
         * Determines if a query is a "write" type.
 
615
         *
 
616
         * @access      public
 
617
         * @param       string  An SQL query string
 
618
         * @return      boolean
 
619
         */
 
620
        function is_write_type($sql)
 
621
        {
 
622
                if ( ! preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD DATA|COPY|ALTER|GRANT|REVOKE|LOCK|UNLOCK)\s+/i', $sql))
 
623
                {
 
624
                        return FALSE;
 
625
                }
 
626
                return TRUE;
 
627
        }
 
628
 
 
629
        // --------------------------------------------------------------------
 
630
 
 
631
        /**
 
632
         * Calculate the aggregate query elapsed time
 
633
         *
 
634
         * @access      public
 
635
         * @param       integer The number of decimal places
 
636
         * @return      integer
 
637
         */
 
638
        function elapsed_time($decimals = 6)
 
639
        {
 
640
                return number_format($this->benchmark, $decimals);
 
641
        }
 
642
 
 
643
        // --------------------------------------------------------------------
 
644
 
 
645
        /**
 
646
         * Returns the total number of queries
 
647
         *
 
648
         * @access      public
 
649
         * @return      integer
 
650
         */
 
651
        function total_queries()
 
652
        {
 
653
                return $this->query_count;
 
654
        }
 
655
 
 
656
        // --------------------------------------------------------------------
 
657
 
 
658
        /**
 
659
         * Returns the last query that was executed
 
660
         *
 
661
         * @access      public
 
662
         * @return      void
 
663
         */
 
664
        function last_query()
 
665
        {
 
666
                return end($this->queries);
 
667
        }
 
668
 
 
669
        // --------------------------------------------------------------------
 
670
 
 
671
        /**
 
672
         * "Smart" Escape String
 
673
         *
 
674
         * Escapes data based on type
 
675
         * Sets boolean and null types
 
676
         *
 
677
         * @access      public
 
678
         * @param       string
 
679
         * @return      mixed
 
680
         */
 
681
        function escape($str)
 
682
        {
 
683
                if (is_string($str))
 
684
                {
 
685
                        $str = "'".$this->escape_str($str)."'";
 
686
                }
 
687
                elseif (is_bool($str))
 
688
                {
 
689
                        $str = ($str === FALSE) ? 0 : 1;
 
690
                }
 
691
                elseif (is_null($str))
 
692
                {
 
693
                        $str = 'NULL';
 
694
                }
 
695
 
 
696
                return $str;
 
697
        }
 
698
 
 
699
        // --------------------------------------------------------------------
 
700
 
 
701
        /**
 
702
         * Escape LIKE String
 
703
         *
 
704
         * Calls the individual driver for platform
 
705
         * specific escaping for LIKE conditions
 
706
         *
 
707
         * @access      public
 
708
         * @param       string
 
709
         * @return      mixed
 
710
         */
 
711
        function escape_like_str($str)
 
712
        {
 
713
                return $this->escape_str($str, TRUE);
 
714
        }
 
715
 
 
716
        // --------------------------------------------------------------------
 
717
 
 
718
        /**
 
719
         * Primary
 
720
         *
 
721
         * Retrieves the primary key.  It assumes that the row in the first
 
722
         * position is the primary key
 
723
         *
 
724
         * @access      public
 
725
         * @param       string  the table name
 
726
         * @return      string
 
727
         */
 
728
        function primary($table = '')
 
729
        {
 
730
                $fields = $this->list_fields($table);
 
731
 
 
732
                if ( ! is_array($fields))
 
733
                {
 
734
                        return FALSE;
 
735
                }
 
736
 
 
737
                return current($fields);
 
738
        }
 
739
 
 
740
        // --------------------------------------------------------------------
 
741
 
 
742
        /**
 
743
         * Returns an array of table names
 
744
         *
 
745
         * @access      public
 
746
         * @return      array
 
747
         */
 
748
        function list_tables($constrain_by_prefix = FALSE)
 
749
        {
 
750
                // Is there a cached result?
 
751
                if (isset($this->data_cache['table_names']))
 
752
                {
 
753
                        return $this->data_cache['table_names'];
 
754
                }
 
755
 
 
756
                if (FALSE === ($sql = $this->_list_tables($constrain_by_prefix)))
 
757
                {
 
758
                        if ($this->db_debug)
 
759
                        {
 
760
                                return $this->display_error('db_unsupported_function');
 
761
                        }
 
762
                        return FALSE;
 
763
                }
 
764
 
 
765
                $retval = array();
 
766
                $query = $this->query($sql);
 
767
 
 
768
                if ($query->num_rows() > 0)
 
769
                {
 
770
                        foreach ($query->result_array() as $row)
 
771
                        {
 
772
                                if (isset($row['TABLE_NAME']))
 
773
                                {
 
774
                                        $retval[] = $row['TABLE_NAME'];
 
775
                                }
 
776
                                else
 
777
                                {
 
778
                                        $retval[] = array_shift($row);
 
779
                                }
 
780
                        }
 
781
                }
 
782
 
 
783
                $this->data_cache['table_names'] = $retval;
 
784
                return $this->data_cache['table_names'];
 
785
        }
 
786
 
 
787
        // --------------------------------------------------------------------
 
788
 
 
789
        /**
 
790
         * Determine if a particular table exists
 
791
         * @access      public
 
792
         * @return      boolean
 
793
         */
 
794
        function table_exists($table_name)
 
795
        {
 
796
                return ( ! in_array($this->_protect_identifiers($table_name, TRUE, FALSE, FALSE), $this->list_tables())) ? FALSE : TRUE;
 
797
        }
 
798
 
 
799
        // --------------------------------------------------------------------
 
800
 
 
801
        /**
 
802
         * Fetch MySQL Field Names
 
803
         *
 
804
         * @access      public
 
805
         * @param       string  the table name
 
806
         * @return      array
 
807
         */
 
808
        function list_fields($table = '')
 
809
        {
 
810
                // Is there a cached result?
 
811
                if (isset($this->data_cache['field_names'][$table]))
 
812
                {
 
813
                        return $this->data_cache['field_names'][$table];
 
814
                }
 
815
 
 
816
                if ($table == '')
 
817
                {
 
818
                        if ($this->db_debug)
 
819
                        {
 
820
                                return $this->display_error('db_field_param_missing');
 
821
                        }
 
822
                        return FALSE;
 
823
                }
 
824
 
 
825
                if (FALSE === ($sql = $this->_list_columns($table)))
 
826
                {
 
827
                        if ($this->db_debug)
 
828
                        {
 
829
                                return $this->display_error('db_unsupported_function');
 
830
                        }
 
831
                        return FALSE;
 
832
                }
 
833
 
 
834
                $query = $this->query($sql);
 
835
 
 
836
                $retval = array();
 
837
                foreach ($query->result_array() as $row)
 
838
                {
 
839
                        if (isset($row['COLUMN_NAME']))
 
840
                        {
 
841
                                $retval[] = $row['COLUMN_NAME'];
 
842
                        }
 
843
                        else
 
844
                        {
 
845
                                $retval[] = current($row);
 
846
                        }
 
847
                }
 
848
 
 
849
                $this->data_cache['field_names'][$table] = $retval;
 
850
                return $this->data_cache['field_names'][$table];
 
851
        }
 
852
 
 
853
        // --------------------------------------------------------------------
 
854
 
 
855
        /**
 
856
         * Determine if a particular field exists
 
857
         * @access      public
 
858
         * @param       string
 
859
         * @param       string
 
860
         * @return      boolean
 
861
         */
 
862
        function field_exists($field_name, $table_name)
 
863
        {
 
864
                return ( ! in_array($field_name, $this->list_fields($table_name))) ? FALSE : TRUE;
 
865
        }
 
866
 
 
867
        // --------------------------------------------------------------------
 
868
 
 
869
        /**
 
870
         * Returns an object with field data
 
871
         *
 
872
         * @access      public
 
873
         * @param       string  the table name
 
874
         * @return      object
 
875
         */
 
876
        function field_data($table = '')
 
877
        {
 
878
                if ($table == '')
 
879
                {
 
880
                        if ($this->db_debug)
 
881
                        {
 
882
                                return $this->display_error('db_field_param_missing');
 
883
                        }
 
884
                        return FALSE;
 
885
                }
 
886
 
 
887
                $query = $this->query($this->_field_data($this->_protect_identifiers($table, TRUE, NULL, FALSE)));
 
888
 
 
889
                return $query->field_data();
 
890
        }
 
891
 
 
892
        // --------------------------------------------------------------------
 
893
 
 
894
        /**
 
895
         * Generate an insert string
 
896
         *
 
897
         * @access      public
 
898
         * @param       string  the table upon which the query will be performed
 
899
         * @param       array   an associative array data of key/values
 
900
         * @return      string
 
901
         */
 
902
        function insert_string($table, $data)
 
903
        {
 
904
                $fields = array();
 
905
                $values = array();
 
906
 
 
907
                foreach ($data as $key => $val)
 
908
                {
 
909
                        $fields[] = $this->_escape_identifiers($key);
 
910
                        $values[] = $this->escape($val);
 
911
                }
 
912
 
 
913
                return $this->_insert($this->_protect_identifiers($table, TRUE, NULL, FALSE), $fields, $values);
 
914
        }
 
915
 
 
916
        // --------------------------------------------------------------------
 
917
 
 
918
        /**
 
919
         * Generate an update string
 
920
         *
 
921
         * @access      public
 
922
         * @param       string  the table upon which the query will be performed
 
923
         * @param       array   an associative array data of key/values
 
924
         * @param       mixed   the "where" statement
 
925
         * @return      string
 
926
         */
 
927
        function update_string($table, $data, $where)
 
928
        {
 
929
                if ($where == '')
 
930
                {
 
931
                        return false;
 
932
                }
 
933
 
 
934
                $fields = array();
 
935
                foreach ($data as $key => $val)
 
936
                {
 
937
                        $fields[$this->_protect_identifiers($key)] = $this->escape($val);
 
938
                }
 
939
 
 
940
                if ( ! is_array($where))
 
941
                {
 
942
                        $dest = array($where);
 
943
                }
 
944
                else
 
945
                {
 
946
                        $dest = array();
 
947
                        foreach ($where as $key => $val)
 
948
                        {
 
949
                                $prefix = (count($dest) == 0) ? '' : ' AND ';
 
950
 
 
951
                                if ($val !== '')
 
952
                                {
 
953
                                        if ( ! $this->_has_operator($key))
 
954
                                        {
 
955
                                                $key .= ' =';
 
956
                                        }
 
957
 
 
958
                                        $val = ' '.$this->escape($val);
 
959
                                }
 
960
 
 
961
                                $dest[] = $prefix.$key.$val;
 
962
                        }
 
963
                }
 
964
 
 
965
                return $this->_update($this->_protect_identifiers($table, TRUE, NULL, FALSE), $fields, $dest);
 
966
        }
 
967
 
 
968
        // --------------------------------------------------------------------
 
969
 
 
970
        /**
 
971
         * Tests whether the string has an SQL operator
 
972
         *
 
973
         * @access      private
 
974
         * @param       string
 
975
         * @return      bool
 
976
         */
 
977
        function _has_operator($str)
 
978
        {
 
979
                $str = trim($str);
 
980
                if ( ! preg_match("/(\s|<|>|!|=|is null|is not null)/i", $str))
 
981
                {
 
982
                        return FALSE;
 
983
                }
 
984
 
 
985
                return TRUE;
 
986
        }
 
987
 
 
988
        // --------------------------------------------------------------------
 
989
 
 
990
        /**
 
991
         * Enables a native PHP function to be run, using a platform agnostic wrapper.
 
992
         *
 
993
         * @access      public
 
994
         * @param       string  the function name
 
995
         * @param       mixed   any parameters needed by the function
 
996
         * @return      mixed
 
997
         */
 
998
        function call_function($function)
 
999
        {
 
1000
                $driver = ($this->dbdriver == 'postgre') ? 'pg_' : $this->dbdriver.'_';
 
1001
 
 
1002
                if (FALSE === strpos($driver, $function))
 
1003
                {
 
1004
                        $function = $driver.$function;
 
1005
                }
 
1006
 
 
1007
                if ( ! function_exists($function))
 
1008
                {
 
1009
                        if ($this->db_debug)
 
1010
                        {
 
1011
                                return $this->display_error('db_unsupported_function');
 
1012
                        }
 
1013
                        return FALSE;
 
1014
                }
 
1015
                else
 
1016
                {
 
1017
                        $args = (func_num_args() > 1) ? array_splice(func_get_args(), 1) : null;
 
1018
                        if (is_null($args))
 
1019
                        {
 
1020
                                return call_user_func($function);
 
1021
                        }
 
1022
                        else
 
1023
                        {
 
1024
                                return call_user_func_array($function, $args);
 
1025
                        }
 
1026
                }
 
1027
        }
 
1028
 
 
1029
        // --------------------------------------------------------------------
 
1030
 
 
1031
        /**
 
1032
         * Set Cache Directory Path
 
1033
         *
 
1034
         * @access      public
 
1035
         * @param       string  the path to the cache directory
 
1036
         * @return      void
 
1037
         */
 
1038
        function cache_set_path($path = '')
 
1039
        {
 
1040
                $this->cachedir = $path;
 
1041
        }
 
1042
 
 
1043
        // --------------------------------------------------------------------
 
1044
 
 
1045
        /**
 
1046
         * Enable Query Caching
 
1047
         *
 
1048
         * @access      public
 
1049
         * @return      void
 
1050
         */
 
1051
        function cache_on()
 
1052
        {
 
1053
                $this->cache_on = TRUE;
 
1054
                return TRUE;
 
1055
        }
 
1056
 
 
1057
        // --------------------------------------------------------------------
 
1058
 
 
1059
        /**
 
1060
         * Disable Query Caching
 
1061
         *
 
1062
         * @access      public
 
1063
         * @return      void
 
1064
         */
 
1065
        function cache_off()
 
1066
        {
 
1067
                $this->cache_on = FALSE;
 
1068
                return FALSE;
 
1069
        }
 
1070
 
 
1071
 
 
1072
        // --------------------------------------------------------------------
 
1073
 
 
1074
        /**
 
1075
         * Delete the cache files associated with a particular URI
 
1076
         *
 
1077
         * @access      public
 
1078
         * @return      void
 
1079
         */
 
1080
        function cache_delete($segment_one = '', $segment_two = '')
 
1081
        {
 
1082
                if ( ! $this->_cache_init())
 
1083
                {
 
1084
                        return FALSE;
 
1085
                }
 
1086
                return $this->CACHE->delete($segment_one, $segment_two);
 
1087
        }
 
1088
 
 
1089
        // --------------------------------------------------------------------
 
1090
 
 
1091
        /**
 
1092
         * Delete All cache files
 
1093
         *
 
1094
         * @access      public
 
1095
         * @return      void
 
1096
         */
 
1097
        function cache_delete_all()
 
1098
        {
 
1099
                if ( ! $this->_cache_init())
 
1100
                {
 
1101
                        return FALSE;
 
1102
                }
 
1103
 
 
1104
                return $this->CACHE->delete_all();
 
1105
        }
 
1106
 
 
1107
        // --------------------------------------------------------------------
 
1108
 
 
1109
        /**
 
1110
         * Initialize the Cache Class
 
1111
         *
 
1112
         * @access      private
 
1113
         * @return      void
 
1114
         */
 
1115
        function _cache_init()
 
1116
        {
 
1117
                if (is_object($this->CACHE) AND class_exists('CI_DB_Cache'))
 
1118
                {
 
1119
                        return TRUE;
 
1120
                }
 
1121
 
 
1122
                if ( ! class_exists('CI_DB_Cache'))
 
1123
                {
 
1124
                        if ( ! @include(BASEPATH.'database/DB_cache.php'))
 
1125
                        {
 
1126
                                return $this->cache_off();
 
1127
                        }
 
1128
                }
 
1129
 
 
1130
                $this->CACHE = new CI_DB_Cache($this); // pass db object to support multiple db connections and returned db objects
 
1131
                return TRUE;
 
1132
        }
 
1133
 
 
1134
        // --------------------------------------------------------------------
 
1135
 
 
1136
        /**
 
1137
         * Close DB Connection
 
1138
         *
 
1139
         * @access      public
 
1140
         * @return      void
 
1141
         */
 
1142
        function close()
 
1143
        {
 
1144
                if (is_resource($this->conn_id) OR is_object($this->conn_id))
 
1145
                {
 
1146
                        $this->_close($this->conn_id);
 
1147
                }
 
1148
                $this->conn_id = FALSE;
 
1149
        }
 
1150
 
 
1151
        // --------------------------------------------------------------------
 
1152
 
 
1153
        /**
 
1154
         * Display an error message
 
1155
         *
 
1156
         * @access      public
 
1157
         * @param       string  the error message
 
1158
         * @param       string  any "swap" values
 
1159
         * @param       boolean whether to localize the message
 
1160
         * @return      string  sends the application/error_db.php template
 
1161
         */
 
1162
        function display_error($error = '', $swap = '', $native = FALSE)
 
1163
        {
 
1164
                $LANG =& load_class('Lang', 'core');
 
1165
                $LANG->load('db');
 
1166
 
 
1167
                $heading = $LANG->line('db_error_heading');
 
1168
 
 
1169
                if ($native == TRUE)
 
1170
                {
 
1171
                        $message = $error;
 
1172
                }
 
1173
                else
 
1174
                {
 
1175
                        $message = ( ! is_array($error)) ? array(str_replace('%s', $swap, $LANG->line($error))) : $error;
 
1176
                }
 
1177
 
 
1178
                // Find the most likely culprit of the error by going through
 
1179
                // the backtrace until the source file is no longer in the
 
1180
                // database folder.
 
1181
 
 
1182
                $trace = debug_backtrace();
 
1183
 
 
1184
                foreach ($trace as $call)
 
1185
                {
 
1186
                        if (isset($call['file']) && strpos($call['file'], BASEPATH.'database') === FALSE)
 
1187
                        {
 
1188
                                // Found it - use a relative path for safety
 
1189
                                $message[] = 'Filename: '.str_replace(array(BASEPATH, APPPATH), '', $call['file']);
 
1190
                                $message[] = 'Line Number: '.$call['line'];
 
1191
 
 
1192
                                break;
 
1193
                        }
 
1194
                }
 
1195
 
 
1196
                $error =& load_class('Exceptions', 'core');
 
1197
                echo $error->show_error($heading, $message, 'error_db');
 
1198
                exit;
 
1199
        }
 
1200
 
 
1201
        // --------------------------------------------------------------------
 
1202
 
 
1203
        /**
 
1204
         * Protect Identifiers
 
1205
         *
 
1206
         * This function adds backticks if appropriate based on db type
 
1207
         *
 
1208
         * @access      private
 
1209
         * @param       mixed   the item to escape
 
1210
         * @return      mixed   the item with backticks
 
1211
         */
 
1212
        function protect_identifiers($item, $prefix_single = FALSE)
 
1213
        {
 
1214
                return $this->_protect_identifiers($item, $prefix_single);
 
1215
        }
 
1216
 
 
1217
        // --------------------------------------------------------------------
 
1218
 
 
1219
        /**
 
1220
         * Protect Identifiers
 
1221
         *
 
1222
         * This function is used extensively by the Active Record class, and by
 
1223
         * a couple functions in this class.
 
1224
         * It takes a column or table name (optionally with an alias) and inserts
 
1225
         * the table prefix onto it.  Some logic is necessary in order to deal with
 
1226
         * column names that include the path.  Consider a query like this:
 
1227
         *
 
1228
         * SELECT * FROM hostname.database.table.column AS c FROM hostname.database.table
 
1229
         *
 
1230
         * Or a query with aliasing:
 
1231
         *
 
1232
         * SELECT m.member_id, m.member_name FROM members AS m
 
1233
         *
 
1234
         * Since the column name can include up to four segments (host, DB, table, column)
 
1235
         * or also have an alias prefix, we need to do a bit of work to figure this out and
 
1236
         * insert the table prefix (if it exists) in the proper position, and escape only
 
1237
         * the correct identifiers.
 
1238
         *
 
1239
         * @access      private
 
1240
         * @param       string
 
1241
         * @param       bool
 
1242
         * @param       mixed
 
1243
         * @param       bool
 
1244
         * @return      string
 
1245
         */
 
1246
        function _protect_identifiers($item, $prefix_single = FALSE, $protect_identifiers = NULL, $field_exists = TRUE)
 
1247
        {
 
1248
                if ( ! is_bool($protect_identifiers))
 
1249
                {
 
1250
                        $protect_identifiers = $this->_protect_identifiers;
 
1251
                }
 
1252
 
 
1253
                if (is_array($item))
 
1254
                {
 
1255
                        $escaped_array = array();
 
1256
 
 
1257
                        foreach ($item as $k => $v)
 
1258
                        {
 
1259
                                $escaped_array[$this->_protect_identifiers($k)] = $this->_protect_identifiers($v);
 
1260
                        }
 
1261
 
 
1262
                        return $escaped_array;
 
1263
                }
 
1264
 
 
1265
                // Convert tabs or multiple spaces into single spaces
 
1266
                $item = preg_replace('/[\t ]+/', ' ', $item);
 
1267
 
 
1268
                // If the item has an alias declaration we remove it and set it aside.
 
1269
                // Basically we remove everything to the right of the first space
 
1270
                if (strpos($item, ' ') !== FALSE)
 
1271
                {
 
1272
                        $alias = strstr($item, ' ');
 
1273
                        $item = substr($item, 0, - strlen($alias));
 
1274
                }
 
1275
                else
 
1276
                {
 
1277
                        $alias = '';
 
1278
                }
 
1279
 
 
1280
                // This is basically a bug fix for queries that use MAX, MIN, etc.
 
1281
                // If a parenthesis is found we know that we do not need to
 
1282
                // escape the data or add a prefix.  There's probably a more graceful
 
1283
                // way to deal with this, but I'm not thinking of it -- Rick
 
1284
                if (strpos($item, '(') !== FALSE)
 
1285
                {
 
1286
                        return $item.$alias;
 
1287
                }
 
1288
 
 
1289
                // Break the string apart if it contains periods, then insert the table prefix
 
1290
                // in the correct location, assuming the period doesn't indicate that we're dealing
 
1291
                // with an alias. While we're at it, we will escape the components
 
1292
                if (strpos($item, '.') !== FALSE)
 
1293
                {
 
1294
                        $parts  = explode('.', $item);
 
1295
 
 
1296
                        // Does the first segment of the exploded item match
 
1297
                        // one of the aliases previously identified?  If so,
 
1298
                        // we have nothing more to do other than escape the item
 
1299
                        if (in_array($parts[0], $this->ar_aliased_tables))
 
1300
                        {
 
1301
                                if ($protect_identifiers === TRUE)
 
1302
                                {
 
1303
                                        foreach ($parts as $key => $val)
 
1304
                                        {
 
1305
                                                if ( ! in_array($val, $this->_reserved_identifiers))
 
1306
                                                {
 
1307
                                                        $parts[$key] = $this->_escape_identifiers($val);
 
1308
                                                }
 
1309
                                        }
 
1310
 
 
1311
                                        $item = implode('.', $parts);
 
1312
                                }
 
1313
                                return $item.$alias;
 
1314
                        }
 
1315
 
 
1316
                        // Is there a table prefix defined in the config file?  If not, no need to do anything
 
1317
                        if ($this->dbprefix != '')
 
1318
                        {
 
1319
                                // We now add the table prefix based on some logic.
 
1320
                                // Do we have 4 segments (hostname.database.table.column)?
 
1321
                                // If so, we add the table prefix to the column name in the 3rd segment.
 
1322
                                if (isset($parts[3]))
 
1323
                                {
 
1324
                                        $i = 2;
 
1325
                                }
 
1326
                                // Do we have 3 segments (database.table.column)?
 
1327
                                // If so, we add the table prefix to the column name in 2nd position
 
1328
                                elseif (isset($parts[2]))
 
1329
                                {
 
1330
                                        $i = 1;
 
1331
                                }
 
1332
                                // Do we have 2 segments (table.column)?
 
1333
                                // If so, we add the table prefix to the column name in 1st segment
 
1334
                                else
 
1335
                                {
 
1336
                                        $i = 0;
 
1337
                                }
 
1338
 
 
1339
                                // This flag is set when the supplied $item does not contain a field name.
 
1340
                                // This can happen when this function is being called from a JOIN.
 
1341
                                if ($field_exists == FALSE)
 
1342
                                {
 
1343
                                        $i++;
 
1344
                                }
 
1345
 
 
1346
                                // Verify table prefix and replace if necessary
 
1347
                                if ($this->swap_pre != '' && strncmp($parts[$i], $this->swap_pre, strlen($this->swap_pre)) === 0)
 
1348
                                {
 
1349
                                        $parts[$i] = preg_replace("/^".$this->swap_pre."(\S+?)/", $this->dbprefix."\\1", $parts[$i]);
 
1350
                                }
 
1351
 
 
1352
                                // We only add the table prefix if it does not already exist
 
1353
                                if (substr($parts[$i], 0, strlen($this->dbprefix)) != $this->dbprefix)
 
1354
                                {
 
1355
                                        $parts[$i] = $this->dbprefix.$parts[$i];
 
1356
                                }
 
1357
 
 
1358
                                // Put the parts back together
 
1359
                                $item = implode('.', $parts);
 
1360
                        }
 
1361
 
 
1362
                        if ($protect_identifiers === TRUE)
 
1363
                        {
 
1364
                                $item = $this->_escape_identifiers($item);
 
1365
                        }
 
1366
 
 
1367
                        return $item.$alias;
 
1368
                }
 
1369
 
 
1370
                // Is there a table prefix?  If not, no need to insert it
 
1371
                if ($this->dbprefix != '')
 
1372
                {
 
1373
                        // Verify table prefix and replace if necessary
 
1374
                        if ($this->swap_pre != '' && strncmp($item, $this->swap_pre, strlen($this->swap_pre)) === 0)
 
1375
                        {
 
1376
                                $item = preg_replace("/^".$this->swap_pre."(\S+?)/", $this->dbprefix."\\1", $item);
 
1377
                        }
 
1378
 
 
1379
                        // Do we prefix an item with no segments?
 
1380
                        if ($prefix_single == TRUE AND substr($item, 0, strlen($this->dbprefix)) != $this->dbprefix)
 
1381
                        {
 
1382
                                $item = $this->dbprefix.$item;
 
1383
                        }
 
1384
                }
 
1385
 
 
1386
                if ($protect_identifiers === TRUE AND ! in_array($item, $this->_reserved_identifiers))
 
1387
                {
 
1388
                        $item = $this->_escape_identifiers($item);
 
1389
                }
 
1390
 
 
1391
                return $item.$alias;
 
1392
        }
 
1393
 
 
1394
        // --------------------------------------------------------------------
 
1395
 
 
1396
        /**
 
1397
         * Dummy method that allows Active Record class to be disabled
 
1398
         *
 
1399
         * This function is used extensively by every db driver.
 
1400
         *
 
1401
         * @return      void
 
1402
         */
 
1403
        protected function _reset_select()
 
1404
        {
 
1405
        }
 
1406
 
 
1407
}
 
1408
 
 
1409
/* End of file DB_driver.php */
 
1410
/* Location: ./system/database/DB_driver.php */
 
 
b'\\ No newline at end of file'