PDO, bindParam и PARAM_*

itprog

Cruftsman
PDO, bindParam и PARAM_*

Имеется MySQL 5.0 и таблица:
[sql]
CREATE TABLE `table` (
`name` int(11) default NULL
) ENGINE=MyISAM;
[/sql]
И добавление записи в эту таблицу:
PHP:
$db = new PDO('mysql:host=localhost;dbname=test', 'root', '');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $db->prepare("INSERT INTO `table` VALUES(:name)");
$value = '';
$stmt->bindParam('name', $value, PDO::PARAM_INT);
$stmt->execute();
Такой код выбрасывает исключение:
SQLSTATE[01000]: Warning: 1264 Out of range value adjusted for column 'name' at row 1
Потому как выполняется запрос:
[sql]INSERT INTO `table` VALUES ('');[/sql]
А я ожидал VALUES (null) или хотя бы VALUES (0)

Для чего тогда в PDOStatement::bindParam указывается data_type третьим аргументом?
 

FractalizeR

Новичок
Re: PDO, bindParam и PARAM_*

Автор оригинала: itprog

А я ожидал VALUES (null) или хотя бы VALUES (0)

Для чего тогда в PDOStatement::bindParam указывается data_type третьим аргументом?
Не понимаю, почему вы этого ждали, если у вас параметр типа string, а вы говорите функции, что он - integer.

Указывается тип параметра, я полагаю, для того, чтобы PDO знал, что к нему применять для того, чтобы избежать SQL Injection (грубо говоря, выбор функции приведения параметра в SQL вид. Я сам для строковых пользуюсь mysql_real_escape_string, а для числовых - settype($param, "integer")).
 

itprog

Cruftsman
Указывается тип параметра, я полагаю, для того, чтобы PDO знал, что к нему применять для того, чтобы избежать SQL Injection
Только для этого глупо.
Если я указываю PDO::pARAM_INT то и в запрос должно вставить число... Правда есть в этом и другая сторона: имеющиеся данные будут отличаться от тех, которые были добавлены в БД.
 

FractalizeR

Новичок
Почему же глупо? На этапе выполнения запроса драйвер не знает тип поля, в качестве значения которого вы передаете параметр. Поэтому и ожидать, то что вы ожидали - не приходится.

Если корректный тип параметра не указан, как драйвер может определить, должен ли он генерировать

INSERT INTO `table`VALUES (''); или INSERT INTO `table` VALUES (0);

А если вы передали string и сказали, что это INT - возникает неоднозначность. Видимо, разработчики библиотеки приняли решение вместо приведения типов генерировать исключение.
 

hermit_refined

Отшельник
itprog
я pdo не использую, хотя и были мысли перейти.
сейчас заглянул в исходники... и если я не ошибаюсь, то в случае указанного простого типа (int/double/bool/string) единственные преобразования входных параметров в соответствии с этим типом суть:
PHP:
	if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_STR && param->max_value_len <= 0 && ! ZVAL_IS_NULL(param->parameter)) {
		convert_to_string(param->parameter);
	} else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_INT && Z_TYPE_P(param->parameter) == IS_BOOL) {
		convert_to_long(param->parameter);
	} else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_BOOL && Z_TYPE_P(param->parameter) == IS_LONG) {
		convert_to_boolean(param->parameter);
	}
(причем последние два появились после сообщения об аналогичном баге с bool/int, а первое все равно действует по умолчанию)
и последующие связывания происходят уже исключительно на основе типа самой переменной.

иными словами, я тоже ничего не понимаю в этом третьем параметре.
с одной стороны - они не могут об этом не знать, значит - expected behavior.
с другой же - ерунда ведь какая-то получается...
 

FractalizeR

Новичок
То есть, если вы указали INT, а он оказался BOOL - тогда он конвертирует сам. А если он окажется STRING, то конвертации автоматической нет....

Вы правы, ерунда какая-то. Зачем вообще конвертировать типы, если конвертируются не все...
 
Сверху