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

Implement drop/add property with if exists #4598

Merged
merged 4 commits into from
Dec 5, 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
4 changes: 2 additions & 2 deletions scripts/antlr4/Cypher.g4
Original file line number Diff line number Diff line change
Expand Up @@ -372,13 +372,13 @@ kU_AlterOptions
| kU_RenameProperty;

kU_AddProperty
: ADD SP oC_PropertyKeyName SP kU_DataType ( SP kU_Default )? ;
: ADD SP (kU_IfNotExists SP)? oC_PropertyKeyName SP kU_DataType ( SP kU_Default )? ;

kU_Default
: DEFAULT SP oC_Expression ;

kU_DropProperty
: DROP SP oC_PropertyKeyName ;
: DROP SP (kU_IfExists SP)? oC_PropertyKeyName ;

kU_RenameTable
: RENAME SP TO SP oC_SchemaName ;
Expand Down
2 changes: 1 addition & 1 deletion scripts/antlr4/hash.md5
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8fec6b40349bcceb6d0edac3bc5d3079
d9c5285da41449cec8a219dc7d558e11
4 changes: 2 additions & 2 deletions src/antlr4/Cypher.g4
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,13 @@ kU_AlterOptions
| kU_RenameProperty;

kU_AddProperty
: ADD SP oC_PropertyKeyName SP kU_DataType ( SP kU_Default )? ;
: ADD SP (kU_IfNotExists SP)? oC_PropertyKeyName SP kU_DataType ( SP kU_Default )? ;

kU_Default
: DEFAULT SP oC_Expression ;

kU_DropProperty
: DROP SP oC_PropertyKeyName ;
: DROP SP (kU_IfExists SP)? oC_PropertyKeyName ;

kU_RenameTable
: RENAME SP TO SP oC_SchemaName ;
Expand Down
61 changes: 42 additions & 19 deletions src/binder/bind/bind_ddl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -383,23 +383,43 @@ std::unique_ptr<BoundStatement> Binder::bindRenameTable(const Statement& stateme
throw BinderException("Table: " + newName + " already exists.");
}
auto boundExtraInfo = std::make_unique<BoundExtraRenameTableInfo>(newName);
auto boundInfo = BoundAlterInfo(AlterType::RENAME_TABLE, tableName, std::move(boundExtraInfo));
auto boundInfo = BoundAlterInfo(AlterType::RENAME_TABLE, tableName, std::move(boundExtraInfo),
info->onConflict);
return std::make_unique<BoundAlter>(std::move(boundInfo));
}

