日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

存儲過程

存儲過程(PROCEDURE)是由一組預編譯的SQL語句組成的集合,可以在數據庫中進行存儲并反復調用。本文為您介紹在Hologres中使用存儲過程的方法。

使用限制

  • Hologres從V3.0版本起支持PL/pgSQL語法的存儲過程,PL/pgSQL語法詳情請參見SQL Procedural Language

  • 在Hologres的存儲過程中,支持多條DDL語句事務,支持多條DML混合事務,暫不支持DDL和DML混合事務,詳情請參見SQL事務能力

  • 存儲過程不支持設置返回值,無法作為UDF(User-defined Functions)使用。

權限說明

  • CREATE PROCEDURE需要用戶有Database中的Create權限,與新建表權限一致,詳情請參見SQL-CREATE PROCEDURE

  • CREATE OR REPLACE需要用戶同時擁有Database的Create權限和目標存儲過程的OWNER權限,詳見SQL-CREATE PROCEDURE

  • 執行存儲過程需要用戶有存儲過程的EXECUTE權限,詳見SQL-CALL

命令參考

Hologres支持的存儲過程語法兼容PostgreSQL,具體語法如下:

創建存儲過程

CREATE [ OR REPLACE ] PROCEDURE
    <procedure_name> ([<argname> <argtype>])
LANGUAGE 'plpgsql'
AS <definition>;

參數

說明

procedure_name

存儲過程名稱。

argname

參數名稱。參數可選,取決于存儲過程設計。

argtype

參數類型。

definition

定義存儲過程的具體實現,可以是一個SQL語句或者代碼塊。

更多參數詳情請參見SQL-CREATE PROCEDURE

修改存儲過程

ALTER PROCEDURE <procedure_name> ([<argname> <argtype>])
    OWNER TO <new_owner> | CURRENT_USER | SESSION_USER;

參數

說明

new_owner

新用戶名。

CURRENT_USER

當前用戶。

SESSION_USER

會話用戶。

參數詳情請參見SQL-ALTER PROCEDURE

刪除存儲過程

DROP PROCEDURE [ IF EXISTS ] <procedure_name> ([<argname> <argtype>]); 

參數詳情請參見SQL-DROP PROCEDURE

執行存儲過程

CALL <procedure_name> ([<argument>]);

參數

說明

argument

存儲過程所需的參數。參數可選,取決于存儲過程設計。

參數詳情請參見SQL-CALL

