Skip to content
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
23 changes: 23 additions & 0 deletions scripts/antlr4/Cypher.g4
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ FROM : ( 'F' | 'f' ) ( 'R' | 'r' ) ( 'O' | 'o' ) ( 'M' | 'm' ) ;

FORCE : ( 'F' | 'f' ) ( 'O' | 'o' ) ( 'R' | 'r' ) ( 'C' | 'c' ) ( 'E' | 'e' ) ;

FOR : ( 'F' | 'f' ) ( 'O' | 'o' ) ( 'R' | 'r' ) ;

GLOB : ( 'G' | 'g' ) ( 'L' | 'l' ) ( 'O' | 'o' ) ( 'B' | 'b' ) ;

GRAPH : ( 'G' | 'g' ) ( 'R' | 'r' ) ( 'A' | 'a' ) ( 'P' | 'p' ) ( 'H' | 'h' ) ;
Expand All @@ -114,6 +116,8 @@ HINT : ( 'H' | 'h' ) ( 'I' | 'i' ) ( 'N' | 'n' ) ( 'T' | 't' ) ;

IMPORT : ( 'I' | 'i' ) ( 'M' | 'm' ) ( 'P' | 'p' ) ( 'O' | 'o' ) ( 'R' | 'r' ) ( 'T' | 't' ) ;

INDEX : ( 'I' | 'i' ) ( 'N' | 'n' ) ( 'D' | 'd' ) ( 'E' | 'e' ) ( 'X' | 'x' ) ;

IF : ( 'I' | 'i' ) ( 'F' | 'f' ) ;

IN : ( 'I' | 'i' ) ( 'N' | 'n' ) ;
Expand Down Expand Up @@ -160,6 +164,8 @@ ON : ( 'O' | 'o' ) ( 'N' | 'n' ) ;

ONLY : ( 'O' | 'o' ) ( 'N' | 'n' ) ( 'L' | 'l' ) ( 'Y' | 'y' ) ;

OPTIONS : ( 'O' | 'o' ) ( 'P' | 'p' ) ( 'T' | 't' ) ( 'I' | 'i' ) ( 'O' | 'o' ) ( 'N' | 'n' ) ( 'S' | 's' ) ;

OPTIONAL : ( 'O' | 'o' ) ( 'P' | 'p' ) ( 'T' | 't' ) ( 'I' | 'i' ) ( 'O' | 'o' ) ( 'N' | 'n' ) ( 'A' | 'a' ) ( 'L' | 'l' ) ;

OR : ( 'O' | 'o' ) ( 'R' | 'r' ) ;
Expand Down Expand Up @@ -258,6 +264,7 @@ oC_Statement
| iC_CreateRole
| iC_CreateNodeTable
| iC_CreateRelTable
| iC_CreateIndex
| iC_CreateSequence
| iC_CreateType
| iC_Drop
Expand Down Expand Up @@ -362,6 +369,22 @@ iC_CreateRelTable
| ')' SP AS SP oC_Query )
( SP WITH SP? '(' SP? iC_Options SP? ')')? ;

iC_CreateIndex
: CREATE (SP oC_SymbolicName)? SP INDEX (SP oC_SchemaName)? (SP iC_IfNotExists)? SP FOR SP iC_IndexPattern SP ON SP iC_IndexPropertyPattern (SP OPTIONS SP? '{' SP? iC_Options? SP? '}')? ;

iC_IndexPattern
: iC_IndexNodePattern
| iC_IndexRelationshipPattern ;

iC_IndexNodePattern
: '(' SP? oC_Variable? SP? ':' SP? oC_LabelName SP? ')' ;

iC_IndexRelationshipPattern
: '(' SP? ')' SP? oC_RelationshipPattern SP? '(' SP? ')' ;

iC_IndexPropertyPattern
: '(' SP? oC_Variable SP? '.' SP? oC_PropertyKeyName SP? ')' ;

iC_FromToConnections
: iC_FromToConnection ( SP? ',' SP? iC_FromToConnection )* ;

Expand Down
2 changes: 1 addition & 1 deletion scripts/antlr4/hash.md5
Original file line number Diff line number Diff line change
@@ -1 +1 @@
c7d54b4e1928e025019b1328811a8c04
8988f28d4f569c88df6df4783174efb9
17 changes: 17 additions & 0 deletions src/antlr4/Cypher.g4
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ oC_Statement
| iC_CreateRole
| iC_CreateNodeTable
| iC_CreateRelTable
| iC_CreateIndex
| iC_CreateSequence
| iC_CreateType
| iC_Drop
Expand Down Expand Up @@ -115,6 +116,22 @@ iC_CreateRelTable
| ')' SP AS SP oC_Query )
( SP WITH SP? '(' SP? iC_Options SP? ')')? ;

