Permalink
Browse files

Fix the handling of the string DatePartType.

  • Loading branch information...
malin1993ml authored and hzxa21 committed Nov 21, 2017
1 parent 42c8bf8 commit c79a3f78eed9a00999d78d21c8bd7ae72053a060
Showing with 60 additions and 8 deletions.
  1. +31 −4 src/binder/bind_node_visitor.cpp
  2. +29 −4 test/sql/timestamp_functions_sql_test.cpp
@@ -10,15 +10,16 @@
//
//===----------------------------------------------------------------------===//
#include "catalog/catalog.h"
#include "binder/bind_node_visitor.h"
#include "catalog/catalog.h"
#include "type/type_id.h"
#include "expression/aggregate_expression.h"
#include "expression/case_expression.h"
#include "expression/tuple_value_expression.h"
#include "expression/function_expression.h"
#include "expression/operator_expression.h"
#include "expression/aggregate_expression.h"
#include "expression/star_expression.h"
#include "expression/tuple_value_expression.h"
namespace peloton {
namespace binder {
@@ -161,7 +162,8 @@ void BindNodeVisitor::Visit(expression::TupleValueExpression *expr) {
// Find the corresponding table in the context
if (!BinderContext::GetTableIdTuple(context_, table_name,
&table_id_tuple))
throw BinderException("Invalid table reference " + expr->GetTableName());
throw BinderException("Invalid table reference " +
expr->GetTableName());
// Find the column offset in that table
if (!BinderContext::GetColumnPosTuple(col_name, table_id_tuple,
col_pos_tuple, value_type, txn_))
@@ -197,6 +199,31 @@ void BindNodeVisitor::Visit(expression::FunctionExpression *expr) {
// Visit the subtree first
SqlNodeVisitor::Visit(expr);
// Specialize the first argument (DatePartType) for date functions, otherwise
// we have to do the string comparison to find out the corresponding
// DatePartType when scanning every tuple.
auto func_name = expr->GetFuncName();
if (func_name == "date_trunc" or expr->GetFuncName() == "extract") {
// Check the type of the first argument. Should be VARCHAR
auto date_part = expr->GetChild(0);
if (date_part->GetValueType() != type::TypeId::VARCHAR) {
throw Exception(EXCEPTION_TYPE_EXPRESSION,
"Incorrect argument type to function: " + func_name +
". Argument 0 expected type VARCHAR but found " +
TypeIdToString(date_part->GetValueType()) + ".");
}
// Convert the first argument to DatePartType
auto date_part_type = StringToDatePartType(
date_part->Evaluate(nullptr, nullptr, nullptr).ToString());
auto date_part_integer = type::ValueFactory::GetIntegerValue(
static_cast<int32_t>(date_part_type));
// Replace the first argument with an Integer expression of the DatePartType
expr->SetChild(0,
new expression::ConstantValueExpression(date_part_integer));
}
// Check catalog and bind function
std::vector<type::TypeId> argtypes;
for (size_t i = 0; i < expr->GetChildrenSize(); i++)
@@ -45,16 +45,41 @@ TEST_F(TimestampFunctionsSQLTest, DateTruncTest) {
std::string error_message;
int rows_affected;
// TODO(lma): We cannot properly test it until the binder supports checking
// the string value of the DatePartType in the function and replace it with
// its id. Right now we can only directly pass the id through the function.
std::string test_query = "select date_trunc(13, value) from foo;";
// wrong argument type
std::string test_query = "select date_trunc(123, value) from foo;";
TestingSQLUtil::ExecuteSQLQuery(test_query.c_str(), result, tuple_descriptor,
rows_affected, error_message);
EXPECT_EQ(result.size(), 0);
// wrong DatePartType
test_query = "select date_trunc('abc', value) from foo;";
TestingSQLUtil::ExecuteSQLQuery(test_query.c_str(), result, tuple_descriptor,
rows_affected, error_message);
EXPECT_EQ(result.size(), 0);
// Test a few end-to-end DatePartType strings. The correctness of the function
// is already tested in the unit tests.
test_query = "select date_trunc('minute', value) from foo;";
std::string expected = "2016-12-07 13:26:00.000000-05";
TestingSQLUtil::ExecuteSQLQuery(test_query.c_str(), result, tuple_descriptor,
rows_affected, error_message);
auto query_result = TestingSQLUtil::GetResultValueAsString(result, 0);
EXPECT_EQ(query_result, expected);
test_query = "select date_trunc('DAY', value) from foo;";
expected = "2016-12-07 00:00:00.000000-05";
TestingSQLUtil::ExecuteSQLQuery(test_query.c_str(), result, tuple_descriptor,
rows_affected, error_message);
query_result = TestingSQLUtil::GetResultValueAsString(result, 0);
EXPECT_EQ(query_result, expected);
test_query = "select date_trunc('CenTuRy', value) from foo;";
expected = "2001-01-01 00:00:00.000000-05";
TestingSQLUtil::ExecuteSQLQuery(test_query.c_str(), result, tuple_descriptor,
rows_affected, error_message);
query_result = TestingSQLUtil::GetResultValueAsString(result, 0);
EXPECT_EQ(query_result, expected);
// free the database just created
txn = txn_manager.BeginTransaction();
catalog::Catalog::GetInstance()->DropDatabaseWithName(DEFAULT_DB_NAME, txn);

0 comments on commit c79a3f7

Please sign in to comment.