Skip to content

Commit

Permalink
Merge branch 'apache:main' into dev/snowflake-privatekey
Browse files Browse the repository at this point in the history
  • Loading branch information
davidhcoe authored Oct 27, 2023
2 parents e241e5d + 3a8f6dc commit a0fcba2
Show file tree
Hide file tree
Showing 29 changed files with 1,389 additions and 536 deletions.
6 changes: 6 additions & 0 deletions c/driver/flightsql/dremio_flightsql_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ class DremioFlightSqlStatementTest : public ::testing::Test,
void TestSqlIngestColumnEscaping() {
GTEST_SKIP() << "Column escaping not implemented";
}
void TestSqlQueryRowsAffectedDelete() {
GTEST_SKIP() << "Cannot query rows affected in delete (not implemented)";
}
void TestSqlQueryRowsAffectedDeleteStream() {
GTEST_SKIP() << "Cannot query rows affected in delete stream (not implemented)";
}

protected:
DremioFlightSqlQuirks quirks_;
Expand Down
6 changes: 6 additions & 0 deletions c/driver/flightsql/sqlite_flightsql_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,12 @@ class SqliteFlightSqlStatementTest : public ::testing::Test,
void TestSqlIngestInterval() {
GTEST_SKIP() << "Cannot ingest Interval (not implemented)";
}
void TestSqlQueryRowsAffectedDelete() {
GTEST_SKIP() << "Cannot query rows affected in delete (not implemented)";
}
void TestSqlQueryRowsAffectedDeleteStream() {
GTEST_SKIP() << "Cannot query rows affected in delete stream (not implemented)";
}

protected:
SqliteFlightSqlQuirks quirks_;
Expand Down
7 changes: 7 additions & 0 deletions c/driver/postgresql/postgresql_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -812,10 +812,17 @@ class PostgresStatementTest : public ::testing::Test,
void TestSqlIngestUInt16() { GTEST_SKIP() << "Not implemented"; }
void TestSqlIngestUInt32() { GTEST_SKIP() << "Not implemented"; }
void TestSqlIngestUInt64() { GTEST_SKIP() << "Not implemented"; }
void TestSqlIngestStringDictionary() { GTEST_SKIP() << "Not implemented"; }

void TestSqlPrepareErrorParamCountMismatch() { GTEST_SKIP() << "Not yet implemented"; }
void TestSqlPrepareGetParameterSchema() { GTEST_SKIP() << "Not yet implemented"; }
void TestSqlPrepareSelectParams() { GTEST_SKIP() << "Not yet implemented"; }
void TestSqlQueryRowsAffectedDelete() {
GTEST_SKIP() << "Cannot query rows affected in delete (not implemented)";
}
void TestSqlQueryRowsAffectedDeleteStream() {
GTEST_SKIP() << "Cannot query rows affected in delete stream (not implemented)";
}

void TestConcurrentStatements() {
// TODO: refactor driver so that we read all the data as soon as
Expand Down
8 changes: 7 additions & 1 deletion c/driver/sqlite/sqlite.c
Original file line number Diff line number Diff line change
Expand Up @@ -1364,7 +1364,13 @@ AdbcStatusCode SqliteStatementExecuteQuery(struct AdbcStatement* statement,
sqlite3_mutex_leave(sqlite3_db_mutex(stmt->conn));

AdbcSqliteBinderRelease(&stmt->binder);
if (rows_affected) *rows_affected = rows;
if (rows_affected) {
if (sqlite3_column_count(stmt->stmt) == 0) {
*rows_affected = sqlite3_changes(stmt->conn);
} else {
*rows_affected = rows;
}
}
return status;
}

Expand Down
38 changes: 36 additions & 2 deletions c/driver/sqlite/sqlite_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -246,10 +246,9 @@ class SqliteStatementTest : public ::testing::Test,

void TestSqlIngestUInt64() {
std::vector<std::optional<uint64_t>> values = {std::nullopt, 0, INT64_MAX};
return TestSqlIngestType(NANOARROW_TYPE_UINT64, values);
return TestSqlIngestType(NANOARROW_TYPE_UINT64, values, /*dictionary_encode*/ false);
}

void TestSqlIngestBinary() { GTEST_SKIP() << "Cannot ingest BINARY (not implemented)"; }
void TestSqlIngestDuration() {
GTEST_SKIP() << "Cannot ingest DURATION (not implemented)";
}
Expand Down Expand Up @@ -555,6 +554,22 @@ TEST_F(SqliteReaderTest, InferIntRejectStr) {
"[SQLite] Type mismatch in column 0: expected INT64 but got STRING/BINARY"));
}

