Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix extension bugs #3364

Merged
merged 1 commit into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ add_subdirectory(third_party)
if(${BUILD_KUZU})
add_definitions(-DKUZU_ROOT_DIRECTORY="${PROJECT_SOURCE_DIR}")
add_definitions(-DKUZU_CMAKE_VERSION="${CMAKE_PROJECT_VERSION}")
add_definitions(-DKUZU_EXTENSION_VERSION="0.2.6")
add_definitions(-DKUZU_EXTENSION_VERSION="0.2.7")

include_directories(src/include)

Expand Down
13 changes: 9 additions & 4 deletions extension/duckdb_scanner/src/duckdb_catalog.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "duckdb_catalog.h"

#include "common/exception/binder.h"
#include "common/exception/runtime.h"
#include "duckdb_scan.h"
#include "duckdb_table_catalog_entry.h"
#include "duckdb_type_converter.h"
Expand All @@ -22,7 +23,7 @@ void DuckDBCatalogContent::init(const std::string& dbPath, const std::string& ca
} catch (std::exception& e) {
throw common::BinderException(e.what());
}
if (resultChunk->size() == 0) {
if (resultChunk == nullptr || resultChunk->size() == 0) {
return;
}
common::ValueVector tableNamesVector{*common::LogicalType::STRING(),
Expand Down Expand Up @@ -126,9 +127,13 @@ std::string DuckDBCatalogContent::getDefaultSchemaName() const {

std::pair<duckdb::DuckDB, duckdb::Connection> DuckDBCatalogContent::getConnection(
const std::string& dbPath) const {
duckdb::DuckDB db(dbPath);
duckdb::Connection con(db);
return std::make_pair(std::move(db), std::move(con));
try {
duckdb::DuckDB db(dbPath);
duckdb::Connection con(db);
return std::make_pair(std::move(db), std::move(con));
} catch (std::exception& e) {
throw common::RuntimeException{e.what()};
}
}

} // namespace duckdb_scanner
Expand Down
7 changes: 7 additions & 0 deletions extension/duckdb_scanner/src/duckdb_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include <filesystem>

#include "common/exception/runtime.h"
#include "common/file_system/virtual_file_system.h"
#include "common/string_utils.h"
#include "duckdb_catalog.h"

Expand All @@ -20,6 +22,11 @@ std::unique_ptr<main::AttachedDatabase> attachDuckDB(std::string dbName, std::st
dbName = catalogName;
}
auto duckdbCatalog = std::make_unique<DuckDBCatalogContent>();
auto vfs = std::make_unique<common::VirtualFileSystem>();
if (!vfs->fileOrPathExists(dbPath)) {
throw common::RuntimeException{
common::stringFormat("'{}' is not a valid duckdb database path.", dbPath)};
}
duckdbCatalog->init(dbPath, catalogName, clientContext);
return std::make_unique<main::AttachedDatabase>(dbName, std::move(duckdbCatalog));
}
Expand Down
38 changes: 32 additions & 6 deletions extension/duckdb_scanner/test/test_files/duckdb_scanner.test
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
---- ok
-STATEMENT ATTACH '${KUZU_ROOT_DIRECTORY}/extension/duckdb_scanner/test/duckdb_database/tinysnb.db' as tinysnb (dbtype 'duckdb');
---- 1
Attach database successfully.
Attached database successfully.
-STATEMENT LOAD FROM tinysnb.person RETURN *;
---- 8
0|Alice|1|True|False|35|5.000000|1900-01-01|2011-08-20 11:25:30|3 years 2 days 13:02:00|[10,5]|[Aida]|[[10,8],[6,7,8]]|1.731000|a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11|[96,54,86,92]
Expand Down Expand Up @@ -41,17 +41,17 @@ The 😂😃🧘🏻‍♂️🌍🌦️🍞🚗 movie|2544| the movie is very v
Catalog exception: Table: person1 does not exist.
-STATEMENT DETACH tinysnb;
---- 1
Detach database successfully.
Detached database successfully.
-STATEMENT LOAD FROM tinysnb.person RETURN *;
---- error
Binder exception: No database named tinysnb has been attached.
-LOG AttachMultipleDuckDB
-STATEMENT ATTACH '${KUZU_ROOT_DIRECTORY}/extension/duckdb_scanner/test/duckdb_database/tinysnb.db' (dbtype 'duckdb');
---- 1
Attach database successfully.
Attached database successfully.
-STATEMENT ATTACH '${KUZU_ROOT_DIRECTORY}/extension/duckdb_scanner/test/duckdb_database/other.db' as Other1 (dbtype 'duckdb');
---- 1
Attach database successfully.
Attached database successfully.
-STATEMENT LOAD FROM other1.person RETURN *;
---- 4
1
Expand All @@ -64,7 +64,7 @@ Attach database successfully.
-LOG UseDatabaseStatement
-STATEMENT USE other1;
---- 1
Use database successfully.
Used database successfully.
-STATEMENT LOAD FROM person RETURN *;
---- 4
1
Expand All @@ -73,7 +73,7 @@ Use database successfully.
5
-STATEMENT USE tinysnb;
---- 1
Use database successfully.
Used database successfully.
-STATEMENT LOAD FROM person RETURN count(*);
---- 1
8
Expand Down Expand Up @@ -107,3 +107,29 @@ Wendy|28
-STATEMENT ATTACH '${KUZU_ROOT_DIRECTORY}/extension/duckdb_scanner/test/duckdb_database/dbfilewithoutext' (dbtype 'duckdb');
---- error
Runtime exception: Database with name: dbfilewithoutext has already been attached.
-LOG DetachExistDB
-STATEMENT DETACH dbfilewithoutext;
---- ok
-LOG DetachNotExistDBError
-STATEMENT DETACH dbfilewithoutext;
---- error
Runtime exception: Database: dbfilewithoutext doesn't exist.
-LOG AttachNotExistDBError
-STATEMENT ATTACH 'notexist.db' (dbtype 'duckdb');
---- error
Runtime exception: 'notexist.db' is not a valid duckdb database path.

-CASE AttachDBWithoutLoadingExtension
-STATEMENT ATTACH 'notexist.db' (dbtype 'duckdb');
---- error
Runtime exception: No loaded extension can handle database type: duckdb.
Did you forget to load duckdb extension?
You can load it by: load extension duckdb_scanner;
-STATEMENT ATTACH 'notexist.db' (dbtype 'postgres');
---- error
Runtime exception: No loaded extension can handle database type: postgres.
Did you forget to load postgres extension?
You can load it by: load extension postgres_scanner;
-STATEMENT ATTACH 'notexist.db' (dbtype 'sqlite');
---- error
Runtime exception: No loaded extension can handle database type: sqlite.
76 changes: 3 additions & 73 deletions src/function/list/list_extract_function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,80 +20,10 @@ static std::unique_ptr<FunctionBindData> ListExtractBindFunc(
const binder::expression_vector& arguments, Function* function) {
auto resultType = ListType::getChildType(&arguments[0]->dataType);
auto scalarFunction = ku_dynamic_cast<Function*, ScalarFunction*>(function);
switch (resultType->getPhysicalType()) {
case PhysicalTypeID::BOOL: {
TypeUtils::visit(resultType->getPhysicalType(), [&]<typename T>(T) {
scalarFunction->execFunc =
BinaryExecListExtractFunction<list_entry_t, int64_t, uint8_t, ListExtract>;
} break;
case PhysicalTypeID::INT64: {
scalarFunction->execFunc =
BinaryExecListExtractFunction<list_entry_t, int64_t, int64_t, ListExtract>;
} break;
case PhysicalTypeID::INT32: {
scalarFunction->execFunc =
BinaryExecListExtractFunction<list_entry_t, int64_t, int32_t, ListExtract>;
} break;
case PhysicalTypeID::INT16: {
scalarFunction->execFunc =
BinaryExecListExtractFunction<list_entry_t, int64_t, int16_t, ListExtract>;
} break;
case PhysicalTypeID::INT8: {
scalarFunction->execFunc =
BinaryExecListExtractFunction<list_entry_t, int64_t, int8_t, ListExtract>;
} break;
case PhysicalTypeID::UINT64: {
scalarFunction->execFunc =
BinaryExecListExtractFunction<list_entry_t, int64_t, uint64_t, ListExtract>;
} break;
case PhysicalTypeID::UINT32: {
scalarFunction->execFunc =
BinaryExecListExtractFunction<list_entry_t, int64_t, uint32_t, ListExtract>;
} break;
case PhysicalTypeID::UINT16: {
scalarFunction->execFunc =
BinaryExecListExtractFunction<list_entry_t, int64_t, uint16_t, ListExtract>;
} break;
case PhysicalTypeID::UINT8: {
scalarFunction->execFunc =
BinaryExecListExtractFunction<list_entry_t, int64_t, uint8_t, ListExtract>;
} break;
case PhysicalTypeID::INT128: {
scalarFunction->execFunc =
BinaryExecListExtractFunction<list_entry_t, int64_t, int128_t, ListExtract>;
} break;
case PhysicalTypeID::DOUBLE: {
scalarFunction->execFunc =
BinaryExecListExtractFunction<list_entry_t, int64_t, double, ListExtract>;
} break;
case PhysicalTypeID::FLOAT: {
scalarFunction->execFunc =
BinaryExecListExtractFunction<list_entry_t, int64_t, float, ListExtract>;
} break;
case PhysicalTypeID::INTERVAL: {
scalarFunction->execFunc =
BinaryExecListExtractFunction<list_entry_t, int64_t, interval_t, ListExtract>;
} break;
case PhysicalTypeID::STRING: {
scalarFunction->execFunc =
BinaryExecListExtractFunction<list_entry_t, int64_t, ku_string_t, ListExtract>;
} break;
case PhysicalTypeID::ARRAY:
case PhysicalTypeID::LIST: {
scalarFunction->execFunc =
BinaryExecListExtractFunction<list_entry_t, int64_t, list_entry_t, ListExtract>;
} break;
case PhysicalTypeID::STRUCT: {
scalarFunction->execFunc =
BinaryExecListExtractFunction<list_entry_t, int64_t, struct_entry_t, ListExtract>;
} break;
case PhysicalTypeID::INTERNAL_ID: {
scalarFunction->execFunc =
BinaryExecListExtractFunction<list_entry_t, int64_t, internalID_t, ListExtract>;
} break;
default: {
KU_UNREACHABLE;
}
}
BinaryExecListExtractFunction<list_entry_t, int64_t, T, ListExtract>;
});
std::vector<LogicalType> paramTypes;
paramTypes.push_back(arguments[0]->getDataType());
paramTypes.push_back(LogicalType(function->parameterTypeIDs[1]));
Expand Down
79 changes: 5 additions & 74 deletions src/function/map/map_extract_function.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "function/map/functions/map_extract_function.h"

#include "common/exception/runtime.h"
#include "common/type_utils.h"
#include "function/map/vector_map_functions.h"
#include "function/scalar_function.h"

Expand All @@ -21,80 +22,10 @@ static std::unique_ptr<FunctionBindData> bindFunc(const binder::expression_vecto
kuzu::function::Function* function) {
validateKeyType(arguments[0], arguments[1]);
auto scalarFunction = ku_dynamic_cast<Function*, ScalarFunction*>(function);
switch (arguments[1]->getDataType().getPhysicalType()) {
case PhysicalTypeID::BOOL: {
scalarFunction->execFunc = ScalarFunction::BinaryExecListStructFunction<list_entry_t,
uint8_t, list_entry_t, MapExtract>;
} break;
case PhysicalTypeID::INT64: {
scalarFunction->execFunc = ScalarFunction::BinaryExecListStructFunction<list_entry_t,
int64_t, list_entry_t, MapExtract>;
} break;
case PhysicalTypeID::INT32: {
scalarFunction->execFunc = ScalarFunction::BinaryExecListStructFunction<list_entry_t,
int32_t, list_entry_t, MapExtract>;
} break;
case PhysicalTypeID::INT16: {
scalarFunction->execFunc = ScalarFunction::BinaryExecListStructFunction<list_entry_t,
int16_t, list_entry_t, MapExtract>;
} break;
case PhysicalTypeID::INT8: {
scalarFunction->execFunc = ScalarFunction::BinaryExecListStructFunction<list_entry_t,
int8_t, list_entry_t, MapExtract>;
} break;
case PhysicalTypeID::UINT64: {
scalarFunction->execFunc = ScalarFunction::BinaryExecListStructFunction<list_entry_t,
uint64_t, list_entry_t, MapExtract>;
} break;
case PhysicalTypeID::UINT32: {
scalarFunction->execFunc = ScalarFunction::BinaryExecListStructFunction<list_entry_t,
uint32_t, list_entry_t, MapExtract>;
} break;
case PhysicalTypeID::UINT16: {
scalarFunction->execFunc = ScalarFunction::BinaryExecListStructFunction<list_entry_t,
uint16_t, list_entry_t, MapExtract>;
} break;
case PhysicalTypeID::UINT8: {
scalarFunction->execFunc = ScalarFunction::BinaryExecListStructFunction<list_entry_t,
uint8_t, list_entry_t, MapExtract>;
} break;
case PhysicalTypeID::INT128: {
scalarFunction->execFunc = ScalarFunction::BinaryExecListStructFunction<list_entry_t,
int128_t, list_entry_t, MapExtract>;
} break;
case PhysicalTypeID::DOUBLE: {
scalarFunction->execFunc = ScalarFunction::BinaryExecListStructFunction<list_entry_t,
double, list_entry_t, MapExtract>;
} break;
case PhysicalTypeID::FLOAT: {
scalarFunction->execFunc = ScalarFunction::BinaryExecListStructFunction<list_entry_t, float,
list_entry_t, MapExtract>;
} break;
case PhysicalTypeID::STRING: {
scalarFunction->execFunc = ScalarFunction::BinaryExecListStructFunction<list_entry_t,
ku_string_t, list_entry_t, MapExtract>;
} break;
case PhysicalTypeID::INTERVAL: {
scalarFunction->execFunc = ScalarFunction::BinaryExecListStructFunction<list_entry_t,
interval_t, list_entry_t, MapExtract>;
} break;
case PhysicalTypeID::INTERNAL_ID: {
scalarFunction->execFunc = ScalarFunction::BinaryExecListStructFunction<list_entry_t,
internalID_t, list_entry_t, MapExtract>;
} break;
case PhysicalTypeID::ARRAY:
case PhysicalTypeID::LIST: {
scalarFunction->execFunc = ScalarFunction::BinaryExecListStructFunction<list_entry_t,
list_entry_t, list_entry_t, MapExtract>;
} break;
case PhysicalTypeID::STRUCT: {
scalarFunction->execFunc = ScalarFunction::BinaryExecListStructFunction<list_entry_t,
struct_entry_t, list_entry_t, MapExtract>;
} break;
default: {
KU_UNREACHABLE;
}
}
TypeUtils::visit(arguments[1]->getDataType().getPhysicalType(), [&]<typename T>(T) {
scalarFunction->execFunc =
ScalarFunction::BinaryExecListStructFunction<list_entry_t, T, list_entry_t, MapExtract>;
});
auto resultType = LogicalType::LIST(MapType::getValueType(&arguments[0]->dataType)->copy());
return FunctionBindData::getSimpleBindData(arguments, *resultType);
}
Expand Down
2 changes: 1 addition & 1 deletion src/include/common/file_system/virtual_file_system.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace kuzu {
namespace common {

class VirtualFileSystem final : public FileSystem {
class KUZU_API VirtualFileSystem final : public FileSystem {

public:
VirtualFileSystem();
Expand Down
3 changes: 2 additions & 1 deletion src/main/database_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ void DatabaseManager::detachDatabase(const std::string& databaseName) {
return;
}
}
KU_UNREACHABLE;
throw common::RuntimeException{
common::stringFormat("Database: {} doesn't exist.", databaseName)};
}

void DatabaseManager::setDefaultDatabase(const std::string& databaseName) {
Expand Down
12 changes: 12 additions & 0 deletions src/processor/operator/simple/attach_database.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "processor/operator/simple/attach_database.h"

#include "common/exception/runtime.h"
#include "main/database.h"
#include "main/database_manager.h"
#include "storage/storage_extension.h"
Expand All @@ -13,8 +14,19 @@ void AttachDatabase::executeInternal(ExecutionContext* context) {
if (storageExtension->canHandleDB(attachInfo.dbType)) {
auto db = storageExtension->attach(attachInfo.dbAlias, attachInfo.dbPath, client);
client->getDatabaseManager()->registerAttachedDatabase(std::move(db));
return;
}
}
auto errMsg = common::stringFormat("No loaded extension can handle database type: {}.",
attachInfo.dbType);
if (attachInfo.dbType == "duckdb") {
errMsg += "\nDid you forget to load duckdb extension?\nYou can load it by: load "
"extension duckdb_scanner;";
} else if (attachInfo.dbType == "postgres") {
errMsg += "\nDid you forget to load postgres extension?\nYou can load it by: load "
"extension postgres_scanner;";
}
throw common::RuntimeException{errMsg};
}

std::string AttachDatabase::getOutputMsg() {
Expand Down
Loading