Что не так в этом запросе PDO для ИЗМЕНЕНИЯ моей ТАБЛИЦЫ с новым столбцом?

Я пытаюсь добавить новый столбец в таблицу с установленной датой в качестве заголовка столбца и tinyint (1) в качестве типа данных.

function addAttendance($date) {
    include('connection.php');
    $column_name = strtolower($date);
    if(!preg_match('/[^A-Za-z0-9.#\\-$]/', $column_name)){
        if(!empty($column_name)) {
            $st = $db->prepare("DESCRIBE attendance");
            $st->execute();
            $st = $st->fetchAll(PDO::FETCH_COLUMN);
            $compare = $st;

            foreach($compare as $key) {
                if($key === $column_name) {
                        die('Project name already exists. Please select a different name.');
                }
            }

            $st = $db->prepare("ALTER TABLE attendance ADD $column_name BOOLEAN");
            $st->execute();

        } else { die('Project name is empty.');}     
    } else { die('Project name can only contain letters and numbers.');}
}

person castor520    schedule 29.05.2014    source источник


Ответы (2)


Вы не описали, что не работает в этом коде, но я предполагаю, что $date содержит некоторое форматирование текущей даты, например '2014-05-28'. Ваша фильтрация регулярных выражений разрешит эту строку. Затем вы используете это как имя столбца:

$column_name = strtolower($date);

Когда вы добавляете столбец, вы создаете то, что кажется арифметическим выражением в качестве имени столбца, что приведет к ошибке:

mysql> ALTER TABLE attendance ADD COLUMN 2014-05-28 BOOLEAN;
ERROR 1064 (42000): You have an error in your SQL syntax; 
check the manual that corresponds to your MySQL server version for the right syntax to use
near '2014-05-28 BOOLEAN' at line 1

Если вы разделите имя столбца обратными кавычками, вы можете использовать его как имя столбца:

mysql> ALTER TABLE attendance ADD COLUMN `2014-05-28` BOOLEAN;
Query OK, 0 rows affected (0.11 sec)

Однако то, что SQL допускает такие странные имена столбцов, не означает, что это хорошая идея. Использование этого столбца будет в лучшем случае неудобным, и вам, вероятно, следует переосмыслить эту идею.


Другая проблема с вашим кодом заключается в том, что вы не проверяете наличие ошибок из prepare() или execute(). Возможно, вы разрешили PDO генерировать исключения при ошибке, но я предполагаю, что вы этого не сделали. Это означает, что вы должны ожидать, что prepare и execute вернут false, если обнаружат ошибку.

И, конечно же, вызов $st->execute() является фатальной ошибкой, если $st не имеет этого метода.

Итак, вы должны проверить наличие ошибок:

if (($st = $db->prepare("ALTER TABLE attendance ADD $column_name BOOLEAN")) === false) {
    die(print_r($db->errorInfo(), true));
}
if ($st->execute() === false) {
    die(print_r($st->errorInfo(), true));
}
person Bill Karwin    schedule 29.05.2014

PDO::prepare действительно не предназначен для такого использования. Это предназначено как способ подготовки оператора к выполнению. (Первый комментарий здесь объясняет гораздо более подробно). Вы ищете PDO::exec. Вот, пожалуй, самый важный отрывок:

Для тех, кто интересуется, почему неправильно добавлять кавычки вокруг заполнителя и почему вы не можете использовать заполнители для имен таблиц или столбцов:

Существует распространенное заблуждение о том, как работают заполнители в подготовленных операторах: они не просто заменяются как (экранированные) строки, а результирующий SQL выполняется. Вместо этого СУБД, которую попросили подготовить оператор, предлагает полный план выполнения этого запроса, включая используемые таблицы и индексы, которые будут одинаковыми независимо от того, как вы заполните заполнители.

План для SELECT name FROM my_table WHERE id = :value будет таким же, что бы вы ни заменяли на :value, но внешне похожее SELECT name FROM :table WHERE id = :value не может быть запланировано, потому что СУБД понятия не имеет, какую таблицу вы Выбираем из.

Следует отметить, что хотя имя столбца, содержащее только буквы и цифры (которое в настоящее время применяется вашим preg_match), будет безопасным, рекомендуется по-прежнему заключать входные данные в кавычки (например, с PDO::quote). Я бы также посоветовал вам изучить правильные правила именования столбцов, потому что это регулярное выражение может быть не самым точным.

person cwallenpoole    schedule 29.05.2014
comment
PDO::quote() не будет правильно заключать в кавычки идентификаторы столбцов. - person Bill Karwin; 29.05.2014
comment
@BillKarwin Вы правы, но опять же, регулярное выражение защищает его, по крайней мере, теоретически. Эта мысль больше связана с тем, что, если в какой-то момент они решат удалить регулярное выражение? Конечно, они все еще будут в ручье, но не так плохо, как если бы у них ничего не было с самого начала. - person cwallenpoole; 29.05.2014