PREPARE 语句

应用程序可使用 PREPARE 语句来动态准备要执行的 SQL 语句。 PREPARE 语句通过语句的字符串形式(称为语句字符串)创建可执行 SQL 语句(称为已准备的语句)。

调用

此语句只能嵌入在应用程序中。 这是一个无法动态准备的可执行语句。

授权

对于在语句准备时执行授权检查的语句 (DML),该语句的授权标识所拥有的特权必须包括执行由 PREPARE 语句指定的 SQL 语句所需的权限。 语句的授权标识可能会受 DYNAMICRULES 绑定选项影响。

对于在语句执行时执行授权检查的语句(DDL、GRANT 和 REVOKE 语句),无需授权即可使用该语句;但是,在执行已准备的语句时会检查授权。

对于涉及受安全策略保护的表的语句,始终会在语句执行时评估与安全策略关联的规则。

如果该语句的授权标识拥有 EXPLAIN、SQLADM 或 DBADM 权限,那么用户可以准备任何语句;但是会在语句执行时重新检查执行语句的能力。

语法

Read syntax diagramSkip visual syntax diagramPREPAREstatement-nameOUTPUTINTOresult-descriptor-nameINPUT INTOinput-descriptor-nameFROM host-variableexpression

描述

statement-name
指定已准备的语句。 如果此名称标识了当前准备的语句,那么将销毁先前准备的语句。 此名称不能标识作为打开游标的 SELECT 语句的已准备语句。
OUTPUT INTO
如果使用了 OUTPUT INTO,并且成功执行了 PREPARE 语句,那么已准备语句中的输出参数标记的相关信息将放入 result-descriptor-name 所指定的 SQLDA 中。
result-descriptor-name
指定 SQLDA 的名称。 (DESCRIBE 语句可用作此子句的替代项。)
INPUT INTO
如果使用了 INPUT INTO,并且成功执行了 PREPARE 语句,那么已准备语句中的输入参数标记的相关信息将放入 input-descriptor-name 所指定的 SQLDA 中。 无论是否使用,输入参数标记始终可为空。
input-descriptor-name
指定 SQLDA 的名称。 (DESCRIBE 语句可用作此子句的替代项。)
FROM
指示语句字符串。 语句字符串是指定的主机变量的值。
host-variable
根据用于声明字符串变量的规则,指定程序中描述的主机变量。 它必须是小于最大语句大小 2 097 152 字节的、固定长度或可变长度的字符串变量。 注意,CLOB(2097152) 可以包含具有最大大小的语句,但 VARCHAR 不能。
expression
用于指定语句字符串的表达式。 该表达式必须返回小于最大语句大小 2 097 152 字节的、固定长度或可变长度的字符串类型。

