如何在错误处理过程中捕获无效的 SQL

How to capture a invalid SQL in a error handling procedure

我们有一个通用的错误处理程序,我们在其他程序中使用它来将错误捕获为通用错误table。

插入table时出错的语句如下,少了一个单引号。 (开头缺少单引号。target err'

这条语句是INSERT语句中的v_err_stmt值。

insert into temp_census (ERROR_DATE, sis_table , census_table ) 
                    values(current_timestamp, target err','target error test')

错误信息是 SQL 编译错误:位置 53 处的语法错误行 2 意外 'err'。解析错误行 2 在位置 78 附近 ''.

程序如下

CREATE OR REPLACE PROCEDURE SNOW_ERROR_CAPTURE(p_batch_id number, p_job_name varchar2,p_error_desc varchar2, p_err_stmt varchar2)
returns varchar(20000)
language sql
as
$$
declare
   v_err_stmt varchar2;
   v_error_desc varchar2;
   v_job_name varchar2;
   v_batch_id number;
   count number;
    begin

  if (p_batch_id IS NULL) then
  v_batch_id :=0;
  else
   v_batch_id :=p_batch_id;
  end if;
 
   if (p_job_name IS NULL) then
  v_job_name :='UNknown';
  else
   v_job_name :=p_job_name;
  end if;
 
    if (p_error_desc IS NULL) then
  v_error_desc :='UNknown';
  else
   v_error_desc :=p_error_desc;
  end if;
  
    if (p_err_stmt IS NULL) then
  v_err_stmt :='UNknown';
  else
   v_err_stmt :=p_err_stmt;
  end if;
  
     let _sql varchar := 'insert into BATCH_ERROR_LOG
                (ERROR_DATE , BATCH_ID, JOB_NAME, DESCRIPTION, ERROR_STMT ) 
                values
                (current_timestamp ,' || v_batch_id || ',''' || v_job_name || ''',''' || v_error_desc|| ''',''' || v_err_stmt || ''')';
    execute immediate _sql;
    --return _sql;
exception
  when statement_error then
    return object_construct('Error type', 'STATEMENT_ERROR',
                            'SQLCODE', sqlcode,
                            'SQLERRM', sqlerrm,
                            'SQLSTATE', sqlstate
                            );
   when other then
    return object_construct('Error type', 'Other error',
                            'SQLCODE', sqlcode,
                            'SQLERRM', sqlerrm,
                            'SQLSTATE', sqlstate);
end;

$$;

                        

假设您在 sql space 中连接字符串。您使用的任何令牌都需要保证安全。所以在你 v_err_msg 你需要用 replace(v_err_msg, '\'', '\\'')

转义那些单引号
select $$insert into temp_census (ERROR_DATE, sis_table , census_table )
                    values(current_timestamp, target err','target error test')$$ as v_err_msg
    ,'SELECT ''' || replace(v_err_msg, '\'', '\\'') || ''';' as output;
     

给出输出

SELECT 'insert into temp_census (ERROR_DATE, sis_table , census_table )                     values(current_timestamp, target err\',\'target error test\')';

有效且安全。

但是我们还需要转义任何存在的转义标记,这必须先完成。因此你需要使用

select $$word 'quoted' and with slash \ $$ as v_err_msg
    ,'SELECT ''' || replace(replace(v_err_msg, '\', '\\'), '\'', '\\'') || ''';' as output;

给出:

SELECT 'word \'qouted\' and with slash \ ';

运行时返回输入:

'WORD 'QUOTED' AND WITH SLASH \ '
word 'quoted' and with slash \