用途
DEALLOCATE被用来释放一个之前PREPARE好的SQL语句。如果不显式地释放一个PREPARE语句,那么会话结束时会释放它。
prepare语句类似oracle的绑定变量
绑定过程:
1)PREPARE,准备绑定变量SQL
2)EXECUTE,绑定并执行
3)DEALLOCATE,释放绑定变量
测试
1.只有本地会话可以看的prepare语句
创建测试表:
test=# create table test_c (id int4, name character varying(12));
CREATE TABLE
test=# insert into test_c values (1,'a'),(2,'b'),(3,'c');
INSERT 0 3
TEST=# select * from test_c ;
id | name
----+------
1 | a
2 | b
3 | c
(3 rows)
备注:创建完表后,接着开启新会话,顺序按以下操作进行:
test=# PREPARE select_1 (character varying) AS
select * From test_c where name=$1;
PREPARE
TEST=# EXECUTE select_1('a');
id | name
----+------
1 | a
(1 row)
在本地会话中可以查询到prepare语句:
TEST=# select * from sys_prepared_statements;
name | statement | prepare_time | parameter_types | from_sql
----------+-----------------------------------------+-------------------------------+-----------------+----------
select_1 | PREPARE select_1 (character varying) AS+| 2023-04-20 10:22:16.063035+08 | {varchar} | t
| select * From test_c where name=$1; | | |
(1 row)
这时,切换到之前创建表的会话查看此视图没有任何信息:
TEST=# select * from sys_prepared_statements;
name | statement | prepare_time | parameter_types | from_sql
------+-----------+--------------+-----------------+----------
(0 rows)
同样,执行的时候也会报错:
TEST=# EXECUTE select_1('a');
ERROR: prepared statement "select_1" does not exist
TEST=#
说明prepare语句只对当前会话可见并生效,采用了会话隔离机制。
2.DDL更改表结构后,prepare语句无法继续使用
依然在创建prepare语句的会话中执行:
TEST=# alter table test_c alter column name type character varying;
ALTER TABLE
由于发生了DDL语句后,原来创建的prepare语句失效:
TEST=# EXECUTE select_1('a');
ERROR: cached plan must not change result type
TEST=#
但是仍然可以查看prepare语句:
TEST=# select * from sys_prepared_statements;
name | statement | prepare_time | parameter_types | from_sql
----------+-----------------------------------------+-------------------------------+-----------------+----------
select_1 | PREPARE select_1 (character varying) AS+| 2023-04-20 10:22:16.063035+08 | {varchar} | t
| select * From test_c where name=$1; | | |
(1 row)
解决方法
1.释放prepare语句
deallocate select_1;
这时,视图中已经查看不到,如需再次使用prepare语句需要重新创建:
TEST=# select * from sys_prepared_statements;
name | statement | prepare_time | parameter_types | from_sql
------+-----------+--------------+-----------------+----------
(0 rows)
执行语句已经提示不存在:
TEST=# EXECUTE select_1('a');
ERROR: prepared statement "select_1" does not exist
2.断开连接会话,重建连接后,已经查不到prepare语句,因为它是会话级别的,如需使用需要重建prepare语句:
TEST=# PREPARE select_1 (character varying) AS
TEST-# select * From test_c where name=$1;
PREPARE
TEST=# EXECUTE select_1('a');
id | name
----+------
1 | a
(1 row)
TEST=#
TEST=# select * from sys_prepared_statements;
name | statement | prepare_time | parameter_types | from_sql
----------+-----------------------------------------+-------------------------------+-----------------+----------
select_1 | PREPARE select_1 (character varying) AS+| 2023-04-20 11:30:56.040584+08 | {varchar} | t
| select * From test_c where name=$1; | | |
(1 row)
TEST=# alter table test_c alter column name type varchar2(5);
ALTER TABLE
TEST=# EXECUTE select_1('a');
ERROR: cached plan must not change result type
TEST=#
TEST=# \q
[kingbase7@localhost ~]$ ksql -USYSTEM TEST
ksql (V8.0)
Type "help" for help.
断开重建连接后,之前prepare语句已无法从视图中查到:
TEST=# select * from sys_prepared_statements;
name | statement | prepare_time | parameter_types | from_sql
------+-----------+--------------+-----------------+----------
(0 rows)
总结
1.PREPARE语句在会话结束后,在视图sys_prepared_statements中会自动消失。
2.同一个prepared语句不能在多个并发会话中共有。
3.对表结构ddl修改后,创建好的对应prepare语句无法再次使用,需要使用deallocate命令取消 prepare语句,然后重新生成prepare语句;或者重建连接会话后,重新创建prepare语句。
备注:DEALLOCATE语句只对本地单个会话生效,如果是应用程序批量报错,这个方法显然不合适。