Class it_dbi:
/**
* Create an SQL query (the stuff after 'WHERE') according to an array of selection criteria.
*
* Example:
* $sql = $table->_where(array('Type' => 'bar',
* 'Date >=' => '1999-01-01', '-Date <' => 'NOW()',
* 'Status' => array('foo', 'bar', 'qux'), # same as 'Status IN' => ...
* 'User NI' => 'chris'), 'ORDER BY Date');
*
* @param $params optional array of fieldname => value tupels. These are ANDed to form a WHERE clause.
* fieldname can contain an operator (separated by space), the default operator is '='.
* The special operator 'NI' specifies that the argument must be contained in a comma-separated list.
* @param $link DB link used to escape values (not used anymore)
* @param $omit_where Do not add 'WHERE ' to result
* @return The generated SQL clause
* @see select()
* @see iterate()
*/
function _where($params)
{
$dyncols_enabled = !strlen($params['JOIN'] . $params['FROM']);
unset($params['JOIN'], $params['FROM']);
if (is_array($params) && (count($params) > 0))
{
$query = '';
$stringquery = '';
$sep = '';
foreach($params as $field => $value)
{
if (is_int($field)) /* no key specified; just append */
{
if (strcasecmp($value, 'OR'))
$stringquery .= " $value";
else
$sep = ' OR ';
}
else if ($field == "LIMIT")
{
if ($value !== false) # only false no null; uninitialized values should not unintentionally omit LIMIT
$stringquery .= " LIMIT " . (it::match('^[ ,\d]+$', $value) ?? it::error(['title' => "invalid LIMIT $value", 'body' => $params]) + 0);
}
else
{
$needs_where = true;
if (!isset($value))
{
$op = 'IS';
$qval = 'NULL';
}
else
{
if (preg_match('/^(\S+)\s+(\S.*)$/', $field, $regs))
{
$field = $regs[1];
$op = strtoupper($regs[2]);
}
else
$op = is_array($value) ? 'IN' : '=';
# If field name starts with '-', the raw value is taken, no escaping is done and no quotes are put around it.
if (substr($field, 0, 1) == '-')
{
$field = substr($field, 1); # Strip that '-' sign
$qval = $value;
}
else if (!is_array($value))
$qval = $this->escape_string((string)$value);
}
if ($dyncols_enabled && $this->_fields['dyncols'] && !$this->_fields[$field] && strpos($field, '(') === false)
$field = $this->_json_extract('dyncols', $field);
else if (it::match('^\w*[A-Z]\w+$', $field, ['casesensitive' => 1]))
$field = $this->escape_name($field);
switch ($op)
{
case 'NI':
if ($value)
{
$parts = array();
foreach ((array)$value as $val)
$parts[] = "CONCAT(',',$field,',') LIKE " . $this->escape_string("%,$val,%");
$query .= $sep . "$field IS NOT NULL AND (" . implode(" OR ", $parts) . ")"; # Check for IS NOT NULL to take advantage of index
}
else
$query .= $sep . "TRUE";
break;
case 'MATCH':
$qval = implode(' ', (array)$value);
$query .= "$sep$op ($field) AGAINST (" . $this->escape_string($qval) . " IN BOOLEAN MODE)";
break;
case 'IN':
case 'NOT IN':
if (is_array($value))
{
if ($value)
{
$qvals = array();
foreach ($value as $val)
$qvals[] = $this->escape_string($val);
$query .= "$sep$field $op (" . implode(",", $qvals) . ")"; # null is mapped to ''
}
else
$query .= $sep . (($op == 'IN') ? "FALSE" : "TRUE");
break;
}
/* FALLTHROUGH */
default:
if (isset($qval))
$query .= "$sep$field $op $qval";
else
it::fatal('Undefined $qval when constructing query due to invalid $value (array)');
break;
}
$sep = ' AND ';
}
}
$query .= $stringquery;
if ($needs_where)
$query = "WHERE $query";
}
return $query;
}