Skip to content

Commit

Permalink
[Database] modify the _implodeWithKeys() function to allow IS NULL in…
Browse files Browse the repository at this point in the history
… query (aces#3551)

This modifies the Database class to allow null values to be used in WHERE clauses or as SET values.
  • Loading branch information
PapillonMcGill authored and Krishna Chatpar committed Apr 15, 2019
1 parent f9529bb commit 9f52b84
Show file tree
Hide file tree
Showing 2 changed files with 174 additions and 20 deletions.
37 changes: 21 additions & 16 deletions php/libraries/Database.class.inc
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ class Database
$query = "INSERT INTO $table SET ";
}
$prepQ = $query;
$query .= $this->_implodeWithKeys(', ', $set);
$query .= $this->_implodeWithKeys(', ', $set, 'set_');

$exec_params = array();
$prepQ .= $this->_implodeAsPrepared(",", $set, $exec_params);
Expand Down Expand Up @@ -454,7 +454,7 @@ class Database
function replace($table, $set)
{
$query = "REPLACE INTO $table SET ";
$query .= $this->_implodeWithKeys(', ', $set);
$query .= $this->_implodeWithKeys(', ', $set, 'set_');

if (DEBUG) {
fwrite(STDERR, $query."\n");
Expand Down Expand Up @@ -531,9 +531,9 @@ class Database
* the top of the page when showDatabaseQueries is on. It isn't
* actually executed. */
$query = "UPDATE $table SET ";
$query .= $this->_implodeWithKeys(', ', $set);
$query .= $this->_implodeWithKeys(', ', $set, 'set_');
$query .= " WHERE ";
$where = $this->_implodeWithKeys(' AND ', $i_where);
$where = $this->_implodeWithKeys(' AND ', $i_where, 'where_');

/* This generates the version of the update statement which is
* executed. */
Expand Down Expand Up @@ -590,7 +590,7 @@ class Database
function delete($table, $where)
{
$query = "DELETE FROM $table WHERE ";
$where = $this->_implodeWithKeys(' AND ', $where);
$where = $this->_implodeWithKeys(' AND ', $where, 'where_');
$query .= $where;

if (DEBUG) {
Expand Down Expand Up @@ -937,22 +937,23 @@ class Database
* Sets each hash element into the format key='value', and then
* implodes the resultant array with the specified glue
*
* @param string $glue The glue to pass to php's implode
* function
* @param array<string,string> $dataArray The array with keys to implode
* @param string $glue The glue to pass to php's implode function
* @param array $dataArray The array with keys to implode
* @param string $clause The type of clause set_|where_
*
* @return string
*/
function _implodeWithKeys($glue, $dataArray)
function _implodeWithKeys($glue, $dataArray, $clause = 'set_')
{
$output = array();
if (!is_array($dataArray) || count($dataArray)==0) {
return '';
}

foreach ($dataArray as $key => $item ) {
if ($item===null || $item==='') {
$output[] = "`$key`=NULL";
if (is_null($item)) {
$output[] = $clause == 'where_'
? "`$key` IS NULL" : "`$key` = NULL";
} else {
$item = $this->quote($item);
$output[] = "`$key`=$item";
Expand Down Expand Up @@ -985,12 +986,16 @@ class Database

$output = array();
foreach ($dataArray as $key => $item ) {
$varname = str_replace("%", "_percent_", $key);
$output[] = "`$key`=:$prefix$varname";
if ($exec_vals !== null) {
$exec_vals["$prefix$varname"] = $item;
$varname = str_replace("%", "_percent_", $key);
if (is_null($item)) {
$output[] = $prefix == 'where_'
? "`$key` IS NULL" : "`$key` = NULL";
} else {
$output[] = "`$key`=:$prefix$varname";
if ($exec_vals !== null) {
$exec_vals["$prefix$varname"] = $item;
}
}

}
return implode($glue, $output);
}
Expand Down
157 changes: 153 additions & 4 deletions test/unittests/Database_Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,7 @@ function testSetFakeData() {
)

)
);

);
}


Expand Down Expand Up @@ -156,7 +155,157 @@ function testUnsafeInsertDoesntEscapeHTML() {
$stub->unsafeinsert("test", array('field' => '<b>Hello</b>'), array());

}
}

function testDeleteWithIsNull() {
$this->_factory = NDB_Factory::singleton();
$DB = Database::singleton();
$DB->setFakeTableData(
"ConfigSettings",
array(
0 => array(
'ID' => 99991,
'Name' => 'test 1',
'Description' => 'permanent',
'Visible' => '1'
),
1 => array(
'ID' => 99992,
'Name' => 'test 2',
'Description' => null,
'Visible' => '1'
)
)
);

$DB->delete("ConfigSettings", array('Visible' => 1, 'Description' => null));
$allSetting = $DB->pselect("SELECT ID, Name, Description, Visible FROM ConfigSettings", array());
$DB->run("DROP TEMPORARY TABLE ConfigSettings");
$this->assertEquals(
$allSetting,
array(
0 => array(
'ID' => '99991',
'Name' => 'test 1',
'Description' => 'permanent',
'Visible' => '1'
)
)
);

}

?>
function testUpdateWithIsNull() {
$this->_factory = NDB_Factory::singleton();
$DB = Database::singleton();
$DB->setFakeTableData(
"ConfigSettings",
array(
0 => array(
'ID' => 99991,
'Name' => 'test 1',
'Description' => 'permanent',
'Visible' => '1'
),
1 => array(
'ID' => 99992,
'Name' => 'test 2',
'Description' => null,
'Visible' => '1'
)
)
);
$DB->update("ConfigSettings", array('Visible' => null, 'Description' => 'new description'), array('Description' => null));
$allSetting = $DB->pselect("SELECT ID, Name, Description, Visible FROM ConfigSettings", array());
$DB->run("DROP TEMPORARY TABLE ConfigSettings");
$this->assertEquals(
$allSetting,
array(
0 => array(
'ID' => 99991,
'Name' => 'test 1',
'Description' => 'permanent',
'Visible' => '1'
),
1 => array(
'ID' => 99992,
'Name' => 'test 2',
'Description' => 'new description',
'Visible' => null
)
)
);
}

function testInsertWithIsNull() {
$this->_factory = NDB_Factory::singleton();
$DB = Database::singleton();
$DB->setFakeTableData(
"ConfigSettings",
array(
0 => array(
'ID' => 99991,
'Name' => 'test 1',
'Description' => 'permanent',
'Visible' => '1'
)
)
);
$DB->insert("ConfigSettings", array('ID' => 99992, 'Name' => 'test 2', 'Visible' => 1, 'Description' => null));
$allSetting = $DB->pselect("SELECT ID, Name, Description, Visible FROM ConfigSettings", array());
$DB->run("DROP TEMPORARY TABLE ConfigSettings");
$this->assertEquals(
$allSetting,
array(
0 => array(
'ID' => 99991,
'Name' => 'test 1',
'Description' => 'permanent',
'Visible' => '1'
),
1 => array(
'ID' => 99992,
'Name' => 'test 2',
'Description' => null,
'Visible' => '1'
)
)
);
}

function testReplaceWithIsNull() {
$this->_factory = NDB_Factory::singleton();
$DB = Database::singleton();
$DB->setFakeTableData(
"ConfigSettings",
array(
0 => array(
'ID' => 99991,
'Name' => 'test 1',
'Description' => 'permanent',
'Visible' => '1'
)
)
);
$DB->replace("ConfigSettings", array('ID' => 99991, 'Name' => 'test 1', 'Visible' => 1, 'Description' => null));
$DB->replace("ConfigSettings", array('ID' => 99992, 'Name' => 'test 2', 'Visible' => 1, 'Description' => null));
$allSetting = $DB->pselect("SELECT ID, Name, Description, Visible FROM ConfigSettings", array());
$DB->run("DROP TEMPORARY TABLE ConfigSettings");
$this->assertEquals(
$allSetting,
array(
0 => array(
'ID' => 99991,
'Name' => 'test 1',
'Description' => null,
'Visible' => '1'
),
1 => array(
'ID' => 99992,
'Name' => 'test 2',
'Description' => null,
'Visible' => '1'
)
)
);
}
}

0 comments on commit 9f52b84

Please sign in to comment.