Skip to content
Open
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
8 changes: 7 additions & 1 deletion scripts/antlr4/Cypher.g4
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ iC_CreateNodeTable
iC_CreateRelTable
: CREATE SP REL SP TABLE ( SP GROUP )? ( SP iC_IfNotExists )? SP oC_SchemaName
SP? '(' SP?
iC_FromToConnections SP? (
iC_CreateFromToConnections SP? (
( ',' SP? iC_PropertyDefinitions SP? )?
( ',' SP? oC_SymbolicName SP? )? // Constraints
')'
Expand All @@ -385,6 +385,12 @@ iC_IndexRelationshipPattern
iC_IndexPropertyPattern
: '(' SP? oC_Variable SP? '.' SP? oC_PropertyKeyName SP? ')' ;

iC_CreateFromToConnections
: iC_CreateFromToConnection ( SP? ',' SP? iC_CreateFromToConnection )* ;

iC_CreateFromToConnection
: FROM SP oC_SchemaName SP TO SP oC_SchemaName ( SP oC_SymbolicName )? ;

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 @@
8988f28d4f569c88df6df4783174efb9
c7234221b1dd80ed6bfdd0373cf59c0d
8 changes: 7 additions & 1 deletion src/antlr4/Cypher.g4
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ iC_CreateNodeTable
iC_CreateRelTable
: CREATE SP REL SP TABLE ( SP GROUP )? ( SP iC_IfNotExists )? SP oC_SchemaName
SP? '(' SP?
iC_FromToConnections SP? (
iC_CreateFromToConnections SP? (
( ',' SP? iC_PropertyDefinitions SP? )?
( ',' SP? oC_SymbolicName SP? )? // Constraints
')'
Expand All @@ -132,6 +132,12 @@ iC_IndexRelationshipPattern
iC_IndexPropertyPattern
: '(' SP? oC_Variable SP? '.' SP? oC_PropertyKeyName SP? ')' ;

iC_CreateFromToConnections
: iC_CreateFromToConnection ( SP? ',' SP? iC_CreateFromToConnection )* ;

iC_CreateFromToConnection
: FROM SP oC_SchemaName SP TO SP oC_SchemaName ( SP oC_SymbolicName )? ;

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

Expand Down
22 changes: 14 additions & 8 deletions src/binder/bind/bind_ddl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,10 @@ BoundCreateTableInfo Binder::bindCreateRelTableGroupInfo(const CreateTableInfo*
}
// Bind from to pairs
node_table_id_pair_set_t nodePairsSet;
std::vector<NodeTableIDPair> nodePairs;
for (auto& [srcTableName, dstTableName] : extraInfo.srcDstTablePairs) {
std::vector<BoundRelTableInfo> relTableInfos;
for (auto& connection : extraInfo.connections) {
const auto& srcTableName = connection.srcTableName;
const auto& dstTableName = connection.dstTableName;
auto [srcEntry, srcDbName] = bindNodeTableEntry(srcTableName);
validateNodeTableType(srcEntry);
auto [dstEntry, dstDbName] = bindNodeTableEntry(dstTableName);
Expand Down Expand Up @@ -372,12 +374,16 @@ BoundCreateTableInfo Binder::bindCreateRelTableGroupInfo(const CreateTableInfo*
std::format("Found duplicate FROM-TO {}-{} pairs.", srcTableName, dstTableName));
}
nodePairsSet.insert(pair);
nodePairs.emplace_back(pair);
const auto& connectionMultiplicity = connection.relMultiplicity.has_value() ?
*connection.relMultiplicity :
extraInfo.relMultiplicity;
relTableInfos.emplace_back(pair, RelMultiplicityUtils::getFwd(connectionMultiplicity),
RelMultiplicityUtils::getBwd(connectionMultiplicity));
}
auto boundExtraInfo = std::make_unique<BoundExtraCreateRelTableGroupInfo>(
std::move(propertyDefinitions), srcMultiplicity, dstMultiplicity, storageDirection,
std::move(nodePairs), std::move(storage), std::move(storageFormat), std::move(scanFunction),
std::move(scanBindData), std::move(foreignDatabaseName));
std::move(relTableInfos), std::move(storage), std::move(storageFormat),
std::move(scanFunction), std::move(scanBindData), std::move(foreignDatabaseName));
return BoundCreateTableInfo(CatalogEntryType::REL_GROUP_ENTRY, info->tableName,
info->onConflict, std::move(boundExtraInfo), clientContext->useInternalCatalogEntry());
}
Expand Down Expand Up @@ -488,7 +494,7 @@ std::unique_ptr<BoundStatement> Binder::bindCreateTableAs(const Statement& state
case TableType::REL: {
auto& extraInfo = createInfo->extraInfo->constCast<ExtraCreateRelTableGroupInfo>();
// Currently we don't support multiple from/to pairs for create rel table as
if (extraInfo.srcDstTablePairs.size() > 1) {
if (extraInfo.connections.size() > 1) {
throw BinderException(
"Multiple FROM/TO pairs are not supported for CREATE REL TABLE AS.");
}
Expand All @@ -497,10 +503,10 @@ std::unique_ptr<BoundStatement> Binder::bindCreateTableAs(const Statement& state
auto catalog = Catalog::Get(*clientContext);
auto transaction = transaction::Transaction::Get(*clientContext);
auto fromTable =
catalog->getTableCatalogEntry(transaction, extraInfo.srcDstTablePairs[0].first)
catalog->getTableCatalogEntry(transaction, extraInfo.connections[0].srcTableName)
->ptrCast<NodeTableCatalogEntry>();
auto toTable =
catalog->getTableCatalogEntry(transaction, extraInfo.srcDstTablePairs[0].second)
catalog->getTableCatalogEntry(transaction, extraInfo.connections[0].dstTableName)
->ptrCast<NodeTableCatalogEntry>();
auto boundCreateInfo = bindCreateRelTableGroupInfo(createInfo);
auto boundCopyFromInfo = bindCopyRelFromInfo(createInfo->tableName, propertyDefinitions,
Expand Down
7 changes: 4 additions & 3 deletions src/catalog/catalog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,10 @@ CatalogEntry* Catalog::createRelGroupEntry(Transaction* transaction,
const BoundCreateTableInfo& info) {
const auto extraInfo = info.extraInfo->ptrCast<BoundExtraCreateRelTableGroupInfo>();
std::vector<RelTableCatalogInfo> relTableInfos;
DASSERT(extraInfo->nodePairs.size() > 0);
for (auto& nodePair : extraInfo->nodePairs) {
relTableInfos.emplace_back(nodePair, tables->getNextOID());
DASSERT(extraInfo->relTableInfos.size() > 0);
for (auto& relTableInfo : extraInfo->relTableInfos) {
relTableInfos.emplace_back(relTableInfo.nodePair, tables->getNextOID(),
relTableInfo.srcMultiplicity, relTableInfo.dstMultiplicity);
}
auto relGroupEntry =
std::make_unique<RelGroupCatalogEntry>(info.tableName, extraInfo->srcMultiplicity,
Expand Down
53 changes: 46 additions & 7 deletions src/catalog/catalog_entry/rel_group_catalog_entry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ static void upgradeLegacyStorageFormat(const std::string& storage,

void RelGroupCatalogEntry::addFromToConnection(table_id_t srcTableID, table_id_t dstTableID,
oid_t oid) {
relTableInfos.emplace_back(NodeTableIDPair{srcTableID, dstTableID}, oid);
relTableInfos.emplace_back(NodeTableIDPair{srcTableID, dstTableID}, oid, srcMultiplicity,
dstMultiplicity);
}

void RelGroupCatalogEntry::dropFromToConnection(table_id_t srcTableID, table_id_t dstTableID) {
Expand All @@ -48,6 +49,10 @@ void RelTableCatalogInfo::serialize(Serializer& ser) const {
nodePair.serialize(ser);
ser.writeDebuggingInfo("oid");
ser.serializeValue(oid);
ser.writeDebuggingInfo("srcMultiplicity");
ser.serializeValue(srcMultiplicity);
ser.writeDebuggingInfo("dstMultiplicity");
ser.serializeValue(dstMultiplicity);
}

RelTableCatalogInfo RelTableCatalogInfo::deserialize(Deserializer& deser) {
Expand All @@ -57,7 +62,15 @@ RelTableCatalogInfo RelTableCatalogInfo::deserialize(Deserializer& deser) {
auto nodePair = NodeTableIDPair::deserialize(deser);
deser.validateDebuggingInfo(debuggingInfo, "oid");
deser.deserializeValue(oid);
return RelTableCatalogInfo{nodePair, oid};
auto srcMultiplicity = RelMultiplicity::MANY;
auto dstMultiplicity = RelMultiplicity::MANY;
if (deser.getStorageVersion() >= ::lbug::storage::StorageVersionInfo::STORAGE_VERSION_42) {
deser.validateDebuggingInfo(debuggingInfo, "srcMultiplicity");
deser.deserializeValue(srcMultiplicity);
deser.validateDebuggingInfo(debuggingInfo, "dstMultiplicity");
deser.deserializeValue(dstMultiplicity);
}
return RelTableCatalogInfo{nodePair, oid, srcMultiplicity, dstMultiplicity};
}

bool RelGroupCatalogEntry::isParent(table_id_t tableID) {
Expand Down Expand Up @@ -147,6 +160,13 @@ std::unique_ptr<RelGroupCatalogEntry> RelGroupCatalogEntry::deserialize(
}
deserializer.validateDebuggingInfo(debuggingInfo, "relTableInfos");
deserializer.deserializeVector(relTableInfos);
if (deserializer.getStorageVersion() <
::lbug::storage::StorageVersionInfo::STORAGE_VERSION_42) {
for (auto& relTableInfo : relTableInfos) {
relTableInfo.srcMultiplicity = srcMultiplicity;
relTableInfo.dstMultiplicity = dstMultiplicity;
}
}
if (deserializer.getStorageVersion() >=
::lbug::storage::StorageVersionInfo::STORAGE_VERSION_41) {
deserializer.validateDebuggingInfo(debuggingInfo, "storageFormat");
Expand Down Expand Up @@ -181,6 +201,12 @@ static std::string getFromToStr(const NodeTableIDPair& pair, const Catalog* cata
return std::format("FROM `{}` TO `{}`", srcTableName, dstTableName);
}

static std::string getMultiplicityStr(RelMultiplicity srcMultiplicity,
RelMultiplicity dstMultiplicity) {
return RelMultiplicityUtils::toString(srcMultiplicity) + "_" +
RelMultiplicityUtils::toString(dstMultiplicity);
}

std::string RelGroupCatalogEntry::toCypher(const ToCypherInfo& info) const {
auto relGroupInfo = info.constCast<RelGroupToCypherInfo>();
auto catalog = Catalog::Get(*relGroupInfo.context);
Expand All @@ -189,12 +215,24 @@ std::string RelGroupCatalogEntry::toCypher(const ToCypherInfo& info) const {
ss << std::format("CREATE REL TABLE `{}` (", getName());
DASSERT(!relTableInfos.empty());
ss << getFromToStr(relTableInfos[0].nodePair, catalog, transaction, storage);
if (relTableInfos[0].srcMultiplicity != srcMultiplicity ||
relTableInfos[0].dstMultiplicity != dstMultiplicity) {
ss << " "
<< getMultiplicityStr(relTableInfos[0].srcMultiplicity,
relTableInfos[0].dstMultiplicity);
}
for (auto i = 1u; i < relTableInfos.size(); ++i) {
ss << std::format(", {}",
getFromToStr(relTableInfos[i].nodePair, catalog, transaction, storage));
if (relTableInfos[i].srcMultiplicity != srcMultiplicity ||
relTableInfos[i].dstMultiplicity != dstMultiplicity) {
ss << " "
<< getMultiplicityStr(relTableInfos[i].srcMultiplicity,
relTableInfos[i].dstMultiplicity);
}
}
ss << ", " << propertyCollection.toCypher() << RelMultiplicityUtils::toString(srcMultiplicity)
<< "_" << RelMultiplicityUtils::toString(dstMultiplicity) << ");";
ss << ", " << propertyCollection.toCypher()
<< getMultiplicityStr(srcMultiplicity, dstMultiplicity) << ");";
return ss.str();
}

Expand Down Expand Up @@ -232,13 +270,14 @@ std::unique_ptr<TableCatalogEntry> RelGroupCatalogEntry::copy() const {

std::unique_ptr<binder::BoundExtraCreateCatalogEntryInfo>
RelGroupCatalogEntry::getBoundExtraCreateInfo(transaction::Transaction*) const {
std::vector<NodeTableIDPair> nodePairs;
std::vector<binder::BoundRelTableInfo> boundRelTableInfos;
for (auto& relTableInfo : relTableInfos) {
nodePairs.push_back(relTableInfo.nodePair);
boundRelTableInfos.emplace_back(relTableInfo.nodePair, relTableInfo.srcMultiplicity,
relTableInfo.dstMultiplicity);
}
return std::make_unique<binder::BoundExtraCreateRelTableGroupInfo>(
copyVector(propertyCollection.getDefinitions()), srcMultiplicity, dstMultiplicity,
storageDirection, std::move(nodePairs), storage, storageFormat);
storageDirection, std::move(boundRelTableInfos), storage, storageFormat);
}

} // namespace catalog
Expand Down
18 changes: 14 additions & 4 deletions src/include/binder/ddl/bound_create_table_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,21 @@ struct BoundExtraCreateNodeTableInfo final : BoundExtraCreateTableInfo {
}
};

struct BoundRelTableInfo {
catalog::NodeTableIDPair nodePair;
common::RelMultiplicity srcMultiplicity;
common::RelMultiplicity dstMultiplicity;

BoundRelTableInfo(catalog::NodeTableIDPair nodePair, common::RelMultiplicity srcMultiplicity,
common::RelMultiplicity dstMultiplicity)
: nodePair{nodePair}, srcMultiplicity{srcMultiplicity}, dstMultiplicity{dstMultiplicity} {}
};

struct BoundExtraCreateRelTableGroupInfo final : BoundExtraCreateTableInfo {
common::RelMultiplicity srcMultiplicity;
common::RelMultiplicity dstMultiplicity;
common::ExtendDirection storageDirection;
std::vector<catalog::NodeTableIDPair> nodePairs;
std::vector<BoundRelTableInfo> relTableInfos;
std::string storage;
common::StorageFormat storageFormat = common::StorageFormat::NONE;
std::optional<function::TableFunction> scanFunction;
Expand All @@ -108,22 +118,22 @@ struct BoundExtraCreateRelTableGroupInfo final : BoundExtraCreateTableInfo {

explicit BoundExtraCreateRelTableGroupInfo(std::vector<PropertyDefinition> definitions,
common::RelMultiplicity srcMultiplicity, common::RelMultiplicity dstMultiplicity,
common::ExtendDirection storageDirection, std::vector<catalog::NodeTableIDPair> nodePairs,
common::ExtendDirection storageDirection, std::vector<BoundRelTableInfo> relTableInfos,
std::string storage = "", common::StorageFormat storageFormat = common::StorageFormat::NONE,
std::optional<function::TableFunction> scanFunction = std::nullopt,
std::optional<std::shared_ptr<function::TableFuncBindData>> scanBindData = std::nullopt,
std::string foreignDatabaseName = "")
: BoundExtraCreateTableInfo{std::move(definitions)}, srcMultiplicity{srcMultiplicity},
dstMultiplicity{dstMultiplicity}, storageDirection{storageDirection},
nodePairs{std::move(nodePairs)}, storage{std::move(storage)},
relTableInfos{std::move(relTableInfos)}, storage{std::move(storage)},
storageFormat{storageFormat}, scanFunction{std::move(scanFunction)},
scanBindData{std::move(scanBindData)},
foreignDatabaseName{std::move(foreignDatabaseName)} {}

BoundExtraCreateRelTableGroupInfo(const BoundExtraCreateRelTableGroupInfo& other)
: BoundExtraCreateTableInfo{copyVector(other.propertyDefinitions)},
srcMultiplicity{other.srcMultiplicity}, dstMultiplicity{other.dstMultiplicity},
storageDirection{other.storageDirection}, nodePairs{other.nodePairs},
storageDirection{other.storageDirection}, relTableInfos{other.relTableInfos},
storage{other.storage}, storageFormat{other.storageFormat},
scanFunction{other.scanFunction}, scanBindData{other.scanBindData},
foreignDatabaseName{other.foreignDatabaseName} {}
Expand Down
23 changes: 21 additions & 2 deletions src/include/catalog/catalog_entry/rel_group_catalog_entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,19 @@ struct RelGroupToCypherInfo final : ToCypherInfo {
struct RelTableCatalogInfo {
NodeTableIDPair nodePair;
common::oid_t oid = common::INVALID_OID;
common::RelMultiplicity srcMultiplicity = common::RelMultiplicity::MANY;
common::RelMultiplicity dstMultiplicity = common::RelMultiplicity::MANY;

RelTableCatalogInfo() = default;
RelTableCatalogInfo(NodeTableIDPair nodePair, common::oid_t oid)
: nodePair{nodePair}, oid{oid} {}
RelTableCatalogInfo(NodeTableIDPair nodePair, common::oid_t oid,
common::RelMultiplicity srcMultiplicity = common::RelMultiplicity::MANY,
common::RelMultiplicity dstMultiplicity = common::RelMultiplicity::MANY)
: nodePair{nodePair}, oid{oid}, srcMultiplicity{srcMultiplicity},
dstMultiplicity{dstMultiplicity} {}

common::RelMultiplicity getMultiplicity(common::RelDataDirection direction) const {
return direction == common::RelDataDirection::FWD ? dstMultiplicity : srcMultiplicity;
}

void serialize(common::Serializer& ser) const;
static RelTableCatalogInfo deserialize(common::Deserializer& deser);
Expand Down Expand Up @@ -60,9 +69,19 @@ class LBUG_API RelGroupCatalogEntry final : public TableCatalogEntry {
common::RelMultiplicity getMultiplicity(common::RelDataDirection direction) const {
return direction == common::RelDataDirection::FWD ? dstMultiplicity : srcMultiplicity;
}
common::RelMultiplicity getMultiplicity(common::table_id_t srcTableID,
common::table_id_t dstTableID, common::RelDataDirection direction) const {
const auto relEntryInfo = getRelEntryInfo(srcTableID, dstTableID);
DASSERT(relEntryInfo);
return relEntryInfo->getMultiplicity(direction);
}
bool isSingleMultiplicity(common::RelDataDirection direction) const {
return getMultiplicity(direction) == common::RelMultiplicity::ONE;
}
bool isSingleMultiplicity(common::table_id_t srcTableID, common::table_id_t dstTableID,
common::RelDataDirection direction) const {
return getMultiplicity(srcTableID, dstTableID, direction) == common::RelMultiplicity::ONE;
}

common::ExtendDirection getStorageDirection() const { return storageDirection; }
const std::string& getStorage() const { return storage; }
Expand Down
20 changes: 16 additions & 4 deletions src/include/parser/ddl/create_table_info.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
Expand Down Expand Up @@ -42,15 +43,26 @@ struct ExtraCreateNodeTableInfo final : ExtraCreateTableInfo {
: pKName{std::move(pKName)}, options{std::move(options)} {}
};

struct ParsedRelConnection {
std::string srcTableName;
std::string dstTableName;
std::optional<std::string> relMultiplicity;

ParsedRelConnection(std::string srcTableName, std::string dstTableName,
std::optional<std::string> relMultiplicity)
: srcTableName{std::move(srcTableName)}, dstTableName{std::move(dstTableName)},
relMultiplicity{std::move(relMultiplicity)} {}
};

struct ExtraCreateRelTableGroupInfo final : ExtraCreateTableInfo {
std::string relMultiplicity;
std::vector<std::pair<std::string, std::string>> srcDstTablePairs;
std::vector<ParsedRelConnection> connections;
options_t options;

ExtraCreateRelTableGroupInfo(std::string relMultiplicity,
std::vector<std::pair<std::string, std::string>> srcDstTablePairs, options_t options)
: relMultiplicity{std::move(relMultiplicity)},
srcDstTablePairs{std::move(srcDstTablePairs)}, options{std::move(options)} {}
std::vector<ParsedRelConnection> connections, options_t options)
: relMultiplicity{std::move(relMultiplicity)}, connections{std::move(connections)},
options{std::move(options)} {}
};

} // namespace parser
Expand Down
7 changes: 5 additions & 2 deletions src/include/storage/storage_version_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ struct StorageVersionInfo {
static constexpr storage_version_t STORAGE_VERSION_40 = 40;
// Storage version 41 adds the table storage FORMAT field to catalog entries (enum encoding).
static constexpr storage_version_t STORAGE_VERSION_41 = 41;
// Storage version 42 adds per-FROM/TO relationship multiplicity to rel table catalog info.
static constexpr storage_version_t STORAGE_VERSION_42 = 42;

static std::unordered_map<std::string, storage_version_t> getStorageVersionInfo() {
return {{"0.12.0", STORAGE_VERSION_40}, {"0.12.2", STORAGE_VERSION_40},
Expand All @@ -25,12 +27,13 @@ struct StorageVersionInfo {
{"0.15.0", STORAGE_VERSION_40}, {"0.15.1", STORAGE_VERSION_40},
{"0.15.2", STORAGE_VERSION_40}, {"0.15.3", STORAGE_VERSION_40},
{"0.15.4", STORAGE_VERSION_40}, {"0.16.0", STORAGE_VERSION_40},
{"0.16.1", STORAGE_VERSION_40}, {"0.17.0", STORAGE_VERSION_41}};
{"0.16.1", STORAGE_VERSION_40}, {"0.17.0", STORAGE_VERSION_42}};
}

static LBUG_API storage_version_t getStorageVersion();
static bool canReadStorageVersion(storage_version_t storageVersion) {
return storageVersion == STORAGE_VERSION_40 || storageVersion == getStorageVersion();
return storageVersion == STORAGE_VERSION_40 || storageVersion == STORAGE_VERSION_41 ||
storageVersion == getStorageVersion();
}

static constexpr const char* MAGIC_BYTES = "LBUG";
Expand Down
Loading
Loading