Database_Core   D
last analyzed

Complexity

Total Complexity 199

Size/Duplication

Total Lines 1326
Duplicated Lines 19.46 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 3
Bugs 2 Features 0
Metric Value
c 3
b 2
f 0
dl 258
loc 1326
rs 4.4102
wmc 199
lcom 1
cbo 3

52 Methods

Rating   Name   Duplication   Size   Complexity  
A instance() 9 9 3
A instance_name() 0 4 1
D __construct() 3 108 16
B connect() 0 13 5
C query() 0 35 7
D select() 7 33 10
C from() 28 34 7
D join() 17 60 12
B where() 18 18 7
B orwhere() 18 18 7
A like() 11 11 4
A orlike() 11 11 4
A notlike() 11 11 4
A ornotlike() 11 11 4
A regex() 11 11 4
A orregex() 11 11 4
A notregex() 11 11 4
A ornotregex() 11 11 4
B groupby() 12 21 5
A having() 0 5 1
A orhaving() 0 5 1
B orderby() 0 24 5
A limit() 0 10 3
A offset() 0 6 1
A set() 8 17 4
A get() 0 20 3
B getwhere() 0 22 4
A compile() 0 16 3
B insert() 0 27 6
B in() 0 19 6
A notin() 0 4 1
B merge() 23 23 5
B update() 27 27 6
B delete() 0 25 5
A last_query() 0 4 1
A count_records() 0 18 4
A reset_select() 0 13 1
A reset_write() 0 6 1
A list_tables() 0 6 2
A table_exists() 0 8 2
A compile_binds() 0 21 3
A field_data() 0 6 2
A list_fields() 0 6 2
A escape() 0 4 1
A escape_str() 0 4 1
A escape_table() 0 4 1
A escape_column() 0 4 1
A table_prefix() 0 4 1
A clear_cache() 0 12 3
A push() 0 20 1
A pop() 0 23 2
B count_last_query() 0 25 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Database_Core often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Database_Core, and based on these observations, apply Extract Interface, too.

1
<?php defined('SYSPATH') or die('No direct access allowed.');
2
/**
3
 * Provides database access in a platform agnostic way, using simple query building blocks.
4
 *
5
 * $Id: Database.php 4342 2009-05-08 16:56:01Z jheathco $
6
 *
7
 * @package    Core
8
 * @author     Kohana Team
9
 * @copyright  (c) 2007-2008 Kohana Team
10
 * @license    http://kohanaphp.com/license.html
11
 */
12
class Database_Core
13
{
14
15
    // Database instances
16
    public static $instances = array();
17
18
    // Global benchmark
19
    public static $benchmarks = array();
20
21
    // Configuration
22
    protected $config = array(
23
        'benchmark'     => true,
24
        'persistent'    => false,
25
        'connection'    => '',
26
        'character_set' => 'utf8',
27
        'table_prefix'  => '',
28
        'object'        => true,
29
        'cache'         => false,
30
        'escape'        => true,
31
    );
32
33
    // Database driver object
34
    protected $driver;
35
    protected $link;
36
37
    // Un-compiled parts of the SQL query
38
    protected $select     = array();
39
    protected $set        = array();
40
    protected $from       = array();
41
    protected $join       = array();
42
    protected $where      = array();
43
    protected $orderby    = array();
44
    protected $order      = array();
45
    protected $groupby    = array();
46
    protected $having     = array();
47
    protected $distinct   = false;
48
    protected $limit      = false;
49
    protected $offset     = false;
50
    protected $last_query = '';
51
52
    // Stack of queries for push/pop
53
    protected $query_history = array();
54
55
    /**
56
     * Returns a singleton instance of Database.
57
     *
58
     * @param   mixed   configuration array or DSN
59
     * @return  Database_Core
60
     */
61 View Code Duplication
    public static function & instance($name = 'default', $config = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
62
    {
63
        if (! isset(Database::$instances[$name])) {
64
            // Create a new instance
65
            Database::$instances[$name] = new Database($config === null ? $name : $config);
66
        }
67
68
        return Database::$instances[$name];
69
    }
70
71
    /**
72
     * Returns the name of a given database instance.
73
     *
74
     * @param   Database  instance of Database
75
     * @return  string
76
     */
77
    public static function instance_name(Database $db)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $db. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
78
    {
79
        return array_search($db, Database::$instances, true);
80
    }
81
82
    /**
83
     * Sets up the database configuration, loads the Database_Driver.
84
     *
85
     * @throws  Kohana_Database_Exception
86
     */
87
    public function __construct($config = array())
88
    {
89
        if (empty($config)) {
90
            // Load the default group
91
            $config = Kohana::config('database.default');
92
        } elseif (is_array($config) and count($config) > 0) {
93
            if (! array_key_exists('connection', $config)) {
94
                $config = array('connection' => $config);
95
            }
96
        } elseif (is_string($config)) {
97
            // The config is a DSN string
98
            if (strpos($config, '://') !== false) {
99
                $config = array('connection' => $config);
100
            }
101
            // The config is a group name
102
            else {
103
                $name = $config;
104
105
                // Test the config group name
106
                if (($config = Kohana::config('database.'.$config)) === null) {
107
                    throw new Kohana_Database_Exception('database.undefined_group', $name);
108
                }
109
            }
110
        }
111
112
        // Merge the default config with the passed config
113
        $this->config = array_merge($this->config, $config);
114
115
        if (is_string($this->config['connection'])) {
116
            // Make sure the connection is valid
117
            if (strpos($this->config['connection'], '://') === false) {
118
                throw new Kohana_Database_Exception('database.invalid_dsn', $this->config['connection']);
119
            }
120
121
            // Parse the DSN, creating an array to hold the connection parameters
122
            $db = array(
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $db. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
123
                'type'     => false,
124
                'user'     => false,
125
                'pass'     => false,
126
                'host'     => false,
127
                'port'     => false,
128
                'socket'   => false,
129
                'database' => false
130
            );
131
132
            // Get the protocol and arguments
133
            list($db['type'], $connection) = explode('://', $this->config['connection'], 2);
134
135
            if (strpos($connection, '@') !== false) {
136
                // Get the username and password
137
                list($db['pass'], $connection) = explode('@', $connection, 2);
138
                // Check if a password is supplied
139
                $logindata = explode(':', $db['pass'], 2);
140
                $db['pass'] = (count($logindata) > 1) ? $logindata[1] : '';
141
                $db['user'] = $logindata[0];
142
143
                // Prepare for finding the database
144
                $connection = explode('/', $connection);
145
146
                // Find the database name
147
                $db['database'] = array_pop($connection);
148
149
                // Reset connection string
150
                $connection = implode('/', $connection);
151
152
                // Find the socket
153
                if (preg_match('/^unix\([^)]++\)/', $connection)) {
154
                    // This one is a little hairy: we explode based on the end of
155
                    // the socket, removing the 'unix(' from the connection string
156
                    list($db['socket'], $connection) = explode(')', substr($connection, 5), 2);
0 ignored issues
show
Unused Code introduced by
The assignment to $connection is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
157
                } elseif (strpos($connection, ':') !== false) {
158
                    // Fetch the host and port name
159
                    list($db['host'], $db['port']) = explode(':', $connection, 2);
160
                } else {
161
                    $db['host'] = $connection;
162
                }
163
            } else {
164
                // File connection
165
                $connection = explode('/', $connection);
166
167
                // Find database file name
168
                $db['database'] = array_pop($connection);
169
170
                // Find database directory name
171
                $db['socket'] = implode('/', $connection).'/';
172
            }
173
174
            // Reset the connection array to the database config
175
            $this->config['connection'] = $db;
176
        }
177
        // Set driver name
178
        $driver = 'Database_'.ucfirst($this->config['connection']['type']).'_Driver';
179
180
        // Load the driver
181 View Code Duplication
        if (! Kohana::auto_load($driver)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
182
            throw new Kohana_Database_Exception('core.driver_not_found', $this->config['connection']['type'], get_class($this));
183
        }
184
185
        // Initialize the driver
186
        $this->driver = new $driver($this->config);
187
188
        // Validate the driver
189
        if (! ($this->driver instanceof Database_Driver)) {
190
            throw new Kohana_Database_Exception('core.driver_implements', $this->config['connection']['type'], get_class($this), 'Database_Driver');
191
        }
192
193
        Kohana::log('debug', 'Database Library initialized');
194
    }
195
196
    /**
197
     * Simple connect method to get the database queries up and running.
198
     *
199
     * @return  void
200
     */
201
    public function connect()
202
    {
203
        // A link can be a resource or an object
204
        if (! is_resource($this->link) and ! is_object($this->link)) {
205
            $this->link = $this->driver->connect();
206
            if (! is_resource($this->link) and ! is_object($this->link)) {
207
                throw new Kohana_Database_Exception('database.connection', $this->driver->show_error());
208
            }
209
210
            // Clear password after successful connect
211
            $this->config['connection']['pass'] = null;
212
        }
213
    }
214
215
    /**
216
     * Runs a query into the driver and returns the result.
217
     *
218
     * @param   string  SQL query to execute
219
     * @return  Database_Result
220
     */
221
    public function query($sql = '')
222
    {
223
        if ($sql == '') {
224
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Database_Core::query of type Database_Result.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
225
        }
226
227
        // No link? Connect!
228
        $this->link or $this->connect();
229
230
        // Start the benchmark
231
        $start = microtime(true);
232
233
        if (func_num_args() > 1) { //if we have more than one argument ($sql)
234
            $argv = func_get_args();
235
            $binds = (is_array(next($argv))) ? current($argv) : array_slice($argv, 1);
236
        }
237
238
        // Compile binds if needed
239
        if (isset($binds)) {
240
            $sql = $this->compile_binds($sql, $binds);
241
        }
242
243
        // Fetch the result
244
        $result = $this->driver->query($this->last_query = $sql);
245
246
        // Stop the benchmark
247
        $stop = microtime(true);
248
249
        if ($this->config['benchmark'] == true) {
250
            // Benchmark the query
251
            Database::$benchmarks[] = array('query' => $sql, 'time' => $stop - $start, 'rows' => count($result));
252
        }
253
254
        return $result;
255
    }
256
257
    /**
258
     * Selects the column names for a database query.
259
     *
260
     * @param   string  string or array of column names to select
261
     * @return  Database_Core  This Database object.
262
     */
263
    public function select($sql = '*')
264
    {
265 View Code Duplication
        if (func_num_args() > 1) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
266
            $sql = func_get_args();
267
        } elseif (is_string($sql)) {
268
            $sql = explode(',', $sql);
269
        } else {
270
            $sql = (array) $sql;
271
        }
272
273
        foreach ($sql as $val) {
274
            if (($val = trim($val)) === '') {
275
                continue;
276
            }
277
278
            if (strpos($val, '(') === false and $val !== '*') {
279
                if (preg_match('/^DISTINCT\s++(.+)$/i', $val, $matches)) {
280
                    // Only prepend with table prefix if table name is specified
281
                    $val = (strpos($matches[1], '.') !== false) ? $this->config['table_prefix'].$matches[1] : $matches[1];
282
283
                    $this->distinct = true;
284
                } else {
285
                    $val = (strpos($val, '.') !== false) ? $this->config['table_prefix'].$val : $val;
286
                }
287
288
                $val = $this->driver->escape_column($val);
289
            }
290
291
            $this->select[] = $val;
292
        }
293
294
        return $this;
295
    }
296
297
    /**
298
     * Selects the from table(s) for a database query.
299
     *
300
     * @param   string  string or array of tables to select
301
     * @param string|boolean $sql
302
     * @return  Database_Core  This Database object.
303
     */
304
    public function from($sql)
305
    {
306 View Code Duplication
        if (func_num_args() > 1) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
307
            $sql = func_get_args();
308
        } elseif (is_string($sql)) {
309
            $sql = explode(',', $sql);
310
        } else {
311
            $sql = array($sql);
312
        }
313
314 View Code Duplication
        foreach ($sql as $val) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
315
            if (is_string($val)) {
316
                if (($val = trim($val)) === '') {
317
                    continue;
318
                }
319
320
                // TODO: Temporary solution, this should be moved to database driver (AS is checked for twice)
321
                if (stripos($val, ' AS ') !== false) {
322
                    $val = str_ireplace(' AS ', ' AS ', $val);
323
324
                    list($table, $alias) = explode(' AS ', $val);
325
326
                    // Attach prefix to both sides of the AS
327
                    $val = $this->config['table_prefix'].$table.' AS '.$this->config['table_prefix'].$alias;
328
                } else {
329
                    $val = $this->config['table_prefix'].$val;
330
                }
331
            }
332
333
            $this->from[] = $val;
334
        }
