Пишу, по большей части, про историю, свою жизнь и немного про программирование.

Ошибка оракула

В одном из проектов при исправлении ошибки всплыло неожиданное. Кусок кода, который работал ошибочно, родился где-то в двухтысячных и по всей видимости в те времена работал правильно. В нём проверялось — если тип переменной «целое», то переменная передавалась в «Оракл» с флагом SQLT_INT, иначе — с SQLT_CHR.

Всё работало хорошо, пока ПХП был 32-битным. Проверка is_int в этом языке возвращала «истину» только для чисел в диапазоне -2147483648…2147483647, всё что шире, трактовалось как float. В 64-битном интерпретаторе целыми считаются числа из гораздо более широкого диапазона, соответственно, в каком-то коде такое значение попало в драйвер «Оракла», промаркированное как SQLT_INT.

Беда в том, что драйвер (в этом месте), похоже, остался в пределах 32 бит, код:

$var = null;
$st = oci_parse($con, "SELECT :int FROM DUAL");
oci_bind_by_name($st, 'int', $var, -1, SQLT_INT);

foreach ([100500, PHP_INT_MAX, 2147483648] as $var) {
    oci_execute($st);
    echo oci_fetch_array($st, OCI_NUM)[0], "\n";
}

Выведет: 100500, -1, -2147483648. Решение я пока знаю только одно: не использовать для целых, которые не помещаются в 32 бита указание типа SQLT_INT.

Проблема в файле oci8_statement.c (это текущий код драйвера из PHP 5.7):

switch (bind->array.type) {
    case SQLT_NUM:
    case SQLT_INT:
    case SQLT_LNG:

        ...
        ZVAL_LONG(entry, ((ub4 *)(bind->array.elements))[i]);
        ...

Значение в этом месте приводится к четырёхбайтному целому.

2 комментария
PHP 2014

ПЫХ — поделие школьников для школьников.
То, что ПЫХ столь популярен, напоминает ситуацию, когда в одной такой стране
был дважды несудимый президент.

Евгений Степанищев (bolknote.ru) 2014

Комментарий для PHP:

Спасибо за ваше интересное мнение!