我正在尝试在PHP(特别是Laravel)中创建一个MySQL视图,我遇到了一个奇怪的错误:
[PDOException]
SQLSTATE[42000]: SSyntax error or access violation: 1142 ANY command denied to user 'user'@'localhost' for table '/tmp/#sql_475_0'
在MySQL中直接运行create语句可以正常工作。如果我删除了视图的连接,那么一切正常。用户具有完全权限(GRANT ALL)。广泛的谷歌搜索没有返回任何类似的东西。
我的代码如下,略有简化,运行第4个语句创建jobs_view时会产生错误。
DB::statement("
CREATE VIEW quote_response_count AS (
SELECT job_id, COUNT(quotes.id) as total FROM quotes
INNER JOIN quote_requests on quote_requests.quote_id = quotes.id
INNER JOIN quote_responses on quote_responses.quote_request_id = quote_requests.id
GROUP BY job_id
);
");
DB::statement("
CREATE VIEW customer_paid AS (
SELECT job_id, SUM(amount) as total FROM transactions
WHERE category = 'customer payment' AND is_verified = 1
GROUP BY job_id, category
);
");
DB::statement("
CREATE VIEW company_paid AS (
SELECT job_id, SUM(amount) as total FROM transactions
WHERE category = 'company payment' AND is_verified = 1
GROUP BY job_id, category
);
");
DB::statement("
CREATE VIEW jobs_view AS (
SELECT
jobs.*,
IFNULL(customer_paid.total, 0) AS customer_paid,
IFNULL(company_paid.total, 0) AS company_paid,
IFNULL(quote_response_count.total, 0) AS responses_received,
price - IFNULL(customer_paid.total, 0) AS customer_owes,
cost - IFNULL(customer_paid.total, 0) AS owes_company,
(
deposit > 0 AND IFNULL(customer_paid.total, 0) >= deposit
) AS deposit_paid
FROM jobs
LEFT OUTER JOIN quote_response_count AS quote_response_count ON quote_response_count.job_id = jobs.id
LEFT OUTER JOIN customer_paid AS customer_paid ON customer_paid.job_id = jobs.id
LEFT OUTER JOIN company_paid AS company_paid ON company_paid.job_id = jobs.id
);
");
PHP应用程序中的SHOW GRANTS输出如下:
[Grants for user@localhost] => GRANT USAGE ON *.* TO 'user'@'localhost' IDENTIFIED BY PASSWORD '****************************'
[Grants for user@localhost] => GRANT ALL PRIVILEGES ON `dbname`.* TO 'user'@'localhost'
以下非常简化的示例也会产生相同的结果:
DB::statement("
CREATE TABLE table1 (
id int(11) NOT NULL AUTO_INCREMENT,
foo varchar(45) DEFAULT NULL,
PRIMARY KEY (id)
);
");
DB::statement("
CREATE VIEW view1 AS (
SELECT id, foo FROM table1
);
");
DB::statement("
CREATE VIEW view2 AS (
SELECT table1.id, view1.foo FROM table1
INNER JOIN view1 ON view1.id = table1.id
);
");
如果只是从view1中选择而不是加入,则会发生同样的错误。
我遇到此问题的系统是运行PHP 5.5.23和MySQL 5.5.41的Ubuntu 12.04服务器。
答案 0 :(得分:3)
尤里卡!对于遇到此问题的任何其他人,由于Laravel设置以下PDO连接选项而出现问题:
PDO::ATTR_EMULATE_PREPARES => false
我的解决方案是克隆我的数据库配置,覆盖PDO选项,然后在创建我的视图时使用该连接,而不是为我的整个应用程序启用Emulate Prepares:
'mysql' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'database',
'username' => 'user',
'password' => 'password',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
'mysql-emulate-prepares' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'database',
'username' => 'user',
'password' => 'password',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'options' => array(
PDO::ATTR_EMULATE_PREPARES => true,
),
),
$rand = rand(10000, 99999);
DB::statement("
CREATE TABLE table".$rand." (
id int(11) NOT NULL AUTO_INCREMENT,
foo varchar(45) DEFAULT NULL,
PRIMARY KEY (id)
);
");
DB::statement("
CREATE VIEW view".$rand." AS (
SELECT id, foo FROM table1
);
");
DB::connection('mysql-emulate-prepares')->statement("
CREATE VIEW view".($rand+2)." AS (
SELECT table".$rand.".id, view".$rand.".foo FROM table".$rand."
INNER JOIN view".$rand." ON view".$rand.".id = table".$rand.".id
);
");
Ryan Vincent帮助我调试这个问题。{/ p>
答案 1 :(得分:0)
这是另一个不涉及创建和指定单独配置的解决方案:
$dconn = DB::connection()->getDoctrineConnection();
$dconn->exec("CREATE OR REPLACE VIEW ...");
请注意:
调用getDoctrineConnection()
方法会创建一个新的PDO对象,而DatabaseManager
不会跟踪该
这意味着DB::reconnect()
,DB::disconnect()
或DB::purge()
不会影响这个新的PDO对象。因此,它将作为请求其余部分的开放连接。
这通常不是Web请求或部署操作中的问题,因为脚本最终会结束。但是,如果一个人正在使用长期运行的妖魔化PHP进程与Gearman或Resque之类的东西,那么最终会抛出一条PDO异常并显示消息MySQL server has gone away (error 2006)
此问题的解决方案是显式关闭Doctrine连接,如下所示:
$dconn = DB::connection()->getDoctrineConnection();
$dconn->exec("CREATE OR REPLACE VIEW ...");
$dconn->close();