335
336
        return $this;
337
    }
338
339
    /**
340
     * Generates the JOIN portion of the query.
341
     *
342
     * @param   string        table name
343
     * @param   string|array  where key or array of key => value pairs
344
     * @param   string        where value
345
     * @param   string        type of join
346
     * @return  Database_Core        This Database object.
347
     */
348
    public function join($table, $key, $value = null, $type = '')
349
    {
350
        $join = array();
351
352
        if (! empty($type)) {
353
            $type = strtoupper(trim($type));
354
355
            if (! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER'), true)) {
356
                $type = '';
357
            } else {
358
                $type .= ' ';
359
            }
360
        }
361
362
        $cond = array();
363
        $keys  = is_array($key) ? $key : array($key => $value);
364
        foreach ($keys as $key => $value) {
365
            $key    = (strpos($key, '.') !== false) ? $this->config['table_prefix'].$key : $key;
366
367
            if (is_string($value)) {
368
                // Only escape if it's a string
369
                $value = $this->driver->escape_column($this->config['table_prefix'].$value);
370
            }
371
372
            $cond[] = $this->driver->where($key, $value, 'AND ', count($cond), false);
373
        }
374
375
        if (! is_array($this->join)) {
376
            $this->join = array();
377
        }
378
379
        if (! is_array($table)) {
380
            $table = array($table);
381
        }
382
383 View Code Duplication
        foreach ($table as $t) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
384
            if (is_string($t)) {
385
                // TODO: Temporary solution, this should be moved to database driver (AS is checked for twice)
386
                if (stripos($t, ' AS ') !== false) {
387
                    $t = str_ireplace(' AS ', ' AS ', $t);
388
389
                    list($table, $alias) = explode(' AS ', $t);
390
391
                    // Attach prefix to both sides of the AS
392
                    $t = $this->config['table_prefix'].$table.' AS '.$this->config['table_prefix'].$alias;
393
                } else {
394
                    $t = $this->config['table_prefix'].$t;
395
                }
396
            }
397
398
            $join['tables'][] = $this->driver->escape_column($t);
399
        }
400
401
        $join['conditions'] = '('.trim(implode(' ', $cond)).')';
402
        $join['type'] = $type;
403
404
        $this->join[] = $join;
405
406
        return $this;
407
    }
408
409
410
    /**
411
     * Selects the where(s) for a database query.
412
     *
413
     * @param   string|array  key name or array of key => value pairs
414
     * @param   string        value to match with key
415
     * @param   boolean       disable quoting of WHERE clause
416
     * @return  Database_Core        This Database object.
417
     */
418 View Code Duplication
    public function where($key, $value = null, $quote = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
419
    {
420
        $quote = (func_num_args() < 2 and ! is_array($key)) ? -1 : $quote;
421
        if (is_object($key)) {
422
            $keys = array((string) $key => '');
423
        } elseif (! is_array($key)) {
424
            $keys = array($key => $value);
425
        } else {
426
            $keys = $key;
427
        }
428
429
        foreach ($keys as $key => $value) {
430
            $key           = (strpos($key, '.') !== false) ? $this->config['table_prefix'].$key : $key;
431
            $this->where[] = $this->driver->where($key, $value, 'AND ', count($this->where), $quote);
432
        }
433
434
        return $this;
435
    }
436
437
    /**
438
     * Selects the or where(s) for a database query.
439
     *
440
     * @param   string|array  key name or array of key => value pairs
441
     * @param   string        value to match with key
442
     * @param   boolean       disable quoting of WHERE clause
443
     * @return  Database_Core        This Database object.
444
     */
445 View Code Duplication
    public function orwhere($key, $value = null, $quote = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
446
    {
447
        $quote = (func_num_args() < 2 and ! is_array($key)) ? -1 : $quote;
448
        if (is_object($key)) {
449
            $keys = array((string) $key => '');
450
        } elseif (! is_array($key)) {
451
            $keys = array($key => $value);
452
        } else {
453
            $keys = $key;
454
        }
455
456
        foreach ($keys as $key => $value) {
457
            $key           = (strpos($key, '.') !== false) ? $this->config['table_prefix'].$key : $key;
458
            $this->where[] = $this->driver->where($key, $value, 'OR ', count($this->where), $quote);
459
        }
460
461
        return $this;
462
    }
463
464
    /**
465
     * Selects the like(s) for a database query.
466
     *
467
     * @param   string|array  field name or array of field => match pairs
468
     * @param   string        like value to match with field
469
     * @param   boolean       automatically add starting and ending wildcards
470
     * @return  Database_Core        This Database object.
471
     */
472 View Code Duplication
    public function like($field, $match = '', $auto = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
473
    {
474
        $fields = is_array($field) ? $field : array($field => $match);
475
476
        foreach ($fields as $field => $match) {
477
            $field         = (strpos($field, '.') !== false) ? $this->config['table_prefix'].$field : $field;
478
            $this->where[] = $this->driver->like($field, $match, $auto, 'AND ', count($this->where));
479
        }
480
481
        return $this;
482
    }
483
484
    /**
485
     * Selects the or like(s) for a database query.
486
     *
487
     * @param   string|array  field name or array of field => match pairs
488
     * @param   string        like value to match with field
489
     * @param   boolean       automatically add starting and ending wildcards
490
     * @return  Database_Core        This Database object.
491
     */
492 View Code Duplication
    public function orlike($field, $match = '', $auto = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
493
    {
494
        $fields = is_array($field) ? $field : array($field => $match);
495
496
        foreach ($fields as $field => $match) {
497
            $field         = (strpos($field, '.') !== false) ? $this->config['table_prefix'].$field : $field;
498
            $this->where[] = $this->driver->like($field, $match, $auto, 'OR ', count($this->where));
499
        }
500
501
        return $this;
502
    }
503
504
    /**
505
     * Selects the not like(s) for a database query.
506
     *
507
     * @param   string|array  field name or array of field => match pairs
508
     * @param   string        like value to match with field
509
     * @param   boolean       automatically add starting and ending wildcards
510
     * @return  Database_Core        This Database object.
511
     */
512 View Code Duplication
    public function notlike($field, $match = '', $auto = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
513
    {
514
        $fields = is_array($field) ? $field : array($field => $match);
515
516
        foreach ($fields as $field => $match) {
517
            $field         = (strpos($field, '.') !== false) ? $this->config['table_prefix'].$field : $field;
518
            $this->where[] = $this->driver->notlike($field, $match, $auto, 'AND ', count($this->where));
519
        }
520
521
        return $this;
522
    }
523
524
    /**
525
     * Selects the or not like(s) for a database query.
526
     *
527
     * @param   string|array  field name or array of field => match pairs
528
     * @param   string        like value to match with field
529
     * @return  Database_Core        This Database object.
530
     */
531 View Code Duplication
    public function ornotlike($field, $match = '', $auto = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
532
    {
533
        $fields = is_array($field) ? $field : array($field => $match);
534
535
        foreach ($fields as $field => $match) {
536
            $field         = (strpos($field, '.') !== false) ? $this->config['table_prefix'].$field : $field;
537
            $this->where[] = $this->driver->notlike($field, $match, $auto, 'OR ', count($this->where));
538
        }
539
540
        return $this;
541
    }
542
543
    /**
544
     * Selects the like(s) for a database query.
545
     *
546
     * @param   string|array  field name or array of field => match pairs
547
     * @param   string        like value to match with field
548
     * @return  Database_Core        This Database object.
549
     */
550 View Code Duplication
    public function regex($field, $match = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
551
    {
552
        $fields = is_array($field) ? $field : array($field => $match);
553
554
        foreach ($fields as $field => $match) {
555
            $field         = (strpos($field, '.') !== false) ? $this->config['table_prefix'].$field : $field;
556
            $this->where[] = $this->driver->regex($field, $match, 'AND ', count($this->where));
557
        }
558
559
        return $this;
560
    }
561
562
    /**
563
     * Selects the or like(s) for a database query.
564
     *
565
     * @param   string|array  field name or array of field => match pairs
566
     * @param   string        like value to match with field
567
     * @return  Database_Core        This Database object.
568
     */
569 View Code Duplication
    public function orregex($field, $match = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
570
    {
571
        $fields = is_array($field) ? $field : array($field => $match);
572
573
        foreach ($fields as $field => $match) {
574
            $field         = (strpos($field, '.') !== false) ? $this->config['table_prefix'].$field : $field;
575
            $this->where[] = $this->driver->regex($field, $match, 'OR ', count($this->where));
576
        }
577
578
        return $this;
579
    }
580
581
    /**
582
     * Selects the not regex(s) for a database query.
583
     *
584
     * @param   string|array  field name or array of field => match pairs
585
     * @param   string        regex value to match with field
586
     * @return  Database_Core        This Database object.
587
     */
588 View Code Duplication
    public function notregex($field, $match = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
589
    {
590
        $fields = is_array($field) ? $field : array($field => $match);
591
592
        foreach ($fields as $field => $match) {
593
            $field         = (strpos($field, '.') !== false) ? $this->config['table_prefix'].$field : $field;
594
            $this->where[] = $this->driver->notregex($field, $match, 'AND ', count($this->where));
595
        }
596
597
        return $this;
598
    }
599
600
    /**
601
     * Selects the or not regex(s) for a database query.
602
     *
603
     * @param   string|array  field name or array of field => match pairs
604
     * @param   string        regex value to match with field
605
     * @return  Database_Core        This Database object.
606
     */
607 View Code Duplication
    public function ornotregex($field, $match = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
608
    {
609
        $fields = is_array($field) ? $field : array($field => $match);
610
611
        foreach ($fields as $field => $match) {
612
            $field         = (strpos($field, '.') !== false) ? $this->config['table_prefix'].$field : $field;
613
            $this->where[] = $this->driver->notregex($field, $match, 'OR ', count($this->where));
614
        }
615
616
        return $this;
617
    }
618
619
    /**
620
     * Chooses the column to group by in a select query.
621
     *
622
     * @param   string  column name to group by
623
     * @return  Database_Core  This Database object.
624
     */
625
    public function groupby($by)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $by. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
626
    {
627
        if (! is_array($by)) {
628
            $by = explode(',', (string) $by);
629
        }
630
631 View Code Duplication
        foreach ($by as $val) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
632
            $val = trim($val);
633
634
            if ($val != '') {
635
                // Add the table prefix if we are using table.column names
636
                if (strpos($val, '.')) {
637
                    $val = $this->config['table_prefix'].$val;
638
                }
639
640
                $this->groupby[] = $this->driver->escape_column($val);
641
            }
642
        }
643
644
        return $this;
645
    }
646
647
    /**
648
     * Selects the having(s) for a database query.
649
     *
650
     * @param   string|array  key name or array of key => value pairs
651
     * @param   string        value to match with key
652
     * @param   boolean       disable quoting of WHERE clause
653
     * @return  Database_Core        This Database object.
654
     */
655
    public function having($key, $value = '', $quote = true)
0 ignored issues
show
Unused Code introduced by
The parameter $quote is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
656
    {
657
        $this->having[] = $this->driver->where($key, $value, 'AND', count($this->having), true);
658
        return $this;
659
    }
660
661
    /**
662
     * Selects the or having(s) for a database query.
663
     *
664
     * @param   string|array  key name or array of key => value pairs
665
     * @param   string        value to match with key
666
     * @param   boolean       disable quoting of WHERE clause
667
     * @return  Database_Core        This Database object.
668
     */
669
    public function orhaving($key, $value = '', $quote = true)
0 ignored issues
show
Unused Code introduced by
The parameter $quote is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
670
    {
671
        $this->having[] = $this->driver->where($key, $value, 'OR', count($this->having), true);
672
        return $this;
673
    }
674
675
    /**
676
     * Chooses which column(s) to order the select query by.
677
     *
678
     * @param   string|array  column(s) to order on, can be an array, single column, or comma seperated list of columns
679
     * @param   string        direction of the order
680
     * @return  Database_Core        This Database object.
681
     */
682
    public function orderby($orderby, $direction = null)
683
    {
684
        if (! is_array($orderby)) {
685
            $orderby = array($orderby => $direction);
686
        }
687
688
        foreach ($orderby as $column => $direction) {
689
            $direction = strtoupper(trim($direction));
690
691
            // Add a direction if the provided one isn't valid
692
            if (! in_array($direction, array('ASC', 'DESC', 'RAND()', 'RANDOM()', 'NULL'))) {
693
                $direction = 'ASC';
694
            }
695
696
            // Add the table prefix if a table.column was passed
697
            if (strpos($column, '.')) {
698
                $column = $this->config['table_prefix'].$column;
699
            }
700
701
            $this->orderby[] = $this->driver->escape_column($column).' '.$direction;
702
        }
703
704
        return $this;
705
    }
706
707
    /**
708
     * Selects the limit section of a query.
709
     *
710
     * @param   integer  number of rows to limit result to
711
     * @param   integer  offset in result to start returning rows from
712
     * @return  Database_Core   This Database object.
713
     */
714
    public function limit($limit, $offset = null)
715
    {
716
        $this->limit  = (int) $limit;
0 ignored issues
show
Documentation Bug introduced by
The property $limit was declared of type boolean, but (int) $limit is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
717
718
        if ($offset !== null or ! is_int($this->offset)) {
719
            $this->offset($offset);
720
        }
721
722
        return $this;
723
    }
724
725
    /**
726
     * Sets the offset portion of a query.
727
     *
728
     * @param   integer  offset value
729
     * @return  Database_Core   This Database object.
730
     */
731
    public function offset($value)
732
    {
733
        $this->offset = (int) $value;
0 ignored issues
show
Documentation Bug introduced by
The property $offset was declared of type boolean, but (int) $value is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
734
735
        return $this;
736
    }
737
738
    /**
739
     * Allows key/value pairs to be set for inserting or updating.
740
     *
741
     * @param   string|array  key name or array of key => value pairs
742
     * @param   string        value to match with key
743
     * @return  Database_Core        This Database object.
744
     */
745
    public function set($key, $value = '')
746
    {
747
        if (! is_array($key)) {
748
            $key = array($key => $value);
749
        }
750
751 View Code Duplication
        foreach ($key as $k => $v) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
752
            // Add a table prefix if the column includes the table.
753
            if (strpos($k, '.')) {
754
                $k = $this->config['table_prefix'].$k;
755
            }
756
757
            $this->set[$k] = $this->driver->escape($v);
758
        }
759
760
        return $this;
761
    }
762
763
    /**
764
     * Compiles the select statement based on the other functions called and runs the query.
765
     *
766
     * @param   string  table name
767
     * @param   string  limit clause
768
     * @param   string  offset clause
769
     * @return  Database_Result
770
     */
771
    public function get($table = '', $limit = null, $offset = null)
772
    {
773
        if ($table != '') {
774
            $this->from($table);
775
        }
776
777
        if (! is_null($limit)) {
778
            $this->limit($limit, $offset);
779
        }
780
781
        $sql = $this->driver->compile_select(get_object_vars($this));
782
783
        $this->reset_select();
784
785
        $result = $this->query($sql);
786
787
        $this->last_query = $sql;
788
789
        return $result;
790
    }
791
792
    /**
793
     * Compiles the select statement based on the other functions called and runs the query.
794
     *
795
     * @param   string  table name
796
     * @param   array   where clause
797
     * @param   string  limit clause
798
     * @param   string  offset clause
799
     * @return  Database_Result  This Database object.
800
     */
801
    public function getwhere($table = '', $where = null, $limit = null, $offset = null)
802
    {
803
        if ($table != '') {
804
            $this->from($table);
805
        }
806
807
        if (! is_null($where)) {
808
            $this->where($where);
809
        }
810
811
        if (! is_null($limit)) {
812
            $this->limit($limit, $offset);
813
        }
814
815
        $sql = $this->driver->compile_select(get_object_vars($this));
816
817
        $this->reset_select();
818
819
        $result = $this->query($sql);
820
821
        return $result;
822
    }
823
824
    /**
825
     * Compiles the select statement based on the other functions called and returns the query string.
826
     *
827
     * @param   string  table name
828
     * @param   string  limit clause
829
     * @param   string  offset clause
830
     * @return  string  sql string
831
     */
832
    public function compile($table = '', $limit = null, $offset = null)
833
    {
834
        if ($table != '') {
835
            $this->from($table);
836
        }
837
838
        if (! is_null($limit)) {
839
            $this->limit($limit, $offset);
840
        }
841
842
        $sql = $this->driver->compile_select(get_object_vars($this));
843
844
        $this->reset_select();
845
846
        return $sql;
847
    }
848
849
    /**
850
     * Compiles an insert string and runs the query.
851
     *
852
     * @param   string  table name
853
     * @param   array   array of key/value pairs to insert
854
     * @return  Database_Result  Query result
855
     */
856
    public function insert($table = '', $set = null)
857
    {
858
        if (! is_null($set)) {
859
            $this->set($set);
860
        }
861
862
        if ($this->set == null) {
863
            throw new Kohana_Database_Exception('database.must_use_set');
864
        }
865
866
        if ($table == '') {
867
            if (! isset($this->from[0])) {
868
                throw new Kohana_Database_Exception('database.must_use_table');
869
            }
870
871
            $table = $this->from[0];
872
        }
873
874
        // If caching is enabled, clear the cache before inserting
875
        ($this->config['cache'] === true) and $this->clear_cache();
876
877
        $sql = $this->driver->insert($this->config['table_prefix'].$table, array_keys($this->set), array_values($this->set));
878
879
        $this->reset_write();
880
881
        return $this->query($sql);
882
    }
883
884
    /**
885
     * Adds an "IN" condition to the where clause
886
     *
887
     * @param   string  Name of the column being examined
888
     * @param   mixed   An array or string to match against
889
     * @param   bool    Generate a NOT IN clause instead
890
     * @return  Database_Core  This Database object.
891
     */
892
    public function in($field, $values, $not = false)
0 ignored issues
show
Coding Style introduced by
This method's name is shorter than the configured minimum length of 3 characters.

Even though PHP does not care about the name of your methods, it is generally a good practice to choose method names which can be easily understood by other human readers.

Loading history...
893
    {
894
        if (is_array($values)) {
895
            $escaped_values = array();
896
            foreach ($values as $v) {
897
                if (is_numeric($v)) {
898
                    $escaped_values[] = $v;
899
                } else {
900
                    $escaped_values[] = "'".$this->driver->escape_str($v)."'";
901
                }
902
            }
903
            $values = implode(",", $escaped_values);
904
        }
905
906
        $where = $this->driver->escape_column(((strpos($field, '.') !== false) ? $this->config['table_prefix'] : ''). $field).' '.($not === true ? 'NOT ' : '').'IN ('.$values.')';
907
        $this->where[] = $this->driver->where($where, '', 'AND ', count($this->where), -1);
908
909
        return $this;
910
    }
911
912
    /**
913
     * Adds a "NOT IN" condition to the where clause
914
     *
915
     * @param   string  Name of the column being examined
916
     * @param   mixed   An array or string to match against
917
     * @return  Database_Core  This Database object.
918
     */
919
    public function notin($field, $values)
920
    {
921
        return $this->in($field, $values, true);
922
    }
923
924
    /**
925
     * Compiles a merge string and runs the query.
926
     *
927
     * @param   string  table name
928
     * @param   array   array of key/value pairs to merge
929
     * @return  Database_Result  Query result
930
     */
931 View Code Duplication
    public function merge($table = '', $set = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
932
    {
933
        if (! is_null($set)) {
934
            $this->set($set);
935
        }
936
937
        if ($this->set == null) {
938
            throw new Kohana_Database_Exception('database.must_use_set');
939
        }
940
941
        if ($table == '') {
942
            if (! isset($this->from[0])) {
943
                throw new Kohana_Database_Exception('database.must_use_table');
944
            }
945
946
            $table = $this->from[0];
947
        }
948
949
        $sql = $this->driver->merge($this->config['table_prefix'].$table, array_keys($this->set), array_values($this->set));
950
951
        $this->reset_write();
952
        return $this->query($sql);
953
    }
954
955
    /**
956
     * Compiles an update string and runs the query.
957
     *
958
     * @param   string  table name
959
     * @param   array   associative array of update values
960
     * @param   array   where clause
961
     * @return  Database_Result  Query result
962
     */
963 View Code Duplication
    public function update($table = '', $set = null, $where = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
964
    {
965
        if (is_array($set)) {
966
            $this->set($set);
967
        }
968
969
        if (! is_null($where)) {
970
            $this->where($where);
971
        }
972
973
        if ($this->set == false) {
974
            throw new Kohana_Database_Exception('database.must_use_set');
975
        }
976
977
        if ($table == '') {
978
            if (! isset($this->from[0])) {
979
                throw new Kohana_Database_Exception('database.must_use_table');
980
            }
981
982
            $table = $this->from[0];
983
        }
984
985
        $sql = $this->driver->update($this->config['table_prefix'].$table, $this->set, $this->where);
986
987
        $this->reset_write();
988
        return $this->query($sql);
989
    }
990
991
    /**
992
     * Compiles a delete string and runs the query.
993
     *
994
     * @param   string  table name
995
     * @param   array   where clause
996
     * @return  Database_Result  Query result
997
     */
998
    public function delete($table = '', $where = null)
999
    {
1000
        if ($table == '') {
1001
            if (! isset($this->from[0])) {
1002
                throw new Kohana_Database_Exception('database.must_use_table');
1003
            }
1004
1005
            $table = $this->from[0];
1006
        } else {
1007
            $table = $this->config['table_prefix'].$table;
1008
        }
1009
1010
        if (! is_null($where)) {
1011
            $this->where($where);
1012
        }
1013
1014
        if (count($this->where) < 1) {
1015
            throw new Kohana_Database_Exception('database.must_use_where');
1016
        }
1017
1018
        $sql = $this->driver->delete($table, $this->where);
1019
1020
        $this->reset_write();
1021
        return $this->query($sql);
1022
    }
1023
1024
    /**
1025
     * Returns the last query run.
1026
     *
1027
     * @return  string SQL
1028
     */
1029
    public function last_query()
1030
    {
1031
        return $this->last_query;
1032
    }
1033
1034
    /**
1035
     * Count query records.
1036
     *
1037
     * @param   string   table name
1038
     * @param   array    where clause
1039
     * @return  integer
1040
     */
1041
    public function count_records($table = false, $where = null)
1042
    {
1043
        if (count($this->from) < 1) {
1044
            if ($table == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
1045
                throw new Kohana_Database_Exception('database.must_use_table');
1046
            }
1047
1048
            $this->from($table);
1049
        }
1050
1051
        if ($where !== null) {
1052
            $this->where($where);
1053
        }
1054
1055
        $query = $this->select('COUNT(*) AS '.$this->escape_column('records_found'))->get()->result(true);
1056
1057
        return (int) $query->current()->records_found;
1058
    }
1059
1060
    /**
1061
     * Resets all private select variables.
1062
     *
1063
     * @return  void
1064
     */
1065
    protected function reset_select()
1066
    {
1067
        $this->select   = array();
1068
        $this->from     = array();
1069
        $this->join     = array();
1070
        $this->where    = array();
1071
        $this->orderby  = array();
1072
        $this->groupby  = array();
1073
        $this->having   = array();
1074
        $this->distinct = false;
1075
        $this->limit    = false;
1076
        $this->offset   = false;
1077
    }
1078
1079
    /**
1080
     * Resets all private insert and update variables.
1081
     *
1082
     * @return  void
1083
     */
1084
    protected function reset_write()
1085
    {
1086
        $this->set   = array();
1087
        $this->from  = array();
1088
        $this->where = array();
1089
    }
1090
1091
    /**
1092
     * Lists all the tables in the current database.
1093
     *
1094
     * @return  array
1095
     */
1096
    public function list_tables()
1097
    {
1098
        $this->link or $this->connect();
1099
1100
        return $this->driver->list_tables();
1101
    }
1102
1103
    /**
1104
     * See if a table exists in the database.
1105
     *
1106
     * @param   string   table name
1107
     * @param   boolean  True to attach table prefix
1108
     * @return  boolean
1109
     */
1110
    public function table_exists($table_name, $prefix = true)
1111
    {
1112
        if ($prefix) {
1113
            return in_array($this->config['table_prefix'].$table_name, $this->list_tables());
1114
        } else {
1115
            return in_array($table_name, $this->list_tables());
1116
        }
1117
    }
1118
1119
    /**
1120
     * Combine a SQL statement with the bind values. Used for safe queries.
1121
     *
1122
     * @param   string  query to bind to the values
1123
     * @param   array   array of values to bind to the query
1124
     * @param string $sql
1125
     * @return  string
1126
     */
1127
    public function compile_binds($sql, $binds)
1128
    {
1129
        foreach ((array) $binds as $val) {
1130
            // If the SQL contains no more bind marks ("?"), we're done.
1131
            if (($next_bind_pos = strpos($sql, '?')) === false) {
1132
                break;
1133
            }
1134
1135
            // Properly escape the bind value.
1136
            $val = $this->driver->escape($val);
1137
1138
            // Temporarily replace possible bind marks ("?"), in the bind value itself, with a placeholder.
1139
            $val = str_replace('?', '{%B%}', $val);
1140
1141
            // Replace the first bind mark ("?") with its corresponding value.
1142
            $sql = substr($sql, 0, $next_bind_pos).$val.substr($sql, $next_bind_pos + 1);
1143
        }
1144
1145
        // Restore placeholders.
1146
        return str_replace('{%B%}', '?', $sql);
1147
    }
1148
1149
    /**
1150
     * Get the field data for a database table, along with the field's attributes.
1151
     *
1152
     * @param   string  table name
1153
     * @return  array
1154
     */
1155
    public function field_data($table = '')
1156
    {
1157
        $this->link or $this->connect();
1158
1159
        return $this->driver->field_data($this->config['table_prefix'].$table);
1160
    }
1161
1162
    /**
1163
     * Get the field data for a database table, along with the field's attributes.
1164
     *
1165
     * @param   string  table name
1166
     * @return  array
1167
     */
1168
    public function list_fields($table = '')
1169
    {
1170
        $this->link or $this->connect();
1171
1172
        return $this->driver->list_fields($this->config['table_prefix'].$table);
1173
    }
1174
1175
    /**
1176
     * Escapes a value for a query.
1177
     *
1178
     * @param   mixed   value to escape
1179
     * @return  string
1180
     */
1181
    public function escape($value)
1182
    {
1183
        return $this->driver->escape($value);
1184
    }
1185
1186
    /**
1187
     * Escapes a string for a query.
1188
     *
1189
     * @param   string  string to escape
1190
     * @return  string
1191
     */
1192
    public function escape_str($str)
1193
    {
1194
        return $this->driver->escape_str($str);
1195
    }
1196
1197
    /**
1198
     * Escapes a table name for a query.
1199
     *
1200
     * @param   string  string to escape
1201
     * @param string $table
1202
     * @return  string
1203
     */
1204
    public function escape_table($table)
1205
    {
1206
        return $this->driver->escape_table($table);
1207
    }
1208
1209
    /**
1210
     * Escapes a column name for a query.
1211
     *
1212
     * @param   string  string to escape
1213
     * @param string $table
1214
     * @return  string
1215
     */
1216
    public function escape_column($table)
1217
    {
1218
        return $this->driver->escape_column($table);
1219
    }
1220
1221
    /**
1222
     * Returns table prefix of current configuration.
1223
     *
1224
     * @return  string
1225
     */
1226
    public function table_prefix()
1227
    {
1228
        return $this->config['table_prefix'];
1229
    }
1230
1231
    /**
1232
     * Clears the query cache.
1233
     *
1234
     * @param   string|TRUE  clear cache by SQL statement or TRUE for last query
1235
     * @return  Database_Core       This Database object.
1236
     */
1237
    public function clear_cache($sql = null)
1238
    {
1239
        if ($sql === true) {
1240
            $this->driver->clear_cache($this->last_query);
1241
        } elseif (is_string($sql)) {
1242
            $this->driver->clear_cache($sql);
1243
        } else {
1244
            $this->driver->clear_cache();
1245
        }
1246
1247
        return $this;
1248
    }
1249
1250
    /**
1251
     * Pushes existing query space onto the query stack.  Use push
1252
     * and pop to prevent queries from clashing before they are
1253
     * executed
1254
     *
1255
     * @return Database_Core This Databaes object
1256
     */
1257
    public function push()
1258
    {
1259
        array_push($this->query_history, array(
1260
            $this->select,
1261
            $this->from,
1262
            $this->join,
1263
            $this->where,
1264
            $this->orderby,
1265
            $this->order,
1266
            $this->groupby,
1267
            $this->having,
1268
            $this->distinct,
1269
            $this->limit,
1270
            $this->offset
1271
        ));
1272
1273
        $this->reset_select();
1274
1275
        return $this;
1276
    }
1277
1278
    /**
1279
     * Pops from query stack into the current query space.
1280
     *
1281
     * @return Database_Core This Databaes object
1282
     */
1283
    public function pop()
1284
    {
1285
        if (count($this->query_history) == 0) {
1286
            // No history
1287
            return $this;
1288
        }
1289
1290
        list(
1291
            $this->select,
1292
            $this->from,
1293
            $this->join,
1294
            $this->where,
1295
            $this->orderby,
1296
            $this->order,
1297
            $this->groupby,
1298
            $this->having,
1299
            $this->distinct,
1300
            $this->limit,
1301
            $this->offset
1302
        ) = array_pop($this->query_history);
1303
1304
        return $this;
1305
    }
1306
1307
    /**
1308
     * Count the number of records in the last query, without LIMIT or OFFSET applied.
1309
     *
1310
     * @return  integer
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|false?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
1311
     */
1312
    public function count_last_query()
1313
    {
1314
        if ($sql = $this->last_query()) {
1315
            if (stripos($sql, 'LIMIT') !== false) {
1316
                // Remove LIMIT from the SQL
1317
                $sql = preg_replace('/\sLIMIT\s+[^a-z]+/i', ' ', $sql);
1318
            }
1319
1320
            if (stripos($sql, 'OFFSET') !== false) {
1321
                // Remove OFFSET from the SQL
1322
                $sql = preg_replace('/\sOFFSET\s+\d+/i', '', $sql);
1323
            }
1324
1325
            // Get the total rows from the last query executed
1326
            $result = $this->query(
1327
                'SELECT COUNT(*) AS '.$this->escape_column('total_rows').' '.
1328
                'FROM ('.trim($sql).') AS '.$this->escape_table('counted_results')
1329
            );
1330
1331
            // Return the total number of rows from the query
1332
            return (int) $result->current()->total_rows;
1333
        }
1334
1335
        return false;
1336
    }
1337
} // End Database Class
1338
1339
1340
/**
1341
 * Sets the code for a Database exception.
1342
 */
1343
class Kohana_Database_Exception extends Kohana_Exception
1344
{
1345
    protected $code = E_DATABASE_ERROR;
1346
} // End Kohana Database Exception
1347