iC_CreateIndex
: CREATE (SP oC_SymbolicName)? SP INDEX (SP oC_SchemaName)? (SP iC_IfNotExists)? SP FOR SP iC_IndexPattern SP ON SP iC_IndexPropertyPattern (SP OPTIONS SP? '{' SP? iC_Options? SP? '}')? ;

iC_IndexPattern
: iC_IndexNodePattern
| iC_IndexRelationshipPattern ;

iC_IndexNodePattern
: '(' SP? oC_Variable? SP? ':' SP? oC_LabelName SP? ')' ;

iC_IndexRelationshipPattern
: '(' SP? ')' SP? oC_RelationshipPattern SP? '(' SP? ')' ;

iC_IndexPropertyPattern
: '(' SP? oC_Variable SP? '.' SP? oC_PropertyKeyName SP? ')' ;

iC_FromToConnections
: iC_FromToConnection ( SP? ',' SP? iC_FromToConnection )* ;

Expand Down
3 changes: 3 additions & 0 deletions src/antlr4/keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@ EXTENSION
FALSE
FROM
FORCE
FOR
GLOB
GRAPH
GROUP
HEADERS
HINT
IMPORT
INDEX
IF
IN
INCREMENT
Expand All @@ -71,6 +73,7 @@ NONE
NULL
ON
ONLY
OPTIONS
OPTIONAL
OR
ORDER
Expand Down
49 changes: 49 additions & 0 deletions src/binder/bind/bind_ddl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "binder/binder.h"
#include "binder/ddl/bound_alter.h"
#include "binder/ddl/bound_create_index.h"
#include "binder/ddl/bound_create_sequence.h"
#include "binder/ddl/bound_create_table.h"
#include "binder/ddl/bound_create_type.h"
Expand All @@ -13,6 +14,7 @@
#include "common/enums/extend_direction_util.h"
#include "common/exception/binder.h"
#include "common/exception/message.h"
#include "common/string_utils.h"
#include "common/system_config.h"
#include "common/types/types.h"
#include "function/cast/functions/cast_from_string_functions.h"
Expand All @@ -21,13 +23,16 @@
#include "main/client_context.h"
#include "main/database_manager.h"
#include "parser/ddl/alter.h"
#include "parser/ddl/create_index.h"
#include "parser/ddl/create_sequence.h"
#include "parser/ddl/create_table.h"
#include "parser/ddl/create_table_info.h"
#include "parser/ddl/create_type.h"
#include "parser/ddl/drop.h"
#include "parser/expression/parsed_function_expression.h"
#include "parser/expression/parsed_literal_expression.h"
#include "storage/index/hash_index.h"
#include "storage/storage_manager.h"
#include "transaction/transaction.h"
#include <format>

