【发布时间】:2021-12-21 17:04:54
【问题描述】:
我正在发出COPY 命令以连接到 S3 并将数据加载到 Redshift。我正在尝试使用 Redshift-Data API 来执行此操作,该 API 声明它支持参数化查询。这就是我需要的。然而,即使尝试了最简单的示例,Redshift-Data API 实际上不能够发出带有参数的COPY 命令,但它很高兴通过 API 运行其他查询。您可以在您使用的任何客户端中重现以下内容,我通过 cli 在本地进行了测试,但在 Python boto3 客户端(最终我想使用)中得到了相同的结果。
最小的可重现示例
在 S3 中有一个文件:
echo 'id,foo,is_test
1,foo,true
2,bar,true
3,baz,false' > testfile.csv
aws s3 cp ./testfile.csv s3://mybucket/testfile.csv
尝试通过 CLI(或 Python,随便你)运行复制命令
###
# DOES NOT WORK
export MYFILE='s3://mybucket/testfile.csv'
aws redshift-data execute-statement \
--database dev \
--cluster-id redshift-clister-id \
--secret-arn 'arn:aws:secret....' \
--region us-east-1 \
--sql "COPY public.table FROM :s3_uri IAM_ROLE 'my-iam-role' REGION 'us-east-1' IGNOREHEADER 1 CSV;" \
--parameters "[{\"name\": \"s3_uri\", \"value\": \"${MYFILE}\"}]"
###
# ALSO DOES NOT WORK
export MYFILE="'s3://mybucket/testfile.csv'"
aws redshift-data execute-statement \
--database dev \
--cluster-id redshift-clister-id \
--secret-arn 'arn:aws:secret....' \
--region us-east-1 \
--sql "COPY public.table FROM :s3_uri IAM_ROLE 'my-iam-role' REGION 'us-east-1' IGNOREHEADER 1 CSV;" \
--parameters "[{\"name\": \"s3_uri\", \"value\": \"${MYFILE}\"}]"
###
# WORKS
export MYFILE="'s3://mybucket/testfile.csv'"
aws redshift-data execute-statement \
--database dev \
--cluster-id redshift-clister-id \
--secret-arn 'arn:aws:secret....' \
--region us-east-1 \
--sql "SELECT COUNT(*) FROM schema.table WHERE column = :s3_uri;" \
--parameters "[{\"name\": \"s3_uri\", \"value\": \"${MYFILE}\"}]"
###
# ALSO "WORKS" but not for my use case
aws redshift-data execute-statement \
--database dev \
--cluster-id redshift-clister-id \
--secret-arn 'arn:aws:secret....' \
--region us-east-1 \
--sql "COPY public.table FROM 's3://mybucket/testfile.csv' IAM_ROLE 'my-iam-role' REGION 'us-east-1' IGNOREHEADER 1 CSV;" \
结果总是给我一些大意:
"Error": "ERROR: syntax error at or near \"$1\"\n Position: ##",
它始终指向 S3 URI 变量的开始位置。当我完全删除参数并对值进行硬编码时,COPY 操作成功了。我尝试将参数用单引号括起来,并且还在针对 API 的 SELECT 查询中尝试了完全相同的参数。 SELECT 查询很容易工作,没有麻烦,只是不是 COPY。
所以最终我想使用参数来更安全地运行查询,因为我不会提前知道s3_uri。我当然可以将字符串插入到查询中,但那时我有一个我无法控制的 SQL 注入向量(s3 对象名称)。我验证了您可以使用给定的对象名称来利用它,因为 s3 对象名称允许空格和创建注入场景所需的任何字符。
我发现redshift_connector 中存在相同的奇怪行为,其中参数适用于SELECT,但不适用于COPY。任何说明不支持或说明如何执行此操作的文档或示例的链接都很好,我只是找不到它。
【问题讨论】:
标签: amazon-web-services amazon-s3 amazon-redshift