SQL Server — PHP PDO — Оператор подготовки динамического SQL не работает как жестко запрограммированный

Я кодировал мини-DBAL и вот часть этого.

private function setWhere($conditions) {
if (count($conditions)>0) {
$where = '1=1';
$params = [];

$ret = $this->iterateWhere($where, $conditions, $params, 'AND', '=');
return [
'where' => 'WHERE '.str_replace('1=1 OR ', '', str_replace('1=1 AND ', '', $ret['where'])),
'params' => $ret['params'],
];
} else
return [
'where' => '',
'params' => [],
];
}

private function iterateWhere($where, $conditions, $params, $logic, $op) {
//go through given set of conditions
foreach ($conditions as $condition=>$value) {
//check for lowest condition
if (is_array($value)) {
//check for logic or operator condition
if (in_array($value[0], ['AND', 'OR', 'and', 'or'])) {
//logic
$where .= ' '.$logic.' (1=1';
$ret = $this->iterateWhere($where, $value, $params, $value[0], $op);
$where = $ret['where'];
$params = $ret['params'];
$where .= ')';
} else {
//operator
foreach($value as $k=>$v) {
if ($k != '0') {
$where .= ' '.$logic.' ('.$k.$value[0].':'.count($params).')';
$params[] = $v;
break;
}
}
}
} else {
if ($condition != '0') {
$where .= ' '.$logic.' ('.$condition.$op.':'.count($params).')';
$params[] = $value;
} else {
if (in_array($value, ['AND', 'OR', 'and', 'or']))
$logic = strtoupper($value);
else
$op = strtoupper($value);
}
}
}

return [
'where' => $where,
'params' => $params,
];
}

public function getTableCol($table, $column, $conditions) {
try {
$condition_part = $this->setWhere($conditions);
$stmt = $this->pdo->prepare('SELECT '.$column.' FROM '.$table.' '.$condition_part['where']);

foreach ($condition_part['params'] as $param=>$pVal) {
switch (strtolower(gettype($pVal))) {
case 'string':
$stmt->bindParam(':'.$param, $pVal, \PDO::PARAM_STR);
break;

case 'integer':
$stmt->bindParam(':'.$param, $pVal, \PDO::PARAM_INT);
break;

case 'float':
case 'double':
$stmt->bindParam(':'.$param, $pVal);
break;

case 'boolean':
$stmt->bindParam(':'.$param, $pVal, \PDO::PARAM_BOOL);
break;

case 'null':
$stmt->bindParam(':'.$param, $pVal, \PDO::PARAM_NULL);
break;

default:
die('Unhandled param type for \''.$pVal.'\'');
break;
}
}

$stmt->execute();
$ret = $stmt->fetchAll(\PDO::FETCH_COLUMN, 0);

return [
'rows' => count($ret),
'result' => $ret,
];
} catch (\PDOException $e) {
return [
'rows' => 0,
'result' => $e->getMessage(),
];
}
}

Я называю свою функцию так:

$client_list = $db->getTableCol("cs_client", "client_id", ["domain" => "PB", "name" => "My Client"]);

Я обнаружил, что мой код правильно заполняет SQL и параметры, но он не возвращает никаких строк, когда я передаю более одного условия WHERE. Если я вручную жестко закодировал динамически подготовленное утверждение, то оно работает. Я не могу понять, почему.

Вот некоторые выводы из echo и print_r:

SQL передается в prepare ():

SELECT client_id FROM cs_client WHERE (domain=:0) AND (name=:1)

Вывод массива параметров:

Array
(
[0] => PB
[1] => My Client
)

Последовательность цикла for для привязки параметра:

0 => PB
1 => My Client

Чтобы повторить, если я скопирую и вставлю этот подготовленный оператор вручную в ‘$ stmt = $ this-> pdo-> prepare («»)’, а затем свяжу: 0 и: 1, используя выходные значения, он возвращает единственную строку в этой таблице.

Если я передаю только одно (одно из двух) или никаких условий, то он возвращает строку, но не, если я прохожу два условия, хотя он заполняет условия правильно.

Не должно иметь большого значения, но я использую MS SQL Server 2014.

0

Решение

Я думаю, я слишком много пытался. Вместо использования count () для увеличения именованных параметров как 0, 1, 2, 3 … Я просто использовал ‘?’ и передал список параметров в оператор execute следующим образом:

$stmt->execute($condition_part['params']);

Делает для меньшего кода, так как мне не нужен цикл для перебора списка параметров.

0

Другие решения

Других решений пока нет …