Skip to content

Commit

Permalink
Implement use database (#3300)
Browse files Browse the repository at this point in the history
  • Loading branch information
acquamarin committed Apr 17, 2024
1 parent c95edc7 commit fc6659e
Show file tree
Hide file tree
Showing 52 changed files with 3,771 additions and 3,355 deletions.
22 changes: 22 additions & 0 deletions extension/duckdb_scanner/test/test_files/duckdb_scanner.test
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,23 @@ Binder exception: No database named tinysnb has been attached.
-STATEMENT LOAD FROM tinysnb.person RETURN count(*);
---- 1
8
-LOG UseDatabaseStatement
-STATEMENT USE other;
---- ok
-STATEMENT LOAD FROM person RETURN *;
---- 4
1
2
3
5
-STATEMENT USE tinysnb;
---- ok
-STATEMENT LOAD FROM person RETURN count(*);
---- 1
8
-STATEMENT LOAD FROM other.person RETURN count(*);
---- 1
4

-CASE InvalidDuckDBDatabase
-STATEMENT LOAD FROM tinysnb1.person RETURN *;
Expand All @@ -65,3 +82,8 @@ Binder exception: No database named tinysnb1 has been attached.
-STATEMENT LOAD FROM tinysnb1_person RETURN *;
---- error
Binder exception: Variable tinysnb1_person is not in scope.

-CASE InvalidUseDatabaseName
-STATEMENT USE NONEXIST;
---- error
Runtime exception: No database named NONEXIST.
10 changes: 9 additions & 1 deletion scripts/antlr4/Cypher.g4.copy
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ oC_Statement
| kU_ExportDatabase
| kU_ImportDatabase
| kU_AttachDatabase
| kU_DetachDatabase;
| kU_DetachDatabase
| kU_UseDatabase;

kU_CopyFrom
: COPY SP oC_SchemaName ( ( SP? kU_ColumnNames SP? ) | SP ) FROM SP kU_ScanSource ( SP? kU_ParsingOptions )? ;
Expand Down Expand Up @@ -76,6 +77,12 @@ DBTYPE:
kU_DetachDatabase
: DETACH SP oC_SchemaName;

kU_UseDatabase
: USE SP oC_SchemaName;

USE:
( 'U' | 'u') ( 'S' | 's') ( 'E' | 'e');

kU_StandaloneCall
: CALL SP oC_SymbolicName SP? '=' SP? oC_Literal ;

Expand Down Expand Up @@ -779,6 +786,7 @@ kU_NonReservedKeywords
| IMPORT
| EXPORT
| DATABASE
| USE
;

UnescapedSymbolicName
Expand Down
10 changes: 9 additions & 1 deletion src/antlr4/Cypher.g4
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ oC_Statement
| kU_ExportDatabase
| kU_ImportDatabase
| kU_AttachDatabase
| kU_DetachDatabase;
| kU_DetachDatabase
| kU_UseDatabase;

kU_CopyFrom
: COPY SP oC_SchemaName ( ( SP? kU_ColumnNames SP? ) | SP ) FROM SP kU_ScanSource ( SP? kU_ParsingOptions )? ;
Expand Down Expand Up @@ -76,6 +77,12 @@ DBTYPE:
kU_DetachDatabase
: DETACH SP oC_SchemaName;

kU_UseDatabase
: USE SP oC_SchemaName;

USE:
( 'U' | 'u') ( 'S' | 's') ( 'E' | 'e');

kU_StandaloneCall
: CALL SP oC_SymbolicName SP? '=' SP? oC_Literal ;

Expand Down Expand Up @@ -779,6 +786,7 @@ kU_NonReservedKeywords
| IMPORT
| EXPORT
| DATABASE
| USE
;

UnescapedSymbolicName
Expand Down
3 changes: 2 additions & 1 deletion src/binder/bind/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ add_library(
bind_updating_clause.cpp
bind_extension.cpp
bind_export_database.cpp
bind_import_database.cpp)
bind_import_database.cpp
bind_use_database.cpp)

