解析 JSON 时出现雪花错误,因为单引号未转义

Snowflake error on parsing JSON as single quotes are not escaped

我在处理 Snowflake 数据仓库中的一些数据时尝试记录错误。

我在特定数据文件上遇到的错误如下,我需要将其放入名为 DATA_LOAD_LOG:

的 table 中

INSERT INTO DWH_OPS.DATA_LOAD_LOG select 'DATA LOAD PROCEDURE', ?, ?, (datediff('milliseconds', ?, ?)/1000), current_schema(), current_database(), current_user(), current_role(), ?, parse_json('[{"Error":"Can't parse 'n/a' as date with format 'YYYY-MM-DD'","Survey Name":"data.csv","Stage Name":"@DWH_OPS.AZURE_BLOB","Execution Duration (in seconds)":5.405}]')::VARIANT

错误信息是:

"Can't parse 'n/a' as date with format 'YYYY-MM-DD'"

catch 部分返回不同的语法错误,因为 t'YYYY-MM-DD' 之前有单引号。所以日志没有添加到 table.

这里是捕获部分脚本:

try {
  // Try code
} catch (err) {
  var obj = {};
  var res = [];
  obj["Error"] = "Exists";
  obj["Error Message"] = err.message;
  obj["Status"] = err.status;
  obj["Error Code"] = err.code;
  res.push(obj);
  var insert_into_data_log =
    "INSERT INTO DWH_OPS.DATA_LOAD_LOG select 'DATA LOAD PROCEDURE', current_timestamp(), " +
    "current_timestamp(), 0, " +
    "current_schema(), current_database(), current_user(), current_role(), " +
    "'SCRIPT ERROR', parse_json('" +
    JSON.stringify(res) +
    "')::VARIANT";
  var data_log_stmt = snowflake
    .createStatement({ sqlText: insert_into_data_log })
    .execute();

  return err;
}

我尝试用 space 替换或使用以下方法转义它:

var errorMsg = err.message; obj['Error Message'] = errorMsg.replace("'","").replace("."," ").replace("\n"," ");

但它根本不起作用,并且抛出了同样的错误。

您可以使用此方法对单引号进行转义:

obj["Error Message"] = obj["Error Message"].replace(/'/g, "\''");

这里有一个简单的测试脚本:

create table DATA_LOAD_LOG ( t timestamp, v variant );

create or replace procedure test_sp()
returns string  
language javascript
as
$$
var obj = {};
var res = [];
obj["Error"] = "Exists";
obj["Error Message"] = "Can't parse 'n/a' as date with format 'YYYY-MM-DD'";

obj["Error Message"] = obj["Error Message"].replace(/'/g, "\''");
obj["Error Code"] = 200;
res.push(obj);

var insert_into_data_log =
"INSERT INTO DATA_LOAD_LOG select current_timestamp(), " +
"parse_json('" + JSON.stringify(res) + "')::VARIANT";
var data_log_stmt = snowflake.createStatement({ sqlText: insert_into_data_log }).execute();
 
return "Ok";

$$;

call test_sp();

如果您打算通过构造 SQL 而不是使用绑定变量来直接插入字符串和日期,那么您需要转义的不仅仅是单引号。您还必须至少转义反斜杠和换行符。这是您可以用来执行此操作的辅助函数。

function escapeString(str){
    str = str.replace(/'/g, "''");
    str = str.replace(/\/g, "\\");
    str = str.replace(/(\r\n|\n|\r)/gm," ");
    return str;
}

在您的 SP 中使用:

try {
  // Try code
} catch (err) {
  var obj = {};
  var res = [];
  obj["Error"] = "Exists";
  obj["Error Message"] = escapeString(err.message);
  obj["Status"] = escapeString(err.status);
  obj["Error Code"] = err.code;
  res.push(obj);
  var insert_into_data_log =
    "INSERT INTO DWH_OPS.DATA_LOAD_LOG select 'DATA LOAD PROCEDURE', current_timestamp(), " +
    "current_timestamp(), 0, " +
    "current_schema(), current_database(), current_user(), current_role(), " +
    "'SCRIPT ERROR', parse_json('" +
    JSON.stringify(res) +
    "')::VARIANT";
  var data_log_stmt = snowflake
    .createStatement({ sqlText: insert_into_data_log })
    .execute();

  return err;


function escapeString(str){
    str = str.replace(/'/g, "''");
    str = str.replace(/\/g, "\\");
    str = str.replace(/(\r\n|\n|\r)/gm," ");
    return str;
}

}