Statement.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815
  1. <?php
  2. namespace Doctrine\DBAL;
  3. use Doctrine\DBAL\Abstraction\Result;
  4. use Doctrine\DBAL\Driver\Exception;
  5. use Doctrine\DBAL\Driver\Statement as DriverStatement;
  6. use Doctrine\DBAL\Exception\NoKeyValue;
  7. use Doctrine\DBAL\Platforms\AbstractPlatform;
  8. use Doctrine\DBAL\Result as BaseResult;
  9. use Doctrine\DBAL\Types\Type;
  10. use Doctrine\Deprecations\Deprecation;
  11. use IteratorAggregate;
  12. use PDO;
  13. use PDOStatement;
  14. use Throwable;
  15. use Traversable;
  16. use function array_shift;
  17. use function is_array;
  18. use function is_string;
  19. /**
  20. * A thin wrapper around a Doctrine\DBAL\Driver\Statement that adds support
  21. * for logging, DBAL mapping types, etc.
  22. */
  23. class Statement implements IteratorAggregate, DriverStatement, Result
  24. {
  25. /**
  26. * The SQL statement.
  27. *
  28. * @var string
  29. */
  30. protected $sql;
  31. /**
  32. * The bound parameters.
  33. *
  34. * @var mixed[]
  35. */
  36. protected $params = [];
  37. /**
  38. * The parameter types.
  39. *
  40. * @var int[]|string[]
  41. */
  42. protected $types = [];
  43. /**
  44. * The underlying driver statement.
  45. *
  46. * @var \Doctrine\DBAL\Driver\Statement
  47. */
  48. protected $stmt;
  49. /**
  50. * The underlying database platform.
  51. *
  52. * @var AbstractPlatform
  53. */
  54. protected $platform;
  55. /**
  56. * The connection this statement is bound to and executed on.
  57. *
  58. * @var Connection
  59. */
  60. protected $conn;
  61. /**
  62. * Creates a new <tt>Statement</tt> for the given SQL and <tt>Connection</tt>.
  63. *
  64. * @internal The statement can be only instantiated by {@link Connection}.
  65. *
  66. * @param string $sql The SQL of the statement.
  67. * @param Connection $conn The connection on which the statement should be executed.
  68. */
  69. public function __construct($sql, Connection $conn)
  70. {
  71. $this->sql = $sql;
  72. $this->stmt = $conn->getWrappedConnection()->prepare($sql);
  73. $this->conn = $conn;
  74. $this->platform = $conn->getDatabasePlatform();
  75. }
  76. /**
  77. * Binds a parameter value to the statement.
  78. *
  79. * The value can optionally be bound with a PDO binding type or a DBAL mapping type.
  80. * If bound with a DBAL mapping type, the binding type is derived from the mapping
  81. * type and the value undergoes the conversion routines of the mapping type before
  82. * being bound.
  83. *
  84. * @param string|int $param The name or position of the parameter.
  85. * @param mixed $value The value of the parameter.
  86. * @param mixed $type Either a PDO binding type or a DBAL mapping type name or instance.
  87. *
  88. * @return bool TRUE on success, FALSE on failure.
  89. */
  90. public function bindValue($param, $value, $type = ParameterType::STRING)
  91. {
  92. $this->params[$param] = $value;
  93. $this->types[$param] = $type;
  94. if ($type !== null) {
  95. if (is_string($type)) {
  96. $type = Type::getType($type);
  97. }
  98. if ($type instanceof Type) {
  99. $value = $type->convertToDatabaseValue($value, $this->platform);
  100. $bindingType = $type->getBindingType();
  101. } else {
  102. $bindingType = $type;
  103. }
  104. return $this->stmt->bindValue($param, $value, $bindingType);
  105. }
  106. return $this->stmt->bindValue($param, $value);
  107. }
  108. /**
  109. * Binds a parameter to a value by reference.
  110. *
  111. * Binding a parameter by reference does not support DBAL mapping types.
  112. *
  113. * @param string|int $param The name or position of the parameter.
  114. * @param mixed $variable The reference to the variable to bind.
  115. * @param int $type The PDO binding type.
  116. * @param int|null $length Must be specified when using an OUT bind
  117. * so that PHP allocates enough memory to hold the returned value.
  118. *
  119. * @return bool TRUE on success, FALSE on failure.
  120. */
  121. public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null)
  122. {
  123. $this->params[$param] = $variable;
  124. $this->types[$param] = $type;
  125. if ($this->stmt instanceof PDOStatement) {
  126. $length = $length ?? 0;
  127. }
  128. return $this->stmt->bindParam($param, $variable, $type, $length);
  129. }
  130. /**
  131. * Executes the statement with the currently bound parameters.
  132. *
  133. * @deprecated Statement::execute() is deprecated, use Statement::executeQuery() or executeStatement() instead
  134. *
  135. * @param mixed[]|null $params
  136. *
  137. * @return bool TRUE on success, FALSE on failure.
  138. *
  139. * @throws Exception
  140. */
  141. public function execute($params = null)
  142. {
  143. Deprecation::triggerIfCalledFromOutside(
  144. 'doctrine/dbal',
  145. 'https://github.com/doctrine/dbal/pull/4580',
  146. 'Statement::execute() is deprecated, use Statement::executeQuery() or Statement::executeStatement() instead'
  147. );
  148. if (is_array($params)) {
  149. $this->params = $params;
  150. }
  151. $logger = $this->conn->getConfiguration()->getSQLLogger();
  152. if ($logger) {
  153. $logger->startQuery($this->sql, $this->params, $this->types);
  154. }
  155. try {
  156. $stmt = $this->stmt->execute($params);
  157. } catch (Throwable $ex) {
  158. if ($logger) {
  159. $logger->stopQuery();
  160. }
  161. $this->conn->handleExceptionDuringQuery($ex, $this->sql, $this->params, $this->types);
  162. }
  163. if ($logger) {
  164. $logger->stopQuery();
  165. }
  166. return $stmt;
  167. }
  168. /**
  169. * Executes the statement with the currently bound parameters and return result.
  170. *
  171. * @param mixed[] $params
  172. *
  173. * @throws Exception
  174. */
  175. public function executeQuery(array $params = []): BaseResult
  176. {
  177. if ($params === []) {
  178. $params = null; // Workaround as long execute() exists and used internally.
  179. }
  180. $this->execute($params);
  181. return new ForwardCompatibility\Result($this);
  182. }
  183. /**
  184. * Executes the statement with the currently bound parameters and return affected rows.
  185. *
  186. * @param mixed[] $params
  187. *
  188. * @throws Exception
  189. */
  190. public function executeStatement(array $params = []): int
  191. {
  192. if ($params === []) {
  193. $params = null; // Workaround as long execute() exists and used internally.
  194. }
  195. $this->execute($params);
  196. return $this->rowCount();
  197. }
  198. /**
  199. * Closes the cursor, freeing the database resources used by this statement.
  200. *
  201. * @deprecated Use Result::free() instead.
  202. *
  203. * @return bool TRUE on success, FALSE on failure.
  204. */
  205. public function closeCursor()
  206. {
  207. Deprecation::triggerIfCalledFromOutside(
  208. 'doctrine/dbal',
  209. 'https://github.com/doctrine/dbal/pull/4049',
  210. 'Statement::closeCursor() is deprecated, use Result::free() instead.'
  211. );
  212. return $this->stmt->closeCursor();
  213. }
  214. /**
  215. * Returns the number of columns in the result set.
  216. *
  217. * @return int
  218. */
  219. public function columnCount()
  220. {
  221. return $this->stmt->columnCount();
  222. }
  223. /**
  224. * Fetches the SQLSTATE associated with the last operation on the statement.
  225. *
  226. * @deprecated The error information is available via exceptions.
  227. *
  228. * @return string|int|bool
  229. */
  230. public function errorCode()
  231. {
  232. Deprecation::triggerIfCalledFromOutside(
  233. 'doctrine/dbal',
  234. 'https://github.com/doctrine/dbal/pull/3507',
  235. 'Connection::errorCode() is deprecated, use getCode() or getSQLState() on Exception instead.'
  236. );
  237. return $this->stmt->errorCode();
  238. }
  239. /**
  240. * {@inheritDoc}
  241. *
  242. * @deprecated The error information is available via exceptions.
  243. */
  244. public function errorInfo()
  245. {
  246. Deprecation::triggerIfCalledFromOutside(
  247. 'doctrine/dbal',
  248. 'https://github.com/doctrine/dbal/pull/3507',
  249. 'Connection::errorInfo() is deprecated, use getCode() or getSQLState() on Exception instead.'
  250. );
  251. return $this->stmt->errorInfo();
  252. }
  253. /**
  254. * {@inheritdoc}
  255. *
  256. * @deprecated Use one of the fetch- or iterate-related methods.
  257. */
  258. public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null)
  259. {
  260. Deprecation::triggerIfCalledFromOutside(
  261. 'doctrine/dbal',
  262. 'https://github.com/doctrine/dbal/pull/4019',
  263. 'Statement::setFetchMode() is deprecated, use explicit Result::fetch*() APIs instead.'
  264. );
  265. if ($arg2 === null) {
  266. return $this->stmt->setFetchMode($fetchMode);
  267. }
  268. if ($arg3 === null) {
  269. return $this->stmt->setFetchMode($fetchMode, $arg2);
  270. }
  271. return $this->stmt->setFetchMode($fetchMode, $arg2, $arg3);
  272. }
  273. /**
  274. * Required by interface IteratorAggregate.
  275. *
  276. * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead.
  277. *
  278. * {@inheritdoc}
  279. */
  280. public function getIterator()
  281. {
  282. Deprecation::trigger(
  283. 'doctrine/dbal',
  284. 'https://github.com/doctrine/dbal/pull/4019',
  285. 'Statement::getIterator() is deprecated, use Result::iterateNumeric(), iterateAssociative() ' .
  286. 'or iterateColumn() instead.'
  287. );
  288. return $this->stmt;
  289. }
  290. /**
  291. * {@inheritdoc}
  292. *
  293. * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead.
  294. */
  295. public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0)
  296. {
  297. Deprecation::triggerIfCalledFromOutside(
  298. 'doctrine/dbal',
  299. 'https://github.com/doctrine/dbal/pull/4019',
  300. 'Statement::fetch() is deprecated, use Result::fetchNumeric(), fetchAssociative() or fetchOne() instead.'
  301. );
  302. return $this->stmt->fetch($fetchMode);
  303. }
  304. /**
  305. * {@inheritdoc}
  306. *
  307. * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchFirstColumn() instead.
  308. */
  309. public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null)
  310. {
  311. Deprecation::triggerIfCalledFromOutside(
  312. 'doctrine/dbal',
  313. 'https://github.com/doctrine/dbal/pull/4019',
  314. 'Statement::fetchAll() is deprecated, use Result::fetchAllNumeric(), fetchAllAssociative() or ' .
  315. 'fetchFirstColumn() instead.'
  316. );
  317. if ($ctorArgs !== null) {
  318. return $this->stmt->fetchAll($fetchMode, $fetchArgument, $ctorArgs);
  319. }
  320. if ($fetchArgument !== null) {
  321. return $this->stmt->fetchAll($fetchMode, $fetchArgument);
  322. }
  323. return $this->stmt->fetchAll($fetchMode);
  324. }
  325. /**
  326. * {@inheritDoc}
  327. *
  328. * @deprecated Use fetchOne() instead.
  329. */
  330. public function fetchColumn($columnIndex = 0)
  331. {
  332. Deprecation::triggerIfCalledFromOutside(
  333. 'doctrine/dbal',
  334. 'https://github.com/doctrine/dbal/pull/4019',
  335. 'Statement::fetchColumn() is deprecated, use Result::fetchOne() instead.'
  336. );
  337. return $this->stmt->fetchColumn($columnIndex);
  338. }
  339. /**
  340. * {@inheritdoc}
  341. *
  342. * @deprecated Use Result::fetchNumeric() instead
  343. *
  344. * @throws Exception
  345. */
  346. public function fetchNumeric()
  347. {
  348. Deprecation::triggerIfCalledFromOutside(
  349. 'doctrine/dbal',
  350. 'https://github.com/doctrine/dbal/issues/4554',
  351. 'Statement::%s() is deprecated, use Result::%s() instead.',
  352. __FUNCTION__,
  353. __FUNCTION__
  354. );
  355. try {
  356. if ($this->stmt instanceof Result) {
  357. return $this->stmt->fetchNumeric();
  358. }
  359. return $this->stmt->fetch(FetchMode::NUMERIC);
  360. } catch (Exception $e) {
  361. $this->conn->handleDriverException($e);
  362. }
  363. }
  364. /**
  365. * {@inheritdoc}
  366. *
  367. * @deprecated Use Result::fetchAssociative() instead
  368. *
  369. * @throws Exception
  370. */
  371. public function fetchAssociative()
  372. {
  373. Deprecation::triggerIfCalledFromOutside(
  374. 'doctrine/dbal',
  375. 'https://github.com/doctrine/dbal/issues/4554',
  376. 'Statement::%s() is deprecated, use Result::%s() instead.',
  377. __FUNCTION__,
  378. __FUNCTION__
  379. );
  380. try {
  381. if ($this->stmt instanceof Result) {
  382. return $this->stmt->fetchAssociative();
  383. }
  384. return $this->stmt->fetch(FetchMode::ASSOCIATIVE);
  385. } catch (Exception $e) {
  386. $this->conn->handleDriverException($e);
  387. }
  388. }
  389. /**
  390. * {@inheritDoc}
  391. *
  392. * @deprecated Use Result::fetchOne() instead
  393. *
  394. * @throws Exception
  395. */
  396. public function fetchOne()
  397. {
  398. Deprecation::triggerIfCalledFromOutside(
  399. 'doctrine/dbal',
  400. 'https://github.com/doctrine/dbal/issues/4554',
  401. 'Statement::%s() is deprecated, use Result::%s() instead.',
  402. __FUNCTION__,
  403. __FUNCTION__
  404. );
  405. try {
  406. if ($this->stmt instanceof Result) {
  407. return $this->stmt->fetchOne();
  408. }
  409. return $this->stmt->fetch(FetchMode::COLUMN);
  410. } catch (Exception $e) {
  411. $this->conn->handleDriverException($e);
  412. }
  413. }
  414. /**
  415. * {@inheritdoc}
  416. *
  417. * @deprecated Use Result::fetchAllNumeric() instead
  418. *
  419. * @throws Exception
  420. */
  421. public function fetchAllNumeric(): array
  422. {
  423. Deprecation::triggerIfCalledFromOutside(
  424. 'doctrine/dbal',
  425. 'https://github.com/doctrine/dbal/issues/4554',
  426. 'Statement::%s() is deprecated, use Result::%s() instead.',
  427. __FUNCTION__,
  428. __FUNCTION__
  429. );
  430. try {
  431. if ($this->stmt instanceof Result) {
  432. return $this->stmt->fetchAllNumeric();
  433. }
  434. return $this->stmt->fetchAll(FetchMode::NUMERIC);
  435. } catch (Exception $e) {
  436. $this->conn->handleDriverException($e);
  437. }
  438. }
  439. /**
  440. * {@inheritdoc}
  441. *
  442. * @deprecated Use Result::fetchAllAssociative() instead
  443. *
  444. * @throws Exception
  445. */
  446. public function fetchAllAssociative(): array
  447. {
  448. Deprecation::triggerIfCalledFromOutside(
  449. 'doctrine/dbal',
  450. 'https://github.com/doctrine/dbal/issues/4554',
  451. 'Statement::%s() is deprecated, use Result::%s() instead.',
  452. __FUNCTION__,
  453. __FUNCTION__
  454. );
  455. try {
  456. if ($this->stmt instanceof Result) {
  457. return $this->stmt->fetchAllAssociative();
  458. }
  459. return $this->stmt->fetchAll(FetchMode::ASSOCIATIVE);
  460. } catch (Exception $e) {
  461. $this->conn->handleDriverException($e);
  462. }
  463. }
  464. /**
  465. * Returns an associative array with the keys mapped to the first column and the values mapped to the second column.
  466. *
  467. * The result must contain at least two columns.
  468. *
  469. * @deprecated Use Result::fetchAllKeyValue() instead
  470. *
  471. * @return array<mixed,mixed>
  472. *
  473. * @throws Exception
  474. */
  475. public function fetchAllKeyValue(): array
  476. {
  477. Deprecation::triggerIfCalledFromOutside(
  478. 'doctrine/dbal',
  479. 'https://github.com/doctrine/dbal/issues/4554',
  480. 'Statement::%s() is deprecated, use Result::%s() instead.',
  481. __FUNCTION__,
  482. __FUNCTION__
  483. );
  484. $this->ensureHasKeyValue();
  485. $data = [];
  486. foreach ($this->fetchAllNumeric() as [$key, $value]) {
  487. $data[$key] = $value;
  488. }
  489. return $data;
  490. }
  491. /**
  492. * Returns an associative array with the keys mapped to the first column and the values being
  493. * an associative array representing the rest of the columns and their values.
  494. *
  495. * @deprecated Use Result::fetchAllAssociativeIndexed() instead
  496. *
  497. * @return array<mixed,array<string,mixed>>
  498. *
  499. * @throws Exception
  500. */
  501. public function fetchAllAssociativeIndexed(): array
  502. {
  503. Deprecation::triggerIfCalledFromOutside(
  504. 'doctrine/dbal',
  505. 'https://github.com/doctrine/dbal/issues/4554',
  506. 'Statement::%s() is deprecated, use Result::%s() instead.',
  507. __FUNCTION__,
  508. __FUNCTION__
  509. );
  510. $data = [];
  511. foreach ($this->fetchAll(FetchMode::ASSOCIATIVE) as $row) {
  512. $data[array_shift($row)] = $row;
  513. }
  514. return $data;
  515. }
  516. /**
  517. * {@inheritdoc}
  518. *
  519. * @deprecated Use Result::fetchFirstColumn() instead
  520. *
  521. * @throws Exception
  522. */
  523. public function fetchFirstColumn(): array
  524. {
  525. Deprecation::triggerIfCalledFromOutside(
  526. 'doctrine/dbal',
  527. 'https://github.com/doctrine/dbal/issues/4554',
  528. 'Statement::%s() is deprecated, use Result::%s() instead.',
  529. __FUNCTION__,
  530. __FUNCTION__
  531. );
  532. try {
  533. if ($this->stmt instanceof Result) {
  534. return $this->stmt->fetchFirstColumn();
  535. }
  536. return $this->stmt->fetchAll(FetchMode::COLUMN);
  537. } catch (Exception $e) {
  538. $this->conn->handleDriverException($e);
  539. }
  540. }
  541. /**
  542. * {@inheritDoc}
  543. *
  544. * @deprecated Use Result::iterateNumeric() instead
  545. *
  546. * @return Traversable<int,array<int,mixed>>
  547. *
  548. * @throws Exception
  549. */
  550. public function iterateNumeric(): Traversable
  551. {
  552. Deprecation::triggerIfCalledFromOutside(
  553. 'doctrine/dbal',
  554. 'https://github.com/doctrine/dbal/issues/4554',
  555. 'Statement::%s() is deprecated, use Result::%s() instead.',
  556. __FUNCTION__,
  557. __FUNCTION__
  558. );
  559. try {
  560. if ($this->stmt instanceof Result) {
  561. while (($row = $this->stmt->fetchNumeric()) !== false) {
  562. yield $row;
  563. }
  564. } else {
  565. while (($row = $this->stmt->fetch(FetchMode::NUMERIC)) !== false) {
  566. yield $row;
  567. }
  568. }
  569. } catch (Exception $e) {
  570. $this->conn->handleDriverException($e);
  571. }
  572. }
  573. /**
  574. * {@inheritDoc}
  575. *
  576. * @deprecated Use Result::iterateAssociative() instead
  577. *
  578. * @return Traversable<int,array<string,mixed>>
  579. *
  580. * @throws Exception
  581. */
  582. public function iterateAssociative(): Traversable
  583. {
  584. Deprecation::triggerIfCalledFromOutside(
  585. 'doctrine/dbal',
  586. 'https://github.com/doctrine/dbal/issues/4554',
  587. 'Statement::%s() is deprecated, use Result::%s() instead.',
  588. __FUNCTION__,
  589. __FUNCTION__
  590. );
  591. try {
  592. if ($this->stmt instanceof Result) {
  593. while (($row = $this->stmt->fetchAssociative()) !== false) {
  594. yield $row;
  595. }
  596. } else {
  597. while (($row = $this->stmt->fetch(FetchMode::ASSOCIATIVE)) !== false) {
  598. yield $row;
  599. }
  600. }
  601. } catch (Exception $e) {
  602. $this->conn->handleDriverException($e);
  603. }
  604. }
  605. /**
  606. * Returns an iterator over the result set with the keys mapped to the first column
  607. * and the values mapped to the second column.
  608. *
  609. * The result must contain at least two columns.
  610. *
  611. * @deprecated Use Result::iterateKeyValue() instead
  612. *
  613. * @return Traversable<mixed,mixed>
  614. *
  615. * @throws Exception
  616. */
  617. public function iterateKeyValue(): Traversable
  618. {
  619. Deprecation::triggerIfCalledFromOutside(
  620. 'doctrine/dbal',
  621. 'https://github.com/doctrine/dbal/issues/4554',
  622. 'Statement::%s() is deprecated, use Result::%s() instead.',
  623. __FUNCTION__,
  624. __FUNCTION__
  625. );
  626. $this->ensureHasKeyValue();
  627. foreach ($this->iterateNumeric() as [$key, $value]) {
  628. yield $key => $value;
  629. }
  630. }
  631. /**
  632. * Returns an iterator over the result set with the keys mapped to the first column and the values being
  633. * an associative array representing the rest of the columns and their values.
  634. *
  635. * @deprecated Use Result::iterateAssociativeIndexed() instead
  636. *
  637. * @return Traversable<mixed,array<string,mixed>>
  638. *
  639. * @throws Exception
  640. */
  641. public function iterateAssociativeIndexed(): Traversable
  642. {
  643. Deprecation::triggerIfCalledFromOutside(
  644. 'doctrine/dbal',
  645. 'https://github.com/doctrine/dbal/issues/4554',
  646. 'Statement::%s() is deprecated, use Result::%s() instead.',
  647. __FUNCTION__,
  648. __FUNCTION__
  649. );
  650. while (($row = $this->stmt->fetch(FetchMode::ASSOCIATIVE)) !== false) {
  651. yield array_shift($row) => $row;
  652. }
  653. }
  654. /**
  655. * {@inheritDoc}
  656. *
  657. * @deprecated Use Result::iterateColumn() instead
  658. *
  659. * @return Traversable<int,mixed>
  660. *
  661. * @throws Exception
  662. */
  663. public function iterateColumn(): Traversable
  664. {
  665. Deprecation::triggerIfCalledFromOutside(
  666. 'doctrine/dbal',
  667. 'https://github.com/doctrine/dbal/issues/4554',
  668. 'Statement::%s() is deprecated, use Result::%s() instead.',
  669. __FUNCTION__,
  670. __FUNCTION__
  671. );
  672. try {
  673. if ($this->stmt instanceof Result) {
  674. while (($value = $this->stmt->fetchOne()) !== false) {
  675. yield $value;
  676. }
  677. } else {
  678. while (($value = $this->stmt->fetch(FetchMode::COLUMN)) !== false) {
  679. yield $value;
  680. }
  681. }
  682. } catch (Exception $e) {
  683. $this->conn->handleDriverException($e);
  684. }
  685. }
  686. /**
  687. * Returns the number of rows affected by the last execution of this statement.
  688. *
  689. * @return int The number of affected rows.
  690. */
  691. public function rowCount()
  692. {
  693. return $this->stmt->rowCount();
  694. }
  695. public function free(): void
  696. {
  697. if ($this->stmt instanceof Result) {
  698. $this->stmt->free();
  699. return;
  700. }
  701. $this->stmt->closeCursor();
  702. }
  703. /**
  704. * Gets the wrapped driver statement.
  705. *
  706. * @return \Doctrine\DBAL\Driver\Statement
  707. */
  708. public function getWrappedStatement()
  709. {
  710. return $this->stmt;
  711. }
  712. private function ensureHasKeyValue(): void
  713. {
  714. $columnCount = $this->columnCount();
  715. if ($columnCount < 2) {
  716. throw NoKeyValue::fromColumnCount($columnCount);
  717. }
  718. }
  719. }