Skip to content

Commit

Permalink
#10 Fixed bind_param to take references too
Browse files Browse the repository at this point in the history
  • Loading branch information
sbuberl committed Mar 17, 2019
1 parent 7c6f477 commit 5561a10
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 45 deletions.
83 changes: 48 additions & 35 deletions src/Statement.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ class Statement
private $params;
private $result;
private $metadata;
private $bound;
private $types;
private $boundParams;
private $boundResults;
private $stored;
private $error;

Expand All @@ -32,7 +34,7 @@ private function set_error($error)
return false;
}

public function bind_param($types, ...$params)
public function bind_param($types, &...$params)
{
$length = strlen($types);
if($this->query === null) {
Expand All @@ -41,27 +43,8 @@ public function bind_param($types, ...$params)
return $this->set_error("bind_param's number of types in the string doesn't match number of parameters passed in");
}

$param = current($params);

for($i = 0; $i < $length; ++$i, $param = next($params)) {
$type = $types[$i];
if($param == null) {
$this->params[] = 'NULL';
} else {
switch($type) {
case 'i':
$this->params[] = (int) $param;
break;
case 'd':
$this->params[] = (float) $param;
break;
case 's':
case 'o':
$this->params[] = "'". addslashes((string) $param) . "'";
break;
}
}
}
$this->boundParams = $params;
$this->types = $types;

return true;
}
Expand All @@ -74,7 +57,7 @@ public function bind_result(&...$variables)
return $this->set_error("No result set found for bind_result");
}

$this->bound = $variables;
$this->boundResults = $variables;
return true;
}

Expand All @@ -84,14 +67,42 @@ public function execute()
return $this->set_error("Unable to perform an execute without a prepare");
}

$that = $this;
$count = 0;
$newQuery = preg_replace_callback(
"/\?(?=[^']*(?:'[^']*'[^']*)*$)/",
function($match) use ($that, &$count) { return $that->params[$count++]; },
$this->query
);
$result = $this->environment->query($newQuery);
if($this->boundParams !== null) {
$length = strlen($this->types);
$param = current($this->boundParams);

$params = [];
for($i = 0; $i < $length; ++$i, $param = next($this->boundParams)) {
$type = $this->types[$i];
if($param == null) {
$params[] = 'NULL';
} else {
switch($type) {
case 'i':
$params[] = (int) $param;
break;
case 'd':
$params[] = (float) $param;
break;
case 's':
case 'o':
$params[] = "'". addslashes((string) $param) . "'";
break;
}
}
}
$parameters = $params;
$count = 0;
$realQuery = preg_replace_callback(
"/\?(?=[^']*(?:'[^']*'[^']*)*$)/",
function($match) use ($parameters, &$count) { return $parameters[$count++]; },
$this->query
);
} else {
$realQuery = $this->query;
}

$result = $this->environment->query($realQuery);
if($result instanceof ResultSet) {
$this->result = $result;
$this->metadata = $result->createMetadata();
Expand All @@ -107,15 +118,15 @@ public function fetch()
{
if($this->query === null) {
return $this->set_error("Unable to perform a fetch without a prepare");
} elseif($this->bound === null) {
} elseif($this->boundResults === null) {
return $this->set_error("Unable to perform a fetch without a bind_result");
}

$result = $this->result->fetchRow();
if($result !== null) {
$i = 0;
foreach ($result as $value) {
$this->bound[$i++] = $value;
$this->boundResults[$i++] = $value;
}
return true;
}
Expand All @@ -128,7 +139,9 @@ public function prepare($query)
$this->params = [];
$this->result = null;
$this->metadata = null;
$this->bound = null;
$this->types = null;
$this->boundParams = null;
$this->boundResults = null;
$this->stored = false;
return true;
}
Expand Down
50 changes: 40 additions & 10 deletions tests/StatementTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ public function testPrepare()
public function testBindParamNoPrepare()
{
$statement = new Statement($this->fsql);
$passed = $statement->bind_param('isd', '5', 'king', 99999);
$id = 5;
$lastName = 'king';
$zip = 99999;
$passed = $statement->bind_param('isd', $id, $lastName, $zip);
$this->assertTrue($passed === false);
$this->assertEquals($statement->error(), "Unable to perform a bind_param without a prepare");
}
Expand All @@ -61,7 +64,9 @@ public function testBindParamTypeParamMismatch()
{
$statement = new Statement($this->fsql);
$statement->prepare("SELECT firstName, lastName, city FROM customers WHERE personId = ? OR lastName = ? OR zip = ?");
$passed = $statement->bind_param('isd', '5', 'king');
$id = 5;
$lastName = 'king';
$passed = $statement->bind_param('isd', $id, $lastName);
$this->assertTrue($passed === false);
$this->assertEquals($statement->error(), "bind_param's number of types in the string doesn't match number of parameters passed in");
}
Expand All @@ -70,7 +75,10 @@ public function testBindParam()
{
$statement = new Statement($this->fsql);
$statement->prepare("SELECT firstName, lastName, city FROM customers WHERE personId = ? OR lastName = ? OR zip = ?");
$passed = $statement->bind_param('isd', '5', 'king', 99999);
$id = 5;
$lastName = 'king';
$zip = 99999;
$passed = $statement->bind_param('isd', $id, $lastName, $zip);
$this->assertTrue($passed === true);
}

Expand Down Expand Up @@ -132,7 +140,13 @@ public function testExecuteParams()

$statement = new Statement($this->fsql);
$statement->prepare("SELECT firstName, lastName, city FROM customers WHERE personId = ? OR lastName = ? OR zip = ?");
$statement->bind_param('isd', '5', 'king', 99999);
$id = 5;
$lastName = 'king';
$zip = 99999;
$statement->bind_param('isd', $id, $lastName, $zip);
$passed = $statement->execute();
$this->assertTrue($passed === true);
}
$passed = $statement->execute();
$this->assertTrue($passed === true);
}
Expand All @@ -145,7 +159,7 @@ public function testBindResultNoPrepare()
$this->assertEquals($statement->error(), "Unable to perform a bind_result without a prepare");
}