规则

  • 语句字符串规则:该语句字符串必须是可动态准备的可执行语句。 它必须是以下 SQL 语句之一:
    • ALTER
    • CALL
    • COMMENT
    • COMMIT
    • 复合 SQL(编译型)
    • 复合 SQL(直接插入型)
    • 创建
    • DECLARE GLOBAL TEMPORARY TABLE
    • 删除
    • DROP
    • EXPLAIN
    • FLUSH EVENT MONITOR
    • FLUSH PACKAGE CACHE
    • GRANT
    • INSERT
    • LOCK TABLE
    • MERGE
    • REFRESH TABLE
    • RELEASE SAVEPOINT
    • RENAME
    • REVOKE
    • ROLLBACK
    • SAVEPOINT
    • SELECT 语句
    • SET COMPILATION ENVIRONMENT
    • SET CURRENT DECFLOAT ROUNDING MODE
    • SET CURRENT DEFAULT TRANSFORM GROUP
    • SET CURRENT DEGREE
    • SET CURRENT EXPLAIN MODE
    • SET CURRENT EXPLAIN SNAPSHOT
    • SET CURRENT FEDERATED ASYNCHRONY
    • SET CURRENT IMPLICIT XMLPARSE OPTION
    • SET CURRENT ISOLATION
    • SET CURRENT LOCALE LC_MESSAGES
    • SET CURRENT LOCALE LC_TIME
    • SET CURRENT LOCK TIMEOUT
    • SET CURRENT MAINTAINED TABLE TYPES FOR OPTIMIZATION
    • SET CURRENT MDC ROLLOUT MODE
    • SET CURRENT OPTIMIZATION PROFILE
    • SET CURRENT QUERY OPTIMIZATION
    • SET CURRENT REFRESH AGE
    • SET CURRENT TEMPORAL BUSINESS_TIME
    • SET CURRENT TEMPORAL SYSTEM_TIME
    • SET ENCRYPTION PASSWORD
    • SET EVENT MONITOR STATE(仅当 DYNAMICRULES 运行行为对包有效时)
    • SET INTEGRITY
    • SET PASSTHRU
    • SET PATH
    • SET ROLE(仅当 DYNAMICRULES 运行行为对程序包生效时)
    • SET SCHEMA
    • SET SERVER OPTION
    • SET SESSION AUTHORIZATION
    • 设置 SQL_CCFLAGS
    • SET USAGE LIST STATE(仅当 DYNAMICRULES 运行行为对包有效时)
    • SET 变量
    • TRANSFER OWNERSHIP(仅当 DYNAMICRULES 运行行为对程序包生效时)
    • TRUNCATE(仅当 DYNAMICRULES 运行行为对程序包生效时)
    • UPDATE

注意

  • 参数标记:虽然语句字符串不能包含对主机变量的引用,但它可以包含参数标记。 执行已准备的语句时,这些标记可由主机变量的值替换。 对于 CALL 语句,参数标记也可用于过程的 OUT 和 INOUT 参数。 执行 CALL 后,参数的返回值将分配给参数标记对应的主机变量。

    参数标记是问号 (?) 或冒号后跟名称 (:name);如果语句字符串是静态 SQL 语句,那么在可以使用主机变量的情况下都可以使用此标记。 有关如何用值替换参数标记的说明,请参阅 OPENEXECUTE

    如果指定了参数标记,那么该名称可以包含字母、数字和符号 @、#、$ 和 _。该名称不会转换为大写形式。

    命名参数标记与主机变量具有相同的语法,但两者不可互换。 主机变量具有一个值,可以直接在静态 SQL 语句中使用。 命名参数标记是动态 SQL 语句中值的占位符,在执行该语句时会提供此值。

    有两种类型的参数标记:
    类型化参数标记
    与目标数据类型一起指定的参数标记。 它采用一般形式:
       CAST(? AS data-type)
    这种表示法不是函数调用,而是一种“承诺”,即运行时该参数的类型是指定的数据类型或可转换为指定数据类型的某种数据类型。 例如,
      UPDATE EMPLOYEE
    SET LASTNAME = TRANSLATE(CAST(? AS VARCHAR(12)))
    WHERE EMPNO = ?
    在运行时会提供 TRANSLATE 函数的参数值。 该值的数据类型要么是 VARCHAR(12),要么是可转换为 VARCHAR(12) 的某种类型。
    非类型化参数标记
    在未指定其目标数据类型的情况下指定的参数标记。 其格式为单个问号。 非类型化参数标记的数据类型由上下文提供。 例如,前一个更新语句的谓词中的非类型化参数标记与 EMPNO 列的数据类型相同。

    只要支持主机变量并且数据类型基于 CAST 函数中给出的承诺,就可以在动态 SQL 语句中使用类型化参数标记。

    只要可以基于 SQL 语句中的上下文派生参数标记的数据类型,就可以在动态 SQL 语句中使用非类型化参数标记 (SQLSTATE 42610)。

    以下示例会产生一个错误,因为在第一个上下文中,c1 将解析为字符串数据类型,但在第二个上下文中,c1 将解析为数字数据类型:
    SELECT 'Hello' || c1, 5 + c1 FROM (VALUES(?)) AS T(c1)
    但是,以下语句是成功的,因为与派生列关联的参数标记 c1 在两个上下文下将解析为数字数据类型:
    SELECT 7 + c1, 5 + c1 FROM (VALUES(?)) AS T(c1)
    有关输入非类型化参数标记的规则,请参阅确定非类型化表达式的数据类型
  • 执行 PREPARE 语句时,会解析语句字符串并检查是否存在错误。 如果语句字符串无效,那么会在 SQLCA 中报告此错误情况。 除非更正了此错误,否则引用此语句的任何后续 EXECUTE 或 OPEN 语句也会收到此错误(由于系统执行的隐式准备)。
  • 可以在以下几种语句中引用已准备的语句,但存在一些限制:
    输入 ...
    准备的语句...
    DESCRIBE
    可以是任何语句
    DECLARE CURSOR
    必须是 SELECT
    EXECUTE
    不得是 SELECT
  • 准备的语句可以执行多次。 实际上,如果已准备的语句不多次执行并且不包含参数标记,那么使用 EXECUTE IMMEDIATE 语句(而不是 PREPARE 和 EXECUTE 语句)会更有效。
  • 由工作单元创建的所有已准备语句在应用程序终止之前都保持已准备状态,但存在以下例外情况:
    • 当工作单元结束时,在与 KEEPDYNAMC NO 绑定的包中准备并且未由使用 WITH HOLD 选项声明的打开游标使用的语句不再处于已准备状态。
    • 使用 KEEPDYNAMIC NO 绑定且由使用 WITH HOLD 选项声明的打开游标使用的动态语句处于已准备状态,直到关闭游标的下一个工作单元边界。