Expand All @@ -38,6 +43,10 @@ using namespace lbug::catalog;
namespace lbug {
namespace binder {

std::string BoundCreateIndexInfo::toString() const {
return std::format("{} INDEX {} ON {}({})", indexType, indexName, tableName, propertyName);
}

static void validatePropertyName(const std::vector<PropertyDefinition>& definitions) {
case_insensitve_set_t nameSet;
for (auto& definition : definitions) {
Expand Down Expand Up @@ -340,6 +349,46 @@ std::unique_ptr<BoundStatement> Binder::bindCreateTable(const Statement& stateme
BoundStatementResult::createSingleStringColumnResult());
}

std::unique_ptr<BoundStatement> Binder::bindCreateIndex(const Statement& statement) {
auto& createIndex = statement.constCast<CreateIndex>();
auto& info = createIndex.getInfo();
auto indexType = info.indexType;
StringUtils::toUpper(indexType);
auto indexTypeOptional = storage::StorageManager::Get(*clientContext)->getIndexType(indexType);
if (!indexTypeOptional.has_value()) {
throw BinderException(std::format("Index type {} does not exist.", info.indexType));
}
if (indexType != storage::PrimaryKeyIndex::getIndexType().typeName) {
throw BinderException(std::format("Only HASH indexes are supported by CREATE INDEX."));
}
auto catalog = Catalog::Get(*clientContext);
auto transaction = transaction::Transaction::Get(*clientContext);
validateTableExistence(*clientContext, info.tableName);
auto tableEntry = catalog->getTableCatalogEntry(transaction, info.tableName);
validateNodeTableType(tableEntry);
validateColumnExistence(tableEntry, info.propertyName);
auto nodeTableEntry = tableEntry->ptrCast<NodeTableCatalogEntry>();
if (!StringUtils::caseInsensitiveEquals(nodeTableEntry->getPrimaryKeyName(),
info.propertyName)) {
throw BinderException("HASH indexes are currently supported only on node primary keys.");
}
auto boundOptions = bindParsingOptions(info.options);
if (!boundOptions.empty()) {
throw BinderException("CREATE HASH INDEX does not support OPTIONS.");
}
auto& property = tableEntry->getProperty(info.propertyName);
std::vector<PropertyDefinition> propertyDefinitions;
propertyDefinitions.push_back(property.copy());
validatePrimaryKey(property.getName(), propertyDefinitions);
auto indexName = info.indexName.empty() ? std::string(storage::PrimaryKeyIndex::DEFAULT_NAME) :
info.indexName;
BoundCreateIndexInfo boundInfo{indexType, std::move(indexName), info.tableName,
tableEntry->getTableID(), property.getName(), tableEntry->getPropertyID(property.getName()),
tableEntry->getColumnID(property.getName()), property.getType().getPhysicalType(),
info.onConflict};
return std::make_unique<BoundCreateIndex>(std::move(boundInfo));
}

std::unique_ptr<BoundStatement> Binder::bindCreateTableAs(const Statement& statement) {
auto& createTable = statement.constCast<CreateTable>();
auto boundInnerQuery = bindQuery(*createTable.getSource()->statement.get());
Expand Down
3 changes: 3 additions & 0 deletions src/binder/binder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ std::unique_ptr<BoundStatement> Binder::bind(const Statement& statement) {
case StatementType::CREATE_TABLE: {
boundStatement = bindCreateTable(statement);
} break;
case StatementType::CREATE_INDEX: {
boundStatement = bindCreateIndex(statement);
} break;
case StatementType::CREATE_TYPE: {
boundStatement = bindCreateType(statement);
} break;
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 @@ -25,6 +25,9 @@ void BoundStatementVisitor::visit(const BoundStatement& statement) {
case StatementType::CREATE_TABLE: {
visitCreateTable(statement);
} break;
case StatementType::CREATE_INDEX: {
visitCreateIndex(statement);
} break;
case StatementType::CREATE_TYPE: {
visitCreateType(statement);
} break;
Expand Down
18 changes: 18 additions & 0 deletions src/catalog/catalog_entry/index_catalog_entry.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#include "catalog/catalog_entry/index_catalog_entry.h"

#include "catalog/catalog.h"
#include "catalog/catalog_entry/table_catalog_entry.h"
#include "common/exception/runtime.h"
#include "common/serializer/buffer_writer.h"
#include "transaction/transaction.h"
#include <format>

namespace lbug {
Expand All @@ -17,6 +20,21 @@ void IndexCatalogEntry::setAuxInfo(std::unique_ptr<IndexAuxInfo> auxInfo_) {
auxBufferSize = 0;
}

std::string BuiltinIndexAuxInfo::toCypher(const IndexCatalogEntry& indexEntry,
const ToCypherInfo& info) const {
auto& indexInfo = common::dynamic_cast_checked<const IndexToCypherInfo&>(info);
auto catalog = Catalog::Get(*indexInfo.context);
auto transaction = transaction::Transaction::Get(*indexInfo.context);
auto tableEntry = catalog->getTableCatalogEntry(transaction, indexEntry.getTableID());
const auto propertyIDs = indexEntry.getPropertyIDs();
if (propertyIDs.empty()) {
return "";
}
auto propertyName = tableEntry->getProperty(propertyIDs[0]).getName();
return std::format("CREATE {} INDEX `{}` FOR (n:`{}`) ON (n.`{}`);", indexEntry.getIndexType(),
indexEntry.getIndexName(), tableEntry->getName(), propertyName);
}

bool IndexCatalogEntry::containsPropertyID(common::property_id_t propertyID) const {
for (auto id : propertyIDs) {
if (id == propertyID) {
Expand Down
2 changes: 2 additions & 0 deletions src/include/binder/binder.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class ReadingClause;
class QueryPart;
class SingleQuery;
struct CreateTableInfo;
struct CreateIndexInfo;
struct BaseScanSource;
struct JoinHintNode;
class Statement;
Expand Down Expand Up @@ -100,6 +101,7 @@ class Binder {
BoundCreateTableInfo bindCreateRelTableGroupInfo(const parser::CreateTableInfo* info);
std::unique_ptr<BoundStatement> bindCreateTable(const parser::Statement& statement);
std::unique_ptr<BoundStatement> bindCreateTableAs(const parser::Statement& createTable);
std::unique_ptr<BoundStatement> bindCreateIndex(const parser::Statement& statement);
std::unique_ptr<BoundStatement> bindCreateType(const parser::Statement& statement) const;
std::unique_ptr<BoundStatement> bindCreateSequence(const parser::Statement& statement) const;

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 @@ -21,6 +21,7 @@ class LBUG_API BoundStatementVisitor {
protected:
virtual void visitCreateSequence(const BoundStatement&) {}
virtual void visitCreateTable(const BoundStatement&) {}
virtual void visitCreateIndex(const BoundStatement&) {}
virtual void visitDrop(const BoundStatement&) {}
virtual void visitCreateType(const BoundStatement&) {}
virtual void visitAlter(const BoundStatement&) {}
Expand Down
41 changes: 41 additions & 0 deletions src/include/binder/ddl/bound_create_index.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once

#include "binder/bound_statement.h"
#include "common/enums/conflict_action.h"
#include "common/types/types.h"

namespace lbug {
namespace binder {

struct BoundCreateIndexInfo {
std::string indexType;
std::string indexName;
std::string tableName;
common::table_id_t tableID;
std::string propertyName;
common::property_id_t propertyID;
common::column_id_t columnID;
common::PhysicalTypeID keyDataType;
common::ConflictAction onConflict;

BoundCreateIndexInfo copy() const { return *this; }

std::string toString() const;
};

class BoundCreateIndex final : public BoundStatement {
static constexpr common::StatementType type_ = common::StatementType::CREATE_INDEX;

public:
explicit BoundCreateIndex(BoundCreateIndexInfo info)
: BoundStatement{type_, BoundStatementResult::createSingleStringColumnResult()},
info{std::move(info)} {}

const BoundCreateIndexInfo& getInfo() const { return info; }

private:
BoundCreateIndexInfo info;
};

} // namespace binder
} // namespace lbug
9 changes: 9 additions & 0 deletions src/include/catalog/catalog_entry/index_catalog_entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ struct LBUG_API IndexAuxInfo {
}
};

struct LBUG_API BuiltinIndexAuxInfo final : IndexAuxInfo {
std::unique_ptr<IndexAuxInfo> copy() override {
return std::make_unique<BuiltinIndexAuxInfo>();
}

std::string toCypher(const IndexCatalogEntry& indexEntry,
const ToCypherInfo& info) const override;
};

class LBUG_API IndexCatalogEntry final : public CatalogEntry {
public:
static std::string getInternalIndexName(common::table_id_t tableID, std::string indexName) {
Expand Down
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 @@ -24,6 +24,7 @@ enum class StatementType : uint8_t {
DETACH_DATABASE = 35,
USE_DATABASE = 36,
CREATE_SEQUENCE = 37,
CREATE_INDEX = 38,
CREATE_TYPE = 39,
EXTENSION_CLAUSE = 40,
CREATE_GRAPH = 41,
Expand Down
41 changes: 41 additions & 0 deletions src/include/parser/ddl/create_index.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once

#include "common/enums/conflict_action.h"
#include "parser/expression/parsed_expression.h"
#include "parser/statement.h"

namespace lbug {
namespace parser {

struct CreateIndexInfo {
std::string indexType;
std::string indexName;
std::string tableName;
std::string variableName;
std::string propertyName;
common::ConflictAction onConflict;
options_t options;

CreateIndexInfo(std::string indexType, std::string indexName, std::string tableName,
std::string variableName, std::string propertyName, common::ConflictAction onConflict,
options_t options)
: indexType{std::move(indexType)}, indexName{std::move(indexName)},
tableName{std::move(tableName)}, variableName{std::move(variableName)},
propertyName{std::move(propertyName)}, onConflict{onConflict},
options{std::move(options)} {}
};

class CreateIndex final : public Statement {
static constexpr common::StatementType type_ = common::StatementType::CREATE_INDEX;

public:
explicit CreateIndex(CreateIndexInfo info) : Statement{type_}, info{std::move(info)} {}

const CreateIndexInfo& getInfo() const { return info; }

private:
CreateIndexInfo info;
};

} // namespace parser
} // namespace lbug
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 @@ -43,6 +43,7 @@ class StatementVisitor {
virtual void visitCreateSequence(const Statement& /*statement*/) {}
virtual void visitDrop(const Statement& /*statement*/) {}
virtual void visitCreateTable(const Statement& /*statement*/) {}
virtual void visitCreateIndex(const Statement& /*statement*/) {}
virtual void visitCreateType(const Statement& /*statement*/) {}
virtual void visitAlter(const Statement& /*statement*/) {}
virtual void visitCopyFrom(const Statement& /*statement*/) {}
Expand Down
Loading
Loading