TEST_F(SqliteReaderTest, InferIntRejectBlob) {
adbc_validation::StreamReader reader;
ASSERT_NO_FATAL_FAILURE(
ExecSelect(R"((1), (NULL), (X''), (NULL))", /*infer_rows=*/2, &reader));
ASSERT_EQ(NANOARROW_TYPE_INT64, reader.fields[0].type);
ASSERT_NO_FATAL_FAILURE(reader.Next());
ASSERT_NO_FATAL_FAILURE(
CompareArray<int64_t>(reader.array_view->children[0], {1, std::nullopt}));

ASSERT_THAT(reader.MaybeNext(), ::testing::Not(IsOkErrno()));
ASSERT_THAT(
reader.stream->get_last_error(&reader.stream.value),
::testing::HasSubstr(
"[SQLite] Type mismatch in column 0: expected INT64 but got STRING/BINARY"));
}

TEST_F(SqliteReaderTest, InferFloatReadIntFloat) {
adbc_validation::StreamReader reader;
ASSERT_NO_FATAL_FAILURE(
Expand Down Expand Up @@ -592,6 +607,25 @@ TEST_F(SqliteReaderTest, InferFloatRejectStr) {
"[SQLite] Type mismatch in column 0: expected DOUBLE but got STRING/BINARY"));
}

TEST_F(SqliteReaderTest, InferFloatRejectBlob) {
adbc_validation::StreamReader reader;
ASSERT_NO_FATAL_FAILURE(ExecSelect(R"((1E0), (NULL), (2E0), (3), (X''), (NULL))",
/*infer_rows=*/2, &reader));
ASSERT_EQ(NANOARROW_TYPE_DOUBLE, reader.fields[0].type);
ASSERT_NO_FATAL_FAILURE(reader.Next());
ASSERT_NO_FATAL_FAILURE(
CompareArray<double>(reader.array_view->children[0], {1.0, std::nullopt}));
ASSERT_NO_FATAL_FAILURE(reader.Next());
ASSERT_NO_FATAL_FAILURE(
CompareArray<double>(reader.array_view->children[0], {2.0, 3.0}));

ASSERT_THAT(reader.MaybeNext(), ::testing::Not(IsOkErrno()));
ASSERT_THAT(
reader.stream->get_last_error(&reader.stream.value),
::testing::HasSubstr(
"[SQLite] Type mismatch in column 0: expected DOUBLE but got STRING/BINARY"));
}

