【问题标题】:Is there a way to execute a prepared DESCRIBE query?有没有办法执行准备好的 DESCRIBE 查询?
【发布时间】:2013-10-23 04:11:46
【问题描述】:

我遇到的问题是:当我尝试准备一个由 DESCRIBE table_nameSHOW COLUMNS FROM table_name 组成的查询时,我收到一条错误消息:

致命错误:未捕获的异常 'PDOException' 带有消息 'SQLSTATE[42000]:语法错误或访问冲突:1064 您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以在 /Applications/MAMP/htdocs/test.php:28 中的第 1 行的“用户”附近使用正确的语法堆栈跟踪:#0 /Applications/MAMP/htdocs /test.php(28): PDOStatement->execute() #1 /Applications/MAMP/htdocs/test.php(6): show_columns_yes_prepared('users') #2 {main} 抛出 /Applications/MAMP/htdocs/第 28 行的 test.php

函数show_columns_not_prepared() 返回以下内容,正如预期/希望的那样:

Array
(
    [0] => uid
    [1] => name
    [2] => pass
    [3] => mail
    [4] => mode
    [5] => sort
    [6] => threshold
    [7] => theme
    [8] => signature
    [9] => signature_format
    [10] => created
    [11] => access
    [12] => login
    [13] => status
    [14] => timezone
    [15] => language
    [16] => picture
    [17] => init
    [18] => data
    [19] => timezone_name
    [20] => timezone_id
)

... 而上述错误是由函数show_columns_yes_prepared() 引起的。两者都可以在下面找到,以及文件test.php 中使用的其余源代码(逐字),该文件位于我的本地主机的根目录中。

准备DESCRIBE SQL 查询是一项不可能完成的任务吗? 还是我做错了什么?两者都不?两者都有?


数据库/表创建

CREATE DATABASE `testdatabaseforpdo` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `testdatabaseforpdo`;

CREATE TABLE `users` (
  `uid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(60) NOT NULL DEFAULT '',
  `pass` varchar(32) NOT NULL DEFAULT '',
  `mail` varchar(64) DEFAULT '',
  `mode` tinyint(4) NOT NULL DEFAULT '0',
  `sort` tinyint(4) DEFAULT '0',
  `threshold` tinyint(4) DEFAULT '0',
  `theme` varchar(255) NOT NULL DEFAULT '',
  `signature` varchar(255) NOT NULL DEFAULT '',
  `signature_format` smallint(6) NOT NULL DEFAULT '0',
  `created` int(11) NOT NULL DEFAULT '0',
  `access` int(11) NOT NULL DEFAULT '0',
  `login` int(11) NOT NULL DEFAULT '0',
  `status` tinyint(4) NOT NULL DEFAULT '0',
  `timezone` varchar(8) DEFAULT NULL,
  `language` varchar(12) NOT NULL DEFAULT '',
  `picture` varchar(255) NOT NULL DEFAULT '',
  `init` varchar(64) DEFAULT '',
  `data` longtext,
  `timezone_name` varchar(50) NOT NULL DEFAULT '',
  `timezone_id` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`uid`),
  UNIQUE KEY `name` (`name`),
  KEY `access` (`access`),
  KEY `created` (`created`),
  KEY `mail` (`mail`),
  KEY `picture` (`picture`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

源代码(根据需要调整getConnection()内的连接信息):

<?php

$table = 'users';

print_r(show_columns_not_prepared($table)); 
print_r(show_columns_yes_prepared($table)); 

function show_columns_not_prepared($table) {
  $db = getConnection();
  // Not prepared, not safe...
  $sql = "DESCRIBE $table";
  $stmt = $db->query($sql);
  $out = array();
  while ($res = $stmt->fetchAll(PDO::FETCH_ASSOC)) {
    for ($i = 0; $i < count($res); $i++) {
      $out[] = $res[$i]['Field'];
    }
  }
  return $out;
}

function show_columns_yes_prepared($table) {
  $db = getConnection();
  // Ready to be prepared...
  $sql = "DESCRIBE :table";
  $stmt = $db->prepare($sql);
  $stmt->bindValue(':table', $table, PDO::PARAM_STR);
  $stmt->execute();
  $out = array();
  while($res = $stmt->fetch(PDO::FETCH_ASSOC)) {
    for ($i = 0; $i < count($res); $i++) {
      $out[] = $res[$i]['Field'];
    }
  }
  return $out;
}

function getConnection() {
  $dbhost="localhost";
  $dbuser="someuser";
  $dbpass="somepass";
  $dbname="testdatabaseforpdo";
  $dbh = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);
  $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  $dbh->exec("set names utf8");
  return $dbh;
}

【问题讨论】:

  • 为什么您甚至需要运行该查询?只需从information_schema 查询即可。
  • 我知道这是一个选项,但这不是我问的问题。
  • 您不能将参数绑定到数据库标识符(表/列名),因为这相当于执行DESCRIBE 'users'。正如杰克所说,使用information_schema 这样做或将标识符名称直接注入查询中。
  • 一些开发人员实际上并不知道这一点,因此提到了这一点。

标签: php mysql pdo


【解决方案1】:

safeMysql 是鸡:

function show_columns_yes_prepared($table)
{
    $db = getConnection(); // I HOPE it's SINGLETON. Yikes, it is not
    return $db->getCol( "DESCRIBE ?n", $table);
}

用丑陋的 PDO 它could be a problem,所以,你最好坚持information_schema 查询为Jack suggested

function show_columns_yes_prepared($pdo, $table)
{
    $sql = "SELECT column_name FROM information_schema.columns WHERE table_name =?";
    $stm = $pdo->prepare($sql);
    $stm->execute([$table]);
    return $stm->fetchAll(PDO::FETCH_COLUMN);
}

但你的主要问题不是那个无用的查询

但是 getConnection(); 函数会在或多或少的生产环境中真正杀死您的数据库服务器。

因为您应该只连接每个应用程序 ONCE 并在整个脚本中使用该单一连接,而不是每次需要查询数据库时都连接。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-20
    • 2021-04-09
    • 1970-01-01
    • 1970-01-01
    • 2018-06-02
    • 2016-06-07
    相关资源
    最近更新 更多