Advertisement
Guest User

Untitled

a guest
Apr 18th, 2019
144
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 66.69 KB | None | 0 0
  1. <?php
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP
  6. *
  7. * This content is released under the MIT License (MIT)
  8. *
  9. * Copyright (c) 2014 - 2019, British Columbia Institute of Technology
  10. *
  11. * Permission is hereby granted, free of charge, to any person obtaining a copy
  12. * of this software and associated documentation files (the "Software"), to deal
  13. * in the Software without restriction, including without limitation the rights
  14. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. * copies of the Software, and to permit persons to whom the Software is
  16. * furnished to do so, subject to the following conditions:
  17. *
  18. * The above copyright notice and this permission notice shall be included in
  19. * all copies or substantial portions of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27. * THE SOFTWARE.
  28. *
  29. * @package CodeIgniter
  30. * @author EllisLab Dev Team
  31. * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
  32. * @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
  33. * @license https://opensource.org/licenses/MIT MIT License
  34. * @link https://codeigniter.com
  35. * @since Version 1.0.0
  36. * @filesource
  37. */
  38. defined('BASEPATH') OR exit('No direct script access allowed');
  39.  
  40. /**
  41. * Query Builder Class
  42. *
  43. * This is the platform-independent base Query Builder implementation class.
  44. *
  45. * @package CodeIgniter
  46. * @subpackage Drivers
  47. * @category Database
  48. * @author EllisLab Dev Team
  49. * @link https://codeigniter.com/user_guide/database/
  50. */
  51.  
  52. abstract class CI_DB_query_builder extends CI_DB_driver {
  53.  
  54. /**
  55. * Return DELETE SQL flag
  56. *
  57. * @var bool
  58. */
  59. protected $return_delete_sql = FALSE;
  60.  
  61. /**
  62. * Reset DELETE data flag
  63. *
  64. * @var bool
  65. */
  66. protected $reset_delete_data = FALSE;
  67.  
  68. /**
  69. * QB SELECT data
  70. *
  71. * @var array
  72. */
  73. protected $qb_select = array();
  74.  
  75. /**
  76. * QB DISTINCT flag
  77. *
  78. * @var bool
  79. */
  80. protected $qb_distinct = FALSE;
  81.  
  82. /**
  83. * QB FROM data
  84. *
  85. * @var array
  86. */
  87. protected $qb_from = array();
  88.  
  89. /**
  90. * QB JOIN data
  91. *
  92. * @var array
  93. */
  94. protected $qb_join = array();
  95.  
  96. /**
  97. * QB WHERE data
  98. *
  99. * @var array
  100. */
  101. protected $qb_where = array();
  102.  
  103. /**
  104. * QB GROUP BY data
  105. *
  106. * @var array
  107. */
  108. protected $qb_groupby = array();
  109.  
  110. /**
  111. * QB HAVING data
  112. *
  113. * @var array
  114. */
  115. protected $qb_having = array();
  116.  
  117. /**
  118. * QB keys
  119. *
  120. * @var array
  121. */
  122. protected $qb_keys = array();
  123.  
  124. /**
  125. * QB LIMIT data
  126. *
  127. * @var int
  128. */
  129. protected $qb_limit = FALSE;
  130.  
  131. /**
  132. * QB OFFSET data
  133. *
  134. * @var int
  135. */
  136. protected $qb_offset = FALSE;
  137.  
  138. /**
  139. * QB ORDER BY data
  140. *
  141. * @var array
  142. */
  143. protected $qb_orderby = array();
  144.  
  145. /**
  146. * QB data sets
  147. *
  148. * @var array
  149. */
  150. protected $qb_set = array();
  151.  
  152. /**
  153. * QB data set for update_batch()
  154. *
  155. * @var array
  156. */
  157. protected $qb_set_ub = array();
  158.  
  159. /**
  160. * QB aliased tables list
  161. *
  162. * @var array
  163. */
  164. protected $qb_aliased_tables = array();
  165.  
  166. /**
  167. * QB WHERE group started flag
  168. *
  169. * @var bool
  170. */
  171. protected $qb_where_group_started = FALSE;
  172.  
  173. /**
  174. * QB WHERE group count
  175. *
  176. * @var int
  177. */
  178. protected $qb_where_group_count = 0;
  179.  
  180. // Query Builder Caching variables
  181.  
  182. /**
  183. * QB Caching flag
  184. *
  185. * @var bool
  186. */
  187. protected $qb_caching = FALSE;
  188.  
  189. /**
  190. * QB Cache exists list
  191. *
  192. * @var array
  193. */
  194. protected $qb_cache_exists = array();
  195.  
  196. /**
  197. * QB Cache SELECT data
  198. *
  199. * @var array
  200. */
  201. protected $qb_cache_select = array();
  202.  
  203. /**
  204. * QB Cache FROM data
  205. *
  206. * @var array
  207. */
  208. protected $qb_cache_from = array();
  209.  
  210. /**
  211. * QB Cache JOIN data
  212. *
  213. * @var array
  214. */
  215. protected $qb_cache_join = array();
  216.  
  217. /**
  218. * QB Cache aliased tables list
  219. *
  220. * @var array
  221. */
  222. protected $qb_cache_aliased_tables = array();
  223.  
  224. /**
  225. * QB Cache WHERE data
  226. *
  227. * @var array
  228. */
  229. protected $qb_cache_where = array();
  230.  
  231. /**
  232. * QB Cache GROUP BY data
  233. *
  234. * @var array
  235. */
  236. protected $qb_cache_groupby = array();
  237.  
  238. /**
  239. * QB Cache HAVING data
  240. *
  241. * @var array
  242. */
  243. protected $qb_cache_having = array();
  244.  
  245. /**
  246. * QB Cache ORDER BY data
  247. *
  248. * @var array
  249. */
  250. protected $qb_cache_orderby = array();
  251.  
  252. /**
  253. * QB Cache data sets
  254. *
  255. * @var array
  256. */
  257. protected $qb_cache_set = array();
  258.  
  259. /**
  260. * QB No Escape data
  261. *
  262. * @var array
  263. */
  264. protected $qb_no_escape = array();
  265.  
  266. /**
  267. * QB Cache No Escape data
  268. *
  269. * @var array
  270. */
  271. protected $qb_cache_no_escape = array();
  272.  
  273. /**
  274. * QB Prefix fields name by tablename
  275. * @var boolean
  276. */
  277. protected $qb_prefix_fields = false;
  278.  
  279. // --------------------------------------------------------------------
  280.  
  281. /**
  282. * Set if table is prefix
  283. * @param boolean $val
  284. */
  285. public function prefixFields($val = false)
  286. {
  287. $this->qb_prefix_fields = $val;
  288. return $this;
  289. }
  290.  
  291. /**
  292. * Select
  293. *
  294. * Generates the SELECT portion of the query
  295. *
  296. * @param string
  297. * @param mixed
  298. * @return CI_DB_query_builder
  299. */
  300. public function select($select = '*', $escape = NULL)
  301. {
  302. if (is_string($select))
  303. {
  304. $select = explode(',', $select);
  305. }
  306.  
  307. // If the escape value was not set, we will base it on the global setting
  308. is_bool($escape) OR $escape = $this->_protect_identifiers;
  309.  
  310. foreach ($select as $val)
  311. {
  312. $val = trim($val);
  313.  
  314. if ($val !== '')
  315. {
  316. $this->qb_select[] = $val;
  317. $this->qb_no_escape[] = $escape;
  318.  
  319. if ($this->qb_caching === TRUE)
  320. {
  321. $this->qb_cache_select[] = $val;
  322. $this->qb_cache_exists[] = 'select';
  323. $this->qb_cache_no_escape[] = $escape;
  324. }
  325. }
  326. }
  327.  
  328. return $this;
  329. }
  330.  
  331. // --------------------------------------------------------------------
  332.  
  333. /**
  334. * Select Max
  335. *
  336. * Generates a SELECT MAX(field) portion of a query
  337. *
  338. * @param string the field
  339. * @param string an alias
  340. * @return CI_DB_query_builder
  341. */
  342. public function select_max($select = '', $alias = '')
  343. {
  344. return $this->_max_min_avg_sum($select, $alias, 'MAX');
  345. }
  346.  
  347. // --------------------------------------------------------------------
  348.  
  349. /**
  350. * Select Min
  351. *
  352. * Generates a SELECT MIN(field) portion of a query
  353. *
  354. * @param string the field
  355. * @param string an alias
  356. * @return CI_DB_query_builder
  357. */
  358. public function select_min($select = '', $alias = '')
  359. {
  360. return $this->_max_min_avg_sum($select, $alias, 'MIN');
  361. }
  362.  
  363. // --------------------------------------------------------------------
  364.  
  365. /**
  366. * Select Average
  367. *
  368. * Generates a SELECT AVG(field) portion of a query
  369. *
  370. * @param string the field
  371. * @param string an alias
  372. * @return CI_DB_query_builder
  373. */
  374. public function select_avg($select = '', $alias = '')
  375. {
  376. return $this->_max_min_avg_sum($select, $alias, 'AVG');
  377. }
  378.  
  379. // --------------------------------------------------------------------
  380.  
  381. /**
  382. * Select Sum
  383. *
  384. * Generates a SELECT SUM(field) portion of a query
  385. *
  386. * @param string the field
  387. * @param string an alias
  388. * @return CI_DB_query_builder
  389. */
  390. public function select_sum($select = '', $alias = '')
  391. {
  392. return $this->_max_min_avg_sum($select, $alias, 'SUM');
  393. }
  394.  
  395. // --------------------------------------------------------------------
  396.  
  397. /**
  398. * SELECT [MAX|MIN|AVG|SUM]()
  399. *
  400. * @used-by select_max()
  401. * @used-by select_min()
  402. * @used-by select_avg()
  403. * @used-by select_sum()
  404. *
  405. * @param string $select Field name
  406. * @param string $alias
  407. * @param string $type
  408. * @return CI_DB_query_builder
  409. */
  410. protected function _max_min_avg_sum($select = '', $alias = '', $type = 'MAX')
  411. {
  412. if ( ! is_string($select) OR $select === '')
  413. {
  414. $this->display_error('db_invalid_query');
  415. }
  416.  
  417. $type = strtoupper($type);
  418.  
  419. if ( ! in_array($type, array('MAX', 'MIN', 'AVG', 'SUM')))
  420. {
  421. show_error('Invalid function type: '.$type);
  422. }
  423.  
  424. if ($alias === '')
  425. {
  426. $alias = $this->_create_alias_from_table(trim($select));
  427. }
  428.  
  429. $sql = $type.'('.$this->protect_identifiers(trim($select)).') AS '.$this->escape_identifiers(trim($alias));
  430.  
  431. $this->qb_select[] = $sql;
  432. $this->qb_no_escape[] = NULL;
  433.  
  434. if ($this->qb_caching === TRUE)
  435. {
  436. $this->qb_cache_select[] = $sql;
  437. $this->qb_cache_exists[] = 'select';
  438. }
  439.  
  440. return $this;
  441. }
  442.  
  443. // --------------------------------------------------------------------
  444.  
  445. /**
  446. * Determines the alias name based on the table
  447. *
  448. * @param string $item
  449. * @return string
  450. */
  451. protected function _create_alias_from_table($item)
  452. {
  453. if (strpos($item, '.') !== FALSE)
  454. {
  455. $item = explode('.', $item);
  456. return end($item);
  457. }
  458.  
  459. return $item;
  460. }
  461.  
  462. // --------------------------------------------------------------------
  463.  
  464. /**
  465. * DISTINCT
  466. *
  467. * Sets a flag which tells the query string compiler to add DISTINCT
  468. *
  469. * @param bool $val
  470. * @return CI_DB_query_builder
  471. */
  472. public function distinct($val = TRUE)
  473. {
  474. $this->qb_distinct = is_bool($val) ? $val : TRUE;
  475. return $this;
  476. }
  477.  
  478. // --------------------------------------------------------------------
  479.  
  480. /**
  481. * From
  482. *
  483. * Generates the FROM portion of the query
  484. *
  485. * @param mixed $from can be a string or array
  486. * @return CI_DB_query_builder
  487. */
  488. public function from($from)
  489. {
  490. foreach ((array) $from as $val)
  491. {
  492. if (strpos($val, ',') !== FALSE)
  493. {
  494. foreach (explode(',', $val) as $v)
  495. {
  496. $v = trim($v);
  497. $this->_track_aliases($v);
  498.  
  499. $this->qb_from[] = $v = $this->protect_identifiers($v, TRUE, NULL, FALSE);
  500.  
  501. if ($this->qb_caching === TRUE)
  502. {
  503. $this->qb_cache_from[] = $v;
  504. $this->qb_cache_exists[] = 'from';
  505. }
  506. }
  507. }
  508. else
  509. {
  510. $val = trim($val);
  511.  
  512. // Extract any aliases that might exist. We use this information
  513. // in the protect_identifiers to know whether to add a table prefix
  514. $this->_track_aliases($val);
  515.  
  516. $this->qb_from[] = $val = $this->protect_identifiers($val, TRUE, NULL, FALSE);
  517.  
  518. if ($this->qb_caching === TRUE)
  519. {
  520. $this->qb_cache_from[] = $val;
  521. $this->qb_cache_exists[] = 'from';
  522. }
  523. }
  524. }
  525.  
  526. return $this;
  527. }
  528.  
  529. // --------------------------------------------------------------------
  530.  
  531. /**
  532. * JOIN
  533. *
  534. * Generates the JOIN portion of the query
  535. *
  536. * @param string
  537. * @param string the join condition
  538. * @param string the type of join
  539. * @param string whether not to try to escape identifiers
  540. * @return CI_DB_query_builder
  541. */
  542. public function join($table, $cond, $type = '', $escape = NULL)
  543. {
  544. if ($type !== '')
  545. {
  546. $type = strtoupper(trim($type));
  547.  
  548. if ( ! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER'), TRUE))
  549. {
  550. $type = '';
  551. }
  552. else
  553. {
  554. $type .= ' ';
  555. }
  556. }
  557.  
  558. // Extract any aliases that might exist. We use this information
  559. // in the protect_identifiers to know whether to add a table prefix
  560. $this->_track_aliases($table);
  561.  
  562. is_bool($escape) OR $escape = $this->_protect_identifiers;
  563.  
  564. if ( ! $this->_has_operator($cond))
  565. {
  566. $cond = ' USING ('.($escape ? $this->escape_identifiers($cond) : $cond).')';
  567. }
  568. elseif ($escape === FALSE)
  569. {
  570. $cond = ' ON '.$cond;
  571. }
  572. else
  573. {
  574. // Split multiple conditions
  575. if (preg_match_all('/\sAND\s|\sOR\s/i', $cond, $joints, PREG_OFFSET_CAPTURE))
  576. {
  577. $conditions = array();
  578. $joints = $joints[0];
  579. array_unshift($joints, array('', 0));
  580.  
  581. for ($i = count($joints) - 1, $pos = strlen($cond); $i >= 0; $i--)
  582. {
  583. $joints[$i][1] += strlen($joints[$i][0]); // offset
  584. $conditions[$i] = substr($cond, $joints[$i][1], $pos - $joints[$i][1]);
  585. $pos = $joints[$i][1] - strlen($joints[$i][0]);
  586. $joints[$i] = $joints[$i][0];
  587. }
  588. }
  589. else
  590. {
  591. $conditions = array($cond);
  592. $joints = array('');
  593. }
  594.  
  595. $cond = ' ON ';
  596. for ($i = 0, $c = count($conditions); $i < $c; $i++)
  597. {
  598. $operator = $this->_get_operator($conditions[$i]);
  599. $cond .= $joints[$i];
  600. $cond .= preg_match("/(\(*)?([\[\]\w\.'-]+)".preg_quote($operator)."(.*)/i", $conditions[$i], $match)
  601. ? $match[1].$this->protect_identifiers($match[2]).$operator.$this->protect_identifiers($match[3])
  602. : $conditions[$i];
  603. }
  604. }
  605.  
  606. // Do we want to escape the table name?
  607. if ($escape === TRUE)
  608. {
  609. $table = $this->protect_identifiers($table, TRUE, NULL, FALSE);
  610. }
  611.  
  612. // Assemble the JOIN statement
  613. $this->qb_join[] = $join = $type.'JOIN '.$table.$cond;
  614.  
  615. if ($this->qb_caching === TRUE)
  616. {
  617. $this->qb_cache_join[] = $join;
  618. $this->qb_cache_exists[] = 'join';
  619. }
  620.  
  621. return $this;
  622. }
  623.  
  624. // --------------------------------------------------------------------
  625.  
  626. /**
  627. * WHERE
  628. *
  629. * Generates the WHERE portion of the query.
  630. * Separates multiple calls with 'AND'.
  631. *
  632. * @param mixed
  633. * @param mixed
  634. * @param bool
  635. * @return CI_DB_query_builder
  636. */
  637. public function where($key, $value = NULL, $escape = NULL)
  638. {
  639. return $this->_wh('qb_where', $key, $value, 'AND ', $escape);
  640. }
  641.  
  642. // --------------------------------------------------------------------
  643.  
  644. /**
  645. * OR WHERE
  646. *
  647. * Generates the WHERE portion of the query.
  648. * Separates multiple calls with 'OR'.
  649. *
  650. * @param mixed
  651. * @param mixed
  652. * @param bool
  653. * @return CI_DB_query_builder
  654. */
  655. public function or_where($key, $value = NULL, $escape = NULL)
  656. {
  657. return $this->_wh('qb_where', $key, $value, 'OR ', $escape);
  658. }
  659.  
  660. // --------------------------------------------------------------------
  661.  
  662. /**
  663. * WHERE, HAVING
  664. *
  665. * @used-by where()
  666. * @used-by or_where()
  667. * @used-by having()
  668. * @used-by or_having()
  669. *
  670. * @param string $qb_key 'qb_where' or 'qb_having'
  671. * @param mixed $key
  672. * @param mixed $value
  673. * @param string $type
  674. * @param bool $escape
  675. * @return CI_DB_query_builder
  676. */
  677. protected function _wh($qb_key, $key, $value = NULL, $type = 'AND ', $escape = NULL)
  678. {
  679. $qb_cache_key = ($qb_key === 'qb_having') ? 'qb_cache_having' : 'qb_cache_where';
  680.  
  681. if ( ! is_array($key))
  682. {
  683. $key = array($key => $value);
  684. }
  685.  
  686. // If the escape value was not set will base it on the global setting
  687. is_bool($escape) OR $escape = $this->_protect_identifiers;
  688.  
  689. foreach ($key as $k => $v)
  690. {
  691. $prefix = (count($this->$qb_key) === 0 && count($this->$qb_cache_key) === 0)
  692. ? $this->_group_get_type('')
  693. : $this->_group_get_type($type);
  694.  
  695. if ($v !== NULL)
  696. {
  697. if ($escape === TRUE)
  698. {
  699. $v = $this->escape($v);
  700. }
  701.  
  702. if ( ! $this->_has_operator($k))
  703. {
  704. $k .= ' = ';
  705. }
  706. }
  707. elseif ( ! $this->_has_operator($k))
  708. {
  709. // value appears not to have been set, assign the test to IS NULL
  710. $k .= ' IS NULL';
  711. }
  712. elseif (preg_match('/\s*(!?=|<>|\sIS(?:\s+NOT)?\s)\s*$/i', $k, $match, PREG_OFFSET_CAPTURE))
  713. {
  714. $k = substr($k, 0, $match[0][1]).($match[1][0] === '=' ? ' IS NULL' : ' IS NOT NULL');
  715. }
  716.  
  717. ${$qb_key} = array('condition' => $prefix.$k, 'value' => $v, 'escape' => $escape);
  718. $this->{$qb_key}[] = ${$qb_key};
  719. if ($this->qb_caching === TRUE)
  720. {
  721. $this->{$qb_cache_key}[] = ${$qb_key};
  722. $this->qb_cache_exists[] = substr($qb_key, 3);
  723. }
  724.  
  725. }
  726.  
  727. return $this;
  728. }
  729.  
  730. // --------------------------------------------------------------------
  731.  
  732. /**
  733. * WHERE IN
  734. *
  735. * Generates a WHERE field IN('item', 'item') SQL query,
  736. * joined with 'AND' if appropriate.
  737. *
  738. * @param string $key The field to search
  739. * @param array $values The values searched on
  740. * @param bool $escape
  741. * @return CI_DB_query_builder
  742. */
  743. public function where_in($key = NULL, $values = NULL, $escape = NULL)
  744. {
  745. return $this->_where_in($key, $values, FALSE, 'AND ', $escape);
  746. }
  747.  
  748. // --------------------------------------------------------------------
  749.  
  750. /**
  751. * OR WHERE IN
  752. *
  753. * Generates a WHERE field IN('item', 'item') SQL query,
  754. * joined with 'OR' if appropriate.
  755. *
  756. * @param string $key The field to search
  757. * @param array $values The values searched on
  758. * @param bool $escape
  759. * @return CI_DB_query_builder
  760. */
  761. public function or_where_in($key = NULL, $values = NULL, $escape = NULL)
  762. {
  763. return $this->_where_in($key, $values, FALSE, 'OR ', $escape);
  764. }
  765.  
  766. // --------------------------------------------------------------------
  767.  
  768. /**
  769. * WHERE NOT IN
  770. *
  771. * Generates a WHERE field NOT IN('item', 'item') SQL query,
  772. * joined with 'AND' if appropriate.
  773. *
  774. * @param string $key The field to search
  775. * @param array $values The values searched on
  776. * @param bool $escape
  777. * @return CI_DB_query_builder
  778. */
  779. public function where_not_in($key = NULL, $values = NULL, $escape = NULL)
  780. {
  781. return $this->_where_in($key, $values, TRUE, 'AND ', $escape);
  782. }
  783.  
  784. // --------------------------------------------------------------------
  785.  
  786. /**
  787. * OR WHERE NOT IN
  788. *
  789. * Generates a WHERE field NOT IN('item', 'item') SQL query,
  790. * joined with 'OR' if appropriate.
  791. *
  792. * @param string $key The field to search
  793. * @param array $values The values searched on
  794. * @param bool $escape
  795. * @return CI_DB_query_builder
  796. */
  797. public function or_where_not_in($key = NULL, $values = NULL, $escape = NULL)
  798. {
  799. return $this->_where_in($key, $values, TRUE, 'OR ', $escape);
  800. }
  801.  
  802. // --------------------------------------------------------------------
  803.  
  804. /**
  805. * Internal WHERE IN
  806. *
  807. * @used-by where_in()
  808. * @used-by or_where_in()
  809. * @used-by where_not_in()
  810. * @used-by or_where_not_in()
  811. *
  812. * @param string $key The field to search
  813. * @param array $values The values searched on
  814. * @param bool $not If the statement would be IN or NOT IN
  815. * @param string $type
  816. * @param bool $escape
  817. * @return CI_DB_query_builder
  818. */
  819. protected function _where_in($key = NULL, $values = NULL, $not = FALSE, $type = 'AND ', $escape = NULL)
  820. {
  821. if ($key === NULL OR $values === NULL)
  822. {
  823. return $this;
  824. }
  825.  
  826. if ( ! is_array($values))
  827. {
  828. $values = array($values);
  829. }
  830.  
  831. is_bool($escape) OR $escape = $this->_protect_identifiers;
  832.  
  833. $not = ($not) ? ' NOT' : '';
  834.  
  835. if ($escape === TRUE)
  836. {
  837. $where_in = array();
  838. foreach ($values as $value)
  839. {
  840. $where_in[] = $this->escape($value);
  841. }
  842. }
  843. else
  844. {
  845. $where_in = array_values($values);
  846. }
  847.  
  848. $prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0)
  849. ? $this->_group_get_type('')
  850. : $this->_group_get_type($type);
  851.  
  852. $where_in = array(
  853. 'condition' => $prefix.$key.$not.' IN('.implode(', ', $where_in).')',
  854. 'value' => NULL,
  855. 'escape' => $escape
  856. );
  857.  
  858. $this->qb_where[] = $where_in;
  859. if ($this->qb_caching === TRUE)
  860. {
  861. $this->qb_cache_where[] = $where_in;
  862. $this->qb_cache_exists[] = 'where';
  863. }
  864.  
  865. return $this;
  866. }
  867.  
  868. // --------------------------------------------------------------------
  869.  
  870. /**
  871. * LIKE
  872. *
  873. * Generates a %LIKE% portion of the query.
  874. * Separates multiple calls with 'AND'.
  875. *
  876. * @param mixed $field
  877. * @param string $match
  878. * @param string $side
  879. * @param bool $escape
  880. * @return CI_DB_query_builder
  881. */
  882. public function like($field, $match = '', $side = 'both', $escape = NULL)
  883. {
  884. return $this->_like($field, $match, 'AND ', $side, '', $escape);
  885. }
  886.  
  887. // --------------------------------------------------------------------
  888.  
  889. /**
  890. * NOT LIKE
  891. *
  892. * Generates a NOT LIKE portion of the query.
  893. * Separates multiple calls with 'AND'.
  894. *
  895. * @param mixed $field
  896. * @param string $match
  897. * @param string $side
  898. * @param bool $escape
  899. * @return CI_DB_query_builder
  900. */
  901. public function not_like($field, $match = '', $side = 'both', $escape = NULL)
  902. {
  903. return $this->_like($field, $match, 'AND ', $side, 'NOT', $escape);
  904. }
  905.  
  906. // --------------------------------------------------------------------
  907.  
  908. /**
  909. * OR LIKE
  910. *
  911. * Generates a %LIKE% portion of the query.
  912. * Separates multiple calls with 'OR'.
  913. *
  914. * @param mixed $field
  915. * @param string $match
  916. * @param string $side
  917. * @param bool $escape
  918. * @return CI_DB_query_builder
  919. */
  920. public function or_like($field, $match = '', $side = 'both', $escape = NULL)
  921. {
  922. return $this->_like($field, $match, 'OR ', $side, '', $escape);
  923. }
  924.  
  925. // --------------------------------------------------------------------
  926.  
  927. /**
  928. * OR NOT LIKE
  929. *
  930. * Generates a NOT LIKE portion of the query.
  931. * Separates multiple calls with 'OR'.
  932. *
  933. * @param mixed $field
  934. * @param string $match
  935. * @param string $side
  936. * @param bool $escape
  937. * @return CI_DB_query_builder
  938. */
  939. public function or_not_like($field, $match = '', $side = 'both', $escape = NULL)
  940. {
  941. return $this->_like($field, $match, 'OR ', $side, 'NOT', $escape);
  942. }
  943.  
  944. // --------------------------------------------------------------------
  945.  
  946. /**
  947. * Internal LIKE
  948. *
  949. * @used-by like()
  950. * @used-by or_like()
  951. * @used-by not_like()
  952. * @used-by or_not_like()
  953. *
  954. * @param mixed $field
  955. * @param string $match
  956. * @param string $type
  957. * @param string $side
  958. * @param string $not
  959. * @param bool $escape
  960. * @return CI_DB_query_builder
  961. */
  962. protected function _like($field, $match = '', $type = 'AND ', $side = 'both', $not = '', $escape = NULL)
  963. {
  964. if ( ! is_array($field))
  965. {
  966. $field = array($field => $match);
  967. }
  968.  
  969. is_bool($escape) OR $escape = $this->_protect_identifiers;
  970. // lowercase $side in case somebody writes e.g. 'BEFORE' instead of 'before' (doh)
  971. $side = strtolower($side);
  972.  
  973. foreach ($field as $k => $v)
  974. {
  975. $prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0)
  976. ? $this->_group_get_type('') : $this->_group_get_type($type);
  977.  
  978. if ($escape === TRUE)
  979. {
  980. $v = $this->escape_like_str($v);
  981. }
  982.  
  983. switch ($side)
  984. {
  985. case 'none':
  986. $v = "'{$v}'";
  987. break;
  988. case 'before':
  989. $v = "'%{$v}'";
  990. break;
  991. case 'after':
  992. $v = "'{$v}%'";
  993. break;
  994. case 'both':
  995. default:
  996. $v = "'%{$v}%'";
  997. break;
  998. }
  999.  
  1000. // some platforms require an escape sequence definition for LIKE wildcards
  1001. if ($escape === TRUE && $this->_like_escape_str !== '')
  1002. {
  1003. $v .= sprintf($this->_like_escape_str, $this->_like_escape_chr);
  1004. }
  1005.  
  1006. $qb_where = array('condition' => "{$prefix} {$k} {$not} LIKE {$v}", 'value' => NULL, 'escape' => $escape);
  1007. $this->qb_where[] = $qb_where;
  1008. if ($this->qb_caching === TRUE)
  1009. {
  1010. $this->qb_cache_where[] = $qb_where;
  1011. $this->qb_cache_exists[] = 'where';
  1012. }
  1013. }
  1014.  
  1015. return $this;
  1016. }
  1017.  
  1018. // --------------------------------------------------------------------
  1019.  
  1020. /**
  1021. * Starts a query group.
  1022. *
  1023. * @param string $not (Internal use only)
  1024. * @param string $type (Internal use only)
  1025. * @return CI_DB_query_builder
  1026. */
  1027. public function group_start($not = '', $type = 'AND ')
  1028. {
  1029. $type = $this->_group_get_type($type);
  1030.  
  1031. $this->qb_where_group_started = TRUE;
  1032. $prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0) ? '' : $type;
  1033. $where = array(
  1034. 'condition' => $prefix.$not.str_repeat(' ', ++$this->qb_where_group_count).' (',
  1035. 'value' => NULL,
  1036. 'escape' => FALSE
  1037. );
  1038.  
  1039. $this->qb_where[] = $where;
  1040. if ($this->qb_caching)
  1041. {
  1042. $this->qb_cache_where[] = $where;
  1043. }
  1044.  
  1045. return $this;
  1046. }
  1047.  
  1048. // --------------------------------------------------------------------
  1049.  
  1050. /**
  1051. * Starts a query group, but ORs the group
  1052. *
  1053. * @return CI_DB_query_builder
  1054. */
  1055. public function or_group_start()
  1056. {
  1057. return $this->group_start('', 'OR ');
  1058. }
  1059.  
  1060. // --------------------------------------------------------------------
  1061.  
  1062. /**
  1063. * Starts a query group, but NOTs the group
  1064. *
  1065. * @return CI_DB_query_builder
  1066. */
  1067. public function not_group_start()
  1068. {
  1069. return $this->group_start('NOT ', 'AND ');
  1070. }
  1071.  
  1072. // --------------------------------------------------------------------
  1073.  
  1074. /**
  1075. * Starts a query group, but OR NOTs the group
  1076. *
  1077. * @return CI_DB_query_builder
  1078. */
  1079. public function or_not_group_start()
  1080. {
  1081. return $this->group_start('NOT ', 'OR ');
  1082. }
  1083.  
  1084. // --------------------------------------------------------------------
  1085.  
  1086. /**
  1087. * Ends a query group
  1088. *
  1089. * @return CI_DB_query_builder
  1090. */
  1091. public function group_end()
  1092. {
  1093. $this->qb_where_group_started = FALSE;
  1094. $where = array(
  1095. 'condition' => str_repeat(' ', $this->qb_where_group_count--).')',
  1096. 'value' => NULL,
  1097. 'escape' => FALSE
  1098. );
  1099.  
  1100. $this->qb_where[] = $where;
  1101. if ($this->qb_caching)
  1102. {
  1103. $this->qb_cache_where[] = $where;
  1104. }
  1105.  
  1106. return $this;
  1107. }
  1108.  
  1109. // --------------------------------------------------------------------
  1110.  
  1111. /**
  1112. * Group_get_type
  1113. *
  1114. * @used-by group_start()
  1115. * @used-by _like()
  1116. * @used-by _wh()
  1117. * @used-by _where_in()
  1118. *
  1119. * @param string $type
  1120. * @return string
  1121. */
  1122. protected function _group_get_type($type)
  1123. {
  1124. if ($this->qb_where_group_started)
  1125. {
  1126. $type = '';
  1127. $this->qb_where_group_started = FALSE;
  1128. }
  1129.  
  1130. return $type;
  1131. }
  1132.  
  1133. // --------------------------------------------------------------------
  1134.  
  1135. /**
  1136. * GROUP BY
  1137. *
  1138. * @param string $by
  1139. * @param bool $escape
  1140. * @return CI_DB_query_builder
  1141. */
  1142. public function group_by($by, $escape = NULL)
  1143. {
  1144. is_bool($escape) OR $escape = $this->_protect_identifiers;
  1145.  
  1146. if (is_string($by))
  1147. {
  1148. $by = ($escape === TRUE)
  1149. ? explode(',', $by)
  1150. : array($by);
  1151. }
  1152.  
  1153. foreach ($by as $val)
  1154. {
  1155. $val = trim($val);
  1156.  
  1157. if ($val !== '')
  1158. {
  1159. $val = array('field' => $val, 'escape' => $escape);
  1160.  
  1161. $this->qb_groupby[] = $val;
  1162. if ($this->qb_caching === TRUE)
  1163. {
  1164. $this->qb_cache_groupby[] = $val;
  1165. $this->qb_cache_exists[] = 'groupby';
  1166. }
  1167. }
  1168. }
  1169.  
  1170. return $this;
  1171. }
  1172.  
  1173. // --------------------------------------------------------------------
  1174.  
  1175. /**
  1176. * HAVING
  1177. *
  1178. * Separates multiple calls with 'AND'.
  1179. *
  1180. * @param string $key
  1181. * @param string $value
  1182. * @param bool $escape
  1183. * @return CI_DB_query_builder
  1184. */
  1185. public function having($key, $value = NULL, $escape = NULL)
  1186. {
  1187. return $this->_wh('qb_having', $key, $value, 'AND ', $escape);
  1188. }
  1189.  
  1190. // --------------------------------------------------------------------
  1191.  
  1192. /**
  1193. * OR HAVING
  1194. *
  1195. * Separates multiple calls with 'OR'.
  1196. *
  1197. * @param string $key
  1198. * @param string $value
  1199. * @param bool $escape
  1200. * @return CI_DB_query_builder
  1201. */
  1202. public function or_having($key, $value = NULL, $escape = NULL)
  1203. {
  1204. return $this->_wh('qb_having', $key, $value, 'OR ', $escape);
  1205. }
  1206.  
  1207. // --------------------------------------------------------------------
  1208.  
  1209. /**
  1210. * ORDER BY
  1211. *
  1212. * @param string $orderby
  1213. * @param string $direction ASC, DESC or RANDOM
  1214. * @param bool $escape
  1215. * @return CI_DB_query_builder
  1216. */
  1217. public function order_by($orderby, $direction = '', $escape = NULL)
  1218. {
  1219. $direction = strtoupper(trim($direction));
  1220.  
  1221. if ($direction === 'RANDOM')
  1222. {
  1223. $direction = '';
  1224.  
  1225. // Do we have a seed value?
  1226. $orderby = ctype_digit((string) $orderby)
  1227. ? sprintf($this->_random_keyword[1], $orderby)
  1228. : $this->_random_keyword[0];
  1229. }
  1230. elseif (empty($orderby))
  1231. {
  1232. return $this;
  1233. }
  1234. elseif ($direction !== '')
  1235. {
  1236. $direction = in_array($direction, array('ASC', 'DESC'), TRUE) ? ' '.$direction : '';
  1237. }
  1238.  
  1239. is_bool($escape) OR $escape = $this->_protect_identifiers;
  1240.  
  1241. if ($escape === FALSE)
  1242. {
  1243. $qb_orderby[] = array('field' => $orderby, 'direction' => $direction, 'escape' => FALSE);
  1244. }
  1245. else
  1246. {
  1247. $qb_orderby = array();
  1248. foreach (explode(',', $orderby) as $field)
  1249. {
  1250. $qb_orderby[] = ($direction === '' && preg_match('/\s+(ASC|DESC)$/i', rtrim($field), $match, PREG_OFFSET_CAPTURE))
  1251. ? array('field' => ltrim(substr($field, 0, $match[0][1])), 'direction' => ' '.$match[1][0], 'escape' => TRUE)
  1252. : array('field' => trim($field), 'direction' => $direction, 'escape' => TRUE);
  1253. }
  1254. }
  1255.  
  1256. $this->qb_orderby = array_merge($this->qb_orderby, $qb_orderby);
  1257. if ($this->qb_caching === TRUE)
  1258. {
  1259. $this->qb_cache_orderby = array_merge($this->qb_cache_orderby, $qb_orderby);
  1260. $this->qb_cache_exists[] = 'orderby';
  1261. }
  1262.  
  1263. return $this;
  1264. }
  1265.  
  1266. // --------------------------------------------------------------------
  1267.  
  1268. /**
  1269. * LIMIT
  1270. *
  1271. * @param int $value LIMIT value
  1272. * @param int $offset OFFSET value
  1273. * @return CI_DB_query_builder
  1274. */
  1275. public function limit($value, $offset = 0)
  1276. {
  1277. is_null($value) OR $this->qb_limit = (int) $value;
  1278. empty($offset) OR $this->qb_offset = (int) $offset;
  1279.  
  1280. return $this;
  1281. }
  1282.  
  1283. // --------------------------------------------------------------------
  1284.  
  1285. /**
  1286. * Sets the OFFSET value
  1287. *
  1288. * @param int $offset OFFSET value
  1289. * @return CI_DB_query_builder
  1290. */
  1291. public function offset($offset)
  1292. {
  1293. empty($offset) OR $this->qb_offset = (int) $offset;
  1294. return $this;
  1295. }
  1296.  
  1297. // --------------------------------------------------------------------
  1298.  
  1299. /**
  1300. * LIMIT string
  1301. *
  1302. * Generates a platform-specific LIMIT clause.
  1303. *
  1304. * @param string $sql SQL Query
  1305. * @return string
  1306. */
  1307. protected function _limit($sql)
  1308. {
  1309. return $sql.' LIMIT '.($this->qb_offset ? $this->qb_offset.', ' : '').(int) $this->qb_limit;
  1310. }
  1311.  
  1312. // --------------------------------------------------------------------
  1313.  
  1314. /**
  1315. * The "set" function.
  1316. *
  1317. * Allows key/value pairs to be set for inserting or updating
  1318. *
  1319. * @param mixed
  1320. * @param string
  1321. * @param bool
  1322. * @return CI_DB_query_builder
  1323. */
  1324. public function set($key, $value = '', $escape = NULL)
  1325. {
  1326. $key = $this->_object_to_array($key);
  1327.  
  1328. if ( ! is_array($key))
  1329. {
  1330. $key = array($key => $value);
  1331. }
  1332.  
  1333. is_bool($escape) OR $escape = $this->_protect_identifiers;
  1334.  
  1335. foreach ($key as $k => $v)
  1336. {
  1337. $this->qb_set[$this->protect_identifiers($k, FALSE, $escape)] = ($escape)
  1338. ? $this->escape($v) : $v;
  1339. }
  1340.  
  1341. return $this;
  1342. }
  1343.  
  1344. // --------------------------------------------------------------------
  1345.  
  1346. /**
  1347. * Get SELECT query string
  1348. *
  1349. * Compiles a SELECT query string and returns the sql.
  1350. *
  1351. * @param string the table name to select from (optional)
  1352. * @param bool TRUE: resets QB values; FALSE: leave QB values alone
  1353. * @return string
  1354. */
  1355. public function get_compiled_select($table = '', $reset = TRUE)
  1356. {
  1357. if ($table !== '')
  1358. {
  1359. $this->_track_aliases($table);
  1360. $this->from($table);
  1361. }
  1362.  
  1363. $select = $this->_compile_select();
  1364.  
  1365. if ($reset === TRUE)
  1366. {
  1367. $this->_reset_select();
  1368. }
  1369.  
  1370. return $select;
  1371. }
  1372.  
  1373. // --------------------------------------------------------------------
  1374.  
  1375. /**
  1376. * Get
  1377. *
  1378. * Compiles the select statement based on the other functions called
  1379. * and runs the query
  1380. *
  1381. * @param string the table
  1382. * @param string the limit clause
  1383. * @param string the offset clause
  1384. * @return CI_DB_result
  1385. */
  1386. public function get($table = '', $limit = NULL, $offset = NULL)
  1387. {
  1388. if ($table !== '')
  1389. {
  1390. $this->_track_aliases($table);
  1391. $this->from($table);
  1392. }
  1393.  
  1394. if ( ! empty($limit))
  1395. {
  1396. $this->limit($limit, $offset);
  1397. }
  1398.  
  1399. $result = $this->query($this->_compile_select());
  1400. $this->_reset_select();
  1401. return $result;
  1402. }
  1403.  
  1404. // --------------------------------------------------------------------
  1405.  
  1406. /**
  1407. * "Count All Results" query
  1408. *
  1409. * Generates a platform-specific query string that counts all records
  1410. * returned by an Query Builder query.
  1411. *
  1412. * @param string
  1413. * @param bool the reset clause
  1414. * @return int
  1415. */
  1416. public function count_all_results($table = '', $reset = TRUE)
  1417. {
  1418. if ($table !== '')
  1419. {
  1420. $this->_track_aliases($table);
  1421. $this->from($table);
  1422. }
  1423.  
  1424. // ORDER BY usage is often problematic here (most notably
  1425. // on Microsoft SQL Server) and ultimately unnecessary
  1426. // for selecting COUNT(*) ...
  1427. $qb_orderby = $this->qb_orderby;
  1428. $qb_cache_orderby = $this->qb_cache_orderby;
  1429. $this->qb_orderby = $this->qb_cache_orderby = array();
  1430.  
  1431. $result = ($this->qb_distinct === TRUE OR ! empty($this->qb_groupby) OR ! empty($this->qb_cache_groupby) OR $this->qb_limit OR $this->qb_offset)
  1432. ? $this->query($this->_count_string.$this->protect_identifiers('numrows')."\nFROM (\n".$this->_compile_select()."\n) CI_count_all_results")
  1433. : $this->query($this->_compile_select($this->_count_string.$this->protect_identifiers('numrows')));
  1434.  
  1435. if ($reset === TRUE)
  1436. {
  1437. $this->_reset_select();
  1438. }
  1439. else
  1440. {
  1441. $this->qb_orderby = $qb_orderby;
  1442. $this->qb_cache_orderby = $qb_cache_orderby;
  1443. }
  1444.  
  1445. if ($result->num_rows() === 0)
  1446. {
  1447. return 0;
  1448. }
  1449.  
  1450. $row = $result->row();
  1451. return (int) $row->numrows;
  1452. }
  1453.  
  1454. // --------------------------------------------------------------------
  1455.  
  1456. /**
  1457. * get_where()
  1458. *
  1459. * Allows the where clause, limit and offset to be added directly
  1460. *
  1461. * @param string $table
  1462. * @param string $where
  1463. * @param int $limit
  1464. * @param int $offset
  1465. * @return CI_DB_result
  1466. */
  1467. public function get_where($table = '', $where = NULL, $limit = NULL, $offset = NULL)
  1468. {
  1469. if ($table !== '')
  1470. {
  1471. $this->from($table);
  1472. }
  1473.  
  1474. if ($where !== NULL)
  1475. {
  1476. $this->where($where);
  1477. }
  1478.  
  1479. if ( ! empty($limit))
  1480. {
  1481. $this->limit($limit, $offset);
  1482. }
  1483.  
  1484. $result = $this->query($this->_compile_select());
  1485. $this->_reset_select();
  1486. return $result;
  1487. }
  1488.  
  1489. // --------------------------------------------------------------------
  1490.  
  1491. /**
  1492. * Insert_Batch
  1493. *
  1494. * Compiles batch insert strings and runs the queries
  1495. *
  1496. * @param string $table Table to insert into
  1497. * @param array $set An associative array of insert values
  1498. * @param bool $escape Whether to escape values and identifiers
  1499. * @return int Number of rows inserted or FALSE on failure
  1500. */
  1501. public function insert_batch($table, $set = NULL, $escape = NULL, $batch_size = 100)
  1502. {
  1503. if ($set === NULL)
  1504. {
  1505. if (empty($this->qb_set))
  1506. {
  1507. return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE;
  1508. }
  1509. }
  1510. else
  1511. {
  1512. if (empty($set))
  1513. {
  1514. return ($this->db_debug) ? $this->display_error('insert_batch() called with no data') : FALSE;
  1515. }
  1516.  
  1517. $this->set_insert_batch($set, '', $escape);
  1518. }
  1519.  
  1520. if (strlen($table) === 0)
  1521. {
  1522. if ( ! isset($this->qb_from[0]))
  1523. {
  1524. return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE;
  1525. }
  1526.  
  1527. $table = $this->qb_from[0];
  1528. }
  1529.  
  1530. // Batch this baby
  1531. $affected_rows = 0;
  1532. for ($i = 0, $total = count($this->qb_set); $i < $total; $i += $batch_size)
  1533. {
  1534. if ($this->query($this->_insert_batch($this->protect_identifiers($table, TRUE, $escape, FALSE), $this->qb_keys, array_slice($this->qb_set, $i, $batch_size))))
  1535. {
  1536. $affected_rows += $this->affected_rows();
  1537. }
  1538. }
  1539.  
  1540. $this->_reset_write();
  1541. return $affected_rows;
  1542. }
  1543.  
  1544. // --------------------------------------------------------------------
  1545.  
  1546. /**
  1547. * Insert batch statement
  1548. *
  1549. * Generates a platform-specific insert string from the supplied data.
  1550. *
  1551. * @param string $table Table name
  1552. * @param array $keys INSERT keys
  1553. * @param array $values INSERT values
  1554. * @return string
  1555. */
  1556. protected function _insert_batch($table, $keys, $values)
  1557. {
  1558. return 'INSERT INTO '.$table.' ('.implode(', ', $keys).') VALUES '.implode(', ', $values);
  1559. }
  1560.  
  1561. // --------------------------------------------------------------------
  1562.  
  1563. /**
  1564. * The "set_insert_batch" function. Allows key/value pairs to be set for batch inserts
  1565. *
  1566. * @param mixed
  1567. * @param string
  1568. * @param bool
  1569. * @return CI_DB_query_builder
  1570. */
  1571. public function set_insert_batch($key, $value = '', $escape = NULL)
  1572. {
  1573. $key = $this->_object_to_array_batch($key);
  1574.  
  1575. if ( ! is_array($key))
  1576. {
  1577. $key = array($key => $value);
  1578. }
  1579.  
  1580. is_bool($escape) OR $escape = $this->_protect_identifiers;
  1581.  
  1582. $keys = array_keys($this->_object_to_array(reset($key)));
  1583. sort($keys);
  1584.  
  1585. foreach ($key as $row)
  1586. {
  1587. $row = $this->_object_to_array($row);
  1588. if (count(array_diff($keys, array_keys($row))) > 0 OR count(array_diff(array_keys($row), $keys)) > 0)
  1589. {
  1590. // batch function above returns an error on an empty array
  1591. $this->qb_set[] = array();
  1592. return;
  1593. }
  1594.  
  1595. ksort($row); // puts $row in the same order as our keys
  1596.  
  1597. if ($escape !== FALSE)
  1598. {
  1599. $clean = array();
  1600. foreach ($row as $value)
  1601. {
  1602. $clean[] = $this->escape($value);
  1603. }
  1604.  
  1605. $row = $clean;
  1606. }
  1607.  
  1608. $this->qb_set[] = '('.implode(',', $row).')';
  1609. }
  1610.  
  1611. foreach ($keys as $k)
  1612. {
  1613. $this->qb_keys[] = $this->protect_identifiers($k, FALSE, $escape);
  1614. }
  1615.  
  1616. return $this;
  1617. }
  1618.  
  1619. // --------------------------------------------------------------------
  1620.  
  1621. /**
  1622. * Get INSERT query string
  1623. *
  1624. * Compiles an insert query and returns the sql
  1625. *
  1626. * @param string the table to insert into
  1627. * @param bool TRUE: reset QB values; FALSE: leave QB values alone
  1628. * @return string
  1629. */
  1630. public function get_compiled_insert($table = '', $reset = TRUE)
  1631. {
  1632. if ($this->_validate_insert($table) === FALSE)
  1633. {
  1634. return FALSE;
  1635. }
  1636.  
  1637. $sql = $this->_insert(
  1638. $this->protect_identifiers(
  1639. $this->qb_from[0], TRUE, NULL, FALSE
  1640. ),
  1641. array_keys($this->qb_set),
  1642. array_values($this->qb_set)
  1643. );
  1644.  
  1645. if ($reset === TRUE)
  1646. {
  1647. $this->_reset_write();
  1648. }
  1649.  
  1650. return $sql;
  1651. }
  1652.  
  1653. // --------------------------------------------------------------------
  1654.  
  1655. /**
  1656. * Insert
  1657. *
  1658. * Compiles an insert string and runs the query
  1659. *
  1660. * @param string the table to insert data into
  1661. * @param array an associative array of insert values
  1662. * @param bool $escape Whether to escape values and identifiers
  1663. * @return bool TRUE on success, FALSE on failure
  1664. */
  1665. public function insert($table = '', $set = NULL, $escape = NULL)
  1666. {
  1667. if ($set !== NULL)
  1668. {
  1669. $this->set($set, '', $escape);
  1670. }
  1671.  
  1672. if ($this->_validate_insert($table) === FALSE)
  1673. {
  1674. return FALSE;
  1675. }
  1676.  
  1677. $sql = $this->_insert(
  1678. $this->protect_identifiers(
  1679. $this->qb_from[0], TRUE, $escape, FALSE
  1680. ),
  1681. array_keys($this->qb_set),
  1682. array_values($this->qb_set)
  1683. );
  1684.  
  1685. $this->_reset_write();
  1686. return $this->query($sql);
  1687. }
  1688.  
  1689. // --------------------------------------------------------------------
  1690.  
  1691. /**
  1692. * Validate Insert
  1693. *
  1694. * This method is used by both insert() and get_compiled_insert() to
  1695. * validate that the there data is actually being set and that table
  1696. * has been chosen to be inserted into.
  1697. *
  1698. * @param string the table to insert data into
  1699. * @return string
  1700. */
  1701. protected function _validate_insert($table = '')
  1702. {
  1703. if (count($this->qb_set) === 0)
  1704. {
  1705. return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE;
  1706. }
  1707.  
  1708. if ($table !== '')
  1709. {
  1710. $this->qb_from[0] = $table;
  1711. }
  1712. elseif ( ! isset($this->qb_from[0]))
  1713. {
  1714. return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE;
  1715. }
  1716.  
  1717. return TRUE;
  1718. }
  1719.  
  1720. // --------------------------------------------------------------------
  1721.  
  1722. /**
  1723. * Replace
  1724. *
  1725. * Compiles an replace into string and runs the query
  1726. *
  1727. * @param string the table to replace data into
  1728. * @param array an associative array of insert values
  1729. * @return bool TRUE on success, FALSE on failure
  1730. */
  1731. public function replace($table = '', $set = NULL)
  1732. {
  1733. if ($set !== NULL)
  1734. {
  1735. $this->set($set);
  1736. }
  1737.  
  1738. if (count($this->qb_set) === 0)
  1739. {
  1740. return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE;
  1741. }
  1742.  
  1743. if ($table === '')
  1744. {
  1745. if ( ! isset($this->qb_from[0]))
  1746. {
  1747. return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE;
  1748. }
  1749.  
  1750. $table = $this->qb_from[0];
  1751. }
  1752.  
  1753. $sql = $this->_replace($this->protect_identifiers($table, TRUE, NULL, FALSE), array_keys($this->qb_set), array_values($this->qb_set));
  1754.  
  1755. $this->_reset_write();
  1756. return $this->query($sql);
  1757. }
  1758.  
  1759. // --------------------------------------------------------------------
  1760.  
  1761. /**
  1762. * Replace statement
  1763. *
  1764. * Generates a platform-specific replace string from the supplied data
  1765. *
  1766. * @param string the table name
  1767. * @param array the insert keys
  1768. * @param array the insert values
  1769. * @return string
  1770. */
  1771. protected function _replace($table, $keys, $values)
  1772. {
  1773. return 'REPLACE INTO '.$table.' ('.implode(', ', $keys).') VALUES ('.implode(', ', $values).')';
  1774. }
  1775.  
  1776. // --------------------------------------------------------------------
  1777.  
  1778. /**
  1779. * FROM tables
  1780. *
  1781. * Groups tables in FROM clauses if needed, so there is no confusion
  1782. * about operator precedence.
  1783. *
  1784. * Note: This is only used (and overridden) by MySQL and CUBRID.
  1785. *
  1786. * @return string
  1787. */
  1788. protected function _from_tables()
  1789. {
  1790. return implode(', ', $this->qb_from);
  1791. }
  1792.  
  1793. // --------------------------------------------------------------------
  1794.  
  1795. /**
  1796. * Get UPDATE query string
  1797. *
  1798. * Compiles an update query and returns the sql
  1799. *
  1800. * @param string the table to update
  1801. * @param bool TRUE: reset QB values; FALSE: leave QB values alone
  1802. * @return string
  1803. */
  1804. public function get_compiled_update($table = '', $reset = TRUE)
  1805. {
  1806. // Combine any cached components with the current statements
  1807. $this->_merge_cache();
  1808.  
  1809. if ($this->_validate_update($table) === FALSE)
  1810. {
  1811. return FALSE;
  1812. }
  1813.  
  1814. $sql = $this->_update($this->qb_from[0], $this->qb_set);
  1815.  
  1816. if ($reset === TRUE)
  1817. {
  1818. $this->_reset_write();
  1819. }
  1820.  
  1821. return $sql;
  1822. }
  1823.  
  1824. // --------------------------------------------------------------------
  1825.  
  1826. /**
  1827. * UPDATE
  1828. *
  1829. * Compiles an update string and runs the query.
  1830. *
  1831. * @param string $table
  1832. * @param array $set An associative array of update values
  1833. * @param mixed $where
  1834. * @param int $limit
  1835. * @return bool TRUE on success, FALSE on failure
  1836. */
  1837. public function update($table = '', $set = NULL, $where = NULL, $limit = NULL)
  1838. {
  1839. // Combine any cached components with the current statements
  1840. $this->_merge_cache();
  1841.  
  1842. if ($set !== NULL)
  1843. {
  1844. $this->set($set);
  1845. }
  1846.  
  1847. if ($this->_validate_update($table) === FALSE)
  1848. {
  1849. return FALSE;
  1850. }
  1851.  
  1852. if ($where !== NULL)
  1853. {
  1854. $this->where($where);
  1855. }
  1856.  
  1857. if ( ! empty($limit))
  1858. {
  1859. $this->limit($limit);
  1860. }
  1861.  
  1862. $sql = $this->_update($this->qb_from[0], $this->qb_set);
  1863. $this->_reset_write();
  1864. return $this->query($sql);
  1865. }
  1866.  
  1867. // --------------------------------------------------------------------
  1868.  
  1869. /**
  1870. * Validate Update
  1871. *
  1872. * This method is used by both update() and get_compiled_update() to
  1873. * validate that data is actually being set and that a table has been
  1874. * chosen to be update.
  1875. *
  1876. * @param string the table to update data on
  1877. * @return bool
  1878. */
  1879. protected function _validate_update($table)
  1880. {
  1881. if (count($this->qb_set) === 0)
  1882. {
  1883. return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE;
  1884. }
  1885.  
  1886. if ($table !== '')
  1887. {
  1888. $this->qb_from = array($this->protect_identifiers($table, TRUE, NULL, FALSE));
  1889. }
  1890. elseif ( ! isset($this->qb_from[0]))
  1891. {
  1892. return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE;
  1893. }
  1894.  
  1895. return TRUE;
  1896. }
  1897.  
  1898. // --------------------------------------------------------------------
  1899.  
  1900. /**
  1901. * Update_Batch
  1902. *
  1903. * Compiles an update string and runs the query
  1904. *
  1905. * @param string the table to retrieve the results from
  1906. * @param array an associative array of update values
  1907. * @param string the where key
  1908. * @return int number of rows affected or FALSE on failure
  1909. */
  1910. public function update_batch($table, $set = NULL, $index = NULL, $batch_size = 100)
  1911. {
  1912. // Combine any cached components with the current statements
  1913. $this->_merge_cache();
  1914.  
  1915. if ($index === NULL)
  1916. {
  1917. return ($this->db_debug) ? $this->display_error('db_must_use_index') : FALSE;
  1918. }
  1919.  
  1920. if ($set === NULL)
  1921. {
  1922. if (empty($this->qb_set_ub))
  1923. {
  1924. return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE;
  1925. }
  1926. }
  1927. else
  1928. {
  1929. if (empty($set))
  1930. {
  1931. return ($this->db_debug) ? $this->display_error('update_batch() called with no data') : FALSE;
  1932. }
  1933.  
  1934. $this->set_update_batch($set, $index);
  1935. }
  1936.  
  1937. if (strlen($table) === 0)
  1938. {
  1939. if ( ! isset($this->qb_from[0]))
  1940. {
  1941. return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE;
  1942. }
  1943.  
  1944. $table = $this->qb_from[0];
  1945. }
  1946.  
  1947. // Batch this baby
  1948. $affected_rows = 0;
  1949. for ($i = 0, $total = count($this->qb_set_ub); $i < $total; $i += $batch_size)
  1950. {
  1951. if ($this->query($this->_update_batch($this->protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->qb_set_ub, $i, $batch_size), $index)))
  1952. {
  1953. $affected_rows += $this->affected_rows();
  1954. }
  1955.  
  1956. $this->qb_where = array();
  1957. }
  1958.  
  1959. $this->_reset_write();
  1960. return $affected_rows;
  1961. }
  1962.  
  1963. // --------------------------------------------------------------------
  1964.  
  1965. /**
  1966. * Update_Batch statement
  1967. *
  1968. * Generates a platform-specific batch update string from the supplied data
  1969. *
  1970. * @param string $table Table name
  1971. * @param array $values Update data
  1972. * @param string $index WHERE key
  1973. * @return string
  1974. */
  1975. protected function _update_batch($table, $values, $index)
  1976. {
  1977. $ids = array();
  1978. foreach ($values as $key => $val)
  1979. {
  1980. $ids[] = $val[$index]['value'];
  1981.  
  1982. foreach (array_keys($val) as $field)
  1983. {
  1984. if ($field !== $index)
  1985. {
  1986. $final[$val[$field]['field']][] = 'WHEN '.$val[$index]['field'].' = '.$val[$index]['value'].' THEN '.$val[$field]['value'];
  1987. }
  1988. }
  1989. }
  1990.  
  1991. $cases = '';
  1992. foreach ($final as $k => $v)
  1993. {
  1994. $cases .= $k." = CASE \n"
  1995. .implode("\n", $v)."\n"
  1996. .'ELSE '.$k.' END, ';
  1997. }
  1998.  
  1999. $this->where($val[$index]['field'].' IN('.implode(',', $ids).')', NULL, FALSE);
  2000.  
  2001. return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
  2002. }
  2003.  
  2004. // --------------------------------------------------------------------
  2005.  
  2006. /**
  2007. * The "set_update_batch" function. Allows key/value pairs to be set for batch updating
  2008. *
  2009. * @param array
  2010. * @param string
  2011. * @param bool
  2012. * @return CI_DB_query_builder
  2013. */
  2014. public function set_update_batch($key, $index = '', $escape = NULL)
  2015. {
  2016. $key = $this->_object_to_array_batch($key);
  2017.  
  2018. if ( ! is_array($key))
  2019. {
  2020. // @todo error
  2021. }
  2022.  
  2023. is_bool($escape) OR $escape = $this->_protect_identifiers;
  2024.  
  2025. foreach ($key as $k => $v)
  2026. {
  2027. $index_set = FALSE;
  2028. $clean = array();
  2029. foreach ($v as $k2 => $v2)
  2030. {
  2031. if ($k2 === $index)
  2032. {
  2033. $index_set = TRUE;
  2034. }
  2035.  
  2036. $clean[$k2] = array(
  2037. 'field' => $this->protect_identifiers($k2, FALSE, $escape),
  2038. 'value' => ($escape === FALSE ? $v2 : $this->escape($v2))
  2039. );
  2040. }
  2041.  
  2042. if ($index_set === FALSE)
  2043. {
  2044. return $this->display_error('db_batch_missing_index');
  2045. }
  2046.  
  2047. $this->qb_set_ub[] = $clean;
  2048. }
  2049.  
  2050. return $this;
  2051. }
  2052.  
  2053. // --------------------------------------------------------------------
  2054.  
  2055. /**
  2056. * Empty Table
  2057. *
  2058. * Compiles a delete string and runs "DELETE FROM table"
  2059. *
  2060. * @param string the table to empty
  2061. * @return bool TRUE on success, FALSE on failure
  2062. */
  2063. public function empty_table($table = '')
  2064. {
  2065. if ($table === '')
  2066. {
  2067. if ( ! isset($this->qb_from[0]))
  2068. {
  2069. return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE;
  2070. }
  2071.  
  2072. $table = $this->qb_from[0];
  2073. }
  2074. else
  2075. {
  2076. $table = $this->protect_identifiers($table, TRUE, NULL, FALSE);
  2077. }
  2078.  
  2079. $sql = $this->_delete($table);
  2080. $this->_reset_write();
  2081. return $this->query($sql);
  2082. }
  2083.  
  2084. // --------------------------------------------------------------------
  2085.  
  2086. /**
  2087. * Truncate
  2088. *
  2089. * Compiles a truncate string and runs the query
  2090. * If the database does not support the truncate() command
  2091. * This function maps to "DELETE FROM table"
  2092. *
  2093. * @param string the table to truncate
  2094. * @return bool TRUE on success, FALSE on failure
  2095. */
  2096. public function truncate($table = '')
  2097. {
  2098. if ($table === '')
  2099. {
  2100. if ( ! isset($this->qb_from[0]))
  2101. {
  2102. return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE;
  2103. }
  2104.  
  2105. $table = $this->qb_from[0];
  2106. }
  2107. else
  2108. {
  2109. $table = $this->protect_identifiers($table, TRUE, NULL, FALSE);
  2110. }
  2111.  
  2112. $sql = $this->_truncate($table);
  2113. $this->_reset_write();
  2114. return $this->query($sql);
  2115. }
  2116.  
  2117. // --------------------------------------------------------------------
  2118.  
  2119. /**
  2120. * Truncate statement
  2121. *
  2122. * Generates a platform-specific truncate string from the supplied data
  2123. *
  2124. * If the database does not support the truncate() command,
  2125. * then this method maps to 'DELETE FROM table'
  2126. *
  2127. * @param string the table name
  2128. * @return string
  2129. */
  2130. protected function _truncate($table)
  2131. {
  2132. return 'TRUNCATE '.$table;
  2133. }
  2134.  
  2135. // --------------------------------------------------------------------
  2136.  
  2137. /**
  2138. * Get DELETE query string
  2139. *
  2140. * Compiles a delete query string and returns the sql
  2141. *
  2142. * @param string the table to delete from
  2143. * @param bool TRUE: reset QB values; FALSE: leave QB values alone
  2144. * @return string
  2145. */
  2146. public function get_compiled_delete($table = '', $reset = TRUE)
  2147. {
  2148. $this->return_delete_sql = TRUE;
  2149. $sql = $this->delete($table, '', NULL, $reset);
  2150. $this->return_delete_sql = FALSE;
  2151. return $sql;
  2152. }
  2153.  
  2154. // --------------------------------------------------------------------
  2155.  
  2156. /**
  2157. * Delete
  2158. *
  2159. * Compiles a delete string and runs the query
  2160. *
  2161. * @param mixed the table(s) to delete from. String or array
  2162. * @param mixed the where clause
  2163. * @param mixed the limit clause
  2164. * @param bool
  2165. * @return mixed
  2166. */
  2167. public function delete($table = '', $where = '', $limit = NULL, $reset_data = TRUE)
  2168. {
  2169. // Combine any cached components with the current statements
  2170. $this->_merge_cache();
  2171.  
  2172. if ($table === '')
  2173. {
  2174. if ( ! isset($this->qb_from[0]))
  2175. {
  2176. return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE;
  2177. }
  2178.  
  2179. $table = $this->qb_from[0];
  2180. }
  2181. elseif (is_array($table))
  2182. {
  2183. empty($where) && $reset_data = FALSE;
  2184.  
  2185. foreach ($table as $single_table)
  2186. {
  2187. $this->delete($single_table, $where, $limit, $reset_data);
  2188. }
  2189.  
  2190. return;
  2191. }
  2192. else
  2193. {
  2194. $table = $this->protect_identifiers($table, TRUE, NULL, FALSE);
  2195. }
  2196.  
  2197. if ($where !== '')
  2198. {
  2199. $this->where($where);
  2200. }
  2201.  
  2202. if ( ! empty($limit))
  2203. {
  2204. $this->limit($limit);
  2205. }
  2206.  
  2207. if (count($this->qb_where) === 0)
  2208. {
  2209. return ($this->db_debug) ? $this->display_error('db_del_must_use_where') : FALSE;
  2210. }
  2211.  
  2212. $sql = $this->_delete($table);
  2213. if ($reset_data)
  2214. {
  2215. $this->_reset_write();
  2216. }
  2217.  
  2218. return ($this->return_delete_sql === TRUE) ? $sql : $this->query($sql);
  2219. }
  2220.  
  2221. // --------------------------------------------------------------------
  2222.  
  2223. /**
  2224. * Delete statement
  2225. *
  2226. * Generates a platform-specific delete string from the supplied data
  2227. *
  2228. * @param string the table name
  2229. * @return string
  2230. */
  2231. protected function _delete($table)
  2232. {
  2233. return 'DELETE FROM '.$table.$this->_compile_wh('qb_where')
  2234. .($this->qb_limit !== FALSE ? ' LIMIT '.$this->qb_limit : '');
  2235. }
  2236.  
  2237. // --------------------------------------------------------------------
  2238.  
  2239. /**
  2240. * DB Prefix
  2241. *
  2242. * Prepends a database prefix if one exists in configuration
  2243. *
  2244. * @param string the table
  2245. * @return string
  2246. */
  2247. public function dbprefix($table = '')
  2248. {
  2249. if ($table === '')
  2250. {
  2251. $this->display_error('db_table_name_required');
  2252. }
  2253.  
  2254. return $this->dbprefix.$table;
  2255. }
  2256.  
  2257. // --------------------------------------------------------------------
  2258.  
  2259. /**
  2260. * Set DB Prefix
  2261. *
  2262. * Set's the DB Prefix to something new without needing to reconnect
  2263. *
  2264. * @param string the prefix
  2265. * @return string
  2266. */
  2267. public function set_dbprefix($prefix = '')
  2268. {
  2269. return $this->dbprefix = $prefix;
  2270. }
  2271.  
  2272. // --------------------------------------------------------------------
  2273.  
  2274. /**
  2275. * Track Aliases
  2276. *
  2277. * Used to track SQL statements written with aliased tables.
  2278. *
  2279. * @param string The table to inspect
  2280. * @return string
  2281. */
  2282. protected function _track_aliases($table)
  2283. {
  2284. if (is_array($table))
  2285. {
  2286. foreach ($table as $t)
  2287. {
  2288. $this->_track_aliases($t);
  2289. }
  2290. return;
  2291. }
  2292.  
  2293. // Does the string contain a comma? If so, we need to separate
  2294. // the string into discreet statements
  2295. if (strpos($table, ',') !== FALSE)
  2296. {
  2297. return $this->_track_aliases(explode(',', $table));
  2298. }
  2299.  
  2300. // if a table alias is used we can recognize it by a space
  2301. if (strpos($table, ' ') !== FALSE)
  2302. {
  2303. // if the alias is written with the AS keyword, remove it
  2304. $table = preg_replace('/\s+AS\s+/i', ' ', $table);
  2305.  
  2306. // Grab the alias
  2307. $table = trim(strrchr($table, ' '));
  2308.  
  2309. // Store the alias, if it doesn't already exist
  2310. if ( ! in_array($table, $this->qb_aliased_tables, TRUE))
  2311. {
  2312. $this->qb_aliased_tables[] = $table;
  2313. if ($this->qb_caching === TRUE && ! in_array($table, $this->qb_cache_aliased_tables, TRUE))
  2314. {
  2315. $this->qb_cache_aliased_tables[] = $table;
  2316. $this->qb_cache_exists[] = 'aliased_tables';
  2317. }
  2318. }
  2319. }
  2320. }
  2321.  
  2322. // --------------------------------------------------------------------
  2323.  
  2324. /**
  2325. * Compile the SELECT statement
  2326. *
  2327. * Generates a query string based on which functions were used.
  2328. * Should not be called directly.
  2329. *
  2330. * @param bool $select_override
  2331. * @return string
  2332. */
  2333. protected function _compile_select($select_override = FALSE)
  2334. {
  2335. // Combine any cached components with the current statements
  2336. $this->_merge_cache();
  2337.  
  2338. // Write the "select" portion of the query
  2339. if ($select_override !== FALSE)
  2340. {
  2341. $sql = $select_override;
  2342. }
  2343. else
  2344. {
  2345. $sql = ( ! $this->qb_distinct) ? 'SELECT ' : 'SELECT DISTINCT ';
  2346.  
  2347. if (count($this->qb_select) === 0)
  2348. {
  2349. $sql .= '*';
  2350. }
  2351. else
  2352. {
  2353. // Cycle through the "select" portion of the query and prep each column name.
  2354. // The reason we protect identifiers here rather than in the select() function
  2355. // is because until the user calls the from() function we don't know if there are aliases
  2356. foreach ($this->qb_select as $key => $val)
  2357. {
  2358. $no_escape = isset($this->qb_no_escape[$key]) ? $this->qb_no_escape[$key] : NULL;
  2359. $this->qb_select[$key] = $this->protect_identifiers($val, FALSE, $no_escape);
  2360. }
  2361.  
  2362. if($this->qb_prefix_fields){
  2363. foreach ( $this->qb_select as $key => $value ) {
  2364. $value = explode('.',$value);
  2365. $value[0] = preg_replace('/[^a-zA-Z_]/', '' , $value[0]);
  2366. $fields_list = $this->list_fields($value[0]);
  2367. if(count($value) > 1){
  2368. if($value[1] === '*'){
  2369. unset($this->qb_select[$key]);
  2370. foreach ( $fields_list as $field_name ) {
  2371. $no_escape = isset($this->qb_no_escape[$key]) ? $this->qb_no_escape[$key] : NULL;
  2372. $this->qb_select[] = $this->protect_identifiers($value[0].'.'.$field_name .' as '.$value[0].'_'.$field_name, FALSE, $no_escape);
  2373. }
  2374. }
  2375. }
  2376. }
  2377.  
  2378. }
  2379.  
  2380. $sql .= implode(', ', $this->qb_select);
  2381. }
  2382. }
  2383.  
  2384. // Write the "FROM" portion of the query
  2385. if (count($this->qb_from) > 0)
  2386. {
  2387. $sql .= "\nFROM ".$this->_from_tables();
  2388. }
  2389.  
  2390. // Write the "JOIN" portion of the query
  2391. if (count($this->qb_join) > 0)
  2392. {
  2393. $sql .= "\n".implode("\n", $this->qb_join);
  2394. }
  2395.  
  2396. $sql .= $this->_compile_wh('qb_where')
  2397. .$this->_compile_group_by()
  2398. .$this->_compile_wh('qb_having')
  2399. .$this->_compile_order_by(); // ORDER BY
  2400.  
  2401. // LIMIT
  2402. if ($this->qb_limit !== FALSE OR $this->qb_offset)
  2403. {
  2404. return $this->_limit($sql."\n");
  2405. }
  2406.  
  2407. return $sql;
  2408. }
  2409.  
  2410. // --------------------------------------------------------------------
  2411.  
  2412. /**
  2413. * Compile WHERE, HAVING statements
  2414. *
  2415. * Escapes identifiers in WHERE and HAVING statements at execution time.
  2416. *
  2417. * Required so that aliases are tracked properly, regardless of whether
  2418. * where(), or_where(), having(), or_having are called prior to from(),
  2419. * join() and dbprefix is added only if needed.
  2420. *
  2421. * @param string $qb_key 'qb_where' or 'qb_having'
  2422. * @return string SQL statement
  2423. */
  2424. protected function _compile_wh($qb_key)
  2425. {
  2426. if (count($this->$qb_key) > 0)
  2427. {
  2428. for ($i = 0, $c = count($this->$qb_key); $i < $c; $i++)
  2429. {
  2430. // Is this condition already compiled?
  2431. if (is_string($this->{$qb_key}[$i]))
  2432. {
  2433. continue;
  2434. }
  2435. elseif ($this->{$qb_key}[$i]['escape'] === FALSE)
  2436. {
  2437. $this->{$qb_key}[$i] = $this->{$qb_key}[$i]['condition'].(isset($this->{$qb_key}[$i]['value']) ? ' '.$this->{$qb_key}[$i]['value'] : '');
  2438. continue;
  2439. }
  2440.  
  2441. // Split multiple conditions
  2442. $conditions = preg_split(
  2443. '/((?:^|\s+)AND\s+|(?:^|\s+)OR\s+)/i',
  2444. $this->{$qb_key}[$i]['condition'],
  2445. -1,
  2446. PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY
  2447. );
  2448.  
  2449. for ($ci = 0, $cc = count($conditions); $ci < $cc; $ci++)
  2450. {
  2451. if (($op = $this->_get_operator($conditions[$ci])) === FALSE
  2452. OR ! preg_match('/^(\(?)(.*)('.preg_quote($op, '/').')\s*(.*(?<!\)))?(\)?)$/i', $conditions[$ci], $matches))
  2453. {
  2454. continue;
  2455. }
  2456.  
  2457. // $matches = array(
  2458. // 0 => '(test <= foo)', /* the whole thing */
  2459. // 1 => '(', /* optional */
  2460. // 2 => 'test', /* the field name */
  2461. // 3 => ' <= ', /* $op */
  2462. // 4 => 'foo', /* optional, if $op is e.g. 'IS NULL' */
  2463. // 5 => ')' /* optional */
  2464. // );
  2465.  
  2466. if ( ! empty($matches[4]))
  2467. {
  2468. $this->_is_literal($matches[4]) OR $matches[4] = $this->protect_identifiers(trim($matches[4]));
  2469. $matches[4] = ' '.$matches[4];
  2470. }
  2471.  
  2472. $conditions[$ci] = $matches[1].$this->protect_identifiers(trim($matches[2]))
  2473. .' '.trim($matches[3]).$matches[4].$matches[5];
  2474. }
  2475.  
  2476. $this->{$qb_key}[$i] = implode('', $conditions).(isset($this->{$qb_key}[$i]['value']) ? ' '.$this->{$qb_key}[$i]['value'] : '');
  2477. }
  2478.  
  2479. return ($qb_key === 'qb_having' ? "\nHAVING " : "\nWHERE ")
  2480. .implode("\n", $this->$qb_key);
  2481. }
  2482.  
  2483. return '';
  2484. }
  2485.  
  2486. // --------------------------------------------------------------------
  2487.  
  2488. /**
  2489. * Compile GROUP BY
  2490. *
  2491. * Escapes identifiers in GROUP BY statements at execution time.
  2492. *
  2493. * Required so that aliases are tracked properly, regardless of whether
  2494. * group_by() is called prior to from(), join() and dbprefix is added
  2495. * only if needed.
  2496. *
  2497. * @return string SQL statement
  2498. */
  2499. protected function _compile_group_by()
  2500. {
  2501. if (count($this->qb_groupby) > 0)
  2502. {
  2503. for ($i = 0, $c = count($this->qb_groupby); $i < $c; $i++)
  2504. {
  2505. // Is it already compiled?
  2506. if (is_string($this->qb_groupby[$i]))
  2507. {
  2508. continue;
  2509. }
  2510.  
  2511. $this->qb_groupby[$i] = ($this->qb_groupby[$i]['escape'] === FALSE OR $this->_is_literal($this->qb_groupby[$i]['field']))
  2512. ? $this->qb_groupby[$i]['field']
  2513. : $this->protect_identifiers($this->qb_groupby[$i]['field']);
  2514. }
  2515.  
  2516. return "\nGROUP BY ".implode(', ', $this->qb_groupby);
  2517. }
  2518.  
  2519. return '';
  2520. }
  2521.  
  2522. // --------------------------------------------------------------------
  2523.  
  2524. /**
  2525. * Compile ORDER BY
  2526. *
  2527. * Escapes identifiers in ORDER BY statements at execution time.
  2528. *
  2529. * Required so that aliases are tracked properly, regardless of whether
  2530. * order_by() is called prior to from(), join() and dbprefix is added
  2531. * only if needed.
  2532. *
  2533. * @return string SQL statement
  2534. */
  2535. protected function _compile_order_by()
  2536. {
  2537. if (empty($this->qb_orderby))
  2538. {
  2539. return '';
  2540. }
  2541.  
  2542. for ($i = 0, $c = count($this->qb_orderby); $i < $c; $i++)
  2543. {
  2544. if (is_string($this->qb_orderby[$i]))
  2545. {
  2546. continue;
  2547. }
  2548.  
  2549. if ($this->qb_orderby[$i]['escape'] !== FALSE && ! $this->_is_literal($this->qb_orderby[$i]['field']))
  2550. {
  2551. $this->qb_orderby[$i]['field'] = $this->protect_identifiers($this->qb_orderby[$i]['field']);
  2552. }
  2553.  
  2554. $this->qb_orderby[$i] = $this->qb_orderby[$i]['field'].$this->qb_orderby[$i]['direction'];
  2555. }
  2556.  
  2557. return "\nORDER BY ".implode(', ', $this->qb_orderby);
  2558. }
  2559.  
  2560. // --------------------------------------------------------------------
  2561.  
  2562. /**
  2563. * Object to Array
  2564. *
  2565. * Takes an object as input and converts the class variables to array key/vals
  2566. *
  2567. * @param object
  2568. * @return array
  2569. */
  2570. protected function _object_to_array($object)
  2571. {
  2572. if ( ! is_object($object))
  2573. {
  2574. return $object;
  2575. }
  2576.  
  2577. $array = array();
  2578. foreach (get_object_vars($object) as $key => $val)
  2579. {
  2580. // There are some built in keys we need to ignore for this conversion
  2581. if ( ! is_object($val) && ! is_array($val) && $key !== '_parent_name')
  2582. {
  2583. $array[$key] = $val;
  2584. }
  2585. }
  2586.  
  2587. return $array;
  2588. }
  2589.  
  2590. // --------------------------------------------------------------------
  2591.  
  2592. /**
  2593. * Object to Array
  2594. *
  2595. * Takes an object as input and converts the class variables to array key/vals
  2596. *
  2597. * @param object
  2598. * @return array
  2599. */
  2600. protected function _object_to_array_batch($object)
  2601. {
  2602. if ( ! is_object($object))
  2603. {
  2604. return $object;
  2605. }
  2606.  
  2607. $array = array();
  2608. $out = get_object_vars($object);
  2609. $fields = array_keys($out);
  2610.  
  2611. foreach ($fields as $val)
  2612. {
  2613. // There are some built in keys we need to ignore for this conversion
  2614. if ($val !== '_parent_name')
  2615. {
  2616. $i = 0;
  2617. foreach ($out[$val] as $data)
  2618. {
  2619. $array[$i++][$val] = $data;
  2620. }
  2621. }
  2622. }
  2623.  
  2624. return $array;
  2625. }
  2626.  
  2627. // --------------------------------------------------------------------
  2628.  
  2629. /**
  2630. * Start Cache
  2631. *
  2632. * Starts QB caching
  2633. *
  2634. * @return CI_DB_query_builder
  2635. */
  2636. public function start_cache()
  2637. {
  2638. $this->qb_caching = TRUE;
  2639. return $this;
  2640. }
  2641.  
  2642. // --------------------------------------------------------------------
  2643.  
  2644. /**
  2645. * Stop Cache
  2646. *
  2647. * Stops QB caching
  2648. *
  2649. * @return CI_DB_query_builder
  2650. */
  2651. public function stop_cache()
  2652. {
  2653. $this->qb_caching = FALSE;
  2654. return $this;
  2655. }
  2656.  
  2657. // --------------------------------------------------------------------
  2658.  
  2659. /**
  2660. * Flush Cache
  2661. *
  2662. * Empties the QB cache
  2663. *
  2664. * @return CI_DB_query_builder
  2665. */
  2666. public function flush_cache()
  2667. {
  2668. $this->_reset_run(array(
  2669. 'qb_cache_select' => array(),
  2670. 'qb_cache_from' => array(),
  2671. 'qb_cache_join' => array(),
  2672. 'qb_cache_where' => array(),
  2673. 'qb_cache_groupby' => array(),
  2674. 'qb_cache_having' => array(),
  2675. 'qb_cache_orderby' => array(),
  2676. 'qb_cache_set' => array(),
  2677. 'qb_cache_exists' => array(),
  2678. 'qb_cache_no_escape' => array(),
  2679. 'qb_cache_aliased_tables' => array()
  2680. ));
  2681.  
  2682. return $this;
  2683. }
  2684.  
  2685. // --------------------------------------------------------------------
  2686.  
  2687. /**
  2688. * Merge Cache
  2689. *
  2690. * When called, this function merges any cached QB arrays with
  2691. * locally called ones.
  2692. *
  2693. * @return void
  2694. */
  2695. protected function _merge_cache()
  2696. {
  2697. if (count($this->qb_cache_exists) === 0)
  2698. {
  2699. return;
  2700. }
  2701. elseif (in_array('select', $this->qb_cache_exists, TRUE))
  2702. {
  2703. $qb_no_escape = $this->qb_cache_no_escape;
  2704. }
  2705.  
  2706. foreach (array_unique($this->qb_cache_exists) as $val) // select, from, etc.
  2707. {
  2708. $qb_variable = 'qb_'.$val;
  2709. $qb_cache_var = 'qb_cache_'.$val;
  2710. $qb_new = $this->$qb_cache_var;
  2711.  
  2712. for ($i = 0, $c = count($this->$qb_variable); $i < $c; $i++)
  2713. {
  2714. if ( ! in_array($this->{$qb_variable}[$i], $qb_new, TRUE))
  2715. {
  2716. $qb_new[] = $this->{$qb_variable}[$i];
  2717. if ($val === 'select')
  2718. {
  2719. $qb_no_escape[] = $this->qb_no_escape[$i];
  2720. }
  2721. }
  2722. }
  2723.  
  2724. $this->$qb_variable = $qb_new;
  2725. if ($val === 'select')
  2726. {
  2727. $this->qb_no_escape = $qb_no_escape;
  2728. }
  2729. }
  2730. }
  2731.  
  2732. // --------------------------------------------------------------------
  2733.  
  2734. /**
  2735. * Is literal
  2736. *
  2737. * Determines if a string represents a literal value or a field name
  2738. *
  2739. * @param string $str
  2740. * @return bool
  2741. */
  2742. protected function _is_literal($str)
  2743. {
  2744. $str = trim($str);
  2745.  
  2746. if (empty($str) OR ctype_digit($str) OR (string) (float) $str === $str OR in_array(strtoupper($str), array('TRUE', 'FALSE'), TRUE))
  2747. {
  2748. return TRUE;
  2749. }
  2750.  
  2751. static $_str;
  2752.  
  2753. if (empty($_str))
  2754. {
  2755. $_str = ($this->_escape_char !== '"')
  2756. ? array('"', "'") : array("'");
  2757. }
  2758.  
  2759. return in_array($str[0], $_str, TRUE);
  2760. }
  2761.  
  2762. // --------------------------------------------------------------------
  2763.  
  2764. /**
  2765. * Reset Query Builder values.
  2766. *
  2767. * Publicly-visible method to reset the QB values.
  2768. *
  2769. * @return CI_DB_query_builder
  2770. */
  2771. public function reset_query()
  2772. {
  2773. $this->_reset_select();
  2774. $this->_reset_write();
  2775. return $this;
  2776. }
  2777.  
  2778. // --------------------------------------------------------------------
  2779.  
  2780. /**
  2781. * Resets the query builder values. Called by the get() function
  2782. *
  2783. * @param array An array of fields to reset
  2784. * @return void
  2785. */
  2786. protected function _reset_run($qb_reset_items)
  2787. {
  2788. foreach ($qb_reset_items as $item => $default_value)
  2789. {
  2790. $this->$item = $default_value;
  2791. }
  2792. }
  2793.  
  2794. // --------------------------------------------------------------------
  2795.  
  2796. /**
  2797. * Resets the query builder values. Called by the get() function
  2798. *
  2799. * @return void
  2800. */
  2801. protected function _reset_select()
  2802. {
  2803. $this->_reset_run(array(
  2804. 'qb_select' => array(),
  2805. 'qb_from' => array(),
  2806. 'qb_join' => array(),
  2807. 'qb_where' => array(),
  2808. 'qb_groupby' => array(),
  2809. 'qb_having' => array(),
  2810. 'qb_orderby' => array(),
  2811. 'qb_aliased_tables' => array(),
  2812. 'qb_no_escape' => array(),
  2813. 'qb_distinct' => FALSE,
  2814. 'qb_limit' => FALSE,
  2815. 'qb_offset' => FALSE
  2816. ));
  2817. }
  2818.  
  2819. // --------------------------------------------------------------------
  2820.  
  2821. /**
  2822. * Resets the query builder "write" values.
  2823. *
  2824. * Called by the insert() update() insert_batch() update_batch() and delete() functions
  2825. *
  2826. * @return void
  2827. */
  2828. protected function _reset_write()
  2829. {
  2830. $this->_reset_run(array(
  2831. 'qb_set' => array(),
  2832. 'qb_set_ub' => array(),
  2833. 'qb_from' => array(),
  2834. 'qb_join' => array(),
  2835. 'qb_where' => array(),
  2836. 'qb_orderby' => array(),
  2837. 'qb_keys' => array(),
  2838. 'qb_limit' => FALSE
  2839. ));
  2840. }
  2841.  
  2842. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement