mysql視圖和存儲過程定義者修改腳本(懶人專用)


前言: 在實際工作中mysql數據庫的遷移、備份恢復、數據庫重命名等一系列涉及到視圖和存儲過程定義者問題都會需要修改,每次都要從基礎表獲取數據,然后手工整理做腳本,十分麻煩,所以簡單寫了個過程,以后可以更加方便的遷移后更新定義者問題了,下面是解決過程~

 

-- 失敗第一個版本 及失敗原因

CREATE DEFINER = CURRENT_USER()
PROCEDURE CHANGE_DEFINER(
    `pr_database_name` VARCHAR(500), -- 數據庫名稱
    `pr_definer_name` VARCHAR(500), -- 定義者名稱
    `pr_definer_ip_name` VARCHAR(500)-- 定義者綁定的ip,默認為 % ,任意ip
)
BEGIN

DECLARE SQL_CHANGE_DEFINER longtext;
DECLARE DATABASE_NAME VARCHAR(500);
DECLARE DEFINER_NAME VARCHAR(500) DEFAULT CURRENT_USER();
DECLARE DEFINER_IP_NAME VARCHAR (500) DEFAULT '%';

SET DATABASE_NAME = TRIM(pr_database_name);

IF pr_definer_name IS NOT NULL AND LENGTH(pr_definer_name)>0 THEN
SET DEFINER_NAME = TRIM(pr_definer_name);
END IF;
IF pr_definer_ip_name IS NOT NULL AND LENGTH(pr_definer_ip_name) > 0 THEN
SET    DEFINER_IP_NAME = pr_definer_ip_name;
END IF;

-- 組裝修改視圖定義者語句
IF DATABASE_NAME IS NOT NULL AND LENGTH(DATABASE_NAME)>0 THEN 
-- group_concat默認查詢結果長度1024,長度不足,設置成足夠長度如下
SET GLOBAL group_concat_max_len=1024000;
SET SESSION group_concat_max_len=1024000;

  SELECT
    GROUP_CONCAT(
        ' alter definer = `',
        DEFINER_NAME,
        '`@`' ,DEFINER_IP_NAME, '` view ',
        TABLE_NAME,
        ' as ',
        VIEW_DEFINITION,
        ';' SEPARATOR ''
    ) INTO SQL_CHANGE_DEFINER
FROM
    information_schema.VIEWS
WHERE
    TABLE_SCHEMA = DATABASE_NAME
GROUP BY
    TABLE_SCHEMA;

  -- 執行修改視圖定義者
  SET @VALUE = CONCAT(SQL_CHANGE_DEFINER);
  PREPARE stmt FROM @VALUE;
  EXECUTE stmt;

  -- 修改存儲過程定義者

  UPDATE mysql.proc  set DEFINER = CONCAT(DEFINER_NAME,'@',DEFINER_IP_NAME) WHERE db = DATABASE_NAME;
 
ELSE
  SELECT '數據庫名稱不允許為空';
END IF;

END
mysql不支持問題代碼

對於這個版本是由於prepare stmt from 語句,這個語句只能是單獨的語句,而我卻 alter ...; alter ...; 肯定不行了,改成每一個單獨就好了吧,繼續改

-- 失敗第二個版本 及失敗原因

CREATE DEFINER = 'harri'@'%'
PROCEDURE my_apm.CHANGE_DEFINER(
    `pr_database_name` VARCHAR(500), -- 數據庫名稱
    `pr_definer_name` VARCHAR(500), -- 定義者名稱
    `pr_definer_ip_name` VARCHAR(500)-- 定義者綁定的ip,默認為 % ,任意ip
)
BEGIN

DECLARE SQL_CHANGE_DEFINER longtext;
DECLARE DATABASE_NAME VARCHAR(500);
DECLARE DEFINER_NAME VARCHAR(500) DEFAULT CURRENT_USER();
DECLARE DEFINER_IP_NAME VARCHAR (500) DEFAULT '%';

DECLARE flag boolean DEFAULT 1;
DECLARE cur CURSOR FOR SELECT value_ FROM sql_value;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET flag = 0;

DROP TEMPORARY TABLE IF EXISTS sql_value; 
CREATE TEMPORARY TABLE sql_value(value_ varchar(15000));


SET DATABASE_NAME = TRIM(pr_database_name);

IF pr_definer_name IS NOT NULL AND LENGTH(pr_definer_name)>0 THEN
SET DEFINER_NAME = TRIM(pr_definer_name);
END IF;
IF pr_definer_ip_name IS NOT NULL AND LENGTH(pr_definer_ip_name) > 0 THEN
SET    DEFINER_IP_NAME = pr_definer_ip_name;
END IF;

-- 組裝修改視圖定義者語句
IF DATABASE_NAME IS NOT NULL AND LENGTH(DATABASE_NAME)>0 THEN 
  INSERT INTO sql_value(value_)
  SELECT
    GROUP_CONCAT(
        ' alter definer = `',
        DEFINER_NAME,
        '`@`' ,DEFINER_IP_NAME, '` view ',
        TABLE_NAME,
        ' as ',
        VIEW_DEFINITION,
        ';' SEPARATOR ''
    )
FROM
    information_schema.VIEWS
WHERE
    TABLE_SCHEMA = DATABASE_NAME
GROUP BY
    TABLE_NAME;

  -- 執行修改視圖定義者
OPEN cur;

rep:LOOP

  FETCH cur INTO SQL_CHANGE_DEFINER;
  set @VALUE = SQL_CHANGE_DEFINER;
  IF flag = 0 THEN 
    LEAVE rep;
  END IF;

   PREPARE stmt FROM @VALUE;
   EXECUTE stmt;
   DEALLOCATE PREPARE stmt;
END LOOP;

CLOSE cur;
  -- 修改存儲過程定義者

  UPDATE mysql.proc  set DEFINER = CONCAT(DEFINER_NAME,'@',DEFINER_IP_NAME) WHERE db = DATABASE_NAME;
 
ELSE
  SELECT '數據庫名稱不允許為空';
END IF;

END
還是mysql不支持問題

感覺穩穩的了,結果出乎意料,看來prepare 支持的語句掌握不牢靠,竟然不支持 alter view, 為什么alter table都支持還差view了嗎,於是乎去查mysql 5.6官方手冊,支持的語句如下:

ALTER TABLE
ALTER USER (as of MySQL 5.6.8)
ANALYZE TABLE
CACHE INDEX
CALL
CHANGE MASTER
CHECKSUM {TABLE | TABLES}
COMMIT
{CREATE | RENAME | DROP} DATABASE
{CREATE | DROP} INDEX
{CREATE | RENAME | DROP} TABLE
{CREATE | RENAME | DROP} USER
{CREATE | DROP} VIEW
DELETE
DO
FLUSH {TABLE | TABLES | TABLES WITH READ LOCK | HOSTS | PRIVILEGES
| LOGS | STATUS | MASTER | SLAVE | DES_KEY_FILE | USER_RESOURCES}
GRANT
INSERT
INSTALL PLUGIN
KILL
LOAD INDEX INTO CACHE
OPTIMIZE TABLE
REPAIR TABLE
REPLACE
RESET {MASTER | SLAVE | QUERY CACHE}
REVOKE
SELECT
SET
SHOW {AUTHORS | CONTRIBUTORS | WARNINGS | ERRORS}
SHOW BINLOG EVENTS
SHOW CREATE {PROCEDURE | FUNCTION | EVENT | TABLE | VIEW}
SHOW {MASTER | BINARY} LOGS
SHOW {MASTER | SLAVE} STATUS
SLAVE {START | STOP}
TRUNCATE TABLE
UNINSTALL PLUGIN
UPDATE

這里還有一句話,Other statements are not supported in MySQL 5.6. 擦汗啊,這么簡單個腳本一波三折,萬幸看到了drop view,和 create view 這不就直接等於alter view了嗎?

就這么改,於是乎終於成功了,如下:

CREATE DEFINER = CURRENT_USER()
PROCEDURE my_apm.CHANGE_DEFINER(
    `pr_database_name` VARCHAR(500), -- 數據庫名稱
    `pr_definer_name` VARCHAR(500), -- 定義者名稱
    `pr_definer_ip_name` VARCHAR(500)-- 定義者綁定的ip,默認為 % ,任意ip
)
BEGIN

DECLARE drop_view_ varchar(500);
DECLARE create_view_ varchar(15000);
DECLARE DATABASE_NAME VARCHAR(500);
DECLARE DEFINER_NAME VARCHAR(500) DEFAULT CURRENT_USER();
DECLARE DEFINER_IP_NAME VARCHAR (500) DEFAULT '%';

DECLARE flag boolean DEFAULT 1;
DECLARE cur CURSOR FOR SELECT drop_view,create_view FROM sql_value;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET flag = 0;

DROP TEMPORARY TABLE IF EXISTS sql_value; 
CREATE TEMPORARY TABLE sql_value(drop_view varchar(500),create_view varchar(15000));


SET DATABASE_NAME = TRIM(pr_database_name);

IF pr_definer_name IS NOT NULL AND LENGTH(pr_definer_name)>0 THEN
SET DEFINER_NAME = TRIM(pr_definer_name);
END IF;
IF pr_definer_ip_name IS NOT NULL AND LENGTH(pr_definer_ip_name) > 0 THEN
SET    DEFINER_IP_NAME = pr_definer_ip_name;
END IF;

-- 組裝修改視圖定義者語句
IF DATABASE_NAME IS NOT NULL AND LENGTH(DATABASE_NAME)>0 THEN 
  INSERT INTO sql_value(drop_view,create_view)
  SELECT
  GROUP_CONCAT('drop view if exists ',TABLE_NAME,';'),
    GROUP_CONCAT('create definer = `',
        DEFINER_NAME,
        '`@`' ,DEFINER_IP_NAME, '` view ',
        TABLE_NAME,
        ' as ',
        VIEW_DEFINITION,
        ';' SEPARATOR ''
    )
FROM
    information_schema.VIEWS
WHERE
    TABLE_SCHEMA = DATABASE_NAME
GROUP BY
    TABLE_NAME;

  -- 執行修改視圖定義者
OPEN cur;

rep:LOOP

  FETCH cur INTO drop_view_,create_view_;
  set @drop_view_ = drop_view_;
  set @create_view_ = create_view_;
  IF flag = 0 THEN 
    LEAVE rep;
  END IF;

   PREPARE stmt FROM @drop_view_;
   EXECUTE stmt;
   DEALLOCATE PREPARE stmt;
   PREPARE stmt FROM @create_view_;
   EXECUTE stmt;
   DEALLOCATE PREPARE stmt;
END LOOP;

CLOSE cur;

-- 修改存儲過程定義者
UPDATE mysql.proc  set DEFINER = CONCAT(DEFINER_NAME,'@',DEFINER_IP_NAME) WHERE db = DATABASE_NAME AND NAME != 'CHANGE_DEFINER';
 
ELSE
  SELECT '數據庫名稱不允許為空';
END IF;

END

上面過程可能有哪里不合理的地方,歡迎指正

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM