Skip to content

Commit f76a3d9

Browse files
authored
Merge bd78eec into e392541
2 parents e392541 + bd78eec commit f76a3d9

File tree

3 files changed

+58
-0
lines changed

3 files changed

+58
-0
lines changed

ydb/core/fq/libs/common/util.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -62,18 +62,24 @@ class TIssueDatabaseRemover {
6262
TString DatabasePath;
6363
};
6464

65+
void EscapeBackslashes(TString& value) {
66+
SubstGlobal(value, "\\", "\\\\");
67+
}
68+
6569
}
6670

6771
TString EscapeString(const TString& value,
6872
const TString& enclosingSeq,
6973
const TString& replaceWith) {
7074
auto escapedValue = value;
75+
EscapeBackslashes(escapedValue);
7176
SubstGlobal(escapedValue, enclosingSeq, replaceWith);
7277
return escapedValue;
7378
}
7479

7580
TString EscapeString(const TString& value, char enclosingChar) {
7681
auto escapedValue = value;
82+
EscapeBackslashes(escapedValue);
7783
SubstGlobal(escapedValue,
7884
TString{enclosingChar},
7985
TStringBuilder{} << '\\' << enclosingChar);

ydb/core/fq/libs/common/util_ut.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,19 @@ Y_UNIT_TEST_SUITE(EscapingBasics) {
2323
UNIT_ASSERT_VALUES_EQUAL(EscapeString("some_secret1", '"'), "some_secret1");
2424
UNIT_ASSERT_VALUES_EQUAL(EscapeString("some_secret1", "}+{", "[*]"), "some_secret1");
2525
UNIT_ASSERT_VALUES_EQUAL(EscapeString("some\"_\"secret1", '"'), "some\\\"_\\\"secret1");
26+
UNIT_ASSERT_VALUES_EQUAL(EscapeString("some\"_\\\"secret1", '"'), "some\\\"_\\\\\\\"secret1");
2627
UNIT_ASSERT_VALUES_EQUAL(EscapeString("some}+{_}+{secret1", "}+{", "[*]"), "some[*]_[*]secret1");
28+
UNIT_ASSERT_VALUES_EQUAL(EscapeString("some}+{\\}+{secret1", "}+{", "[*]"), "some[*]\\\\[*]secret1");
2729
}
2830

2931
Y_UNIT_TEST(EncloseAndEscapeStringShouldWork) {
3032
UNIT_ASSERT_VALUES_EQUAL(EncloseAndEscapeString("some_secret1", '"'), "\"some_secret1\"");
3133
UNIT_ASSERT_VALUES_EQUAL(EncloseAndEscapeString("some_secret1\nsome_secret2", "}+{", "[*]"), "}+{some_secret1\nsome_secret2}+{");
3234

3335
UNIT_ASSERT_VALUES_EQUAL(EncloseAndEscapeString("some\"_\"secret1", '"'), "\"some\\\"_\\\"secret1\"");
36+
UNIT_ASSERT_VALUES_EQUAL(EncloseAndEscapeString("some\"_\\\"secret1", '"'), "\"some\\\"_\\\\\\\"secret1\"");
3437
UNIT_ASSERT_VALUES_EQUAL(EncloseAndEscapeString("some_secret1}+{\n}+{some_secret2", "}+{", "[*]"), "}+{some_secret1[*]\n[*]some_secret2}+{");
38+
UNIT_ASSERT_VALUES_EQUAL(EncloseAndEscapeString("some_secret1}+{\\}+{some_secret2", "}+{", "[*]"), "}+{some_secret1[*]\\\\[*]some_secret2}+{");
3539
}
3640
}
3741

ydb/tests/fq/s3/test_bindings_1.py

+48
Original file line numberDiff line numberDiff line change
@@ -277,3 +277,51 @@ def test_raw_empty_schema_binding(self, kikimr, client, unique_prefix):
277277
assert "Only one column in schema supported in raw format" in str(binding_response.issues), str(
278278
binding_response.issues
279279
)
280+
281+
@yq_all
282+
@pytest.mark.parametrize("client", [{"folder_id": "my_folder"}], indirect=True)
283+
def test_binding_with_backslash_in_location(self, s3, client, unique_prefix):
284+
resource = boto3.resource(
285+
"s3", endpoint_url=s3.s3_url, aws_access_key_id="key", aws_secret_access_key="secret_key"
286+
)
287+
288+
bucket = resource.Bucket("backslash_bucket")
289+
bucket.create(ACL='public-read')
290+
291+
s3_client = boto3.client(
292+
"s3", endpoint_url=s3.s3_url, aws_access_key_id="key", aws_secret_access_key="secret_key"
293+
)
294+
295+
data = R'''data
296+
test'''
297+
s3_client.put_object(Body=data, Bucket='backslash_bucket', Key='\\', ContentType='text/plain')
298+
299+
connection_response = client.create_storage_connection(unique_prefix + "backslash_bucket", "backslash_bucket")
300+
301+
data_type = ydb.Column(name="data", type=ydb.Type(type_id=ydb.Type.PrimitiveTypeId.UTF8))
302+
storage_binding_name = unique_prefix + "binding_name"
303+
client.create_object_storage_binding(
304+
name=storage_binding_name,
305+
path="\\",
306+
format="csv_with_names",
307+
connection_id=connection_response.result.connection_id,
308+
columns=[data_type],
309+
)
310+
311+
sql = fR'''
312+
SELECT *
313+
FROM bindings.{storage_binding_name};
314+
'''
315+
316+
query_id = client.create_query(
317+
"simple", sql, type=fq.QueryContent.QueryType.ANALYTICS, pg_syntax=True
318+
).result.query_id
319+
client.wait_query_status(query_id, fq.QueryMeta.COMPLETED)
320+
321+
data = client.get_result_data(query_id)
322+
result_set = data.result.result_set
323+
logging.debug(str(result_set))
324+
assert len(result_set.columns) == 1
325+
assert result_set.columns[0].name == "data"
326+
assert len(result_set.rows) == 1
327+
assert result_set.rows[0].items[0].text_value == "test"

0 commit comments

Comments
 (0)