简体   繁体   English

在PDO查询中用新列更改TABLE有什么问题?

[英]What is wrong in this PDO query to ALTERing my TABLE with a new column?

I am trying to add a new column to a table with a set date as the column head and a tinyint(1) as the datatype 我正在尝试向表中添加一个新列,并将日期设置为列头,并以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.');}
}

You haven't described what isn't working in this code, but I'll offer a guess that $date contains some formatting of the current date, like '2014-05-28' . 您尚未描述这段代码中没有起作用的内容,但我会猜测$date包含当前日期的某些格式,例如'2014-05-28' Your regular expression filtering would permit that string. 您的正则表达式过滤将允许该字符串。 Then you use that as a column name: 然后,将其用作列名:

$column_name = strtolower($date);

When you go to add the column you generate what appears to be an arithmetic expression as a column name, which will result in an error: 当您添加列时,您会生成一个看起来像算术表达式的列名,这将导致错误:

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

If you delimit the column name in back-ticks, you can actually use that as a column name: 如果用反引号分隔列名,则可以将其实际用作列名:

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

However, just because SQL permits such strange column names, doesn't mean it's a good idea. 但是,仅仅因为SQL允许这样奇怪的列名,并不意味着它是一个好主意。 Using that column will be inconvenient at best, and you should probably rethink this idea. 使用该专栏充其量是最不便的,您可能应该重新考虑这个想法。


The other thing wrong with your code is that you don't check for errors from prepare() or execute() . 代码的另一件事是您不检查prepare()execute() You may have enabled PDO to throw exceptions on error, but I'm assuming you haven't. 您可能已启用PDO引发错误错误,但我假设您没有。 That would mean that you should expect prepare and execute to return false if they find an error. 这意味着您应该期望prepare和execute在发现错误时返回false

And of course calling $st->execute() is a fatal error if $st doesn't have that method. 如果$st没有该方法,则调用$st->execute()当然是一个致命错误。

So you should check for errors: 因此,您应该检查错误:

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));
}

PDO::prepare really isn't meant to be used that way. PDO :: prepare确实不是那样使用的。 It is meant as a way of preparing a statement for execution. 它是作为准备执行语句的一种方式。 ( The first comment here explains in much more depth). 这里的第一条评论更深入地解释了这一点)。 You are looking for PDO::exec . 您正在寻找PDO::exec Here is probably the most important excerpt: 这可能是最重要的摘录:

To those wondering why adding quotes to around a placeholder is wrong, and why you can't use placeholders for table or column names: 对于那些想知道为什么在占位符周围添加引号是错误的,以及为什么不能对表名或列名使用占位符的人,请问:

There is a common misconception about how the placeholders in prepared statements work: they are not simply substituted in as (escaped) strings, and the resulting SQL executed. 对于准备好的语句中的占位符如何工作,存在一个普遍的误解:不是简单地将它们替换为(转义的)字符串,然后执行结果SQL。 Instead, a DBMS asked to "prepare" a statement comes up with a complete query plan for how it would execute that query, including which tables and indexes it would use, which will be the same regardless of how you fill in the placeholders. 取而代之的是,要求“准​​备”语句的DBMS提出了完整的查询计划,以说明如何执行该查询,包括它将使用哪些表和索引,无论您如何填充占位符,它们都是相同的。

The plan for "SELECT name FROM my_table WHERE id = :value" will be the same whatever you substitute for ":value", but the seemingly similar "SELECT name FROM :table WHERE id = :value" cannot be planned, because the DBMS has no idea what table you're actually going to select from. 无论用什么替换“:value”,“ SELECT name FROM my_table WHERE id =:value”的计划都是相同的,但是看似相似的“ SELECT name FROM:table WHERE id =:value”却无法计划,因为DBMS不知道您实际上要从哪个表中进行选择。

It should be noted that while a column name containing only letters and numbers (which is currently enforced by your preg_match ) will be safe, it is best practice to still quote an input (such as with PDO::quote ). 应该注意的是,虽然仅包含字母和数字的列名(目前由preg_match强制执行)是安全的,但最佳做法是仍然对输入进行引用(例如PDO::quote )。 I would also suggest that you look into proper naming rules for columns , because that regular expression might not be the most accurate. 我还建议您研究适当的column命名规则 ,因为该正则表达式可能不是最准确的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM