Skip to content

Commit

Permalink
Implementing Postgre prepared query.
Browse files Browse the repository at this point in the history
  • Loading branch information
lonnieezell committed Aug 9, 2016
1 parent 0b8fb31 commit dfc39cd
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 5 deletions.
11 changes: 10 additions & 1 deletion system/Database/BasePreparedQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public function execute(...$data)
// Return a result object
$resultClass = str_replace('PreparedQuery', 'Result', get_class($this));

$resultID = $this->statement->get_result();
$resultID = $this->_getResult();

return new $resultClass($this->db->connID, $resultID);
}
Expand All @@ -139,6 +139,15 @@ abstract public function _execute($data);

//--------------------------------------------------------------------

/**
* Returns the result object for the prepared query.
*
* @return mixed
*/
abstract public function _getResult();

//--------------------------------------------------------------------

/**
* Explicity closes the statement.
*/
Expand Down
12 changes: 12 additions & 0 deletions system/Database/MySQLi/PreparedQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,16 @@ public function _execute($data)

//--------------------------------------------------------------------

/**
* Returns the result object for the prepared query.
*
* @return mixed
*/
public function _getResult()
{
return $this->statement->get_result();
}

//--------------------------------------------------------------------

}
112 changes: 112 additions & 0 deletions system/Database/Postgre/PreparedQuery.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<?php namespace CodeIgniter\Database\Postgre;

use CodeIgniter\Database\PreparedQueryInterface;
use \CodeIgniter\Database\BasePreparedQuery;

class PreparedQuery extends BasePreparedQuery implements PreparedQueryInterface
{
/**
* Stores the name this query can be
* used under by postgres. Only used internally.
*
* @var string
*/
protected $name;

/**
* The result resource from a successful
* pg_exec. Or false.
* @var
*/
protected $result;

//--------------------------------------------------------------------

/**
* Prepares the query against the database, and saves the connection
* info necessary to execute the query later.
*
* NOTE: This version is based on SQL code. Child classes should
* override this method.
*
* @param string $sql
* @param array $options Passed to the connection's prepare statement.
* Unused in the MySQLi driver.
*
* @return mixed
*/
public function _prepare(string $sql, array $options = [])
{
$this->name = mt_rand(1, 10000000000000000);

$this->sql = $this->parameterize($sql);

if (! $this->statement = pg_prepare($this->db->connID, $this->name, $this->sql))
{
$this->errorCode = 0;
$this->errorString = pg_last_error($this->db->connID);
}

return $this;
}

//--------------------------------------------------------------------

/**
* Takes a new set of data and runs it against the currently
* prepared query. Upon success, will return a Results object.
*
* @param array $data
*
* @return ResultInterface
*/
public function _execute($data)
{
if (is_null($this->statement))
{
throw new \BadMethodCallException('You must call prepare before trying to execute a prepared statement.');
}

$this->result = pg_execute($this->db->connID, $this->name, $data);

return (bool)$this->result;
}

//--------------------------------------------------------------------

/**
* Returns the result object for the prepared query.
*
* @return mixed
*/
public function _getResult()
{
return $this->result;
}

//--------------------------------------------------------------------

/**
* Replaces the ? placeholders with $1, $2, etc parameters for use
* within the prepared query.
*
* @param string $sql
*
* @return string
*/
public function parameterize(string $sql): string
{
// Track our current value
$count = 0;

$sql = preg_replace_callback('/\?/', function($matches) use (&$count){
$count++;
return "\${$count}";
}, $sql);

return $sql;
}

//--------------------------------------------------------------------

}
16 changes: 12 additions & 4 deletions tests/system/Database/Live/PreparedQueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,14 @@ public function testPrepareReturnsPreparedQuery()
$ec = $this->db->escapeChar;
$pre = $this->db->DBPrefix;

$expected = "INSERT INTO {$ec}{$pre}user{$ec} ({$ec}name{$ec}, {$ec}email{$ec}) VALUES (?, ?)";
$placeholders = '?, ?';

if ($this->db->DBDriver == 'Postgre')
{
$placeholders = '$1, $2';
}

$expected = "INSERT INTO {$ec}{$pre}user{$ec} ({$ec}name{$ec}, {$ec}email{$ec}) VALUES ({$placeholders})";
$this->assertEquals($expected, $query->getQueryString());

$query->close();
Expand All @@ -37,12 +44,13 @@ public function testExecuteRunsQueryAndReturnsResultObject()
$query = $this->db->prepare(function($db){
return $db->table('user')->insert([
'name' => 'a',
'email' => '[email protected]'
'email' => '[email protected]',
'country' => 'x'
]);
});

$query->execute('foo', '[email protected]');
$query->execute('bar', '[email protected]');
$query->execute('foo', '[email protected]', 'US');
$query->execute('bar', '[email protected]', 'GB');

$this->seeInDatabase($this->db->DBPrefix.'user', ['name' => 'foo', 'email' => '[email protected]']);
$this->seeInDatabase($this->db->DBPrefix.'user', ['name' => 'bar', 'email' => '[email protected]']);
Expand Down

0 comments on commit dfc39cd

Please sign in to comment.