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) |
|
|
|
|
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) |
|
|
|
|
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( |
|
|
|
|
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); |
|
|
|
|
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)) { |
|
|
|
|
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; |
|
|
|
|
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) { |
|
|
|
|
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) { |
|
|
|
|
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) { |
|
|
|
|
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) { |
|
|
|
|
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) |
|
|
|
|
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) |
|
|
|
|
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) |
|
|
|
|
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) |
|
|
|
|
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) |
|
|
|
|
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) |
|
|
|
|
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 = '') |
|
|
|
|
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 = '') |
|
|
|
|
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 = '') |
|
|
|
|
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 = '') |
|
|
|
|
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) |
|
|
|
|
626
|
|
|
{ |
627
|
|
|
if (! is_array($by)) { |
628
|
|
|
$by = explode(',', (string) $by); |
629
|
|
|
} |
630
|
|
|
|
631
|
|
View Code Duplication |
foreach ($by as $val) { |
|
|
|
|
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) |
|
|
|
|
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) |
|
|
|
|
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; |
|
|
|
|
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; |
|
|
|
|
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) { |
|
|
|
|
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) |
|
|
|
|
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) |
|
|
|
|
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) |
|
|
|
|
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) { |
|
|
|
|
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 |
|
|
|
|
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
|
|
|
|
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.