Builder.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. <?php
  2. /**
  3. * Database query builder. See [Query Builder](/database/query/builder) for usage and examples.
  4. *
  5. * @package Kohana/Database
  6. * @category Query
  7. * @author Kohana Team
  8. * @copyright (c) Kohana Team
  9. * @license https://koseven.ga/LICENSE.md
  10. */
  11. abstract class Kohana_Database_Query_Builder extends Database_Query {
  12. /**
  13. * Compiles an array of JOIN statements into an SQL partial.
  14. *
  15. * @param object $db Database instance
  16. * @param array $joins join statements
  17. * @return string
  18. */
  19. protected function _compile_join(Database $db, array $joins)
  20. {
  21. $statements = [];
  22. foreach ($joins as $join)
  23. {
  24. // Compile each of the join statements
  25. $statements[] = $join->compile($db);
  26. }
  27. return implode(' ', $statements);
  28. }
  29. /**
  30. * Compiles an array of conditions into an SQL partial. Used for WHERE
  31. * and HAVING.
  32. *
  33. * @param object $db Database instance
  34. * @param array $conditions condition statements
  35. * @return string
  36. */
  37. protected function _compile_conditions(Database $db, array $conditions)
  38. {
  39. $last_condition = NULL;
  40. $sql = '';
  41. foreach ($conditions as $group)
  42. {
  43. // Process groups of conditions
  44. foreach ($group as $logic => $condition)
  45. {
  46. if ($condition === '(')
  47. {
  48. if ( ! empty($sql) AND $last_condition !== '(')
  49. {
  50. // Include logic operator
  51. $sql .= ' '.$logic.' ';
  52. }
  53. $sql .= '(';
  54. }
  55. elseif ($condition === ')')
  56. {
  57. $sql .= ')';
  58. }
  59. else
  60. {
  61. if ( ! empty($sql) AND $last_condition !== '(')
  62. {
  63. // Add the logic operator
  64. $sql .= ' '.$logic.' ';
  65. }
  66. // Split the condition
  67. list($column, $op, $value) = $condition;
  68. if ($value === NULL)
  69. {
  70. if ($op === '=')
  71. {
  72. // Convert "val = NULL" to "val IS NULL"
  73. $op = 'IS';
  74. }
  75. elseif ($op === '!=' OR $op === '<>')
  76. {
  77. // Convert "val != NULL" to "valu IS NOT NULL"
  78. $op = 'IS NOT';
  79. }
  80. }
  81. // Database operators are always uppercase
  82. $op = strtoupper($op);
  83. if ($op === 'BETWEEN' AND is_array($value))
  84. {
  85. // BETWEEN always has exactly two arguments
  86. list($min, $max) = $value;
  87. if ((is_string($min) AND array_key_exists($min, $this->_parameters)) === FALSE)
  88. {
  89. // Quote the value, it is not a parameter
  90. $min = $db->quote($min);
  91. }
  92. if ((is_string($max) AND array_key_exists($max, $this->_parameters)) === FALSE)
  93. {
  94. // Quote the value, it is not a parameter
  95. $max = $db->quote($max);
  96. }
  97. // Quote the min and max value
  98. $value = $min.' AND '.$max;
  99. }
  100. elseif ($op === 'IN' AND is_array($value) AND count($value) === 0)
  101. {
  102. $value = '(NULL)';
  103. }
  104. elseif ((is_string($value) AND array_key_exists($value, $this->_parameters)) === FALSE)
  105. {
  106. // Quote the value, it is not a parameter
  107. $value = $db->quote($value);
  108. }
  109. if ($column)
  110. {
  111. if (is_array($column))
  112. {
  113. // Use the column name
  114. $column = $db->quote_identifier(reset($column));
  115. }
  116. else
  117. {
  118. // Apply proper quoting to the column
  119. $column = $db->quote_column($column);
  120. }
  121. }
  122. // Append the statement to the query
  123. $sql .= trim($column.' '.$op.' '.$value);
  124. }
  125. $last_condition = $condition;
  126. }
  127. }
  128. return $sql;
  129. }
  130. /**
  131. * Compiles an array of set values into an SQL partial. Used for UPDATE.
  132. *
  133. * @param object $db Database instance
  134. * @param array $values updated values
  135. * @return string
  136. */
  137. protected function _compile_set(Database $db, array $values)
  138. {
  139. $set = [];
  140. foreach ($values as $group)
  141. {
  142. // Split the set
  143. list ($column, $value) = $group;
  144. // Quote the column name
  145. $column = $db->quote_column($column);
  146. if ((is_string($value) AND array_key_exists($value, $this->_parameters)) === FALSE)
  147. {
  148. // Quote the value, it is not a parameter
  149. $value = $db->quote($value);
  150. }
  151. $set[$column] = $column.' = '.$value;
  152. }
  153. return implode(', ', $set);
  154. }
  155. /**
  156. * Compiles an array of GROUP BY columns into an SQL partial.
  157. *
  158. * @param object $db Database instance
  159. * @param array $columns
  160. * @return string
  161. */
  162. protected function _compile_group_by(Database $db, array $columns)
  163. {
  164. $group = [];
  165. foreach ($columns as $column)
  166. {
  167. if (is_array($column))
  168. {
  169. // Use the column alias
  170. $column = $db->quote_identifier(end($column));
  171. }
  172. else
  173. {
  174. // Apply proper quoting to the column
  175. $column = $db->quote_column($column);
  176. }
  177. $group[] = $column;
  178. }
  179. return 'GROUP BY '.implode(', ', $group);
  180. }
  181. /**
  182. * Compiles an array of ORDER BY statements into an SQL partial.
  183. *
  184. * @param Database $db Database instance
  185. * @param array $columns sorting columns
  186. *
  187. * @return string
  188. * @throws Database_Exception
  189. */
  190. protected function _compile_order_by(Database $db, array $columns)
  191. {
  192. $sort = [];
  193. foreach ($columns as $group)
  194. {
  195. list ($column, $direction) = $group;
  196. if (is_array($column))
  197. {
  198. // Use the column alias
  199. $column = $db->quote_identifier(end($column));
  200. }
  201. else
  202. {
  203. // Apply proper quoting to the column
  204. $column = $db->quote_column($column);
  205. }
  206. if ($direction)
  207. {
  208. // Make the direction uppercase
  209. $direction = ' '.strtoupper($direction);
  210. // Make sure direction is either ASC or DESC to prevent injections
  211. if ( ! in_array($direction, [' ASC', ' DESC'])) {
  212. throw new Database_Exception('Invalid sorting direction: ' . $direction);
  213. }
  214. }
  215. $sort[] = $column.$direction;
  216. }
  217. return 'ORDER BY '.implode(', ', $sort);
  218. }
  219. /**
  220. * Reset the current builder status.
  221. *
  222. * @return $this
  223. */
  224. abstract public function reset();
  225. } // End Database_Query_Builder