使用示例

  • 示例1:含多條DDL語句事務的存儲過程。

    1. 創建存儲過程。

      CREATE OR REPLACE PROCEDURE procedure_1()
      LANGUAGE 'plpgsql'
      AS $$
      BEGIN
          --- TXN1 --- 
          CREATE TABLE a1(key int);
          CREATE TABLE a2(key int);
          COMMIT; 
      
          --- TXN2 ---
          CREATE TABLE a3(key int);
          CREATE TABLE a4(key int);
          ROLLBACK;
      END; 
      $$;
    2. 調用存儲過程:表a1、a2創建成功,a3、a4未創建。

      CALL procedure_1();
  • 示例2:含多條DML語句事務的存儲過程。

    1. 創建存儲過程

      CREATE OR REPLACE PROCEDURE procedure_2()
      LANGUAGE 'plpgsql'
      AS $$
      BEGIN
          INSERT INTO a1 VALUES(1);
          INSERT INTO a2 VALUES(2);
          ROLLBACK;
      END;
      $$;
      
      CREATE OR REPLACE PROCEDURE procedure_3()
      LANGUAGE 'plpgsql'
      AS $$
      BEGIN
          INSERT INTO a1 VALUES(1);
          INSERT INTO a2 VALUES(2);
      END;
      $$;
    2. 執行存儲過程

      • 執行procedure_2:支持ROLLBACK,數據未成功寫入

        -- 開啟DML事務功能
        SET hg_experimental_enable_transaction = ON;
        
        -- 執行存儲過程
        CALL procedure_2();
      • 執行procedure_3:數據成功寫入

        -- 開啟DML事務功能
        SET hg_experimental_enable_transaction = ON;
        
        -- 執行存儲過程
        CALL procedure_3();
  • 示例3:同時含DDL和DML的存儲過程。

    1. 創建存儲過程:Hologres暫不支持DDL和DML混合事務,因此在存儲過程中,需要對DDL和DML分別執行COMMIT。

      CREATE OR REPLACE PROCEDURE procedure_4()
      LANGUAGE 'plpgsql'
      AS $$
      BEGIN
          INSERT INTO a1 VALUES(1);
          COMMIT;	
          CREATE TABLE bb(key int);
          COMMIT;	
          INSERT INTO a1 VALUES(2);
          INSERT INTO bb VALUES(1);    
          COMMIT;	
      END;
      $$;
    2. 執行存儲過程:建表和數據寫入均成功。

      -- 開啟DML事務功能
      SET hg_experimental_enable_transaction = ON;
      
      -- 執行存儲過程
      CALL procedure_4();
  • 示例4:含常見用法的存儲過程包括定義入參、定義中間變量、定義循環、定義IF條件、定義EXCEPTION等。

    1. 創建存儲過程。

      CREATE OR REPLACE PROCEDURE procedure_5(input text)
      LANGUAGE 'plpgsql'
      AS $$
      -- 定義中間變量
      DECLARE
      sql1 text;
      BEGIN
          -- 向入參的表里寫入一行數據
          EXECUTE 'insert into ' || input || ' values(1);';
          COMMIT;
      
          -- 建a3表
          CREATE TABLE a3(key int);
          COMMIT;
      
          -- 使用中間變量,向a3表寫入一條數據
          sql1 = 'insert into a3 values(1);';
          EXECUTE sql1;
      
          -- 定義FOR循環
          FOR i IN 1..10 LOOP
              BEGIN
                  -- i=1已存在表中,所以只打一條日志
                  IF i IN (SELECT KEY FROM a3) THEN
                      RAISE NOTICE 'Data already exists.';
                  -- 其他數字不存在表中,所以嘗試寫入,同時RAISE EXCEPTION,而后COMMIT
                  ELSE
                      INSERT INTO a3 VALUES(i);
                      RAISE EXCEPTION 'HG_PLPGSQL_NEED_RETRY';
                      COMMIT; 
                  END IF;
              -- 針對RAISE的EXCEPTION,打一條日志
              EXCEPTION 
                  WHEN OTHERS THEN
                      RAISE NOTICE 'Catch error.';
              END;
          END LOOP;
      
      END;
      $$;
    2. 執行存儲過程:a3表中寫入數據1、其余數據不寫入,相關日志全部打印。

      -- 開啟DML事務功能
      SET hg_experimental_enable_transaction = ON;
      
      -- 執行存儲過程
      CALL procedure_5('a1');

管理存儲過程

  • 查看已創建的存儲過程。

    SELECT
        p.proname AS function_name,
        p.prosrc AS function_detail,
        n.nspname AS schema_name,
        r.rolname AS owner_name,
        d.description AS description
    FROM
        pg_proc p
        INNER JOIN pg_namespace n ON p.pronamespace = n.oid
        INNER JOIN pg_roles r ON p.proowner = r.oid
        LEFT JOIN pg_description d ON p.oid = d.objoid
    WHERE
        r.rolname != 'holo_admin'
        AND p.prokind = 'p'
    ORDER BY
        n.nspname,
        p.proname;
  • 查看存儲過程定義。

    SELECT pg_get_functiondef('<procedure_name>'::regproc);

常見問題

由于Hologres是分布式系統,其中接入節點FE也是分布式的。當表發生DDL變更時,不同接入節點之間需要實時同步元數據,如果元數據未同步完成,DDL變更可能會失敗。針對上述場景,Hologres在大部分情況下會自動重試,無需手動重復提交DDL變更。但在存儲過程中,無法支持自動重試,上述場景會直接返回錯誤信息為“HG_PLPGSQL_NEED_RETRY”的報錯。

針對高頻DDL變更的表,建議在存儲過程中手動定義重試邏輯,以免存儲過程頻繁報錯。重試邏輯如下:

CREATE OR REPLACE PROCEDURE procedure_6()
LANGUAGE 'plpgsql'
AS $$
BEGIN
    WHILE TRUE LOOP
        BEGIN
            -- 嘗試執行DDL語句,如果成功,則退出循環
            CREATE TABLE a3(key int);
            COMMIT;
            EXIT;
        EXCEPTION
            -- 如果遇到HG_PLPGSQL_NEED_RETRY報錯,則打印日志,并自動重試
            WHEN HG_PLPGSQL_NEED_RETRY THEN 
                RAISE NOTICE 'DDL need retry';
        END;
    END LOOP;
END;
$$;