PageRenderTime 24ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/App/Library/vendor/doctrine/dbal/lib/Doctrine/DBAL/SQLParserUtils.php

https://gitlab.com/aleksbenmaza/PPE_NEW
PHP | 243 lines | 215 code | 3 blank | 25 comment | 0 complexity | f1f7a3fed7d680c9cf5e0ff8b6e83ba7 MD5 | raw file
  1. <?php
  2. /*
  3. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  4. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  5. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  6. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  7. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  8. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  9. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  10. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  11. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  13. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  14. *
  15. * This software consists of voluntary contributions made by many individuals
  16. * and is licensed under the MIT license. For more information, see
  17. * <http://www.doctrine-project.org>.
  18. */
  19. namespace Doctrine\DBAL;
  20. /**
  21. * Utility class that parses sql statements with regard to types and parameters.
  22. *
  23. * @link www.doctrine-project.org
  24. * @since 2.0
  25. * @author Benjamin Eberlei <kontakt@beberlei.de>
  26. */
  27. class SQLParserUtils
  28. {
  29. const POSITIONAL_TOKEN = '\?';
  30. const NAMED_TOKEN = '(?<!:):[a-zA-Z_][a-zA-Z0-9_]*';
  31. // Quote characters within string literals can be preceded by a backslash.
  32. const ESCAPED_SINGLE_QUOTED_TEXT = "'(?:[^'\\\\]|\\\\'?|'')*'";
  33. const ESCAPED_DOUBLE_QUOTED_TEXT = '"(?:[^"\\\\]|\\\\"?)*"';
  34. const ESCAPED_BACKTICK_QUOTED_TEXT = '`(?:[^`\\\\]|\\\\`?)*`';
  35. const ESCAPED_BRACKET_QUOTED_TEXT = '(?<!\bARRAY)\[(?:[^\]])*\]';
  36. /**
  37. * Gets an array of the placeholders in an sql statements as keys and their positions in the query string.
  38. *
  39. * Returns an integer => integer pair (indexed from zero) for a positional statement
  40. * and a string => int[] pair for a named statement.
  41. *
  42. * @param string $statement
  43. * @param boolean $isPositional
  44. *
  45. * @return array
  46. */
  47. static public function getPlaceholderPositions($statement, $isPositional = true)
  48. {
  49. $match = ($isPositional) ? '?' : ':';
  50. if (strpos($statement, $match) === false) {
  51. return array();
  52. }
  53. $token = ($isPositional) ? self::POSITIONAL_TOKEN : self::NAMED_TOKEN;
  54. $paramMap = array();
  55. foreach (self::getUnquotedStatementFragments($statement) as $fragment) {
  56. preg_match_all("/$token/", $fragment[0], $matches, PREG_OFFSET_CAPTURE);
  57. foreach ($matches[0] as $placeholder) {
  58. if ($isPositional) {
  59. $paramMap[] = $placeholder[1] + $fragment[1];
  60. } else {
  61. $pos = $placeholder[1] + $fragment[1];
  62. $paramMap[$pos] = substr($placeholder[0], 1, strlen($placeholder[0]));
  63. }
  64. }
  65. }
  66. return $paramMap;
  67. }
  68. /**
  69. * For a positional query this method can rewrite the sql statement with regard to array parameters.
  70. *
  71. * @param string $query The SQL query to execute.
  72. * @param array $params The parameters to bind to the query.
  73. * @param array $types The types the previous parameters are in.
  74. *
  75. * @return array
  76. *
  77. * @throws SQLParserUtilsException
  78. */
  79. static public function expandListParameters($query, $params, $types)
  80. {
  81. $isPositional = is_int(key($params));
  82. $arrayPositions = array();
  83. $bindIndex = -1;
  84. if ($isPositional) {
  85. ksort($params);
  86. ksort($types);
  87. }
  88. foreach ($types as $name => $type) {
  89. ++$bindIndex;
  90. if ($type !== Connection::PARAM_INT_ARRAY && $type !== Connection::PARAM_STR_ARRAY) {
  91. continue;
  92. }
  93. if ($isPositional) {
  94. $name = $bindIndex;
  95. }
  96. $arrayPositions[$name] = false;
  97. }
  98. if (( ! $arrayPositions && $isPositional)) {
  99. return array($query, $params, $types);
  100. }
  101. $paramPos = self::getPlaceholderPositions($query, $isPositional);
  102. if ($isPositional) {
  103. $paramOffset = 0;
  104. $queryOffset = 0;
  105. $params = array_values($params);
  106. $types = array_values($types);
  107. foreach ($paramPos as $needle => $needlePos) {
  108. if ( ! isset($arrayPositions[$needle])) {
  109. continue;
  110. }
  111. $needle += $paramOffset;
  112. $needlePos += $queryOffset;
  113. $count = count($params[$needle]);
  114. $params = array_merge(
  115. array_slice($params, 0, $needle),
  116. $params[$needle],
  117. array_slice($params, $needle + 1)
  118. );
  119. $types = array_merge(
  120. array_slice($types, 0, $needle),
  121. $count ?
  122. array_fill(0, $count, $types[$needle] - Connection::ARRAY_PARAM_OFFSET) : // array needles are at PDO::PARAM_* + 100
  123. array(),
  124. array_slice($types, $needle + 1)
  125. );
  126. $expandStr = $count ? implode(", ", array_fill(0, $count, "?")) : 'NULL';
  127. $query = substr($query, 0, $needlePos) . $expandStr . substr($query, $needlePos + 1);
  128. $paramOffset += ($count - 1); // Grows larger by number of parameters minus the replaced needle.
  129. $queryOffset += (strlen($expandStr) - 1);
  130. }
  131. return array($query, $params, $types);
  132. }
  133. $queryOffset = 0;
  134. $typesOrd = array();
  135. $paramsOrd = array();
  136. foreach ($paramPos as $pos => $paramName) {
  137. $paramLen = strlen($paramName) + 1;
  138. $value = static::extractParam($paramName, $params, true);
  139. if ( ! isset($arrayPositions[$paramName]) && ! isset($arrayPositions[':' . $paramName])) {
  140. $pos += $queryOffset;
  141. $queryOffset -= ($paramLen - 1);
  142. $paramsOrd[] = $value;
  143. $typesOrd[] = static::extractParam($paramName, $types, false, \PDO::PARAM_STR);
  144. $query = substr($query, 0, $pos) . '?' . substr($query, ($pos + $paramLen));
  145. continue;
  146. }
  147. $count = count($value);
  148. $expandStr = $count > 0 ? implode(', ', array_fill(0, $count, '?')) : 'NULL';
  149. foreach ($value as $val) {
  150. $paramsOrd[] = $val;
  151. $typesOrd[] = static::extractParam($paramName, $types, false) - Connection::ARRAY_PARAM_OFFSET;
  152. }
  153. $pos += $queryOffset;
  154. $queryOffset += (strlen($expandStr) - $paramLen);
  155. $query = substr($query, 0, $pos) . $expandStr . substr($query, ($pos + $paramLen));
  156. }
  157. return array($query, $paramsOrd, $typesOrd);
  158. }
  159. /**
  160. * Slice the SQL statement around pairs of quotes and
  161. * return string fragments of SQL outside of quoted literals.
  162. * Each fragment is captured as a 2-element array:
  163. *
  164. * 0 => matched fragment string,
  165. * 1 => offset of fragment in $statement
  166. *
  167. * @param string $statement
  168. * @return array
  169. */
  170. static private function getUnquotedStatementFragments($statement)
  171. {
  172. $literal = self::ESCAPED_SINGLE_QUOTED_TEXT . '|' .
  173. self::ESCAPED_DOUBLE_QUOTED_TEXT . '|' .
  174. self::ESCAPED_BACKTICK_QUOTED_TEXT . '|' .
  175. self::ESCAPED_BRACKET_QUOTED_TEXT;
  176. preg_match_all("/([^'\"`\[]+)(?:$literal)?/s", $statement, $fragments, PREG_OFFSET_CAPTURE);
  177. return $fragments[1];
  178. }
  179. /**
  180. * @param string $paramName The name of the parameter (without a colon in front)
  181. * @param array $paramsOrTypes A hash of parameters or types
  182. * @param bool $isParam
  183. * @param mixed $defaultValue An optional default value. If omitted, an exception is thrown
  184. *
  185. * @throws SQLParserUtilsException
  186. * @return mixed
  187. */
  188. static private function extractParam($paramName, $paramsOrTypes, $isParam, $defaultValue = null)
  189. {
  190. if (array_key_exists($paramName, $paramsOrTypes)) {
  191. return $paramsOrTypes[$paramName];
  192. }
  193. // Hash keys can be prefixed with a colon for compatibility
  194. if (array_key_exists(':' . $paramName, $paramsOrTypes)) {
  195. return $paramsOrTypes[':' . $paramName];
  196. }
  197. if (null !== $defaultValue) {
  198. return $defaultValue;
  199. }
  200. if ($isParam) {
  201. throw SQLParserUtilsException::missingParam($paramName);
  202. }
  203. throw SQLParserUtilsException::missingType($paramName);
  204. }
  205. }