set(ALL_OBJECT_FILES
${ALL_OBJECT_FILES} $<TARGET_OBJECTS:kuzu_binder_bind>
Expand Down
4 changes: 1 addition & 3 deletions src/binder/bind/bind_attach_database.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
#include "binder/binder.h"
#include "binder/bound_attach_database.h"
#include "common/cast.h"
#include "parser/attach_database.h"

namespace kuzu {
namespace binder {

std::unique_ptr<BoundStatement> Binder::bindAttachDatabase(const parser::Statement& statement) {
auto& attachDatabase =
common::ku_dynamic_cast<const parser::Statement&, const parser::AttachDatabase&>(statement);
auto& attachDatabase = statement.constCast<parser::AttachDatabase>();
return std::make_unique<BoundAttachDatabase>(attachDatabase.getAttachInfo());
}

Expand Down
4 changes: 1 addition & 3 deletions src/binder/bind/bind_detach_database.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
#include "binder/binder.h"
#include "binder/bound_detach_database.h"
#include "common/cast.h"
#include "parser/detach_database.h"

namespace kuzu {
namespace binder {

std::unique_ptr<BoundStatement> Binder::bindDetachDatabase(const parser::Statement& statement) {
auto& detachDatabase =
common::ku_dynamic_cast<const parser::Statement&, const parser::DetachDatabase&>(statement);
auto& detachDatabase = statement.constCast<parser::DetachDatabase>();
return std::make_unique<BoundDetachDatabase>(detachDatabase.getDBName());
}

Expand Down
14 changes: 14 additions & 0 deletions src/binder/bind/bind_use_database.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include "binder/binder.h"
#include "binder/bound_use_database.h"
#include "parser/use_database.h"

namespace kuzu {
namespace binder {

std::unique_ptr<BoundStatement> Binder::bindUseDatabase(const parser::Statement& statement) {
auto useDatabase = statement.constCast<parser::UseDatabase>();
return std::make_unique<BoundUseDatabase>(useDatabase.getDBName());
}

} // namespace binder
} // namespace kuzu
45 changes: 28 additions & 17 deletions src/binder/bind/read/bind_load_from.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,38 +16,49 @@ using namespace kuzu::catalog;
namespace kuzu {
namespace binder {

static TableFunction getObjectScanFunc(const ObjectScanSource* objectSource,
main::ClientContext* clientContext) {
// Bind external database table
auto dbName = objectSource->objectNames[0];
auto attachedDB = clientContext->getDatabaseManager()->getAttachedDatabase(dbName);
if (attachedDB == nullptr) {
throw BinderException{stringFormat("No database named {} has been attached.", dbName)};
}
auto tableName = objectSource->objectNames[1];
auto attachedCatalog = attachedDB->getCatalogContent();
auto tableID = attachedCatalog->getTableID(tableName);
auto entry = attachedCatalog->getTableCatalogEntry(tableID);
auto tableEntry = ku_dynamic_cast<CatalogEntry*, TableCatalogEntry*>(entry);
return tableEntry->getScanFunction();
}

std::unique_ptr<BoundReadingClause> Binder::bindLoadFrom(const ReadingClause& readingClause) {
auto& loadFrom = readingClause.constCast<LoadFrom>();
TableFunction scanFunction;
std::unique_ptr<TableFuncBindData> bindData;
auto source = loadFrom.getSource();
switch (source->type) {
case ScanSourceType::OBJECT: {
auto objectSource = source->constPtrCast<ObjectScanSource>();
auto objectSource = reinterpret_cast<ObjectScanSource*>(source);
KU_ASSERT(!objectSource->objectNames.empty());
if (objectSource->objectNames.size() == 1) {
// Bind external object as table
auto objectName = objectSource->objectNames[0];
auto replacementData = clientContext->tryReplace(objectName);
if (replacementData == nullptr) {
if (replacementData != nullptr) {
scanFunction = replacementData->func;
bindData = scanFunction.bindFunc(clientContext, &replacementData->bindInput);
} else if (clientContext->getDatabaseManager()->hasDefaultDatabase()) {
objectSource->objectNames.insert(objectSource->objectNames.begin(),
clientContext->getDatabaseManager()->getDefaultDatabase());
scanFunction = getObjectScanFunc(objectSource, clientContext);
auto bindInput = function::TableFuncBindInput();
bindData = scanFunction.bindFunc(clientContext, &bindInput);
} else {
throw BinderException(ExceptionMessage::variableNotInScope(objectName));
}
scanFunction = replacementData->func;
bindData = scanFunction.bindFunc(clientContext, &replacementData->bindInput);
} else if (objectSource->objectNames.size() == 2) {
// Bind external database table
auto dbName = objectSource->objectNames[0];
auto attachedDB = clientContext->getDatabaseManager()->getAttachedDatabase(dbName);
if (attachedDB == nullptr) {
throw BinderException{
stringFormat("No database named {} has been attached.", dbName)};
}
auto tableName = objectSource->objectNames[1];
auto attachedCatalog = attachedDB->getCatalogContent();
auto tableID = attachedCatalog->getTableID(tableName);
auto entry = attachedCatalog->getTableCatalogEntry(tableID);
auto tableEntry = ku_dynamic_cast<CatalogEntry*, TableCatalogEntry*>(entry);
scanFunction = tableEntry->getScanFunction();
scanFunction = getObjectScanFunc(objectSource, clientContext);
auto bindInput = function::TableFuncBindInput();
bindData = scanFunction.bindFunc(clientContext, &bindInput);
} else {
Expand Down
3 changes: 3 additions & 0 deletions src/binder/binder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ std::unique_ptr<BoundStatement> Binder::bind(const Statement& statement) {
case StatementType::DETACH_DATABASE: {
boundStatement = bindDetachDatabase(statement);
} break;
case StatementType::USE_DATABASE: {
boundStatement = bindUseDatabase(statement);
} break;
default: {
KU_UNREACHABLE;
}
Expand Down
3 changes: 3 additions & 0 deletions src/binder/bound_statement_visitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ void BoundStatementVisitor::visit(const BoundStatement& statement) {
case StatementType::DETACH_DATABASE: {
visitDetachDatabase(statement);
} break;
case StatementType::USE_DATABASE: {
visitUseDatabase(statement);
} break;
default:
KU_UNREACHABLE;
}
Expand Down
1 change: 1 addition & 0 deletions src/include/binder/binder.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ class Binder {

std::unique_ptr<BoundStatement> bindAttachDatabase(const parser::Statement& statement);
std::unique_ptr<BoundStatement> bindDetachDatabase(const parser::Statement& statement);
std::unique_ptr<BoundStatement> bindUseDatabase(const parser::Statement& statement);

/*** bind scan source ***/
std::unique_ptr<BoundBaseScanSource> bindScanSource(parser::BaseScanSource* scanSource,
Expand Down
21 changes: 21 additions & 0 deletions src/include/binder/bound_database_statement.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include "binder/bound_statement.h"

namespace kuzu {
namespace binder {

class BoundDatabaseStatement : public BoundStatement {
public:
explicit BoundDatabaseStatement(common::StatementType statementType, std::string dbName)
: BoundStatement{statementType, BoundStatementResult::createEmptyResult()},
dbName{std::move(dbName)} {}

std::string getDBName() const { return dbName; }

private:
std::string dbName;
};

} // namespace binder
} // namespace kuzu
13 changes: 3 additions & 10 deletions src/include/binder/bound_detach_database.h
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
#pragma once

#include "binder/bound_statement.h"
#include "binder/bound_database_statement.h"

namespace kuzu {
namespace binder {

class BoundDetachDatabase final : public BoundStatement {
class BoundDetachDatabase final : public BoundDatabaseStatement {
public:
explicit BoundDetachDatabase(std::string dbName)
: BoundStatement{common::StatementType::DETACH_DATABASE,
BoundStatementResult::createEmptyResult()},
dbName{std::move(dbName)} {}

std::string getDBName() const { return dbName; }

private:
std::string dbName;
: BoundDatabaseStatement{common::StatementType::DETACH_DATABASE, std::move(dbName)} {}
};

} // namespace binder
Expand Down
1 change: 1 addition & 0 deletions src/include/binder/bound_statement_visitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class BoundStatementVisitor {
virtual void visitProjectionBodyPredicate(const std::shared_ptr<Expression>& /* predicate*/) {}
virtual void visitAttachDatabase(const BoundStatement&) {}
virtual void visitDetachDatabase(const BoundStatement&) {}
virtual void visitUseDatabase(const BoundStatement&) {}
};

} // namespace binder
Expand Down
15 changes: 15 additions & 0 deletions src/include/binder/bound_use_database.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include "binder/bound_database_statement.h"

namespace kuzu {
namespace binder {

class BoundUseDatabase final : public BoundDatabaseStatement {
public:
explicit BoundUseDatabase(std::string dbName)
: BoundDatabaseStatement{common::StatementType::USE_DATABASE, std::move(dbName)} {}
};

} // namespace binder
} // namespace kuzu
1 change: 1 addition & 0 deletions src/include/common/enums/statement_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ enum class StatementType : uint8_t {
IMPORT_DATABASE = 33,
ATTACH_DATABASE = 34,
DETACH_DATABASE = 35,
USE_DATABASE = 36,
};

struct StatementTypeUtils {
Expand Down
6 changes: 6 additions & 0 deletions src/include/main/database_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,18 @@ namespace main {

class DatabaseManager {
public:
DatabaseManager();

void registerAttachedDatabase(std::unique_ptr<AttachedDatabase> attachedDatabase);
AttachedDatabase* getAttachedDatabase(const std::string& name);
void detachDatabase(const std::string& databaseName);
std::string getDefaultDatabase() const { return defaultDatabase; }
bool hasDefaultDatabase() const { return defaultDatabase != ""; }
void setDefaultDatabase(const std::string& databaseName);

private:
std::vector<std::unique_ptr<AttachedDatabase>> attachedDatabases;
std::string defaultDatabase;
};

} // namespace main
Expand Down
22 changes: 22 additions & 0 deletions src/include/parser/database_statement.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include <string>

#include "parser/statement.h"

namespace kuzu {
namespace parser {

class DatabaseStatement : public Statement {
public:
explicit DatabaseStatement(common::StatementType type, std::string dbName)
: Statement{type}, dbName{std::move(dbName)} {}

std::string getDBName() const { return dbName; }

private:
std::string dbName;
};

} // namespace parser
} // namespace kuzu
11 changes: 3 additions & 8 deletions src/include/parser/detach_database.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,15 @@

#include <string>

#include "parser/statement.h"
#include "parser/database_statement.h"

namespace kuzu {
namespace parser {

class DetachDatabase final : public Statement {
class DetachDatabase final : public DatabaseStatement {
public:
explicit DetachDatabase(std::string dbName)
: Statement{common::StatementType::DETACH_DATABASE}, dbName{std::move(dbName)} {}

std::string getDBName() const { return dbName; }

private:
std::string dbName;
: DatabaseStatement{common::StatementType::DETACH_DATABASE, std::move(dbName)} {}
};

} // namespace parser
Expand Down
1 change: 1 addition & 0 deletions src/include/parser/parsed_statement_visitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class StatementVisitor {
virtual void visitImportDatabase(const Statement& /*statement*/) {}
virtual void visitAttachDatabase(const Statement& /*statement*/) {}
virtual void visitDetachDatabase(const Statement& /*statement*/) {}
virtual void visitUseDatabase(const Statement& /*statement*/) {}
// LCOV_EXCL_STOP
};

Expand Down
Loading

0 comments on commit fc6659e

Please sign in to comment.