Skip to content

Commit

Permalink
Add bind to table star
Browse files Browse the repository at this point in the history
  • Loading branch information
andyfengHKU committed Jul 11, 2023
1 parent 47ab5b8 commit 6c2bf07
Show file tree
Hide file tree
Showing 11 changed files with 236 additions and 130 deletions.
41 changes: 27 additions & 14 deletions src/binder/bind/bind_projection_clause.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "binder/binder.h"
#include "binder/expression/expression_visitor.h"
#include "binder/expression/literal_expression.h"
#include "parser/expression/parsed_property_expression.h"

using namespace kuzu::common;
using namespace kuzu::parser;
Expand All @@ -10,8 +11,8 @@ namespace binder {

std::unique_ptr<BoundWithClause> Binder::bindWithClause(const WithClause& withClause) {
auto projectionBody = withClause.getProjectionBody();
auto projectionExpressions = bindProjectionExpressions(
projectionBody->getProjectionExpressions(), projectionBody->containsStar());
auto projectionExpressions =
bindProjectionExpressions(projectionBody->getProjectionExpressions());
validateProjectionColumnsInWithClauseAreAliased(projectionExpressions);
expression_vector newProjectionExpressions;
for (auto& expression : projectionExpressions) {
Expand Down Expand Up @@ -47,8 +48,8 @@ std::unique_ptr<BoundWithClause> Binder::bindWithClause(const WithClause& withCl

std::unique_ptr<BoundReturnClause> Binder::bindReturnClause(const ReturnClause& returnClause) {
auto projectionBody = returnClause.getProjectionBody();
auto boundProjectionExpressions = bindProjectionExpressions(
projectionBody->getProjectionExpressions(), projectionBody->containsStar());
auto boundProjectionExpressions =
bindProjectionExpressions(projectionBody->getProjectionExpressions());
auto statementResult = std::make_unique<BoundStatementResult>();
for (auto& expression : boundProjectionExpressions) {
statementResult->addColumn(expression);
Expand Down Expand Up @@ -161,18 +162,30 @@ std::unique_ptr<BoundProjectionBody> Binder::bindProjectionBody(
}

expression_vector Binder::bindProjectionExpressions(
const parsed_expression_vector& projectionExpressions, bool star) {
const parsed_expression_vector& projectionExpressions) {
expression_vector result;
for (auto& expression : projectionExpressions) {
result.push_back(expressionBinder.bindExpression(*expression));
}
if (star) {
if (variableScope->empty()) {
throw BinderException(
"RETURN or WITH * is not allowed when there are no variables in scope.");
}
for (auto& expression : variableScope->getExpressions()) {
result.push_back(expression);
if (expression->getExpressionType() == common::ExpressionType::STAR) {
// Rewrite star expression as all expression in scope.
if (variableScope->empty()) {
throw BinderException(
"RETURN or WITH * is not allowed when there are no variables in scope.");
}
for (auto& expr : variableScope->getExpressions()) {
result.push_back(expr);
}
} else if (expression->getExpressionType() == common::ExpressionType::PROPERTY) {
auto propertyExpression = (ParsedPropertyExpression*)expression.get();
if (propertyExpression->isStar()) {
// Rewrite property star expression
for (auto& expr : expressionBinder.bindPropertyStarExpression(*expression)) {
result.push_back(expr);
}
} else {
result.push_back(expressionBinder.bindExpression(*expression));
}
} else {
result.push_back(expressionBinder.bindExpression(*expression));
}
}
resolveAnyDataTypeWithDefaultType(result);
Expand Down
7 changes: 7 additions & 0 deletions src/binder/bind_expression/bind_literal_expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "parser/expression/parsed_literal_expression.h"

using namespace kuzu::parser;
using namespace kuzu::common;

namespace kuzu {
namespace binder {
Expand All @@ -24,6 +25,12 @@ std::shared_ptr<Expression> ExpressionBinder::createLiteralExpression(
return std::make_unique<LiteralExpression>(std::move(value), uniqueName);
}

std::shared_ptr<Expression> ExpressionBinder::createStringLiteralExpression(
const std::string& strVal) {
auto value = std::make_unique<Value>(LogicalType{LogicalTypeID::STRING}, strVal);
return createLiteralExpression(std::move(value));
}

std::shared_ptr<Expression> ExpressionBinder::createNullLiteralExpression() {
return make_shared<LiteralExpression>(
std::make_unique<common::Value>(common::Value::createNullValue()),
Expand Down
100 changes: 76 additions & 24 deletions src/binder/bind_expression/bind_property_expression.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "binder/expression/literal_expression.h"
#include "binder/expression/rel_expression.h"
#include "binder/expression_binder.h"
#include "common/string_utils.h"
#include "parser/expression/parsed_property_expression.h"

using namespace kuzu::common;
Expand All @@ -12,14 +13,59 @@ namespace binder {

expression_vector ExpressionBinder::bindPropertyStarExpression(
const parser::ParsedExpression& parsedExpression) {
auto& propertyExpression = (ParsedPropertyExpression&)parsedExpression;
auto child = bindExpression(*parsedExpression.getChild(0));
validateExpectedDataType(*child,
std::vector<LogicalTypeID>{LogicalTypeID::NODE, LogicalTypeID::REL, LogicalTypeID::STRUCT});
if (ExpressionUtil::isNodeVariable(*child)) {
return bindNodePropertyStarExpression(*child);
} else if (ExpressionUtil::isRelVariable(*child)) {
return bindRelPropertyStarExpression(*child);
} else {
return bindStructPropertyStarExpression(child);
}
}

expression_vector ExpressionBinder::bindNodePropertyStarExpression(const Expression& child) {
expression_vector result;
auto& node = (NodeExpression&)child;
for (auto& property : node.getPropertyExpressions()) {
result.push_back(property->copy());
}
return result;
}

Check warning on line 35 in src/binder/bind_expression/bind_property_expression.cpp

View check run for this annotation

Codecov / codecov/patch

src/binder/bind_expression/bind_property_expression.cpp#L35

Added line #L35 was not covered by tests

expression_vector ExpressionBinder::bindRelPropertyStarExpression(const Expression& child) {
expression_vector result;
auto& node = (RelExpression&)child;
for (auto& property : node.getPropertyExpressions()) {
auto propertyExpression = (PropertyExpression*)property.get();
if (TableSchema::isReservedPropertyName(propertyExpression->getPropertyName())) {
continue;
}
result.push_back(property->copy());
}
return result;
}

Check warning on line 48 in src/binder/bind_expression/bind_property_expression.cpp

View check run for this annotation

Codecov / codecov/patch

src/binder/bind_expression/bind_property_expression.cpp#L48

Added line #L48 was not covered by tests

expression_vector ExpressionBinder::bindStructPropertyStarExpression(
std::shared_ptr<Expression> child) {
assert(child->getDataType().getLogicalTypeID() == common::LogicalTypeID::STRUCT);
expression_vector result;
auto childType = child->getDataType();
for (auto field : StructType::getFields(&childType)) {
result.push_back(bindStructPropertyExpression(child, field->getName()));
}
return result;
}

Check warning on line 59 in src/binder/bind_expression/bind_property_expression.cpp

View check run for this annotation

Codecov / codecov/patch

src/binder/bind_expression/bind_property_expression.cpp#L59

Added line #L59 was not covered by tests

std::shared_ptr<Expression> ExpressionBinder::bindPropertyExpression(
const ParsedExpression& parsedExpression) {
auto& propertyExpression = (ParsedPropertyExpression&)parsedExpression;
if (propertyExpression.)
auto propertyName = propertyExpression.getPropertyName();
if (propertyExpression.isStar()) {
throw BinderException(StringUtils::string_format(
"Cannot bind {} as a single property expression.", parsedExpression.toString()));
}
auto propertyName = propertyExpression.getPropertyName();
if (TableSchema::isReservedPropertyName(propertyName)) {
// Note we don't expose direct access to internal properties in case user tries to modify
// them. However, we can expose indirect read-only access through function e.g. ID().
Expand All @@ -35,30 +81,46 @@ std::shared_ptr<Expression> ExpressionBinder::bindPropertyExpression(
return bindRelPropertyExpression(*child, propertyName);
} else {
assert(child->expressionType == common::FUNCTION);
auto stringValue =
std::make_unique<Value>(LogicalType{LogicalTypeID::STRING}, propertyName);
return bindScalarFunctionExpression(
expression_vector{child, createLiteralExpression(std::move(stringValue))},
STRUCT_EXTRACT_FUNC_NAME);
return bindStructPropertyExpression(child, propertyName);
}
}

std::shared_ptr<Expression> ExpressionBinder::bindNodePropertyExpression(
const Expression& expression, const std::string& propertyName) {
auto& nodeOrRel = (NodeOrRelExpression&)expression;
if (!nodeOrRel.hasPropertyExpression(propertyName)) {
const Expression& child, const std::string& propertyName) {
auto& node = (NodeExpression&)child;
if (!node.hasPropertyExpression(propertyName)) {
throw BinderException(
"Cannot find property " + propertyName + " for " + expression.toString() + ".");
"Cannot find property " + propertyName + " for " + child.toString() + ".");
}
return nodeOrRel.getPropertyExpression(propertyName);
return node.getPropertyExpression(propertyName);
}

std::shared_ptr<Expression> ExpressionBinder::bindRelPropertyExpression(
const Expression& child, const std::string& propertyName) {
auto& rel = (RelExpression&)child;
if (!rel.hasPropertyExpression(propertyName)) {
throw BinderException(
"Cannot find property " + propertyName + " for " + child.toString() + ".");

Check warning on line 103 in src/binder/bind_expression/bind_property_expression.cpp

View check run for this annotation

Codecov / codecov/patch

src/binder/bind_expression/bind_property_expression.cpp#L102-L103

Added lines #L102 - L103 were not covered by tests
}
return rel.getPropertyExpression(propertyName);
}

std::shared_ptr<Expression> ExpressionBinder::bindStructPropertyExpression(
std::shared_ptr<Expression> child, const std::string& propertyName) {
auto children =
expression_vector{std::move(child), createStringLiteralExpression(propertyName)};
return bindScalarFunctionExpression(children, STRUCT_EXTRACT_FUNC_NAME);
}

static void validatePropertiesWithSameDataType(const std::vector<Property>& properties,
const LogicalType& dataType, const std::string& propertyName, const std::string& variableName) {
auto propertyLookup = variableName + "." + propertyName;
for (auto& property : properties) {
if (property.dataType != dataType) {
throw BinderException(
"Cannot resolve data type of " + propertyName + " for " + variableName + ".");
StringUtils::string_format("Expect one data type for {} but find {} and {}",
propertyLookup, LogicalTypeUtils::dataTypeToString(property.dataType),
LogicalTypeUtils::dataTypeToString(dataType)));

Check warning on line 123 in src/binder/bind_expression/bind_property_expression.cpp

View check run for this annotation

Codecov / codecov/patch

src/binder/bind_expression/bind_property_expression.cpp#L121-L123

Added lines #L121 - L123 were not covered by tests
}
}
}
Expand All @@ -72,16 +134,6 @@ static std::unordered_map<table_id_t, property_id_t> populatePropertyIDPerTable(
return propertyIDPerTable;
}

std::shared_ptr<Expression> ExpressionBinder::bindRelPropertyExpression(
const Expression& expression, const std::string& propertyName) {
auto& rel = (RelExpression&)expression;
if (!rel.hasPropertyExpression(propertyName)) {
throw BinderException(
"Cannot find property " + propertyName + " for " + expression.toString() + ".");
}
return rel.getPropertyExpression(propertyName);
}

std::unique_ptr<Expression> ExpressionBinder::createPropertyExpression(
const Expression& nodeOrRel, const std::vector<Property>& properties, bool isPrimaryKey) {
assert(!properties.empty());
Expand Down
2 changes: 1 addition & 1 deletion src/include/binder/binder.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ class Binder {
const expression_vector& projectionExpressions);

expression_vector bindProjectionExpressions(
const parser::parsed_expression_vector& parsedExpressions, bool star);
const parser::parsed_expression_vector& parsedExpressions);

expression_vector bindOrderByExpressions(
const std::vector<std::unique_ptr<parser::ParsedExpression>>& orderByExpressions);
Expand Down
29 changes: 18 additions & 11 deletions src/include/binder/expression_binder.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,33 +22,39 @@ class ExpressionBinder {
static void resolveAnyDataType(Expression& expression, const common::LogicalType& targetType);

private:
// Boolean expressions.
std::shared_ptr<Expression> bindBooleanExpression(
const parser::ParsedExpression& parsedExpression);
std::shared_ptr<Expression> bindBooleanExpression(
common::ExpressionType expressionType, const expression_vector& children);
std::shared_ptr<Expression> combineConjunctiveExpressions(
std::shared_ptr<Expression> left, std::shared_ptr<Expression> right);

// Comparison expressions.
std::shared_ptr<Expression> bindComparisonExpression(
const parser::ParsedExpression& parsedExpression);
std::shared_ptr<Expression> bindComparisonExpression(
common::ExpressionType expressionType, const expression_vector& children);
std::shared_ptr<Expression> createEqualityComparisonExpression(
std::shared_ptr<Expression> left, std::shared_ptr<Expression> right);

// Null operator expressions.
std::shared_ptr<Expression> bindNullOperatorExpression(
const parser::ParsedExpression& parsedExpression);

// Property expressions.
expression_vector bindPropertyStarExpression(const parser::ParsedExpression& parsedExpression);
expression_vector bindNodePropertyStarExpression(const Expression& child);
expression_vector bindRelPropertyStarExpression(const Expression& child);
expression_vector bindStructPropertyStarExpression(std::shared_ptr<Expression> child);
std::shared_ptr<Expression> bindPropertyExpression(
const parser::ParsedExpression& parsedExpression);
std::shared_ptr<Expression> bindNodePropertyExpression(
const Expression& expression, const std::string& propertyName);
const Expression& child, const std::string& propertyName);
std::shared_ptr<Expression> bindRelPropertyExpression(
const Expression& expression, const std::string& propertyName);
const Expression& child, const std::string& propertyName);
std::shared_ptr<Expression> bindStructPropertyExpression(
std::shared_ptr<Expression> child, const std::string& propertyName);
std::unique_ptr<Expression> createPropertyExpression(const Expression& nodeOrRel,
const std::vector<catalog::Property>& propertyName, bool isPrimaryKey);

// Function expressions.
std::shared_ptr<Expression> bindFunctionExpression(
const parser::ParsedExpression& parsedExpression);

Expand All @@ -69,23 +75,24 @@ class ExpressionBinder {
std::shared_ptr<Expression> bindLabelFunction(const Expression& expression);
std::unique_ptr<Expression> createInternalLengthExpression(const Expression& expression);
std::shared_ptr<Expression> bindRecursiveJoinLengthFunction(const Expression& expression);

// Parameter expressions.
std::shared_ptr<Expression> bindParameterExpression(
const parser::ParsedExpression& parsedExpression);

// Literal expressions.
std::shared_ptr<Expression> bindLiteralExpression(
const parser::ParsedExpression& parsedExpression);
std::shared_ptr<Expression> createLiteralExpression(std::unique_ptr<common::Value> value);
std::shared_ptr<Expression> createStringLiteralExpression(const std::string& strVal);
std::shared_ptr<Expression> createNullLiteralExpression();

// Variable expressions.
std::shared_ptr<Expression> bindVariableExpression(
const parser::ParsedExpression& parsedExpression);
std::shared_ptr<Expression> createVariableExpression(
common::LogicalType logicalType, std::string uniqueName, std::string name);

// Subquery expressions.
std::shared_ptr<Expression> bindExistentialSubqueryExpression(
const parser::ParsedExpression& parsedExpression);

// Case expressions.
std::shared_ptr<Expression> bindCaseExpression(
const parser::ParsedExpression& parsedExpression);

Expand Down
1 change: 1 addition & 0 deletions src/include/common/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ struct InternalKeyword {
static constexpr char NODES[] = "_NODES";
static constexpr char RELS[] = "_RELS";
static constexpr char TAG[] = "_TAG";
static constexpr char STAR[] = "*";
};

enum PageSizeClass : uint8_t {
Expand Down
1 change: 1 addition & 0 deletions src/include/parser/expression/parsed_property_expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class ParsedPropertyExpression : public ParsedExpression {
propertyName{std::move(propertyName)} {}

inline std::string getPropertyName() const { return propertyName; }
inline bool isStar() const { return propertyName == common::InternalKeyword::STAR; }

private:
std::string propertyName;
Expand Down
1 change: 0 additions & 1 deletion src/include/parser/transformer.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,6 @@ class Transformer {
std::unique_ptr<ParsedExpression> transformExistentialSubquery(
CypherParser::OC_ExistentialSubqueryContext& ctx);

// std::string transformPropertyLookup(CypherParser::OC_PropertyLookupContext& ctx);
std::unique_ptr<ParsedExpression> createPropertyExpression(
CypherParser::OC_PropertyLookupContext& ctx, std::unique_ptr<ParsedExpression> child);

Expand Down
10 changes: 2 additions & 8 deletions src/parser/transformer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -896,14 +896,8 @@ std::unique_ptr<ParsedExpression> Transformer::transformExistentialSubquery(

std::unique_ptr<ParsedExpression> Transformer::createPropertyExpression(
CypherParser::OC_PropertyLookupContext& ctx, std::unique_ptr<ParsedExpression> child) {
std::string key;
if (ctx.STAR()) {
key = ctx.start->getText();
child =
std::make_unique<ParsedExpression>(common::ExpressionType::STAR, key);
} else {
key = transformPropertyKeyName(*ctx.oC_PropertyKeyName());
}
auto key = ctx.STAR() ? common::InternalKeyword::STAR :
transformPropertyKeyName(*ctx.oC_PropertyKeyName());
return std::make_unique<ParsedPropertyExpression>(
key, std::move(child), child->toString() + ctx.getText());
}
Expand Down
Loading

0 comments on commit 6c2bf07

Please sign in to comment.