Skip to content

Commit 75ebd1f

Browse files
committed
Basic sql parameter quote handling and updated readme describing problems.
1 parent 283f77a commit 75ebd1f

File tree

4 files changed

+99
-17
lines changed

4 files changed

+99
-17
lines changed

README.md

+40
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,46 @@ The mysqli::real_escape_string requires a link. But, the link is one of many.
111111
Last minute escaping once the command and connection were married from the pool.
112112
Could potentially have one dedicated link for escaping.
113113

114+
### Query Building Support
115+
116+
Many MySQL wrapper packages have been analyzed, but none are completely independent of
117+
a connection object that could be found.
118+
119+
For now, we will escape parameters, but require the user to provide a sql query that quotes the parameters.
120+
121+
This is obviously sub-optimal since a variable like $created_at could be NOW() or '2016-01-01' or NULL.
122+
123+
The litmus test I have been using is the following query:
124+
125+
INSERT INTO `simple_table` (`id`, `name`, `value`, `created_at`)
126+
VALUES (NULL, 'John\'s Name', 7, NOW());
127+
128+
The key points here are:
129+
130+
- Support for putting the parameter in quotes! This is the first step. The rest is intelligently knowing when not to quote.
131+
- Support for a null value converted to NULL.
132+
- Support for escaping the parameter using either \\\' or '' is fine.
133+
- Support for not escaping functions such as NOW()
134+
- Support for recognizing integer values. Optional, since '7' will work fine.
135+
136+
### Wrapper Options Reviewed
137+
138+
1. [nilportugues/php-sql-query-builder](https://github.com/nilportugues/php-sql-query-builder) - No connection required! But, odd syntax.
139+
1. [usmanhalalit/pixie](https://github.com/usmanhalalit/pixie) - Requires connection. Pretty close to needs.
140+
1. [joshcam/PHP-MySQLi-Database-Class](https://github.com/joshcam/PHP-MySQLi-Database-Class) - Requires connection.
141+
1. [aviat4ion/Query](https://git.timshomepage.net/aviat4ion/Query) - Requires connection.
142+
1. [rkrx/php-mysql-query-builder](https://github.com/rkrx/php-mysql-query-builder) - Requires connection.
143+
1. [stefangabos/Zebra_Database](https://github.com/stefangabos/Zebra_Database) - Requires connection, does more than needed.
144+
1. [indeyets/MySQL-Query-Builder](https://github.com/indeyets/MySQL-Query-Builder) - Not maintained. Odd syntax.
145+
146+
The nilportugues/php-sql-query-builder package is very close, but it does not quote the parameters.
147+
148+
## Install
149+
150+
The recommended way to install this library is through Composer.
151+
152+
$ composer require dustingraham/react-mysql
153+
114154
## Credits
115155

116156
Much appreciation to the hard work over at [reactphp/react](https://github.com/reactphp/react).

src/Command.php

+42-2
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,51 @@ public function bindValues($params)
6363
*/
6464
public function getPreparedQuery(Connection $connection)
6565
{
66-
$this->params = $connection->escape($this->params);
66+
$quotedSql = $this->quoteIntoSql($connection);
6767

68-
return strtr($this->sql, $this->params);
68+
return $quotedSql;
6969
}
7070

71+
/**
72+
* TODO: This is exactly what I don't want to do. "Roll my own" SQL handler.
73+
* However, the requirements for this package have led to this point for now.
74+
*
75+
* @param Connection $connection
76+
* @return mixed
77+
*/
78+
protected function quoteIntoSql(Connection $connection)
79+
{
80+
$quotedSql = $this->sql;
81+
$quotedParams = [];
82+
83+
foreach($this->params as $key => $value)
84+
{
85+
if (is_null($value))
86+
{
87+
$quotedParams[$key] = 'NULL';
88+
}
89+
else if (is_integer($value))
90+
{
91+
$quotedParams[$key] = (int)$value;
92+
}
93+
else if (in_array($value, $this->reserved_words))
94+
{
95+
$quotedParams[$key] = $value;
96+
}
97+
else
98+
{
99+
$quotedParams[$key] = '\''.$connection->escape($value).'\'';
100+
}
101+
}
102+
103+
return strtr($quotedSql, $quotedParams);
104+
}
105+
106+
// TODO: Find all of these...
107+
protected $reserved_words = [
108+
'NOW()'
109+
];
110+
71111
/**
72112
* @return \React\Promise\PromiseInterface
73113
*/

tests/DatabaseTest.php

+2-4
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public function testMysqliSynchronous()
4343
$c = $this->getMysqliConnection();
4444

4545
$result = $c->query('SELECT * FROM simple_table;');
46-
$this->assertEquals(2, $result->num_rows);
46+
$this->assertEquals(3, $result->num_rows);
4747

4848
$tempTableName = 'temptable123';
4949
$c->query('CREATE TEMPORARY TABLE ' . $tempTableName . ' LIKE simple_table;');
@@ -69,7 +69,7 @@ public function testMysqliAsynchronous()
6969
$c->query('SELECT * FROM simple_table;', MYSQLI_ASYNC);
7070

7171
$result = $c->reap_async_query();
72-
$this->assertEquals(2, $result->num_rows);
72+
$this->assertEquals(3, $result->num_rows);
7373
}
7474

7575
public function testCreateCommandGetPromise()
@@ -141,8 +141,6 @@ public function testSimpleCommandParameterBinding()
141141

142142
public function testComplexCommandParameterBinding()
143143
{
144-
$this->markTestSkipped('TODO: Implement binding null values.');
145-
146144
$db = new Database();
147145

148146
$cmd = $db->createCommand();

tests/sql.sql

+15-11
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
1-
DROP TABLE IF EXISTS `abc`;
1+
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
2+
SET time_zone = "+00:00";
3+
24
DROP TABLE IF EXISTS `simple_table`;
35
CREATE TABLE IF NOT EXISTS `simple_table` (
4-
`id` INT(10) UNSIGNED NOT NULL,
5-
`name` VARCHAR(255) NOT NULL
6-
)
7-
ENGINE = InnoDB
8-
AUTO_INCREMENT = 3
9-
DEFAULT CHARSET = utf8;
6+
`id` int(10) unsigned NOT NULL,
7+
`name` varchar(255) NOT NULL,
8+
`value` int(11) NOT NULL,
9+
`created_at` datetime NOT NULL
10+
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
11+
12+
INSERT INTO `simple_table` (`id`, `name`, `value`, `created_at`) VALUES
13+
(1, 'a', 2, '2016-04-12 05:23:31'),
14+
(2, 'b', 5, '0000-00-00 00:00:00'),
15+
(3, 'John''s Cafe', 54321, '2016-04-26 16:18:59');
1016

11-
INSERT INTO `simple_table` (`id`, `name`) VALUES
12-
(1, 'a'),
13-
(2, 'b');
1417

1518
ALTER TABLE `simple_table`
1619
ADD PRIMARY KEY (`id`);
1720

21+
1822
ALTER TABLE `simple_table`
19-
MODIFY `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT = 3;
23+
MODIFY `id` int(10) unsigned NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=4;

0 commit comments

Comments
 (0)