示例

示例 1:在 COBOL 程序中准备并执行一个非选择语句。 假设该语句包含在主机变量 HOLDER 中,并且该程序将根据用户的一些指令将语句字符串放入该主机变量中。 要准备的语句不含任何参数标记。
EXEC SQL  PREPARE STMT_NAME FROM :HOLDER
END-EXEC.
EXEC SQL  EXECUTE STMT_NAME
END-EXEC.
示例 2:准备并执行示例 1 中的非选择语句,唯一的不同是针对 C 程序编写该语句。 另外还假设要准备的语句可以包含任意数量的参数标记。
EXEC SQL  PREPARE STMT_NAME FROM :holder;
EXEC SQL  EXECUTE STMT_NAME USING DESCRIPTOR :insert_da;
假设要准备以下语句:
INSERT INTO DEPT VALUES(?, ?, ?, ?)

DEPT 表中的列将定义如下:

DEPT_NO   CHAR(3) NOT NULL, -- department number
DEPTNAME  VARCHAR(29), -- department name
MGRNO     CHAR(6), -- manager number
ADMRDEPT  CHAR(3)  -- admin department number
要插入名为投诉的部门编号 $TAG1 G01 $TAG2 (该部门没有经理并向部门 $TAG3 A00 $TAG4 报告) ,在发出 EXECUTE 语句之前,结构 INSERT_DA 应具有 表 1 中的值。
表 1. INSERT_DA 结构的必需值
SQLDA 字段
SQLDAID SQLDA
SQLDABC 192(见注 1。)
SQLN 4
SQLD 4
   
SQLTYPE 452
SQLLEN 3
SQLDATA 指向 G01 的指针
SQLIND (见注 2。)
SQLNAME  
   
SQLTYPE 449
SQLLEN 29
SQLDATA 指向 COMPLAINTS 的指针
SQLIND 指向 0 的指针
SQLNAME  
   
SQLTYPE 453
SQLLEN 6
SQLDATA (见注 3。)
SQLIND 指向 -1 的指针
SQLNAME  
   
SQLTYPE 453
SQLLEN 3
SQLDATA 指向 A00 的指针
SQLIND 指向 0 的指针
SQLNAME  
注:
  1. 此值适用于从 32 位应用程序中完成的 PREPARE。 如果在 64 位应用程序中完成了 PREPARE,那么 SQLDABC 的值为 240。
  2. 将忽略此 SQLVAR 的 SQLIND 中的值,因为 SQLTYPE 标识了不可空的数据类型。
  3. 将忽略此 SQLVAR 的 SQLDATA 中的值,因为 SQLIND 的值表明这是一个空值。