public function testBindParamNoResult()
public function testBindResultNoResult()
{
$table = CachedTable::create($this->fsql->current_schema(), 'customers', self::$columns);
$cursor = $table->getWriteCursor();
Expand All @@ -156,7 +170,10 @@ public function testBindParamNoResult()

$statement = new Statement($this->fsql);
$statement->prepare("SELECT firstName, lastName, city FROM customers WHERE personId = ? OR lastName = ? OR zip = ?");
$statement->bind_param('isd', '5', 'king', null);
$id = 5;
$last = 'king';
$zip = 99999;
$statement->bind_param('isd', $id, $last, $zip);
$passed = $statement->bind_result($firstName, $lastName, $city);
$this->assertTrue($passed === false);
$this->assertEquals($statement->error(), "No result set found for bind_result");
Expand All @@ -173,7 +190,10 @@ public function testBindResult()

$statement = new Statement($this->fsql);
$statement->prepare("SELECT firstName, lastName, city FROM customers WHERE personId = ? OR lastName = ? OR zip = ?");
$statement->bind_param('isd', '5', 'king', null);
$id = 5;
$last = 'king';
$zip = 99999;
$statement->bind_param('isd', $id, $last, $zip);
$statement->execute();
$passed = $statement->bind_result($firstName, $lastName, $city);
$this->assertTrue($passed === true);
Expand All @@ -198,7 +218,10 @@ public function testFetchNoBindResult()

$statement = new Statement($this->fsql);
$statement->prepare("SELECT firstName, lastName, city FROM customers WHERE personId = ? OR lastName = ? OR zip = ?");
$statement->bind_param('isd', '5', 'king', null);
$id = 5;
$last = 'king';
$zip = 99999;
$statement->bind_param('isd', $id, $last, $zip);
$statement->execute();
$passed = $statement->fetch();
$this->assertTrue($passed === false);
Expand All @@ -216,13 +239,17 @@ public function testFetch()

$statement = new Statement($this->fsql);
$statement->prepare("SELECT firstName, lastName, city FROM customers WHERE personId = ? OR lastName = ? OR zip = ?");
$statement->bind_param('isd', '5', 'king', null);
$id = 5;
$last = 'king';
$zip = 99999;
$statement->bind_param('isd', $id, $last, $zip);
$statement->execute();
$statement->bind_result($firstName, $lastName, $city);
$i = 0;
$expected = [
['stephen', 'king', 'derry'],
['bart', 'simpson', 'springfield'],
['douglas', 'adams', 'london'],
[null, 'king', 'tokyo'],
];
while($statement->fetch()) {
Expand Down Expand Up @@ -252,7 +279,10 @@ public function testStoreResult()

$statement = new Statement($this->fsql);
$statement->prepare("SELECT firstName, lastName, city FROM customers WHERE personId = ? OR lastName = ? OR zip = ?");
$statement->bind_param('isd', '5', 'king', null);
$id = 5;
$last = 'king';
$zip = 99999;
$statement->bind_param('isd', $id, $last, $zip);
$statement->execute();
$passed = $statement->store_result();
$this->assertTrue($passed === true);
Expand Down

0 comments on commit 5561a10

Please sign in to comment.