PageRenderTime 54ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php

http://github.com/doctrine/dbal
PHP | 368 lines | 228 code | 64 blank | 76 comment | 24 complexity | 6f8176fc06bd3fc461f5e429b75fdf62 MD5 | raw file
Possible License(s): Unlicense
  1. <?php
  2. namespace Doctrine\DBAL\Driver\SQLAnywhere;
  3. use Doctrine\DBAL\Driver\Statement;
  4. use Doctrine\DBAL\Driver\StatementIterator;
  5. use Doctrine\DBAL\FetchMode;
  6. use Doctrine\DBAL\ParameterType;
  7. use IteratorAggregate;
  8. use PDO;
  9. use ReflectionClass;
  10. use ReflectionObject;
  11. use stdClass;
  12. use function array_key_exists;
  13. use function func_get_args;
  14. use function func_num_args;
  15. use function gettype;
  16. use function is_array;
  17. use function is_int;
  18. use function is_object;
  19. use function is_resource;
  20. use function is_string;
  21. use function sasql_fetch_array;
  22. use function sasql_fetch_assoc;
  23. use function sasql_fetch_object;
  24. use function sasql_fetch_row;
  25. use function sasql_prepare;
  26. use function sasql_stmt_affected_rows;
  27. use function sasql_stmt_bind_param_ex;
  28. use function sasql_stmt_errno;
  29. use function sasql_stmt_error;
  30. use function sasql_stmt_execute;
  31. use function sasql_stmt_field_count;
  32. use function sasql_stmt_reset;
  33. use function sasql_stmt_result_metadata;
  34. use function sprintf;
  35. use const SASQL_BOTH;
  36. /**
  37. * SAP SQL Anywhere implementation of the Statement interface.
  38. */
  39. class SQLAnywhereStatement implements IteratorAggregate, Statement
  40. {
  41. /** @var resource The connection resource. */
  42. private $conn;
  43. /** @var string Name of the default class to instantiate when fetching class instances. */
  44. private $defaultFetchClass = '\stdClass';
  45. /** @var mixed[] Constructor arguments for the default class to instantiate when fetching class instances. */
  46. private $defaultFetchClassCtorArgs = [];
  47. /** @var int Default fetch mode to use. */
  48. private $defaultFetchMode = FetchMode::MIXED;
  49. /** @var resource The result set resource to fetch. */
  50. private $result;
  51. /** @var resource The prepared SQL statement to execute. */
  52. private $stmt;
  53. /** @var mixed[] The references to bound parameter values. */
  54. private $boundValues = [];
  55. /**
  56. * Prepares given statement for given connection.
  57. *
  58. * @param resource $conn The connection resource to use.
  59. * @param string $sql The SQL statement to prepare.
  60. *
  61. * @throws SQLAnywhereException
  62. */
  63. public function __construct($conn, $sql)
  64. {
  65. if (! is_resource($conn)) {
  66. throw new SQLAnywhereException('Invalid SQL Anywhere connection resource: ' . $conn);
  67. }
  68. $this->conn = $conn;
  69. $this->stmt = sasql_prepare($conn, $sql);
  70. if (! is_resource($this->stmt)) {
  71. throw SQLAnywhereException::fromSQLAnywhereError($conn);
  72. }
  73. }
  74. /**
  75. * {@inheritdoc}
  76. *
  77. * @throws SQLAnywhereException
  78. */
  79. public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null)
  80. {
  81. switch ($type) {
  82. case ParameterType::INTEGER:
  83. case ParameterType::BOOLEAN:
  84. $type = 'i';
  85. break;
  86. case ParameterType::LARGE_OBJECT:
  87. $type = 'b';
  88. break;
  89. case ParameterType::NULL:
  90. case ParameterType::STRING:
  91. case ParameterType::BINARY:
  92. $type = 's';
  93. break;
  94. default:
  95. throw new SQLAnywhereException('Unknown type: ' . $type);
  96. }
  97. $this->boundValues[$column] =& $variable;
  98. if (! sasql_stmt_bind_param_ex($this->stmt, $column - 1, $variable, $type, $variable === null)) {
  99. throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt);
  100. }
  101. return true;
  102. }
  103. /**
  104. * {@inheritdoc}
  105. */
  106. public function bindValue($param, $value, $type = ParameterType::STRING)
  107. {
  108. return $this->bindParam($param, $value, $type);
  109. }
  110. /**
  111. * {@inheritdoc}
  112. *
  113. * @throws SQLAnywhereException
  114. */
  115. public function closeCursor()
  116. {
  117. if (! sasql_stmt_reset($this->stmt)) {
  118. throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt);
  119. }
  120. return true;
  121. }
  122. /**
  123. * {@inheritdoc}
  124. */
  125. public function columnCount()
  126. {
  127. return sasql_stmt_field_count($this->stmt);
  128. }
  129. /**
  130. * {@inheritdoc}
  131. */
  132. public function errorCode()
  133. {
  134. return sasql_stmt_errno($this->stmt);
  135. }
  136. /**
  137. * {@inheritdoc}
  138. */
  139. public function errorInfo()
  140. {
  141. return sasql_stmt_error($this->stmt);
  142. }
  143. /**
  144. * {@inheritdoc}
  145. *
  146. * @throws SQLAnywhereException
  147. */
  148. public function execute($params = null)
  149. {
  150. if (is_array($params)) {
  151. $hasZeroIndex = array_key_exists(0, $params);
  152. foreach ($params as $key => $val) {
  153. if ($hasZeroIndex && is_int($key)) {
  154. $this->bindValue($key + 1, $val);
  155. } else {
  156. $this->bindValue($key, $val);
  157. }
  158. }
  159. }
  160. if (! sasql_stmt_execute($this->stmt)) {
  161. throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt);
  162. }
  163. $this->result = sasql_stmt_result_metadata($this->stmt);
  164. return true;
  165. }
  166. /**
  167. * {@inheritdoc}
  168. *
  169. * @throws SQLAnywhereException
  170. */
  171. public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0)
  172. {
  173. if (! is_resource($this->result)) {
  174. return false;
  175. }
  176. $fetchMode = $fetchMode ?: $this->defaultFetchMode;
  177. switch ($fetchMode) {
  178. case FetchMode::COLUMN:
  179. return $this->fetchColumn();
  180. case FetchMode::ASSOCIATIVE:
  181. return sasql_fetch_assoc($this->result);
  182. case FetchMode::MIXED:
  183. return sasql_fetch_array($this->result, SASQL_BOTH);
  184. case FetchMode::CUSTOM_OBJECT:
  185. $className = $this->defaultFetchClass;
  186. $ctorArgs = $this->defaultFetchClassCtorArgs;
  187. if (func_num_args() >= 2) {
  188. $args = func_get_args();
  189. $className = $args[1];
  190. $ctorArgs = $args[2] ?? [];
  191. }
  192. $result = sasql_fetch_object($this->result);
  193. if ($result instanceof stdClass) {
  194. $result = $this->castObject($result, $className, $ctorArgs);
  195. }
  196. return $result;
  197. case FetchMode::NUMERIC:
  198. return sasql_fetch_row($this->result);
  199. case FetchMode::STANDARD_OBJECT:
  200. return sasql_fetch_object($this->result);
  201. default:
  202. throw new SQLAnywhereException('Fetch mode is not supported: ' . $fetchMode);
  203. }
  204. }
  205. /**
  206. * {@inheritdoc}
  207. */
  208. public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null)
  209. {
  210. $rows = [];
  211. switch ($fetchMode) {
  212. case FetchMode::CUSTOM_OBJECT:
  213. while (($row = $this->fetch(...func_get_args())) !== false) {
  214. $rows[] = $row;
  215. }
  216. break;
  217. case FetchMode::COLUMN:
  218. while (($row = $this->fetchColumn()) !== false) {
  219. $rows[] = $row;
  220. }
  221. break;
  222. default:
  223. while (($row = $this->fetch($fetchMode)) !== false) {
  224. $rows[] = $row;
  225. }
  226. }
  227. return $rows;
  228. }
  229. /**
  230. * {@inheritdoc}
  231. */
  232. public function fetchColumn($columnIndex = 0)
  233. {
  234. $row = $this->fetch(FetchMode::NUMERIC);
  235. if ($row === false) {
  236. return false;
  237. }
  238. return $row[$columnIndex] ?? null;
  239. }
  240. /**
  241. * {@inheritdoc}
  242. */
  243. public function getIterator()
  244. {
  245. return new StatementIterator($this);
  246. }
  247. /**
  248. * {@inheritdoc}
  249. */
  250. public function rowCount()
  251. {
  252. return sasql_stmt_affected_rows($this->stmt);
  253. }
  254. /**
  255. * {@inheritdoc}
  256. */
  257. public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null)
  258. {
  259. $this->defaultFetchMode = $fetchMode;
  260. $this->defaultFetchClass = $arg2 ?: $this->defaultFetchClass;
  261. $this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs;
  262. return true;
  263. }
  264. /**
  265. * Casts a stdClass object to the given class name mapping its' properties.
  266. *
  267. * @param stdClass $sourceObject Object to cast from.
  268. * @param string|object $destinationClass Name of the class or class instance to cast to.
  269. * @param mixed[] $ctorArgs Arguments to use for constructing the destination class instance.
  270. *
  271. * @return object
  272. *
  273. * @throws SQLAnywhereException
  274. */
  275. private function castObject(stdClass $sourceObject, $destinationClass, array $ctorArgs = [])
  276. {
  277. if (! is_string($destinationClass)) {
  278. if (! is_object($destinationClass)) {
  279. throw new SQLAnywhereException(sprintf(
  280. 'Destination class has to be of type string or object, %s given.',
  281. gettype($destinationClass)
  282. ));
  283. }
  284. } else {
  285. $destinationClass = new ReflectionClass($destinationClass);
  286. $destinationClass = $destinationClass->newInstanceArgs($ctorArgs);
  287. }
  288. $sourceReflection = new ReflectionObject($sourceObject);
  289. $destinationClassReflection = new ReflectionObject($destinationClass);
  290. foreach ($sourceReflection->getProperties() as $sourceProperty) {
  291. $sourceProperty->setAccessible(true);
  292. $name = $sourceProperty->getName();
  293. $value = $sourceProperty->getValue($sourceObject);
  294. if ($destinationClassReflection->hasProperty($name)) {
  295. $destinationProperty = $destinationClassReflection->getProperty($name);
  296. $destinationProperty->setAccessible(true);
  297. $destinationProperty->setValue($destinationClass, $value);
  298. } else {
  299. $destinationClass->$name = $value;
  300. }
  301. }
  302. return $destinationClass;
  303. }
  304. }