static void validatePropertyExist(TableCatalogEntry* tableEntry, const std::string& propertyName) {
if (!tableEntry->containsProperty(propertyName)) {
throw BinderException(
tableEntry->getName() + " table does not have property " + propertyName + ".");
using on_conflict_throw_action = std::function<void()>;

static void validateProperty(common::ConflictAction action, on_conflict_throw_action throwAction) {
switch (action) {
case common::ConflictAction::ON_CONFLICT_THROW: {
throwAction();
} break;
case common::ConflictAction::ON_CONFLICT_DO_NOTHING:
break;
default:
KU_UNREACHABLE;
}
}

static void validatePropertyNotExist(TableCatalogEntry* tableEntry,
static void validatePropertyExist(common::ConflictAction action, TableCatalogEntry* tableEntry,
const std::string& propertyName) {
if (tableEntry->containsProperty(propertyName)) {
throw BinderException(
tableEntry->getName() + " table already has property " + propertyName + ".");
}
validateProperty(action, [&tableEntry, &propertyName]() {
if (!tableEntry->containsProperty(propertyName)) {
throw BinderException(
tableEntry->getName() + " table does not have property " + propertyName + ".");
}
});
}

static void validatePropertyNotExist(common::ConflictAction action, TableCatalogEntry* tableEntry,
const std::string& propertyName) {
validateProperty(action, [&tableEntry, &propertyName] {
if (tableEntry->containsProperty(propertyName)) {
throw BinderException(
tableEntry->getName() + " table already has property " + propertyName + ".");
}
});
}

static void validatePropertyDDLOnTable(TableCatalogEntry* tableEntry,
Expand Down Expand Up @@ -430,7 +450,7 @@ std::unique_ptr<BoundStatement> Binder::bindAddProperty(const Statement& stateme
validateTableExist(tableName);
auto tableEntry = catalog->getTableCatalogEntry(clientContext->getTx(), tableName);
validatePropertyDDLOnTable(tableEntry, "add");
validatePropertyNotExist(tableEntry, propertyName);
validatePropertyNotExist(info->onConflict, tableEntry, propertyName);
auto defaultValue = std::move(extraInfo->defaultValue);
auto boundDefault = expressionBinder.implicitCastIfNecessary(
expressionBinder.bindExpression(*defaultValue), dataType);
Expand All @@ -453,7 +473,8 @@ std::unique_ptr<BoundStatement> Binder::bindAddProperty(const Statement& stateme
PropertyDefinition(std::move(columnDefinition), std::move(defaultValue));
auto boundExtraInfo = std::make_unique<BoundExtraAddPropertyInfo>(std::move(propertyDefinition),
std::move(boundDefault));
auto boundInfo = BoundAlterInfo(AlterType::ADD_PROPERTY, tableName, std::move(boundExtraInfo));
auto boundInfo = BoundAlterInfo(AlterType::ADD_PROPERTY, tableName, std::move(boundExtraInfo),
info->onConflict);
return std::make_unique<BoundAlter>(std::move(boundInfo));
}

Expand All @@ -467,13 +488,14 @@ std::unique_ptr<BoundStatement> Binder::bindDropProperty(const Statement& statem
auto catalog = clientContext->getCatalog();
auto tableEntry = catalog->getTableCatalogEntry(clientContext->getTx(), tableName);
validatePropertyDDLOnTable(tableEntry, "drop");
validatePropertyExist(tableEntry, propertyName);
validatePropertyExist(info->onConflict, tableEntry, propertyName);
if (tableEntry->getTableType() == TableType::NODE &&
tableEntry->constCast<NodeTableCatalogEntry>().getPrimaryKeyName() == propertyName) {
throw BinderException("Cannot drop primary key of a node table.");
}
auto boundExtraInfo = std::make_unique<BoundExtraDropPropertyInfo>(propertyName);
auto boundInfo = BoundAlterInfo(AlterType::DROP_PROPERTY, tableName, std::move(boundExtraInfo));
auto boundInfo = BoundAlterInfo(AlterType::DROP_PROPERTY, tableName, std::move(boundExtraInfo),
info->onConflict);
return std::make_unique<BoundAlter>(std::move(boundInfo));
}

Expand All @@ -488,11 +510,11 @@ std::unique_ptr<BoundStatement> Binder::bindRenameProperty(const Statement& stat
auto catalog = clientContext->getCatalog();
auto tableSchema = catalog->getTableCatalogEntry(clientContext->getTx(), tableName);
validatePropertyDDLOnTable(tableSchema, "rename");
validatePropertyExist(tableSchema, propertyName);
validatePropertyNotExist(tableSchema, newName);
validatePropertyExist(common::ConflictAction::ON_CONFLICT_THROW, tableSchema, propertyName);
validatePropertyNotExist(common::ConflictAction::ON_CONFLICT_THROW, tableSchema, newName);
auto boundExtraInfo = std::make_unique<BoundExtraRenamePropertyInfo>(newName, propertyName);
auto boundInfo =
BoundAlterInfo(AlterType::RENAME_PROPERTY, tableName, std::move(boundExtraInfo));
auto boundInfo = BoundAlterInfo(AlterType::RENAME_PROPERTY, tableName,
std::move(boundExtraInfo), info->onConflict);
return std::make_unique<BoundAlter>(std::move(boundInfo));
}

Expand All @@ -504,7 +526,8 @@ std::unique_ptr<BoundStatement> Binder::bindCommentOn(const Statement& statement
auto comment = extraInfo->comment;
validateTableExist(tableName);
auto boundExtraInfo = std::make_unique<BoundExtraCommentInfo>(comment);
auto boundInfo = BoundAlterInfo(AlterType::COMMENT, tableName, std::move(boundExtraInfo));
auto boundInfo =
BoundAlterInfo(AlterType::COMMENT, tableName, std::move(boundExtraInfo), info->onConflict);
return std::make_unique<BoundAlter>(std::move(boundInfo));
}

Expand Down
10 changes: 7 additions & 3 deletions src/include/binder/ddl/bound_alter_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "binder/ddl/property_definition.h"
#include "binder/expression/expression.h"
#include "common/enums/alter_type.h"
#include "common/enums/conflict_action.h"

namespace kuzu {
namespace binder {
Expand All @@ -26,18 +27,21 @@ struct BoundAlterInfo {
common::AlterType alterType;
std::string tableName;
std::unique_ptr<BoundExtraAlterInfo> extraInfo;
common::ConflictAction onConflict;

BoundAlterInfo(common::AlterType alterType, std::string tableName,
std::unique_ptr<BoundExtraAlterInfo> extraInfo)
: alterType{alterType}, tableName{std::move(tableName)}, extraInfo{std::move(extraInfo)} {}
std::unique_ptr<BoundExtraAlterInfo> extraInfo,
common::ConflictAction onConflict = common::ConflictAction::ON_CONFLICT_THROW)
: alterType{alterType}, tableName{std::move(tableName)}, extraInfo{std::move(extraInfo)},
onConflict{std::move(onConflict)} {}
EXPLICIT_COPY_DEFAULT_MOVE(BoundAlterInfo);

std::string toString() const;

private:
BoundAlterInfo(const BoundAlterInfo& other)
: alterType{other.alterType}, tableName{other.tableName},
extraInfo{other.extraInfo->copy()} {}
extraInfo{other.extraInfo->copy()}, onConflict{other.onConflict} {}
};

struct BoundExtraRenameTableInfo : public BoundExtraAlterInfo {
Expand Down
8 changes: 6 additions & 2 deletions src/include/parser/ddl/alter_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

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

namespace kuzu {
Expand All @@ -26,10 +27,13 @@ struct AlterInfo {
common::AlterType type;
std::string tableName;
std::unique_ptr<ExtraAlterInfo> extraInfo;
common::ConflictAction onConflict;

AlterInfo(common::AlterType type, std::string tableName,
std::unique_ptr<ExtraAlterInfo> extraInfo)
: type{type}, tableName{std::move(tableName)}, extraInfo{std::move(extraInfo)} {}
std::unique_ptr<ExtraAlterInfo> extraInfo,
common::ConflictAction onConflict = common::ConflictAction::ON_CONFLICT_THROW)
: type{type}, tableName{std::move(tableName)}, extraInfo{std::move(extraInfo)},
onConflict{std::move(onConflict)} {}
DELETE_COPY_DEFAULT_MOVE(AlterInfo);
};

Expand Down
16 changes: 12 additions & 4 deletions src/parser/transform/transform_ddl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,17 +225,25 @@ std::unique_ptr<Statement> Transformer::transformAddProperty(
}
auto extraInfo = std::make_unique<ExtraAddPropertyInfo>(std::move(propertyName),
std::move(dataType), std::move(defaultValue));
auto info = AlterInfo(AlterType::ADD_PROPERTY, tableName, std::move(extraInfo));
ConflictAction action = ConflictAction::ON_CONFLICT_THROW;
if (addPropertyCtx->kU_IfNotExists()) {
action = ConflictAction::ON_CONFLICT_DO_NOTHING;
}
auto info = AlterInfo(AlterType::ADD_PROPERTY, tableName, std::move(extraInfo), action);
return std::make_unique<Alter>(std::move(info));
}

std::unique_ptr<Statement> Transformer::transformDropProperty(
CypherParser::KU_AlterTableContext& ctx) {
auto tableName = transformSchemaName(*ctx.oC_SchemaName());
auto propertyName =
transformPropertyKeyName(*ctx.kU_AlterOptions()->kU_DropProperty()->oC_PropertyKeyName());
auto dropProperty = ctx.kU_AlterOptions()->kU_DropProperty();
auto propertyName = transformPropertyKeyName(*dropProperty->oC_PropertyKeyName());
auto extraInfo = std::make_unique<ExtraDropPropertyInfo>(std::move(propertyName));
auto info = AlterInfo(AlterType::DROP_PROPERTY, tableName, std::move(extraInfo));
common::ConflictAction action = common::ConflictAction::ON_CONFLICT_THROW;
if (dropProperty->kU_IfExists()) {
action = common::ConflictAction::ON_CONFLICT_DO_NOTHING;
}
auto info = AlterInfo(AlterType::DROP_PROPERTY, tableName, std::move(extraInfo), action);
return std::make_unique<Alter>(std::move(info));
}

Expand Down
36 changes: 36 additions & 0 deletions src/processor/operator/ddl/alter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,45 @@ using namespace kuzu::binder;
namespace kuzu {
namespace processor {

using skip_alter_on_conflict = std::function<bool()>;

bool skipAlter(common::ConflictAction action, skip_alter_on_conflict skipAlterOnConflict) {
switch (action) {
case common::ConflictAction::ON_CONFLICT_THROW:
return false;
case common::ConflictAction::ON_CONFLICT_DO_NOTHING:
return skipAlterOnConflict();
default:
KU_UNREACHABLE;
}
}

void Alter::executeDDLInternal(ExecutionContext* context) {
auto catalog = context->clientContext->getCatalog();
auto transaction = context->clientContext->getTx();
switch (info.alterType) {
case common::AlterType::ADD_PROPERTY: {
if (skipAlter(info.onConflict, [&]() {
return catalog->getTableCatalogEntry(transaction, info.tableName)
->containsProperty(info.extraInfo->constCast<BoundExtraAddPropertyInfo>()
.propertyDefinition.getName());
})) {
return;
}
} break;
case common::AlterType::DROP_PROPERTY: {
if (skipAlter(info.onConflict, [&]() {
return !catalog->getTableCatalogEntry(transaction, info.tableName)
->containsProperty(
info.extraInfo->constCast<BoundExtraDropPropertyInfo>()
.propertyName);
})) {
return;
}
} break;
default:
break;
}
const auto storageManager = context->clientContext->getStorageManager();
catalog->alterTableEntry(transaction, info);
if (info.alterType == common::AlterType::ADD_PROPERTY) {
Expand Down
23 changes: 23 additions & 0 deletions test/test_files/ddl/ddl.test
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,13 @@ Table university has been dropped.
-STATEMENT ALTER TABLE person DROP fName
---- 1
Table person altered.
-STATEMENT ALTER TABLE person DROP if exists fName
---- ok
-STATEMENT ALTER TABLE knows DROP date
---- 1
Table knows altered.
-STATEMENT ALTER TABLE knows DROP if exists date
acquamarin marked this conversation as resolved.
Show resolved Hide resolved
---- ok

-CASE CreateRelGroup
-STATEMENT CREATE REL TABLE GROUP likes (FROM person TO person, FROM person TO organisation, since INT64);
Expand Down Expand Up @@ -138,6 +142,16 @@ Binder exception: Table knows does not exist.
---- 1
215489

-LOG AddNodePropertyIfNotExists
-STATEMENT alter table Comment add IF NOT EXISTS id int64 default 1;
---- ok

-STATEMENT CALL TABLE_INFO('Comment') RETURN *;
---- 3
0|id|INT64|NULL|True
1|propx|INT64|NULL|False
2|propy|INT64|1|False

-CASE AddRelProperty
-STATEMENT create node table Comment (id int64, PRIMARY KEY (id));
---- ok
Expand All @@ -158,6 +172,15 @@ Binder exception: Table knows does not exist.
---- 1
108027

-LOG AddRelPropertyIfNotExists
-STATEMENT alter table replyOf add if not exists propy int64 default 1;
---- ok

-STATEMENT CALL TABLE_INFO('replyOf') RETURN *;
---- 2
1|propx|INT64|NULL
2|propy|INT64|1

-CASE DropNodeTablePropertyNormalExecution
-STATEMENT ALTER TABLE person DROP gender
---- ok
Expand Down
Loading