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

Table star #1803

Merged
merged 1 commit into from
Jul 12, 2023
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
2 changes: 1 addition & 1 deletion src/antlr4/Cypher.g4
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ oC_ExistentialSubquery
EXISTS : ( 'E' | 'e' ) ( 'X' | 'x' ) ( 'I' | 'i' ) ( 'S' | 's' ) ( 'T' | 't' ) ( 'S' | 's' ) ;

oC_PropertyLookup
: '.' SP? ( oC_PropertyKeyName ) ;
: '.' SP? ( oC_PropertyKeyName | STAR ) ;

oC_CaseExpression
: ( ( CASE ( SP? oC_CaseAlternative )+ ) | ( CASE SP? oC_Expression ( SP? oC_CaseAlternative )+ ) ) ( SP? ELSE SP? oC_Expression )? SP? END ;
Expand Down
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) {
andyfengHKU marked this conversation as resolved.
Show resolved Hide resolved
// 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: 79 additions & 21 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 @@ -10,9 +11,60 @@
namespace kuzu {
namespace binder {

expression_vector ExpressionBinder::bindPropertyStarExpression(
const parser::ParsedExpression& 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.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
Expand All @@ -29,30 +81,46 @@
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 @@ -66,16 +134,6 @@
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: 2 additions & 0 deletions src/common/expression_type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@
return "PROPERTY";
case LITERAL:
return "LITERAL";
case STAR:
return "STAR";

Check warning on line 72 in src/common/expression_type.cpp

View check run for this annotation

Codecov / codecov/patch

src/common/expression_type.cpp#L72

Added line #L72 was not covered by tests
case VARIABLE:
return "VARIABLE";
case PATH:
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
30 changes: 19 additions & 11 deletions src/include/binder/expression_binder.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,32 +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 @@ -68,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
2 changes: 2 additions & 0 deletions src/include/common/expression_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ enum ExpressionType : uint8_t {

LITERAL = 70,

STAR = 80,

VARIABLE = 90,
PATH = 91,

Expand Down
8 changes: 4 additions & 4 deletions src/include/parser/expression/parsed_expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ class ParsedExpression {
ParsedExpression(common::ExpressionType type, std::unique_ptr<ParsedExpression> left,
std::unique_ptr<ParsedExpression> right, std::string rawName);

ParsedExpression(common::ExpressionType type, std::string rawName)
: type{type}, rawName{std::move(rawName)} {}

virtual ~ParsedExpression() = default;

inline common::ExpressionType getExpressionType() const { return type; }
Expand All @@ -33,12 +36,9 @@ class ParsedExpression {
inline std::string getRawName() const { return rawName; }

inline uint32_t getNumChildren() const { return children.size(); }

inline ParsedExpression* getChild(uint32_t idx) const { return children[idx].get(); }

protected:
ParsedExpression(common::ExpressionType type, std::string rawName)
: type{type}, rawName{std::move(rawName)} {}
inline std::string toString() const { return rawName; }

protected:
common::ExpressionType type;
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
Loading
Loading