From dfc39cdde2ee38c1e04845ba0c6cb8b7e4962893 Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Mon, 8 Aug 2016 23:41:25 -0500 Subject: [PATCH] Implementing Postgre prepared query. --- system/Database/BasePreparedQuery.php | 11 +- system/Database/MySQLi/PreparedQuery.php | 12 ++ system/Database/Postgre/PreparedQuery.php | 112 ++++++++++++++++++ .../Database/Live/PreparedQueryTest.php | 16 ++- 4 files changed, 146 insertions(+), 5 deletions(-) create mode 100644 system/Database/Postgre/PreparedQuery.php diff --git a/system/Database/BasePreparedQuery.php b/system/Database/BasePreparedQuery.php index d6fd21eca7ff..04427c72cd2d 100644 --- a/system/Database/BasePreparedQuery.php +++ b/system/Database/BasePreparedQuery.php @@ -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); } @@ -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. */ diff --git a/system/Database/MySQLi/PreparedQuery.php b/system/Database/MySQLi/PreparedQuery.php index 5051b6de6287..88a1e171d8b6 100644 --- a/system/Database/MySQLi/PreparedQuery.php +++ b/system/Database/MySQLi/PreparedQuery.php @@ -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(); + } + + //-------------------------------------------------------------------- + } diff --git a/system/Database/Postgre/PreparedQuery.php b/system/Database/Postgre/PreparedQuery.php new file mode 100644 index 000000000000..ee2aa4374f0b --- /dev/null +++ b/system/Database/Postgre/PreparedQuery.php @@ -0,0 +1,112 @@ +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; + } + + //-------------------------------------------------------------------- + +} diff --git a/tests/system/Database/Live/PreparedQueryTest.php b/tests/system/Database/Live/PreparedQueryTest.php index fe040f63585e..2d8ae3dcac88 100644 --- a/tests/system/Database/Live/PreparedQueryTest.php +++ b/tests/system/Database/Live/PreparedQueryTest.php @@ -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(); @@ -37,12 +44,13 @@ public function testExecuteRunsQueryAndReturnsResultObject() $query = $this->db->prepare(function($db){ return $db->table('user')->insert([ 'name' => 'a', - 'email' => 'b@example.com' + 'email' => 'b@example.com', + 'country' => 'x' ]); }); - $query->execute('foo', 'foo@example.com'); - $query->execute('bar', 'bar@example.com'); + $query->execute('foo', 'foo@example.com', 'US'); + $query->execute('bar', 'bar@example.com', 'GB'); $this->seeInDatabase($this->db->DBPrefix.'user', ['name' => 'foo', 'email' => 'foo@example.com']); $this->seeInDatabase($this->db->DBPrefix.'user', ['name' => 'bar', 'email' => 'bar@example.com']);