Changeset: ade2492d7e7e for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/ade2492d7e7e
Modified Files:
sql/backends/monet5/sql_bincopyfrom.c
Branch: Sep2022
Log Message:
Merge branch 'Jan2022' into 'Sep2022'
diffs (149 lines):
diff --git a/sql/backends/monet5/sql_bincopyfrom.c
b/sql/backends/monet5/sql_bincopyfrom.c
--- a/sql/backends/monet5/sql_bincopyfrom.c
+++ b/sql/backends/monet5/sql_bincopyfrom.c
@@ -327,7 +327,7 @@ convert_timestamp(void *dst_start, void
static str
-convert_and_validate(char *text)
+convert_and_validate_utf8(char *text)
{
unsigned char *r = (unsigned char*)text;
unsigned char *w = r;
@@ -375,29 +375,18 @@ bad_utf8:
return createException(SQL, "BATattach_stream", SQLSTATE(42000)
"malformed utf-8 byte sequence");
}
-static str
-append_text(BAT *bat, char *start)
-{
- str msg = convert_and_validate(start);
- if (msg != MAL_SUCCEED)
- return msg;
-
- if (BUNappend(bat, start, false) != GDK_SUCCEED)
- return createException(SQL, "sql.importColumn", GDK_EXCEPTION);
-
- return MAL_SUCCEED;
-}
-
// Load items from the stream and put them in the BAT.
// Because it's text read from a binary stream, we replace \r\n with \n.
-// We don't have to validate the utf-8 structure because BUNappend does that
for us.
static str
load_zero_terminated_text(BAT *bat, stream *s, int *eof_reached)
{
str msg = MAL_SUCCEED;
bstream *bs = NULL;
+ int tpe = BATttype(bat);
+ void *buffer = NULL;
+ size_t buffer_len = 0;
- // convert_and_validate() above counts on the following property to
hold:
+ // convert_and_validate_utf8() above counts on the following property
to hold:
assert(strNil((const char[2]){ 0x80, 0 }));
bs = bstream_create(s, 1 << 20);
@@ -419,9 +408,24 @@ load_zero_terminated_text(BAT *bat, stre
char *buf_end = &bs->buf[bs->len];
char *start, *end;
for (start = buf_start; (end = memchr(start, '\0', buf_end -
start)) != NULL; start = end + 1) {
- msg = append_text(bat, start);
+ char *value;
+ msg = convert_and_validate_utf8(start);
if (msg != NULL)
goto end;
+ if (tpe == TYPE_str) {
+ value = start;
+ } else {
+ ssize_t n = ATOMfromstr(tpe, &buffer,
&buffer_len, start, false);
+ if (n <= 0) {
+ msg = createException(SQL,
"sql.importColumn", GDK_EXCEPTION);
+ goto end;
+ }
+ value = buffer;
+ }
+ if (BUNappend(bat, value, false) != GDK_SUCCEED) {
+ msg = createException(SQL, "sql.importColumn",
GDK_EXCEPTION);
+ goto end;
+ }
}
bs->pos = start - buf_start;
}
@@ -432,6 +436,7 @@ load_zero_terminated_text(BAT *bat, stre
end:
*eof_reached = 0;
+ GDKfree(buffer);
if (bs != NULL) {
*eof_reached = (int)bs->eof;
bs->s = NULL;
diff --git a/sql/test/bincopy/Tests/All b/sql/test/bincopy/Tests/All
--- a/sql/test/bincopy/Tests/All
+++ b/sql/test/bincopy/Tests/All
@@ -41,6 +41,8 @@ bincopy_json_objects_on_server
bincopy_uuids_on_client
bincopy_uuids_on_server
+bincopy_invalid_json
+
bincopy_little_endians_on_client
bincopy_little_endians_on_server
bincopy_big_endians_on_client
diff --git a/sql/test/bincopy/Tests/bincopy_invalid_json.SQL.py
b/sql/test/bincopy/Tests/bincopy_invalid_json.SQL.py
new file mode 100644
--- /dev/null
+++ b/sql/test/bincopy/Tests/bincopy_invalid_json.SQL.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python3
+
+from cmath import exp
+import os
+import pymonetdb
+
+conn = pymonetdb.connect(
+ database=os.getenv("TSTDB"),
+ port=int(os.getenv("MAPIPORT")))
+
+conn.set_autocommit(False)
+
+CONTENT = dict(
+ invalid_utf8=b'"invali\x80\x80"',
+ unterminated_object=b'{"foo": "bar',
+ valid_json=b'{"foo":42}'
+)
+
+
+class MyUploader(pymonetdb.Uploader):
+ def handle_upload(self, upload: pymonetdb.Upload, filename: str,
text_mode: bool, skip_amount: int):
+ assert text_mode == False
+ assert skip_amount == 0
+ json = CONTENT[filename]
+ bw = upload.binary_writer()
+ bw.write(json + b'\x00')
+
+
+conn.set_uploader(MyUploader())
+
+def run_test(content_name, expected_exception):
+ c = conn.cursor()
+ try:
+ c.execute("DROP TABLE IF EXISTS foo")
+ c.execute("CREATE TABLE foo(j JSON)")
+ try:
+ c.execute("COPY BINARY INTO foo FROM %s ON CLIENT", [content_name])
+ if expected_exception:
+ content = CONTENT[content_name]
+ msg = f"Expected error involving '{expected_exception}' when
loading {content!r}"
+ raise Exception(msg)
+ except pymonetdb.OperationalError as e:
+ if expected_exception in str(e):
+ conn.rollback()
+ return
+ raise e
+ finally:
+ c.close()
+
+run_test('valid_json', None)
+run_test('invalid_utf8', 'malformed utf')
+run_test('unterminated_object', 'JSONfromString')
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]