You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 lines
4.8 KiB

  1. <?php
  2. /**
  3. * @copyright NetMonsters <team@netmonsters.ru>
  4. * @link http://netmonsters.ru
  5. * @package Majestic
  6. * @subpackage db
  7. * @since 2010-02-19
  8. * @version SVN: $Id$
  9. * @filesource $URL$
  10. */
  11. /**
  12. * @property MySQLiDriver $driver
  13. * @property MySQLi_Result $result
  14. */
  15. class MySQLiStatement extends DbStatement
  16. {
  17. protected $map = null;
  18. public function bindParam($param, &$value)
  19. {
  20. if ($this->map === null) {
  21. $this->mapPlaceholders();
  22. }
  23. if (count($this->map) > 0) {
  24. if (!is_string($param) && !is_int($param)) {
  25. throw new GeneralException('Placeholder must be an integer or string');
  26. }
  27. if (is_object($value) && ! ($value instanceof DbExpr)) {
  28. throw new GeneralException('Objects excepts DbExpr not allowed.');
  29. }
  30. if (isset($this->map[$param])) {
  31. $this->params[$param] = &$value;
  32. return true;
  33. }
  34. }
  35. return false;
  36. }
  37. protected function mapPlaceholders()
  38. {
  39. $matches = array();
  40. if(preg_match_all('/(\?|:[A-z0-9_]+)/u', $this->request, $matches, PREG_OFFSET_CAPTURE)) {
  41. $noname = 0;
  42. foreach ($matches[0] as $id=>$match) {
  43. $match[2] = $matches[1][$id][0];
  44. $name = ($match[2][0] === ':') ? ltrim($match[2], ':') : $noname++;
  45. $this->map[$name]['placeholder'] = $match[0];
  46. $this->map[$name]['offset'][] = $match[1];
  47. }
  48. }
  49. }
  50. protected function assemble()
  51. {
  52. if (empty($this->map)) {
  53. return $this->request;
  54. }
  55. $query = $this->request;
  56. $placeholders = array();
  57. foreach($this->map as $name => $place) {
  58. $value = $this->driver->quote($this->params[$name]);
  59. foreach ($place['offset'] as $offset) {
  60. $placeholders[$offset] = array('placeholder' => $place['placeholder'], 'value' => $value);
  61. }
  62. }
  63. ksort($placeholders);
  64. $increment = 0;
  65. foreach($placeholders as $current_offset => $placeholder) {
  66. $offset = $current_offset + $increment;
  67. $length = mb_strlen($placeholder['placeholder']);
  68. $query = mb_substr($query, 0, $offset) . $placeholder['value'] . mb_substr($query, $offset + $length);
  69. $increment = (($increment - $length) + mb_strlen($placeholder['value']));
  70. }
  71. return $query;
  72. }
  73. /**
  74. * Fetches single row
  75. *
  76. * @param mixed $style
  77. * @return mixed
  78. * @throws GeneralException
  79. */
  80. public function fetch($style = Db::FETCH_OBJ)
  81. {
  82. if (!$this->result) {
  83. return false;
  84. }
  85. switch ($style) {
  86. case Db::FETCH_OBJ:
  87. $row = $this->result->fetch_object();
  88. break;
  89. case Db::FETCH_NUM:
  90. $row = $this->result->fetch_array(MYSQLI_NUM);
  91. break;
  92. case Db::FETCH_ASSOC:
  93. $row = $this->result->fetch_assoc();
  94. break;
  95. case Db::FETCH_BOTH:
  96. $row = $this->result->fetch_array(MYSQLI_BOTH);
  97. break;
  98. default:
  99. throw new GeneralException('Invalid fetch mode "' . $style . '" specified');
  100. }
  101. return $row;
  102. }
  103. /**
  104. * @param string $class
  105. * @return object
  106. */
  107. public function fetchObject($class = 'stdClass')
  108. {
  109. return $this->result->fetch_object($class);
  110. }
  111. /**
  112. * @return array
  113. */
  114. public function fetchPairs()
  115. {
  116. $data = array();
  117. while ($row = $this->fetch(Db::FETCH_NUM)) {
  118. $data[$row[0]] = $row[1];
  119. }
  120. return $data;
  121. }
  122. public function close()
  123. {
  124. if ($this->result !== null) {
  125. $this->result->close();
  126. $this->result = null;
  127. }
  128. }
  129. public function affectedRows()
  130. {
  131. return $this->driver->getConnection()->affected_rows;
  132. }
  133. public function numRows()
  134. {
  135. if ($this->result) {
  136. return $this->result->num_rows;
  137. }
  138. return false;
  139. }
  140. protected function driverExecute($request)
  141. {
  142. /**
  143. * @var MySQLi
  144. */
  145. $mysqli = $this->driver->getConnection();
  146. if (Config::get('PROFILER_DETAILS')) {
  147. $profiler = Profiler::getInstance()->profilerCommand('MySQL', $request);
  148. $result = $mysqli->query($request);
  149. $profiler->end();
  150. } else {
  151. $result = $mysqli->query($request);
  152. }
  153. if ($result === false) {
  154. $message = $mysqli->error . "\nQuery: \"" . $request . '"';
  155. throw new GeneralException($message, $mysqli->errno);
  156. }
  157. if ($result instanceof MySQLi_Result) {
  158. $this->result = $result;
  159. }
  160. return true;
  161. }
  162. }