【问题标题】:Invalid stored procedure syntax on MySQL 5.7 but works on MariaDBMySQL 5.7 上的存储过程语法无效,但适用于 MariaDB
【发布时间】:2020-08-08 15:16:54
【问题描述】:

我正在尝试编写一个 MySQL 脚本来将管理员用户添加到服务器上的每个 WordPress 数据库并更新用户名中的用户信息已经存在。

我编写了以下脚本,它可以在带有 MariaDB 10.2.31 和 innodb_version 5.7.29 的服务器上运行,但它不能在运行 MySQL Community Server 5.7.29 的服务器上运行,我收到一条错误消息:

#1064 - 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 'IF EXISTS (SELECT * FROM cpaneluser_wp.wp_users WHERE user_login = 'newwpuser') THEN' at line 1

这是创建存储过程的脚本:

-- Create and update a WordPress administrator across all databases
USE mysql;

delimiter $$

DROP PROCEDURE IF EXISTS ensure_global_wp_user $$

CREATE PROCEDURE ensure_global_wp_user(
  IN username VARCHAR(255),
  IN email VARCHAR(255),
  IN password VARCHAR(255),
  IN nicename VARCHAR(255),
  IN displayname VARCHAR(255)
)
BEGIN

DECLARE current_schema VARCHAR(255);
DECLARE finished INTEGER DEFAULT 0;

DECLARE wp_schemas CURSOR FOR
  SELECT DISTINCT table_schema
    FROM INFORMATION_SCHEMA.tables
    WHERE table_name = 'wp_users';

DECLARE CONTINUE HANDLER
  FOR NOT FOUND
  SET finished = 1;

OPEN wp_schemas;

DROP TEMPORARY TABLE IF EXISTS exec_results;
CREATE TEMPORARY TABLE IF NOT EXISTS exec_results (
  username VARCHAR(255),
  dbname VARCHAR(255),
  action VARCHAR(255)
);