TEST_F(SqliteReaderTest, InferStrReadAll) {
adbc_validation::StreamReader reader;
ASSERT_NO_FATAL_FAILURE(ExecSelect(R"((""), (NULL), (2), (3E0), ("foo"), (NULL))",
Expand Down
116 changes: 104 additions & 12 deletions c/driver/sqlite/statement_reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ AdbcStatusCode AdbcSqliteBinderSet(struct AdbcSqliteBinder* binder,
struct ArrowSchemaView view = {0};
for (int i = 0; i < binder->schema.n_children; i++) {
status = ArrowSchemaViewInit(&view, binder->schema.children[i], &arrow_error);
if (status != 0) {
if (status != NANOARROW_OK) {
SetError(error, "Failed to parse schema for column %d: %s (%d): %s", i,
strerror(status), status, arrow_error.message);
return ADBC_STATUS_INVALID_ARGUMENT;
Expand All @@ -70,6 +70,31 @@ AdbcStatusCode AdbcSqliteBinderSet(struct AdbcSqliteBinder* binder,
SetError(error, "Column %d has UNINITIALIZED type", i);
return ADBC_STATUS_INTERNAL;
}

if (view.type == NANOARROW_TYPE_DICTIONARY) {
struct ArrowSchemaView value_view = {0};
status = ArrowSchemaViewInit(&value_view, binder->schema.children[i]->dictionary,
&arrow_error);
if (status != NANOARROW_OK) {
SetError(error, "Failed to parse schema for column %d->dictionary: %s (%d): %s",
i, strerror(status), status, arrow_error.message);
return ADBC_STATUS_INVALID_ARGUMENT;
}

// We only support string/binary dictionary-encoded values
switch (value_view.type) {
case NANOARROW_TYPE_STRING:
case NANOARROW_TYPE_LARGE_STRING:
case NANOARROW_TYPE_BINARY:
case NANOARROW_TYPE_LARGE_BINARY:
break;
default:
SetError(error, "Column %d dictionary has unsupported type %s", i,
ArrowTypeString(value_view.type));
return ADBC_STATUS_NOT_IMPLEMENTED;
}
}

binder->types[i] = view.type;
}

Expand Down Expand Up @@ -308,7 +333,7 @@ AdbcStatusCode AdbcSqliteBinderBindNext(struct AdbcSqliteBinder* binder, sqlite3
case NANOARROW_TYPE_LARGE_BINARY: {
struct ArrowBufferView value =
ArrowArrayViewGetBytesUnsafe(binder->batch.children[col], binder->next_row);
status = sqlite3_bind_text(stmt, col + 1, value.data.as_char, value.size_bytes,
status = sqlite3_bind_blob(stmt, col + 1, value.data.as_char, value.size_bytes,
SQLITE_STATIC);
break;
}
Expand Down Expand Up @@ -353,6 +378,20 @@ AdbcStatusCode AdbcSqliteBinderBindNext(struct AdbcSqliteBinder* binder, sqlite3
SQLITE_STATIC);
break;
}
case NANOARROW_TYPE_DICTIONARY: {
int64_t value_index =
ArrowArrayViewGetIntUnsafe(binder->batch.children[col], binder->next_row);
if (ArrowArrayViewIsNull(binder->batch.children[col]->dictionary,
value_index)) {
status = sqlite3_bind_null(stmt, col + 1);
} else {
struct ArrowBufferView value = ArrowArrayViewGetBytesUnsafe(
binder->batch.children[col]->dictionary, value_index);
status = sqlite3_bind_text(stmt, col + 1, value.data.as_char,
value.size_bytes, SQLITE_STATIC);
}
break;
}
case NANOARROW_TYPE_DATE32: {
int64_t value =
ArrowArrayViewGetIntUnsafe(binder->batch.children[col], binder->next_row);
Expand Down Expand Up @@ -529,14 +568,8 @@ int StatementReaderGetOneValue(struct StatementReader* reader, int col,
case SQLITE_INTEGER:
case SQLITE_FLOAT:
case SQLITE_TEXT:
case SQLITE_BLOB: {
// Let SQLite convert
struct ArrowStringView value = {
.data = (const char*)sqlite3_column_text(reader->stmt, col),
.size_bytes = sqlite3_column_bytes(reader->stmt, col),
};
return ArrowArrayAppendString(out, value);
}
case SQLITE_BLOB:
break;
default: {
snprintf(reader->error.message, sizeof(reader->error.message),
"[SQLite] Type mismatch in column %d: expected STRING but got unknown "
Expand All @@ -545,7 +578,34 @@ int StatementReaderGetOneValue(struct StatementReader* reader, int col,
return ENOTSUP;
}
}
break;

// Let SQLite convert
struct ArrowStringView value = {
.data = (const char*)sqlite3_column_text(reader->stmt, col),
.size_bytes = sqlite3_column_bytes(reader->stmt, col),
};
return ArrowArrayAppendString(out, value);
}

case NANOARROW_TYPE_BINARY: {
switch (sqlite_type) {
case SQLITE_TEXT:
case SQLITE_BLOB:
break;
default: {
snprintf(reader->error.message, sizeof(reader->error.message),
"[SQLite] Type mismatch in column %d: expected BLOB but got unknown "
"type %d",
col, sqlite_type);
return ENOTSUP;
}
}

// Let SQLite convert
struct ArrowBufferView value;
value.data.data = sqlite3_column_blob(reader->stmt, col);
value.size_bytes = sqlite3_column_bytes(reader->stmt, col);
return ArrowArrayAppendBytes(out, value);
}

default: {
Expand Down Expand Up @@ -1014,7 +1074,39 @@ AdbcStatusCode StatementReaderInferOneValue(
CHECK_NA(INTERNAL, ArrowBufferAppend(data, &offset, sizeof(offset)), error);
break;
}
case SQLITE_BLOB:
case SQLITE_BLOB: {
ArrowBitmapAppendUnsafe(validity, /*set=*/1, /*length=*/1);

switch (*current_type) {
case NANOARROW_TYPE_INT64: {
AdbcStatusCode status = StatementReaderUpcastInt64ToBinary(data, binary, error);
if (status != ADBC_STATUS_OK) return status;
*current_type = NANOARROW_TYPE_BINARY;
break;
}
case NANOARROW_TYPE_DOUBLE: {
AdbcStatusCode status =
StatementReaderUpcastDoubleToBinary(data, binary, error);
if (status != ADBC_STATUS_OK) return status;
*current_type = NANOARROW_TYPE_BINARY;
break;
}
case NANOARROW_TYPE_STRING:
*current_type = NANOARROW_TYPE_BINARY;
break;
case NANOARROW_TYPE_BINARY:
break;
default:
return ADBC_STATUS_INTERNAL;
}

const void* value = sqlite3_column_blob(stmt, col);
const int size = sqlite3_column_bytes(stmt, col);
const int32_t offset = ((int32_t*)data->data)[data->size_bytes / 4 - 1] + size;
CHECK_NA(INTERNAL, ArrowBufferAppend(binary, value, size), error);
CHECK_NA(INTERNAL, ArrowBufferAppend(data, &offset, sizeof(offset)), error);
break;
}
default: {
return ADBC_STATUS_NOT_IMPLEMENTED;
}
Expand Down
6 changes: 6 additions & 0 deletions c/driver_manager/adbc_driver_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,11 @@ AdbcStatusCode StatementBind(struct AdbcStatement*, struct ArrowArray*,
return ADBC_STATUS_NOT_IMPLEMENTED;
}

AdbcStatusCode StatementBindStream(struct AdbcStatement*, struct ArrowArrayStream*,
struct AdbcError* error) {
return ADBC_STATUS_NOT_IMPLEMENTED;
}

AdbcStatusCode StatementCancel(struct AdbcStatement* statement, struct AdbcError* error) {
return ADBC_STATUS_NOT_IMPLEMENTED;
}
Expand Down Expand Up @@ -1666,6 +1671,7 @@ AdbcStatusCode AdbcLoadDriverFromInitFunc(AdbcDriverInitFunc init_func, int vers
CHECK_REQUIRED(driver, StatementNew);
CHECK_REQUIRED(driver, StatementRelease);
FILL_DEFAULT(driver, StatementBind);
FILL_DEFAULT(driver, StatementBindStream);
FILL_DEFAULT(driver, StatementGetParameterSchema);
FILL_DEFAULT(driver, StatementPrepare);
FILL_DEFAULT(driver, StatementSetOption);
Expand Down
6 changes: 6 additions & 0 deletions c/integration/duckdb/duckdb_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ class DuckDbStatementTest : public ::testing::Test,
}

void TestSqlQueryErrors() { GTEST_SKIP() << "DuckDB does not set AdbcError.release"; }
void TestSqlQueryRowsAffectedDelete() {
GTEST_SKIP() << "Cannot query rows affected in delete (not implemented)";
}
void TestSqlQueryRowsAffectedDeleteStream() {
GTEST_SKIP() << "Cannot query rows affected in delete stream (not implemented)";
}

void TestErrorCompatibility() {
GTEST_SKIP() << "DuckDB does not set AdbcError.release";
Expand Down
Loading

0 comments on commit a0fcba2

Please sign in to comment.