00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00034 abstract class PreparedStatementCommon {
00035
00040 protected $conn;
00041
00046 protected $limit = 0;
00047
00053 protected $offset = 0;
00054
00059 protected $sql;
00060
00068 protected $sql_cache;
00069
00074 protected $sql_cache_valid = false;
00075
00080 protected $positions;
00081
00082
00087 protected $positionsCount;
00088
00093 protected $boundInVars = array();
00094
00099 protected $resultSet;
00100
00105 protected $updateCount;
00106
00115 public function __construct(Connection $conn, $sql)
00116 {
00117 $this->conn = $conn;
00118 $this->sql = $sql;
00119
00120 $this->positions = $this->parseQuery ( $sql );
00121
00122 $this->positionsCount = count ( $this->positions );
00123 }
00124
00131 protected function parseQuery ( $sql )
00132 {
00133
00134 $positions = array();
00135
00136 if ( preg_match_all ( '([\?]|[\']|[\"]|[\\\])', $sql, $matches, PREG_OFFSET_CAPTURE ) !== 0 ) {
00137 $matches = $matches['0'];
00138 $open = NULL;
00139
00140 for ( $i = 0, $j = count ( $matches ); $i < $j; $i++ ) {
00141 switch ( $matches[$i]['0'] ) {
00142
00143
00144 case $open:
00145 $open = NULL;
00146 break;
00147
00148 case '"':
00149 case "'":
00150 $open = $matches[$i]['0'];
00151 break;
00152
00153 case '\\':
00154 $next_match = $matches[$i+1]['0'];
00155 if ( $next_match === '"' || $next_match === "'" ) {
00156 $i++;
00157 }
00158 unset ( $next_match );
00159 break;
00160
00161
00162 default:
00163 if ( $open === NULL ) {
00164 $positions[] = $matches[$i]['1'];
00165 }
00166 }
00167 unset ( $matches[$i] );
00168 }
00169 unset ( $open, $matches, $i, $j );
00170 }
00171
00172 return $positions;
00173
00174 }
00175
00179 public function setLimit($v)
00180 {
00181 $this->limit = (int) $v;
00182 }
00183
00187 public function getLimit()
00188 {
00189 return $this->limit;
00190 }
00191
00195 public function setOffset($v)
00196 {
00197 $this->offset = (int) $v;
00198 }
00199
00203 public function getOffset()
00204 {
00205 return $this->offset;
00206 }
00207
00211 public function getResultSet()
00212 {
00213 return $this->resultSet;
00214 }
00215
00219 public function getUpdateCount()
00220 {
00221 return $this->updateCount;
00222 }
00223
00227 public function getMoreResults()
00228 {
00229 if ($this->resultSet) $this->resultSet->close();
00230 $this->resultSet = null;
00231 return false;
00232 }
00233
00237 public function getConnection()
00238 {
00239 return $this->conn;
00240 }
00241
00247 public function getResource()
00248 {
00249 return null;
00250 }
00251
00255 public function close()
00256 {
00257 }
00258
00267 protected function replaceParams()
00268 {
00269
00270 if ( $this->sql_cache_valid === true ) {
00271 return $this->sql_cache;
00272 }
00273
00274
00275 $sql = '';
00276 $last_position = 0;
00277
00278 for ($position = 0; $position < $this->positionsCount; $position++) {
00279 if (!isset($this->boundInVars[$position + 1])) {
00280 throw new SQLException('Replace params: undefined query param: ' . ($position + 1));
00281 }
00282 $current_position = $this->positions[$position];
00283 $sql .= substr($this->sql, $last_position, $current_position - $last_position);
00284 $sql .= $this->boundInVars[$position + 1];
00285 $last_position = $current_position + 1;
00286 }
00287
00288 $sql .= substr($this->sql, $last_position);
00289
00290
00291 if ( strlen ( $sql ) > 2048 ) {
00292 $this->sql_cache = $sql;
00293 $this->sql_cache_valid = true;
00294 return $this->sql_cache;
00295 } else {
00296 return $sql;
00297 }
00298 }
00299
00310 public function executeQuery($p1 = null, $fetchmode = null)
00311 {
00312 $params = null;
00313 if ($fetchmode !== null) {
00314 $params = $p1;
00315 } elseif ($p1 !== null) {
00316 if (is_array($p1)) $params = $p1;
00317 else $fetchmode = $p1;
00318 }
00319
00320 foreach ( (array) $params as $i=>$param ) {
00321 $this->set ( $i + 1, $param );
00322 unset ( $i, $param );
00323 }
00324 unset ( $params );
00325
00326 $this->updateCount = null;
00327 $sql = $this->replaceParams();
00328
00329 if ($this->limit > 0 || $this->offset > 0) {
00330 $this->conn->applyLimit($sql, $this->offset, $this->limit);
00331 }
00332
00333 $this->resultSet = $this->conn->executeQuery($sql, $fetchmode);
00334 return $this->resultSet;
00335 }
00336
00344 public function executeUpdate($params = null)
00345 {
00346 foreach ( (array) $params as $i=>$param ) {
00347 $this->set ( $i + 1, $param );
00348 unset ( $i, $param );
00349 }
00350 unset ( $params );
00351
00352 if($this->resultSet) $this->resultSet->close();
00353 $this->resultSet = null;
00354 $sql = $this->replaceParams();
00355 $this->updateCount = $this->conn->executeUpdate($sql);
00356 return $this->updateCount;
00357 }
00358
00364 abstract protected function escape($str);
00365
00378 function set($paramIndex, $value)
00379 {
00380 $type = gettype($value);
00381 if ($type == "object") {
00382 if (is_a($value, 'Blob')) {
00383 $this->setBlob($paramIndex, $value);
00384 } elseif (is_a($value, 'Clob')) {
00385 $this->setClob($paramIndex, $value);
00386 } elseif (is_a($value, 'Date')) {
00387
00388
00389
00390 $this->setTimestamp($paramIndex, $value);
00391 } else {
00392 throw new SQLException("Unsupported object type passed to set(): " . get_class($value));
00393 }
00394 } else {
00395 switch ( $type ) {
00396 case 'integer':
00397 $type = 'int';
00398 break;
00399 case 'double':
00400 $type = 'float';
00401 break;
00402 }
00403 $setter = 'set' . ucfirst($type);
00404 if ( method_exists ( $this, $setter ) ) {
00405 $this->$setter($paramIndex, $value);
00406 } else {
00407 throw new SQLException ( "Unsupported datatype passed to set(): " . $type );
00408 }
00409 }
00410 }
00411
00420 function setArray($paramIndex, $value)
00421 {
00422 $this->sql_cache_valid = false;
00423 if ($value === null) {
00424 $this->setNull($paramIndex);
00425 } else {
00426 $this->boundInVars[$paramIndex] = "'" . $this->escape(serialize($value)) . "'";
00427 }
00428 }
00429
00437 function setBoolean($paramIndex, $value)
00438 {
00439 $this->sql_cache_valid = false;
00440 if ($value === null) {
00441 $this->setNull($paramIndex);
00442 } else {
00443 $this->boundInVars[$paramIndex] = (int) $value;
00444 }
00445 }
00446
00447
00451 function setBlob($paramIndex, $blob)
00452 {
00453 $this->sql_cache_valid = false;
00454 if ($blob === null) {
00455 $this->setNull($paramIndex);
00456 } else {
00457
00458 if (is_object($blob)) {
00459 $this->boundInVars[$paramIndex] = "'" . $this->escape($blob->__toString()) . "'";
00460 } else {
00461 $this->boundInVars[$paramIndex] = "'" . $this->escape($blob) . "'";
00462 }
00463 }
00464 }
00465
00469 function setClob($paramIndex, $clob)
00470 {
00471 $this->sql_cache_valid = false;
00472 if ($clob === null) {
00473 $this->setNull($paramIndex);
00474 } else {
00475
00476 if (is_object($clob)) {
00477 $this->boundInVars[$paramIndex] = "'" . $this->escape($clob->__toString()) . "'";
00478 } else {
00479 $this->boundInVars[$paramIndex] = "'" . $this->escape($clob) . "'";
00480 }
00481 }
00482 }
00483
00489 function setDate($paramIndex, $value)
00490 {
00491 $this->sql_cache_valid = false;
00492 if ($value === null) {
00493 $this->setNull($paramIndex);
00494 } else {
00495 if (is_numeric($value)) $value = date("Y-m-d", $value);
00496 elseif (is_object($value)) $value = date("Y-m-d", $value->getTime());
00497 $this->boundInVars[$paramIndex] = "'" . $this->escape($value) . "'";
00498 }
00499 }
00500
00506 function setDecimal($paramIndex, $value)
00507 {
00508 $this->sql_cache_valid = false;
00509 if ($value === null) {
00510 $this->setNull($paramIndex);
00511 } else {
00512 $this->boundInVars[$paramIndex] = (float) $value;
00513 }
00514 }
00515
00521 function setDouble($paramIndex, $value)
00522 {
00523 $this->sql_cache_valid = false;
00524 if ($value === null) {
00525 $this->setNull($paramIndex);
00526 } else {
00527 $this->boundInVars[$paramIndex] = (double) $value;
00528 }
00529 }
00530
00536 function setFloat($paramIndex, $value)
00537 {
00538 $this->sql_cache_valid = false;
00539 if ($value === null) {
00540 $this->setNull($paramIndex);
00541 } else {
00542 $this->boundInVars[$paramIndex] = (float) $value;
00543 }
00544 }
00545
00551 function setInt($paramIndex, $value)
00552 {
00553 $this->sql_cache_valid = false;
00554 if ($value === null) {
00555 $this->setNull($paramIndex);
00556 } else {
00557 $this->boundInVars[$paramIndex] = (int) $value;
00558 }
00559 }
00560
00566 function setInteger($paramIndex, $value)
00567 {
00568 $this->sql_cache_valid = false;
00569 $this->setInt($paramIndex, $value);
00570 }
00571
00576 function setNull($paramIndex)
00577 {
00578 $this->sql_cache_valid = false;
00579 $this->boundInVars[$paramIndex] = 'NULL';
00580 }
00581
00587 function setString($paramIndex, $value)
00588 {
00589 $this->sql_cache_valid = false;
00590 if ($value === null) {
00591 $this->setNull($paramIndex);
00592 } else {
00593
00594
00595 if ( is_object ( $value ) ) {
00596 $this->boundInVars[$paramIndex] = "'" . $this->escape($value->__toString()) . "'";
00597 } else {
00598 $this->boundInVars[$paramIndex] = "'" . $this->escape((string)$value) . "'";
00599 }
00600 }
00601 }
00602
00608 function setTime($paramIndex, $value)
00609 {
00610 $this->sql_cache_valid = false;
00611 if ($value === null) {
00612 $this->setNull($paramIndex);
00613 } else {
00614 if ( is_numeric ( $value ) ) {
00615 $value = date ('H:i:s', $value );
00616 } elseif ( is_object ( $value ) ) {
00617 $value = date ('H:i:s', $value->getTime ( ) );
00618 }
00619 $this->boundInVars [ $paramIndex ] = "'" . $this->escape ( $value ) . "'";
00620 }
00621 }
00622
00628 function setTimestamp($paramIndex, $value)
00629 {
00630 $this->sql_cache_valid = false;
00631 if ($value === null) {
00632 $this->setNull($paramIndex);
00633 } else {
00634 if (is_numeric($value)) $value = date('Y-m-d H:i:s', $value);
00635 elseif (is_object($value)) $value = date('Y-m-d H:i:s', $value->getTime());
00636 $this->boundInVars[$paramIndex] = "'".$this->escape($value)."'";
00637 }
00638 }
00639
00640 }