loopSchemas: LOOP
  FETCH wp_schemas INTO current_schema;
  IF finished = 1 THEN
    LEAVE loopSchemas;
  END IF;

  SET @expression = CONCAT("
    IF EXISTS (SELECT * FROM ",current_schema,".wp_users WHERE user_login = '",username,"') THEN
      UPDATE ",current_schema,".wp_users
        SET
          user_pass = MD5('",password,"'),
          user_email = '",email,"',
          user_nicename = '",nicename,"',
          display_name = '",displayname,"'
        WHERE user_login = '",username,"';
      INSERT INTO exec_results VALUES ('",username,"','",current_schema,"','updated');
    ELSE
      INSERT INTO ",current_schema,".wp_users (user_login, user_pass, user_nicename, user_email, user_status, display_name, user_registered) VALUES
        ('",username,"', MD5('",password,"'), '",nicename,"', '",email,"', '0', '",displayname,"', NOW());
      SET @user_insert_id = LAST_INSERT_ID();
      INSERT INTO ",current_schema,".wp_usermeta (user_id, meta_key, meta_value) VALUES
        (@user_insert_id, 'wp_capabilities', 'a:1:{s:13:\"administrator\";b:1;}');
      INSERT INTO ",current_schema,".wp_usermeta (user_id, meta_key, meta_value) VALUES
        (@user_insert_id, 'wp_user_level', '10');
      INSERT INTO exec_results VALUES ('",username,"','",current_schema,"','added');
    END IF;
  ");
  PREPARE stmt FROM @expression;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;

END LOOP loopSchemas;

CLOSE wp_schemas;

SELECT * FROM exec_results;

END $$

delimiter ;

你可以这样称呼它:

-- Create or update the newwpuser user on all wordpress databases
call ensure_global_wp_user('newwpuser', 'newwpuser@example.com', 'newpassword', 'newwpuser', 'newwpuser');

是否有不同的语法来实现这一点?我也尝试将sql_mode 设置为'',但没有任何区别。

【问题讨论】:

    标签: mysql sql stored-procedures mysql-5.7


    【解决方案1】:

    似乎根本问题在于,在 MySQL 中,与 MariaDB 不同,每次执行只需要 ONE 准备好的语句。

    感谢nbk 帮助分离 if 语句,我能够让它按如下方式工作:

    USE mysql;
    
    delimiter $$
    
    DROP PROCEDURE IF EXISTS ensure_global_wp_user $$
    CREATE PROCEDURE ensure_global_wp_user(
      IN username VARCHAR(255),
      IN email VARCHAR(255),
      IN password VARCHAR(255),
      IN nicename VARCHAR(255),
      IN displayname VARCHAR(255)
    )
    BEGIN
    
      DECLARE wp_schema VARCHAR(255);
      DECLARE finished INTEGER DEFAULT 0;
    
      DECLARE wp_schemas CURSOR FOR
        SELECT DISTINCT table_schema
          FROM INFORMATION_SCHEMA.tables
          WHERE table_name = 'wp_users';
    
      DECLARE CONTINUE HANDLER
        FOR NOT FOUND
        SET finished = 1;
    
      OPEN wp_schemas;
    
      DROP TEMPORARY TABLE IF EXISTS exec_results;
      CREATE TEMPORARY TABLE exec_results (
        username VARCHAR(255),
        dbname VARCHAR(255),
        action VARCHAR(255)
      );
    
      loopSchemas: LOOP
        FETCH wp_schemas INTO wp_schema;
        IF finished = 1 THEN
          LEAVE loopSchemas;
        END IF;
    
        SET @sql = CONCAT("
          SELECT EXISTS (
            SELECT *
              FROM ",wp_schema,".wp_users
              WHERE user_login = '",username,"'
          ) INTO @user_exists;");
        PREPARE stmt FROM @sql;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
    
        IF @user_exists = 1 THEN
          SET @sql = CONCAT("
            UPDATE ",wp_schema,".wp_users
              SET
                user_pass = MD5('",password,"'),
                user_email = '",email,"',
                user_nicename = '",nicename,"',
                display_name = '",displayname,"'
              WHERE user_login = '",username,"';
          ");
          PREPARE stmt FROM @sql;
          EXECUTE stmt;
          DEALLOCATE PREPARE stmt;
    
          INSERT INTO exec_results VALUES (username, wp_schema, 'updated');
        ELSE
          SET @sql = CONCAT("
            INSERT INTO ",wp_schema,".wp_users (user_login, user_pass, user_nicename, user_email, user_status, display_name, user_registered) VALUES
              ('",username,"', MD5('",password,"'), '",nicename,"', '",email,"', '0', '",displayname,"', NOW());
          ");
          PREPARE stmt FROM @sql;
          EXECUTE stmt;
          DEALLOCATE PREPARE stmt;
    
          SET @user_insert_id = LAST_INSERT_ID();
    
          SET @sql = CONCAT("
            INSERT INTO ",wp_schema,".wp_usermeta (user_id, meta_key, meta_value) VALUES
              (@user_insert_id, 'wp_capabilities', 'a:1:{s:13:\"administrator\";b:1;}');
          ");
          PREPARE stmt FROM @sql;
          EXECUTE stmt;
          DEALLOCATE PREPARE stmt;
    
          SET @sql = CONCAT("
            INSERT INTO ",wp_schema,".wp_usermeta (user_id, meta_key, meta_value) VALUES
              (@user_insert_id, 'wp_user_level', '10');
          ");
          PREPARE stmt FROM @sql;
          EXECUTE stmt;
          DEALLOCATE PREPARE stmt;
    
          INSERT INTO exec_results VALUES (username, wp_schema, 'added');
        END IF;
    
      END LOOP loopSchemas;
    
      CLOSE wp_schemas;
    
      SELECT * FROM exec_results;
    
    END $$
    
    delimiter ;
    

    【讨论】:

      【解决方案2】:

      你的@expression 在 mysql 中不是有效的代码。

      试试这个,当然没有你的表我无法完全测试它

      现在首先我通过另一个准备好的语句确定,如果用户存在,则返回 1 表示存在,否则返回 0。@res 中的此公园。

      并使用它来确定我应该使用和更新的方式,当存在时插入而不是插入。

      Thbis 也应该在 mariadb 中工作。

      DROP procedure IF EXISTS `ensure_global_wp_user`;
      
      DELIMITER $$
      USE `testdb`$$
      CREATE DEFINER=`root`@`localhost` PROCEDURE `ensure_global_wp_user`(
        IN username VARCHAR(255),
        IN email VARCHAR(255),
        IN password VARCHAR(255),
        IN nicename VARCHAR(255),
        IN displayname VARCHAR(255)
      )
      BEGIN
      
      DECLARE current_schema VARCHAR(255);
      DECLARE finished INTEGER DEFAULT 0;
      
      DECLARE wp_schemas CURSOR FOR
        SELECT DISTINCT table_schema
          FROM INFORMATION_SCHEMA.tables
          WHERE table_name = 'wp_users';
      
      DECLARE CONTINUE HANDLER
        FOR NOT FOUND
        SET finished = 1;
      
      OPEN wp_schemas;
      
      DROP TEMPORARY TABLE IF EXISTS exec_results;
      CREATE TEMPORARY TABLE IF NOT EXISTS exec_results (
        username VARCHAR(255),
        dbname VARCHAR(255),
        action VARCHAR(255)
      );
      
      loopSchemas: LOOP
        FETCH wp_schemas INTO current_schema;
        IF finished = 1 THEN
          LEAVE loopSchemas;
        END IF;
      SET @sql = CONCAT("SELECT  EXISTS (SELECT * FROM ",current_schema,".wp_users WHERE user_login = '",username,"') INTO @res;");
        PREPARE stmt FROM @sql;
        EXECUTE stmt;
      
          IF @res = 1 THEN
            SET @expression = CONCAT("UPDATE ",current_schema,".wp_users
              SET
                user_pass = MD5('",password,"'),
                user_email = '",email,"',
                user_nicename = '",nicename,"',
                display_name = '",displayname,"'
              WHERE user_login = '",username,"';
            INSERT INTO exec_results VALUES ('",username,"','",current_schema,"','updated');");
          ELSE
            SET @expression = CONCAT("INSERT INTO ",current_schema,".wp_users (user_login, user_pass, user_nicename, user_email, user_status, display_name, user_registered) VALUES
              ('",username,"', MD5('",password,"'), '",nicename,"', '",email,"', '0', '",displayname,"', NOW());
            SET @user_insert_id = LAST_INSERT_ID();
            INSERT INTO ",current_schema,".wp_usermeta (user_id, meta_key, meta_value) VALUES
              (@user_insert_id, 'wp_capabilities', 'a:1:{s:13:\"administrator\";b:1;}');
            INSERT INTO ",current_schema,".wp_usermeta (user_id, meta_key, meta_value) VALUES
              (@user_insert_id, 'wp_user_level', '10');
            INSERT INTO exec_results VALUES ('",username,"','",current_schema,"','added');");
          END IF;
      
        PREPARE stmt FROM @expression;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
      
      END LOOP loopSchemas;
      
      CLOSE wp_schemas; 
      
      SELECT * FROM exec_results;
      
      END$$
      
      DELIMITER ;
      

      【讨论】:

      • 如果我尝试得到:#1064 - 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 'INSERT INTO exec_results VALUES ('newuser','sysuser_wp','updated')' at line 8(更新/插入的错误相同)- 我使用临时表是否也有问题?
      • 我看不到任何错误,但就像我说的没有数据我无法完全测试它。但是你的基本问题是固定的。看看它是否更新了 wp_users 剩下的就是调试一下
      • 接受这个,因为它导致了解决方案,对于最终的 SQL,请参见下面的答案。
      猜你喜欢
      • 2020-01-10
      • 1970-01-01
      • 2017-06-05
      • 2020-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-28
      相关资源
      最近更新 更多