Example #1
0
TEST_F(ExpressionTests, DistinctFromTest) {
  // Create a table with id column and value column
  std::vector<catalog::Column> columns;

  catalog::Column column1(type::TypeId::INTEGER,
                          type::Type::GetTypeSize(type::TypeId::INTEGER), "id",
                          true);
  catalog::Column column2(type::TypeId::INTEGER,
                          type::Type::GetTypeSize(type::TypeId::INTEGER), "value",
                          true);

  columns.push_back(column1);
  columns.push_back(column2);

  std::unique_ptr<catalog::Schema> schema(new catalog::Schema(columns));

  std::unique_ptr<storage::Tuple> tuple(new storage::Tuple(schema.get(), true));

  // Create "id IS DISTINCT FROM value" comparison
  auto lexpr = new expression::TupleValueExpression(type::TypeId::INTEGER, 0, 0);
  auto rexpr = new expression::TupleValueExpression(type::TypeId::INTEGER, 1, 1);

  expression::ComparisonExpression expr(
      StringToExpressionType("COMPARE_DISTINCT_FROM"), lexpr, rexpr);

  auto pool = TestingHarness::GetInstance().GetTestingPool();

  // id, value not NULL with the same values, should be false
  tuple->SetValue(0, type::ValueFactory::GetIntegerValue(10), pool);
  tuple->SetValue(1, type::ValueFactory::GetIntegerValue(10), pool);
  EXPECT_TRUE(expr.Evaluate(tuple.get(), tuple.get(), nullptr).IsFalse());

  // id, value not NULL with different values, should be true
  tuple->SetValue(1, type::ValueFactory::GetIntegerValue(5), pool);
  EXPECT_TRUE(expr.Evaluate(tuple.get(), tuple.get(), nullptr).IsTrue());

  // id not NULL, value is NULL, should be true
  tuple->SetValue(1,
      type::ValueFactory::GetNullValueByType(type::TypeId::INTEGER), pool);
  EXPECT_TRUE(expr.Evaluate(tuple.get(), tuple.get(), nullptr).IsTrue());

  // id is NULL, value not NULL, should be true
  tuple->SetValue(0,
      type::ValueFactory::GetNullValueByType(type::TypeId::INTEGER), pool);
  tuple->SetValue(1, type::ValueFactory::GetIntegerValue(10), pool);
  EXPECT_TRUE(expr.Evaluate(tuple.get(), tuple.get(), nullptr).IsTrue());

  // id is NULL, value is NULL, should be false
  tuple->SetValue(1,
       type::ValueFactory::GetNullValueByType(type::TypeId::INTEGER), pool);
  EXPECT_TRUE(expr.Evaluate(tuple.get(), tuple.get(), nullptr).IsFalse());
}
AbstractExpression *AbstractExpression::CreateExpressionTreeRecurse(
    json_spirit::Object &obj) {
  // build a tree recursively from the bottom upwards.
  // when the expression node is instantiated, its type,
  // value and child types will have been discovered.

  ExpressionType peek_type = EXPRESSION_TYPE_INVALID;
  ValueType value_type = VALUE_TYPE_INVALID;
  AbstractExpression *left_child = nullptr;
  AbstractExpression *right_child = nullptr;

  // read the expression type
  json_spirit::Value expression_type_value =
      json_spirit::find_value(obj, "TYPE");

  if (expression_type_value == json_spirit::Value::null) {
    throw ExpressionException(
        "AbstractExpression:: buildExpressionTree_recurse:"
        "Couldn't find TYPE value");
  }

  assert(StringToExpressionType(expression_type_value.get_str()) !=
         EXPRESSION_TYPE_INVALID);
  peek_type = StringToExpressionType(expression_type_value.get_str());

  // and the value type
  json_spirit::Value valueTypeValue =
      json_spirit::find_value(obj, "VALUE_TYPE");
  if (valueTypeValue == json_spirit::Value::null) {
    throw ExpressionException(
        "AbstractExpression:: buildExpressionTree_recurse:"
        " Couldn't find VALUE_TYPE value");
  }

  std::string value_type_string = valueTypeValue.get_str();
  value_type = StringToValueType(value_type_string);

  // this should be relatively safe, though it ignores overflow.
  if ((value_type == VALUE_TYPE_TINYINT) ||
      (value_type == VALUE_TYPE_SMALLINT) ||
      (value_type == VALUE_TYPE_INTEGER)) {
    value_type = VALUE_TYPE_BIGINT;
  }

  assert(value_type != VALUE_TYPE_INVALID);

  // add the value size
  json_spirit::Value value_size_value =
      json_spirit::find_value(obj, "VALUE_SIZE");

  if (value_size_value == json_spirit::Value::null) {
    throw ExpressionException(
        "AbstractExpression:: buildExpressionTree_recurse:"
        " Couldn't find VALUE_SIZE value");
  }

  int value_size = value_size_value.get_int();

  // recurse to children
  try {
    json_spirit::Value leftValue = json_spirit::find_value(obj, "LEFT");

    if (!(leftValue == json_spirit::Value::null)) {
      left_child =
          AbstractExpression::CreateExpressionTreeRecurse(leftValue.get_obj());
    } else {
      left_child = nullptr;
    }

    json_spirit::Value rightValue = json_spirit::find_value(obj, "RIGHT");

    if (!(rightValue == json_spirit::Value::null)) {
      right_child =
          AbstractExpression::CreateExpressionTreeRecurse(rightValue.get_obj());
    } else {
      right_child = nullptr;
    }

    // Invoke the factory. obviously it has to handle null children.
    // pass it the serialization stream in case a subclass has more
    // to read. yes, the per-class data really does follow the
    // child serializations.

    return ExpressionUtil::ExpressionFactory(obj, peek_type, value_type, value_size, left_child,
                             right_child);
  } catch (ExpressionException &ex) {
    // clean up children
    delete left_child;
    delete right_child;
    throw;
  }
}