輸入 name 創建的規則名. event 事件是 SELECT, UPDATE,DELETE 或 INSERT 之一. object 對象是 table 或 table.column.(目前只有 table 形式實際上是實現了的. condition 任意 SQL 布爾條件表達式.條件表達式除了引用 new 和 old 之外不能引用任何表. query 組成 action 的查詢可以是任何 SQL SELECT,INSERT, UPDATE,DELETE,或 NOTIFY 語句之一. 在 condition 和 action 里,特殊表名字 new 和 old 可以用于指向引用表 ( object) 里的數值 new 在 ON INSERT 和 ON UPDATE 規則里 可以指向被插入或更新的新行. old 在 ON UPDATE,和 ON DELETE 規則里可以指向現存的被更新,或者刪除的行. 輸出 CREATE 成功創建規則后的返回信息. 描述 PostgreSQL 規則系統 允許我們在從數據庫或表中更新, 插入或刪除東西時定義一個可選的動作來執行。目前,規則用于實現表視圖。 規則的語意是在一個單獨的記錄正被訪問,更新,插入或刪除時, 將存在一個舊記錄(用于檢索,更新和刪除)和一個新記錄(用于更新和追加).這時給定事件類型和給定目標對象(表)的所有規則都將被檢查, (順序不定). 如果在 WHERE (如果有)子句里面所聲明的 condition? 為真,那么 action 部分的規則就被執行. 如果聲明了 INSTEAD,那么 action 就會代替原來的查詢;否則,如果是 ON INSERT 那么它在原來的查詢之后執行,如果是 ON UPDATE 或者 ON DELETE,那么它在原來的查詢之前執行.在 condition 和 action 里面, 在舊記錄里字段的數值和/或新記錄里字段的數值被 old. attribute-name 和 new. attribute-name 代替. 規則的 action 部分可以由一條或者多條查詢組成.要寫多個查詢,用圓括弧或者方括弧 把它們包圍起來.這樣的查詢將以聲明的順序執行(只是我們不能保證對一個對象的多個規則的執行順序). action 還可以是 NOTHING 表示沒有動作.因此,一個 DO INSTEAD NOTHING 規則制止了原來的查詢的運行(當條件為真時); DO NOTHING 規則是沒有用的. 規則的 action 部分 執行的時候帶有和觸發動作的用戶命令相同的命令和事務標識符. 規則和視圖 目前,ON SELECT 規則必須是無條件的 INSTEAD 規則并且 必須有一個由一條 SELECT 查詢組成的動作.因此,一條 ON SELECT 規則有效地把對象表轉成視圖,它的可見內容 是規則的 SELECT 查詢返回的記錄而不是存儲在表中的內容(如果有的話).我們認為寫一條 CREATE VIEW 命令比創建一個表然后定義一條 ON SELECT 規則在上面的風格要好. CREATE VIEW 創建一個虛擬表(沒有下層的存儲) 以及相關的 ON SELECT 規則.系統不允許對視圖進行更新,因為它知道在視圖上沒有真正的表.你可以創建一個可以更新的視圖的幻覺, 方法是在視圖上定義 ON INSERT,ON UPDATE,和 ON DELETE 規則 (或者滿足你需要的任何上述規則的子集),用合適的對其它表的更新替換 在視圖上更新的動作. 如果你想在視圖更新上使用條件規則,那么這里就有一個補充∶ 對你希望在視圖上允許的每個動作,你都必須有一個無條件的 INSTEAD 規則.如果規則是有條件的,或者它不是 INSTEAD, 那么系統仍將拒絕執行更新動作的企圖,因為它認為它最終會在某種 程度上在虛擬表上執行動作.如果你想處理條件規則上的所由有用的情況,那也可以;只需要增加一個無條件的 DO INSTEAD NOTHING 規則確保系統明白它將決不會被調用來更新虛擬表就可以了.然后把條件規則做成非 INSTEAD; 在這種情況下,如果它們被觸發,那么它們就增加到缺省的 INSTEAD NOTHING 動作中.
注意 為了在表上定義規則,你必須有規則定義權限. 用 GRANT 和 REVOKE 修改權限. 有一件很重要的事情是要避免循環規則. 比如,盡管下面兩條規則定義都是 PostgreSQL 可以接受的, select 命令會導致 PostgreSQL 報告 一條錯誤信息,因為該查詢循環了太多次: CREATE RULE bad_rule_combination_1 AS ON SELECT TO emp DO INSTEAD SELECT * FROM toyemp; CREATE RULE bad_rule_combination_2 AS ON SELECT TO toyemp DO INSTEAD SELECT * FROM emp; 下面這個對 EMP 的查詢企圖將導致 PostgreSQL 產生一個錯誤信息, 因為該查詢循環了太多次: SELECT * FROM emp; 目前,如果一個規則包含一個 NOTIFY 查詢,那么該 NOTIFY 將被 無條件執行 --- 也就是說,如果規則不施加到任何行上頭,該 NOTIFY 也會被發出.比如,在 CREATE RULE notify_me AS ON UPDATE TO mytable DO NOTIFY mytable; UPDATE mytable SET name = 'foo' WHERE id = 42; 里,一個 NOTIFY 事件將在 UPDATE 的時候發出,不管是否有某行的 id = 42.這是一個實現的限制,將來的版本應該修補這個毛?。? 兼容性 SQL92 CREATE RULE語句是 PostgreSQL 語言的擴展. 在里沒有CREATE RULE 語句.
CREATE TRIGGER Name CREATE TRIGGER -- 定義一個新的觸發器 Synopsis CREATE TRIGGER name { BEFORE | AFTER } { event [OR ...] } ON table FOR EACH { ROW | STATEMENT } EXECUTE PROCEDURE func ( arguments ) 輸入 name 賦予新觸發器的名稱. table 現有表名稱. event INSERT,DELETE 或 UPDATE 之一. func 一個用戶提供的函數. 輸出 CREATE 如果觸發器成功創建,返回此信息. 描述 CREATE TRIGGER將向現有數據庫中增加一個新的觸發器. 觸發器將與表 table 相聯并且將執行聲明的函數 func. 觸發器可以聲明為在對記錄進行操作之前 在檢查約束之前和 INSERT,UPDATE 或 DELETE 執行前)或之后(在檢 查約束之后和完成 INSERT, UPDATE 或 DELETE 操作)觸發. 如果觸發器在事件之前,觸發器可能略過當前記錄的操作或改變被插入的(當前)記錄(只對 INSERT 和 UPDATE 操作有效). 如果觸發器在事件之后,所有更改,包括最后的插入,更新或刪除對觸發器都是"可見"的. SELECT并不更改任何行,因此你不能創建 SELECT 觸發器.這種場合下規則和視圖更合適些. 請參考 PostgreSQL 程序員手冊中SPI 和觸發器章節獲取更多信息. 注意 CREATE TRIGGER是 PostgreSQL 語言擴展. 只有表所有者可以就此表創建一個觸發器. 在當前的版本,STATEMENT 觸發器還沒有實現. 請參考 DROP TRIGGER 獲取如何刪除觸發器的信息. 用法 在插入或更新表 films 之前檢查一下聲明的分銷商代碼是否存在于 distributors 表中: CREATE TRIGGER if_dist_exists BEFORE INSERT OR UPDATE ON films FOR EACH ROW EXECUTE PROCEDURE check_primary_key ('did', 'distributors', 'did');
在刪除或更新一個分銷商的內容之前, 將所有記錄移到表 films 中: CREATE TRIGGER if_film_exists BEFORE DELETE OR UPDATE ON distributors FOR EACH ROW EXECUTE PROCEDURE check_foreign_key (1, 'CASCADE', 'did', 'films', 'did'); 兼容性 SQL92 在 里沒有 CREATE TRIGGER語句. 上面第二個例子可以使用一個 FOREIGN KEY 約束實現: CREATE TABLE distributors ( did DECIMAL(3), name VARCHAR(40), CONSTRAINT if_film_exists FOREIGN KEY(did) REFERENCES films ON UPDATE CASCADE ON DELETE CASCADE );
DELETE DELETE Name DELETE -- 刪除一個表中的行 Synopsis DELETE FROM [ ONLY ] table [ WHERE condition ]
輸入 table 一個現存表的名字 condition 這是一個 SQL 選擇查詢,它返回要被刪除的行. 請參考 SELECT 語句獲取關于 WHERE 子句的更多信息. 輸出 DELETE count 如果行被成功的刪除返回此信息. count 是要被刪除的行數. 如果 count 為 0, 沒有行被刪除. 描述 DELETE從指明的表里刪除滿足 WHERE condition (條件)的行. 如果 condition (WHERE 子句)不存在, 效果是刪除表中所有行.結果是一個有效的空表. 小技巧: TRUNCATE 是一個 PostgreSQL 擴展, 它提供一個更快的從表中刪除所有行的機制。 缺省時DELETE將刪除所聲明的表和所有它的子表的記錄. 如果你希望只更新提到的表,你應該使用OLNY子句. 要對表進行修改,你必須有寫權限,同樣也必須有讀表的權限,這樣才能對符合 condition(條件) 的值進行讀取操作. 用法 刪除所有電影(films)但不刪除音樂(musicals): DELETE FROM films WHERE kind <> 'Musical'; SELECT * FROM films;
code | title | did | date_prod | kind | len -------+---------------------------+-----+------------+---------+------- UA501 | West Side Story | 105 | 1961-01-03 | Musical | 02:32 TC901 | The King and I | 109 | 1956-08-11 | Musical | 02:13 WD101 | Bed Knobs and Broomsticks | 111 | | Musical | 01:57 (3 rows) 清空表 films: DELETE FROM films; SELECT * FROM films;
code | title | did | date_prod | kind | len ------+-------+-----+-----------+------+----- (0 rows) 兼容性 SQL92 允許定位的 DELETE (刪除)語句: DELETE FROM table WHERE CURRENT OF cursor 這里 cursor 表示一個打開的游標. PostgreSQL 里交互式游標是只讀的.
DROP AGGREGATE DROP AGGREGATE Name DROP AGGREGATE -- 刪除一個用戶定義的聚集函數 Synopsis DROP AGGREGATE name type 輸入 name 現存的聚集函數名。 type 現存的聚集函數的輸入數據類型,或者 * -- 如果這個聚集函數接受任意輸入類型.(請參考 PostgreSQL 用戶手冊 獲取關于數據類型的更多信息)。 輸出 DROP 命令成功的返回信息. ERROR: RemoveAggregate: aggregate 'name' for type type does not exist 如果聲明的函數在數據庫中不存在,返回此信息. 描述 DROP AGGREGATE將刪除對一個現存聚集函數的所有索引. 執行這條命令的用戶必須是該聚集函數的所有者. 注意 使用 CREATE AGGREGATE語句創建一個聚集函數。 用法 將類型 int4的聚集函數 myavg 刪除: DROP AGGREGATE myavg(int4); 兼容性 SQL92 在 中沒有 DROP AGGREGATE語句. 該語句是一個 PostgreSQL 語言的擴展.
DROP DATABASE Name DROP DATABASE -- 刪除一個數據庫. Synopsis DROP DATABASE name 輸入 name 要被刪除的現有數據庫名. 輸出 DROP DATABASE 如果命令成功執行,返回此命令. DROP DATABASE: cannot be executed on the currently open database 你不能和準備刪除的數據庫建立聯接.你需要和 template1 或者任何其它的數據庫相連來運行這些命令. DROP DATABASE: cannot be executed on the currently open database 執行這條命令之前你必須先結束正在處理的事務。 描述 DROP DATABASE刪除一個現存數據庫的目錄入口并且刪除包含數據的目錄.只有數據庫所有者能夠執行這條命令(通常也是數據庫創建者). DROP DATABASE不能撤銷,小心使用. 注意 這條命令在和目標數據庫聯接時不能執行. 通常更好的做法是用 dropdb腳本代替,該腳本是此命令的一個封裝。 , 請參考 CREATE DATABASE語句獲取如何創建數據庫的信息. 兼容性 SQL92
DROP FUNCTION Name DROP FUNCTION -- 刪除一個用戶定義的函數 Synopsis DROP FUNCTION name ( [ type [, ...] ] ) 輸入 name 現存的函數名稱. type 函數參數的類型. 輸出 DROP 命令成功執行的返回信息. NOTICE RemoveFunction: Function "name" ("types") does not exist 如果當前數據庫里不存在所聲明的函數,返回此信息. 描述 DROP FUNCTION 將刪除一個現存的函數的引用.要執行這條命令,用戶必須是函數的所有者. 必須聲明函數的輸入參數類型,因為幾個不同的函數可能會有同樣的名字 和不同的參數列表. 注意 請參考 CREATE FUNCTION 獲取創建聚集函數的信息. 對依賴于該函數的類型, 操作符訪問方式或者觸發器是否事先被刪除不做任何校驗. 用法 這條命令刪除平方根函數: DROP FUNCTION sqrt(int4); 兼容性 SQL92 DROP FUNCTION是 PostgreSQL 語言的擴展. SQL/PSM SQL/PSM 是一個為實現函數擴展能力而提出的標準. SQL/PSM DROP FUNCTION 語句有下面的語法: DROP [ SPECIFIC ] FUNCTION name { RESTRICT | CASCADE }
DROP GROUP DROP GROUP Name DROP GROUP -- 刪除一個用戶組 Synopsis DROP GROUP name
輸入 name 現存組名。 輸出 DROP GROUP 成功刪除組后返回的信息。 描述 DROP GROUP從數據庫中刪除指定的組。組中的用戶不被刪除。 組中的用戶不被刪除。 使用 CREATE GROUP增加新組,用 ALTER GROUP修改組的成員。 用法 刪除一個組: DROP GROUP staff; 兼容性 SQL92
DROP INDEX Name DROP INDEX -- 刪除一個索引 Synopsis DROP INDEX index_name [, ...] 輸入 index_name 要刪除的索引名. 輸出 DROP 如果索引成功刪除返回的信息. ERROR: index "index_name" does not exist 如果 index_name 不是這個數據庫的索引,返回此信息. 描述 DROP INDEX從數據庫中刪除一個現存的索引. 要執行這個命令,你必須是索引的所有者. the index. 注意 DROP INDEX是PostgreSQL 語言擴展. 請參考 CREATE INDEX語句獲取如何創建索引的信息. 用法 此命令將刪除title_idx 索引: DROP INDEX title_idx; 兼容性 SQL92 定義用于訪問純關系型數據庫的命令. 索引是一個與具體實現相關的特性,因而沒有與具體實現相關的特性或定義在 語言里面.
DROP RULE DROP RULE Name DROP RULE -- 刪除一個重寫規則 Synopsis DROP RULE name [, ...] 輸入 name 要刪除的現存的規則. 輸出 DROP 刪除成功返回的信息. ERROR: Rule or view "name" not found 如果聲明的規則不存在,返回此信息. 描述 DROP RULE從聲明的 PostgreSQL規則系統里刪除一個規則. PostgreSQL 將立即停止使用之并且將會把它從系統表中清理出去. 注意 DROP RULE語句是 PostgreSQL 語言的擴展. 請參考 CREATE RULE 獲取如何創建規則的信息. 一旦一個規則被刪除掉,該規則所寫的歷史記錄信息將可能不存在. 用法 刪除重寫規則 newrule: DROP RULE newrule; 兼容性 SQL92 在 中沒有DROP RULE.
DROP SEQUENCE DROP SEQUENCE Name DROP SEQUENCE -- 刪除一個序列 Synopsis DROP SEQUENCE name [, ...] 輸入 name 序列名. 輸出 DROP 序列成功刪除后返回的信息. ERROR: sequence "name" does not exist 如果聲明的序列不存在,返回此信息. 描述 DROP SEQUENCE從數據庫中刪除序列號生成器. 因為目前的序列實現是作為一個特殊的表,所以此語句就象 DROP TABLE 語句一樣. 注意 DROP SEQUENCE語句是 Postgres 語言擴展. 請參考 CREATE SEQUENCE 語句獲取如何創建一個序列的信息. 用法 從數據庫中刪除序列 serial: DROP SEQUENCE serial; 兼容性 SQL92 在里沒有 DROP SEQUENCE.
DROP TRIGGER DROP TRIGGER Name DROP TRIGGER -- 刪除一個觸發器定義. Synopsis DROP TRIGGER name ON table
輸入 name 現存的觸發器名. table 表的名稱. 輸出 DROP 如果觸發器成功的刪除,返回此信息. ERROR: DropTrigger: there is no trigger name on relation "table" 如果聲明的觸發器不存在,返回此信息. 描述 DROP TRIGGER將刪除所有對一個現存觸發器的引用. 要執行這個命令,當前用戶必須是觸發器的所有者. 注意 DROP TRIGGER是 PostgreSQL 語言的擴展. 請參考 CREATE TRIGGER 獲取如何創建觸發器的信息. 用法 刪除表films的if_dist_exists觸發器: DROP TRIGGER if_dist_exists ON films; 兼容性 SQL92 在里沒有DROP TRIGGER.
DROP TYPE DROP TYPE Name DROP TYPE -- 刪除一個用戶定義數據類型 Synopsis DROP TYPE typename [, ...] 輸入 typename 現存的類型名. 輸出 DROP 命令執行成功的返回信息. ERROR: RemoveType: type 'typename' does not exist 如果聲明的類型沒有找到,返回此信息. 描述 DROP TYPE將從系統表里刪除用戶的類型. 只有類型所有者可以刪除類型. 注意 DROP TYPE 語句是 PostgreSQL 語言的擴展. 請參考 CREATE TYPE 獲取如何創建類型的信息. 用戶有責任刪除任何使用了被刪除類型的操作符,函數,聚集,訪問模式, 子類型和表.不過,相關等數組數據類型(由 CREATE TYPE 自動創建)將自動刪除. 如果刪除了一個內建的類型,后端的行為將不可預測. 用法 刪除 box 類型: DROP TYPE box; 兼容性 SQL92 SQL3 DROP TYPE是 SQL3 語句.
DROP USER DROP USER Name DROP USER -- 刪除一個數據庫用戶帳號 Synopsis DROP USER name 輸入 name 一個現存用戶的名稱. 輸出 DROP USER 用戶被成功刪除的返回信息. ERROR: DROP USER: user "name" does not exist 如果用戶名沒有找到,返回此信息. DROP USER: user "name" owns database "name", cannot be removed 你必須先刪除數據庫或者改變其所有者。 描述 DROP USER從數據庫中刪除指定的用戶。 它不刪除數據庫里此用戶所有的表,視圖或其他對象。 如果該用戶擁有任何數據庫,你會收到一個錯誤信息。 使用 CREATE USER增加新用戶,用 ALTER USER修改用戶屬性。 PostgreSQL 還有一個腳本 dropuser,這個腳本和這條命令功能相同(實際上,腳本里調用此命令),但是可以在命令行上運行。 用法 刪除一個用戶帳戶: DROP USER jonathan; 兼容性 SQL92 在里沒有DROP USER.
DROP VIEW DROP VIEW Name DROP VIEW -- 刪除一個視圖 Synopsis DROP VIEW name [, ...] 輸入 name 現存視圖名稱. 輸出 DROP 命令成功執行的返回. ERROR: view name does not exist 如果聲明的視圖在數據庫中不存在,返回此信息. 描述 DROP VIEW從數據庫中刪除一個現存的視圖. 執行這條命令必須是視圖的所有者. 注意 請參考CREATE VIEW 獲取關于如何創建視圖的信息. 用法 下面命令將刪除視圖 kinds: DROP VIEW kinds; 兼容性 SQL92 為 DROP VIEW 聲明了一些附加的功能: DROP VIEW view { RESTRICT | CASCADE } 輸入 RESTRICT 確保只有不存在關聯視圖或完整性約束的視圖可以被刪除. CASCADE 任何引用的視圖和完整性約束都將被刪除. 注意 目前,要從 PostgreSQL 數據庫中刪除一個視圖, 你必須明確地將其刪除.
END Name END -- 提交當前的事務 Synopsis END [ WORK | TRANSACTION ] 輸入 WORK TRANSACTION 可選關鍵字。沒有作用。 輸出 COMMIT 事務成功提交后的返回信息。 NOTICE: COMMIT: no transaction in progress 如果沒有正在處理的事務,返回此信息。 描述 END是 PostgreSQL 而 -兼容的同義語句是 COMMIT. 注意 關鍵字 WORK 和 TRANSACTION 是多余的,可以省略。 使用 ROLLBACK退出一個事務。 用法 令所有改變生效: END WORK; 兼容性 SQL92 END是 PostgreSQL 的擴展,提供與 COMMIT相同的功能。
GRANT Name GRANT -- 定義訪問權限 Synopsis GRANT { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER } [,...] | ALL [ PRIVILEGES ] } ON [ TABLE ] objectname [, ...] TO { username | GROUP groupname | PUBLIC } [, ...] 描述 GRANT命令將某對象(表,視圖,序列) 上的特定權限給予一個用戶或者多個用戶或者一組用戶.這些權限將增加到那些已經賦予的權限上,如果存在這些權限的話. 鍵字 PUBLIC 表示該權限要賦予所有用戶, 包括那些以后可能創建的用戶.PUBLIC 可以看做是一個隱含定義好的組,它總是包括所有用戶.請注意,任何特定的用戶都將擁有直接賦予他/她的權限,加上 他/她所處的任何組,以及再加上賦予 PUBLIC 的權限的總和. 在創建完對象之后,除了對象的創建者之外, 其它用戶沒有任何訪問該對象的權限,除非創建者賦予某些權限.對對象的創建者而言,沒有什么權限需要賦予,因為創建者自動持有所有權限.(不過,創建者出于安全考慮可以選擇廢棄一些他自己的權限.請注意賦予和廢止權限的能力是創建者與生具來的,并且不會丟失.刪除對象的權利也是創建者固有的,并且不能賦予或 撤銷.) 可能的權限有∶ SELECT 允許對聲明的表,試圖,或者序列 SELECT 仁義字段.還允許做 COPY 的源. INSERT 允許向聲明的表 INSERT 一個新行. 同時還允許做 COPY 的目標. UPDATE 允許對聲明的表中任意字段做 UPDATE . SELECT ... FOR UPDATE 也要求這個權限 (除了 SELECT 權限之外).比如, 這個權限允許使用nextval, currval 和 setval. DELETE 允許從聲明的表中 DELETE 行. RULE 允許在該表/視圖上創建規則.(參閱 CREATE RULE 語句.) REFERENCES 要在一個表上創建一個外鍵約束,你必須在帶參考健字的表上 擁有這個權限. TRIGGER 允許在聲明表上創建觸發器.(參閱 CREATE TRIGGER 語句.) ALL PRIVILEGES 把上面所有權限都一次賦予.PRIVILEGES 關鍵字在 PostgreSQL 里是可選的, 但是嚴格的 SQL 要求有這個關鍵字. 其它命令要求的權限都在相應的命令的參考頁上列出. 注意 我們要注意數據庫 superusers 可以訪問所有對象, 而不會受對象的權限設置影響.這個特點類似 Unix 系統的 root 的權限.和 root 一樣,除了必要的情況,總是以超級用戶 身分進行操作是不明智的做法. 目前,要在 PostgreSQL 里只對某幾列 賦予權限,你必須創建一個擁有那幾行的視圖然后給那個視圖賦予權限. 使用 psql的 /z 命令 獲取在現有對象上的與權限有關的信息. Database = lusitania +------------------+---------------------------------------------+ | Relation | Grant/Revoke Permissions | +------------------+---------------------------------------------+ | mytable | {"=rw","miriam=arwdRxt","group todos=rw"} | +------------------+---------------------------------------------+ Legend: uname=arwR -- privileges granted to a user group gname=arwR -- privileges granted to a group =arwR -- privileges granted to PUBLIC
r -- SELECT ("read") w -- UPDATE ("write") a -- INSERT ("append") d -- DELETE R -- RULE x -- REFERENCES t -- TRIGGER arwdRxt -- ALL PRIVILEGES 用 REVOKE 命令刪除訪問權限. 例子 把表 films 的插入權限賦予所有用戶∶ GRANT INSERT ON films TO PUBLIC; 賦予用戶manuel對視圖kinds的所有權限∶ GRANT ALL PRIVILEGES ON kinds TO manuel; 兼容性 SQL92 在 ALL PRIVILEGES 里的 PRIVILEGES 關鍵字是必須的.SQL 不支持在一條命令里 對多個表設置權限. 的 GRANT 語法允許在一個表里 為獨立的字段設置權限,并且允許設置一個權限用來給其它人賦予同樣的權限∶ GRANT privilege [, ...] ON object [ ( column [, ...] ) ] [, ...] TO { PUBLIC | username [, ...] } [ WITH GRANT OPTION ] SQL 允許對其它類型的對象賦予 USAGE 權限∶CHARACTER SET,COLLATION,TRANSLATION,DOMAIN. TRIGGER 權限是 SQL99 引入的.RULE 權限是 PostgreSQL 擴展. 又見 REVOKE