| 95 | | // Merge the default config with the passed config |
| 96 | | $this->config = array_merge($this->config, $config); |
| 97 | | |
| 98 | | // Make sure the connection is valid |
| 99 | | if (strpos($this->config['connection'], '://') === FALSE) |
| 100 | | throw new Kohana_Database_Exception('database.invalid_dsn', $this->config['connection']); |
| 101 | | |
| 102 | | // Parse the DSN, creating an array to hold the connection parameters |
| 103 | | $db = array |
| 104 | | ( |
| 105 | | 'type' => FALSE, |
| 106 | | 'user' => FALSE, |
| 107 | | 'pass' => FALSE, |
| 108 | | 'host' => FALSE, |
| 109 | | 'port' => FALSE, |
| 110 | | 'socket' => FALSE, |
| 111 | | 'database' => FALSE |
| 112 | | ); |
| 113 | | |
| 114 | | // Get the protocol and arguments |
| 115 | | list ($db['type'], $connection) = explode('://', $this->config['connection'], 2); |
| 116 | | |
| 117 | | if (strpos($connection, '@') !== FALSE) |
| 118 | | { |
| 119 | | // Get the username and password |
| 120 | | list ($db['pass'], $connection) = explode('@', $connection, 2); |
| 121 | | // Check if a password is supplied |
| 122 | | $logindata = explode(':', $db['pass'], 2); |
| 123 | | $db['pass'] = (count($logindata) > 1) ? $logindata[1] : ''; |
| 124 | | $db['user'] = $logindata[0]; |
| 125 | | |
| 126 | | // Prepare for finding the database |
| 127 | | $connection = explode('/', $connection); |
| 128 | | |
| 129 | | // Find the database name |
| 130 | | $db['database'] = array_pop($connection); |
| 131 | | |
| 132 | | // Reset connection string |
| 133 | | $connection = implode('/', $connection); |
| 134 | | |
| 135 | | // Find the socket |
| 136 | | if (preg_match('/^unix\([^)]++\)/', $connection)) |
| 137 | | { |
| 138 | | // This one is a little hairy: we explode based on the end of |
| 139 | | // the socket, removing the 'unix(' from the connection string |
| 140 | | list ($db['socket'], $connection) = explode(')', substr($connection, 5), 2); |
| 141 | | } |
| 142 | | elseif (strpos($connection, ':') !== FALSE) |
| 143 | | { |
| 144 | | // Fetch the host and port name |
| 145 | | list ($db['host'], $db['port']) = explode(':', $connection, 2); |
| 146 | | } |
| 147 | | else |
| 148 | | { |
| 149 | | $db['host'] = $connection; |
| 150 | | } |
| 151 | | } |
| 152 | | else |
| 153 | | { |
| 154 | | // File connection |
| 155 | | $connection = explode('/', $connection); |
| 156 | | |
| 157 | | // Find database file name |
| 158 | | $db['database'] = array_pop($connection); |
| 159 | | |
| 160 | | // Find database directory name |
| 161 | | $db['socket'] = implode('/', $connection).'/'; |
| 162 | | } |
| 163 | | |
| 164 | | // Reset the connection array to the database config |
| 165 | | $this->config['connection'] = $db; |
| 166 | | |
| 167 | | // Set driver name |
| 168 | | $driver = 'Database_'.ucfirst($this->config['connection']['type']).'_Driver'; |
| 169 | | |
| 170 | | // Load the driver |
| 171 | | if ( ! Kohana::auto_load($driver)) |
| 172 | | throw new Kohana_Database_Exception('database.driver_not_supported', $this->config['connection']['type']); |
| 173 | | |
| 174 | | // Initialize the driver |
| 175 | | $this->driver = new $driver($this->config); |
| 176 | | |
| 177 | | // Validate the driver |
| 178 | | if ( ! ($this->driver instanceof Database_Driver)) |
| 179 | | throw new Kohana_Database_Exception('database.driver_not_supported', 'Database drivers must use the Database_Driver interface.'); |
| 180 | | |
| 181 | | Log::add('debug', 'Database Library initialized'); |
| | 53 | return new Database_Select($args, $this); |
| 203 | | /** |
| 204 | | * Runs a query into the driver and returns the result. |
| 205 | | * |
| 206 | | * @param string SQL query to execute |
| 207 | | * @return object Database_Result |
| 208 | | */ |
| 209 | | public function query($sql = '') |
| 210 | | { |
| 211 | | if ($sql == '') return FALSE; |
| 212 | | |
| 213 | | // No link? Connect! |
| 214 | | $this->link or $this->connect(); |
| 215 | | |
| 216 | | // Start the benchmark |
| 217 | | $start = microtime(TRUE); |
| 218 | | |
| 219 | | if (func_num_args() > 1) //if we have more than one argument ($sql) |
| 220 | | { |
| 221 | | $argv = func_get_args(); |
| 222 | | $binds = (is_array(next($argv))) ? current($argv) : array_slice($argv, 1); |
| 223 | | } |
| 224 | | |
| 225 | | // Compile binds if needed |
| 226 | | if (isset($binds)) |
| 227 | | { |
| 228 | | $sql = $this->compile_binds($sql, $binds); |
| 229 | | } |
| 230 | | |
| 231 | | // Fetch the result |
| 232 | | $result = $this->driver->query($this->last_query = $sql); |
| 233 | | |
| 234 | | // Stop the benchmark |
| 235 | | $stop = microtime(TRUE); |
| 236 | | |
| 237 | | if ($this->config['benchmark'] == TRUE) |
| 238 | | { |
| 239 | | // Benchmark the query |
| 240 | | self::$benchmarks[] = array('query' => $sql, 'time' => $stop - $start, 'rows' => count($result)); |
| 241 | | } |
| 242 | | |
| 243 | | return $result; |
| 244 | | } |
| 245 | | |
| 246 | | /** |
| 247 | | * Selects the column names for a database query. |
| 248 | | * |
| 249 | | * @param string string or array of column names to select |
| 250 | | * @return object This Database object. |
| 251 | | */ |
| 252 | | public function select($sql = '*') |
| 253 | | { |
| 254 | | if (func_num_args() > 1) |
| 255 | | { |
| 256 | | $sql = func_get_args(); |
| 257 | | } |
| 258 | | elseif (is_string($sql)) |
| 259 | | { |
| 260 | | $sql = explode(',', $sql); |
| 261 | | } |
| 262 | | else |
| 263 | | { |
| 264 | | $sql = (array) $sql; |
| 265 | | } |
| 266 | | |
| 267 | | foreach($sql as $val) |
| 268 | | { |
| 269 | | if (($val = trim($val)) === '') continue; |
| 270 | | |
| 271 | | if (strpos($val, '(') === FALSE AND $val !== '*') |
| 272 | | { |
| 273 | | if (preg_match('/^DISTINCT\s++(.+)$/i', $val, $matches)) |
| 274 | | { |
| 275 | | $val = $this->config['table_prefix'].$matches[1]; |
| 276 | | $this->distinct = TRUE; |
| 277 | | } |
| 278 | | else |
| 279 | | { |
| 280 | | $val = (strpos($val, '.') !== FALSE) ? $this->config['table_prefix'].$val : $val; |
| 281 | | } |
| 282 | | |
| 283 | | $val = $this->driver->escape_column($val); |
| 284 | | } |
| 285 | | |
| 286 | | $this->select[] = $val; |
| 287 | | } |
| 288 | | |
| 289 | | return $this; |
| 290 | | } |
| 291 | | |
| 292 | | /** |
| 293 | | * Selects the from table(s) for a database query. |
| 294 | | * |
| 295 | | * @param string string or array of tables to select |
| 296 | | * @return object This Database object. |
| 297 | | */ |
| 298 | | public function from($sql) |
| 299 | | { |
| 300 | | foreach((array) $sql as $val) |
| 301 | | { |
| 302 | | if (($val = trim($val)) === '') continue; |
| 303 | | |
| 304 | | $this->from[] = $this->config['table_prefix'].$val; |
| 305 | | } |
| 306 | | |
| 307 | | return $this; |
| 308 | | } |
| 309 | | |
| 310 | | /** |
| 311 | | * Generates the JOIN portion of the query. |
| 312 | | * |
| 313 | | * @param string table name |
| 314 | | * @param string|array where key or array of key => value pairs |
| 315 | | * @param string where value |
| 316 | | * @param string type of join |
| 317 | | * @return object This Database object. |
| 318 | | */ |
| 319 | | public function join($table, $key, $value = NULL, $type = '') |
| 320 | | { |
| 321 | | if ($type != '') |
| 322 | | { |
| 323 | | $type = strtoupper(trim($type)); |
| 324 | | |
| 325 | | if ( ! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER'), TRUE)) |
| 326 | | { |
| 327 | | $type = ''; |
| 328 | | } |
| 329 | | else |
| 330 | | { |
| 331 | | $type .= ' '; |
| 332 | | } |
| 333 | | } |
| 334 | | |
| 335 | | $cond = array(); |
| 336 | | $keys = is_array($key) ? $key : array($key => $value); |
| 337 | | foreach ($keys as $key => $value) |
| 338 | | { |
| 339 | | $key = (strpos($key, '.') !== FALSE) ? $this->config['table_prefix'].$key : $key; |
| 340 | | $cond[] = $this->driver->where($key, $this->driver->escape_column($this->config['table_prefix'].$value), 'AND ', count($cond), FALSE); |
| 341 | | } |
| 342 | | |
| 343 | | $this->join[] = $type.'JOIN '.$this->driver->escape_column($this->config['table_prefix'].$table).' ON '.implode(' ', $cond); |
| 344 | | |
| 345 | | return $this; |
| 346 | | } |
| 347 | | |
| 348 | | /** |
| 349 | | * Selects the where(s) for a database query. |
| 350 | | * |
| 351 | | * @param string|array key name or array of key => value pairs |
| 352 | | * @param string value to match with key |
| 353 | | * @param boolean disable quoting of WHERE clause |
| 354 | | * @return object This Database object. |
| 355 | | */ |
| 356 | | public function where($key, $value = NULL, $quote = TRUE) |
| 357 | | { |
| 358 | | $quote = (func_num_args() < 2 AND ! is_array($key)) ? -1 : $quote; |
| 359 | | $keys = is_array($key) ? $key : array($key => $value); |
| 360 | | |
| 361 | | foreach ($keys as $key => $value) |
| 362 | | { |
| 363 | | $key = (strpos($key, '.') !== FALSE) ? $this->config['table_prefix'].$key : $key; |
| 364 | | $this->where[] = $this->driver->where($key, $value, 'AND ', count($this->where), $quote); |
| 365 | | } |
| 366 | | |
| 367 | | return $this; |
| 368 | | } |
| 369 | | |
| 370 | | /** |
| 371 | | * Selects the or where(s) for a database query. |
| 372 | | * |
| 373 | | * @param string|array key name or array of key => value pairs |
| 374 | | * @param string value to match with key |
| 375 | | * @param boolean disable quoting of WHERE clause |
| 376 | | * @return object This Database object. |
| 377 | | */ |
| 378 | | public function orwhere($key, $value = NULL, $quote = TRUE) |
| 379 | | { |
| 380 | | $quote = (func_num_args() < 2 AND ! is_array($key)) ? -1 : $quote; |
| 381 | | $keys = is_array($key) ? $key : array($key => $value); |
| 382 | | |
| 383 | | foreach ($keys as $key => $value) |
| 384 | | { |
| 385 | | $key = (strpos($key, '.') !== FALSE) ? $this->config['table_prefix'].$key : $key; |
| 386 | | $this->where[] = $this->driver->where($key, $value, 'OR ', count($this->where), $quote); |
| 387 | | } |
| 388 | | |
| 389 | | return $this; |
| 390 | | } |
| 391 | | |
| 392 | | /** |
| 393 | | * Selects the like(s) for a database query. |
| 394 | | * |
| 395 | | * @param string|array field name or array of field => match pairs |
| 396 | | * @param string like value to match with field |
| 397 | | * @param boolean automatically add starting and ending wildcards |
| 398 | | * @return object This Database object. |
| 399 | | */ |
| 400 | | public function like($field, $match = '', $auto = TRUE) |
| 401 | | { |
| 402 | | $fields = is_array($field) ? $field : array($field => $match); |
| 403 | | |
| 404 | | foreach ($fields as $field => $match) |
| 405 | | { |
| 406 | | $field = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field; |
| 407 | | $this->where[] = $this->driver->like($field, $match, $auto, 'AND ', count($this->where)); |
| 408 | | } |
| 409 | | |
| 410 | | return $this; |
| 411 | | } |
| 412 | | |
| 413 | | /** |
| 414 | | * Selects the or like(s) for a database query. |
| 415 | | * |
| 416 | | * @param string|array field name or array of field => match pairs |
| 417 | | * @param string like value to match with field |
| 418 | | * @param boolean automatically add starting and ending wildcards |
| 419 | | * @return object This Database object. |
| 420 | | */ |
| 421 | | public function orlike($field, $match = '', $auto = TRUE) |
| 422 | | { |
| 423 | | $fields = is_array($field) ? $field : array($field => $match); |
| 424 | | |
| 425 | | foreach ($fields as $field => $match) |
| 426 | | { |
| 427 | | $field = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field; |
| 428 | | $this->where[] = $this->driver->like($field, $match, $auto, 'OR ', count($this->where)); |
| 429 | | } |
| 430 | | |
| 431 | | return $this; |
| 432 | | } |
| 433 | | |
| 434 | | /** |
| 435 | | * Selects the not like(s) for a database query. |
| 436 | | * |
| 437 | | * @param string|array field name or array of field => match pairs |
| 438 | | * @param string like value to match with field |
| 439 | | * @param boolean automatically add starting and ending wildcards |
| 440 | | * @return object This Database object. |
| 441 | | */ |
| 442 | | public function notlike($field, $match = '', $auto = TRUE) |
| 443 | | { |
| 444 | | $fields = is_array($field) ? $field : array($field => $match); |
| 445 | | |
| 446 | | foreach ($fields as $field => $match) |
| 447 | | { |
| 448 | | $field = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field; |
| 449 | | $this->where[] = $this->driver->notlike($field, $match, 'AND ', count($this->where)); |
| 450 | | } |
| 451 | | |
| 452 | | return $this; |
| 453 | | } |
| 454 | | |
| 455 | | /** |
| 456 | | * Selects the or not like(s) for a database query. |
| 457 | | * |
| 458 | | * @param string|array field name or array of field => match pairs |
| 459 | | * @param string like value to match with field |
| 460 | | * @return object This Database object. |
| 461 | | */ |
| 462 | | public function ornotlike($field, $match = '') |
| 463 | | { |
| 464 | | $fields = is_array($field) ? $field : array($field => $match); |
| 465 | | |
| 466 | | foreach ($fields as $field => $match) |
| 467 | | { |
| 468 | | $field = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field; |
| 469 | | $this->where[] = $this->driver->notlike($field, $match, 'OR ', count($this->where)); |
| 470 | | } |
| 471 | | |
| 472 | | return $this; |
| 473 | | } |
| 474 | | |
| 475 | | /** |
| 476 | | * Selects the like(s) for a database query. |
| 477 | | * |
| 478 | | * @param string|array field name or array of field => match pairs |
| 479 | | * @param string like value to match with field |
| 480 | | * @return object This Database object. |
| 481 | | */ |
| 482 | | public function regex($field, $match = '') |
| 483 | | { |
| 484 | | $fields = is_array($field) ? $field : array($field => $match); |
| 485 | | |
| 486 | | foreach ($fields as $field => $match) |
| 487 | | { |
| 488 | | $field = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field; |
| 489 | | $this->where[] = $this->driver->regex($field, $match, 'AND ', count($this->where)); |
| 490 | | } |
| 491 | | |
| 492 | | return $this; |
| 493 | | } |
| 494 | | |
| 495 | | /** |
| 496 | | * Selects the or like(s) for a database query. |
| 497 | | * |
| 498 | | * @param string|array field name or array of field => match pairs |
| 499 | | * @param string like value to match with field |
| 500 | | * @return object This Database object. |
| 501 | | */ |
| 502 | | public function orregex($field, $match = '') |
| 503 | | { |
| 504 | | $fields = is_array($field) ? $field : array($field => $match); |
| 505 | | |
| 506 | | foreach ($fields as $field => $match) |
| 507 | | { |
| 508 | | $field = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field; |
| 509 | | $this->where[] = $this->driver->regex($field, $match, 'OR ', count($this->where)); |
| 510 | | } |
| 511 | | |
| 512 | | return $this; |
| 513 | | } |
| 514 | | |
| 515 | | /** |
| 516 | | * Selects the not regex(s) for a database query. |
| 517 | | * |
| 518 | | * @param string|array field name or array of field => match pairs |
| 519 | | * @param string regex value to match with field |
| 520 | | * @return object This Database object. |
| 521 | | */ |
| 522 | | public function notregex($field, $match = '') |
| 523 | | { |
| 524 | | $fields = is_array($field) ? $field : array($field => $match); |
| 525 | | |
| 526 | | foreach ($fields as $field => $match) |
| 527 | | { |
| 528 | | $field = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field; |
| 529 | | $this->where[] = $this->driver->notregex($field, $match, 'AND ', count($this->where)); |
| 530 | | } |
| 531 | | |
| 532 | | return $this; |
| 533 | | } |
| 534 | | |
| 535 | | /** |
| 536 | | * Selects the or not regex(s) for a database query. |
| 537 | | * |
| 538 | | * @param string|array field name or array of field => match pairs |
| 539 | | * @param string regex value to match with field |
| 540 | | * @return object This Database object. |
| 541 | | */ |
| 542 | | public function ornotregex($field, $match = '') |
| 543 | | { |
| 544 | | $fields = is_array($field) ? $field : array($field => $match); |
| 545 | | |
| 546 | | foreach ($fields as $field => $match) |
| 547 | | { |
| 548 | | $field = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field; |
| 549 | | $this->where[] = $this->driver->notregex($field, $match, 'OR ', count($this->where)); |
| 550 | | } |
| 551 | | |
| 552 | | return $this; |
| 553 | | } |
| 554 | | |
| 555 | | /** |
| 556 | | * Chooses the column to group by in a select query. |
| 557 | | * |
| 558 | | * @param string column name to group by |
| 559 | | * @return object This Database object. |
| 560 | | */ |
| 561 | | public function groupby($by) |
| 562 | | { |
| 563 | | if ( ! is_array($by)) |
| 564 | | { |
| 565 | | $by = explode(',', (string) $by); |
| 566 | | } |
| 567 | | |
| 568 | | foreach ($by as $val) |
| 569 | | { |
| 570 | | $val = trim($val); |
| 571 | | |
| 572 | | if ($val != '') |
| 573 | | { |
| 574 | | $this->groupby[] = $val; |
| 575 | | } |
| 576 | | } |
| 577 | | |
| 578 | | return $this; |
| 579 | | } |
| 580 | | |
| 581 | | /** |
| 582 | | * Selects the having(s) for a database query. |
| 583 | | * |
| 584 | | * @param string|array key name or array of key => value pairs |
| 585 | | * @param string value to match with key |
| 586 | | * @param boolean disable quoting of WHERE clause |
| 587 | | * @return object This Database object. |
| 588 | | */ |
| 589 | | public function having($key, $value = '', $quote = TRUE) |
| 590 | | { |
| 591 | | $this->having[] = $this->driver->where($key, $value, 'AND', count($this->having), TRUE); |
| 592 | | return $this; |
| 593 | | } |
| 594 | | |
| 595 | | /** |
| 596 | | * Selects the or having(s) for a database query. |
| 597 | | * |
| 598 | | * @param string|array key name or array of key => value pairs |
| 599 | | * @param string value to match with key |
| 600 | | * @param boolean disable quoting of WHERE clause |
| 601 | | * @return object This Database object. |
| 602 | | */ |
| 603 | | public function orhaving($key, $value = '', $quote = TRUE) |
| 604 | | { |
| 605 | | $this->having[] = $this->driver->where($key, $value, 'OR', count($this->having), TRUE); |
| 606 | | return $this; |
| 607 | | } |
| 608 | | |
| 609 | | /** |
| 610 | | * Chooses which column(s) to order the select query by. |
| 611 | | * |
| 612 | | * @param string|array column(s) to order on, can be an array, single column, or comma seperated list of columns |
| 613 | | * @param string direction of the order |
| 614 | | * @return object This Database object. |
| 615 | | */ |
| 616 | | public function orderby($orderby, $direction = '') |
| 617 | | { |
| 618 | | $direction = strtoupper(tri |