PageRenderTime 92ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/system/database/DB_query_builder.php

https://github.com/coderkid/No-CMS
PHP | 2698 lines | 1252 code | 390 blank | 1056 comment | 135 complexity | 8f4fbc18ac7eabbc6dd927973c28eac1 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, GPL-2.0

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file