From a9ba7645226f200148de44a19aff204dd0841493 Mon Sep 17 00:00:00 2001 From: Henning Baldersheim Date: Tue, 6 Jun 2017 19:38:18 +0200 Subject: Hide BucketDistribution --- document/src/tests/documentselectparsertest.cpp | 1 + .../src/vespa/document/bucket/bucketdistribution.h | 2 +- .../src/vespa/document/bucket/bucketselector.cpp | 2 +- document/src/vespa/document/select/CMakeLists.txt | 21 +- .../vespa/document/select/bodyfielddetector.cpp | 13 +- .../src/vespa/document/select/cloningvisitor.cpp | 2 +- document/src/vespa/document/select/gid_filter.cpp | 9 +- .../src/vespa/document/select/orderingselector.cpp | 6 +- document/src/vespa/document/select/simpleparser.h | 17 +- .../vespa/document/select/traversingvisitor.cpp | 8 +- document/src/vespa/document/select/valuenode.cpp | 1180 +------------------ document/src/vespa/document/select/valuenode.h | 343 +----- document/src/vespa/document/select/valuenodes.cpp | 1183 ++++++++++++++++++++ document/src/vespa/document/select/valuenodes.h | 348 ++++++ fastos/src/vespa/fastos/time.h | 19 +- fastos/src/vespa/fastos/unix_time.cpp | 8 +- fastos/src/vespa/fastos/unix_time.h | 3 +- messagebus/src/vespa/messagebus/callstack.cpp | 1 + .../src/tests/proton/common/selectpruner_test.cpp | 1 + .../proton/common/attributefieldvaluenode.cpp | 11 +- .../proton/common/attributefieldvaluenode.h | 32 +- .../searchcore/proton/common/cachedselect.cpp | 7 +- .../searchcore/proton/common/selectpruner.cpp | 1 + .../vespa/searchcore/proton/common/selectpruner.h | 127 +-- .../src/vespa/storage/persistence/fieldvisitor.cpp | 4 +- 25 files changed, 1643 insertions(+), 1706 deletions(-) create mode 100644 document/src/vespa/document/select/valuenodes.cpp create mode 100644 document/src/vespa/document/select/valuenodes.h diff --git a/document/src/tests/documentselectparsertest.cpp b/document/src/tests/documentselectparsertest.cpp index 6957634cbde..7fb7703c04a 100644 --- a/document/src/tests/documentselectparsertest.cpp +++ b/document/src/tests/documentselectparsertest.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include diff --git a/document/src/vespa/document/bucket/bucketdistribution.h b/document/src/vespa/document/bucket/bucketdistribution.h index cc7232c81e6..aabc615bdda 100644 --- a/document/src/vespa/document/bucket/bucketdistribution.h +++ b/document/src/vespa/document/bucket/bucketdistribution.h @@ -12,8 +12,8 @@ */ #pragma once +#include "bucketid.h" #include -#include #include namespace document { diff --git a/document/src/vespa/document/bucket/bucketselector.cpp b/document/src/vespa/document/bucket/bucketselector.cpp index b41b1c284a6..7eb3821e283 100644 --- a/document/src/vespa/document/bucket/bucketselector.cpp +++ b/document/src/vespa/document/bucket/bucketselector.cpp @@ -4,7 +4,7 @@ #include "bucketidfactory.h" #include #include -#include +#include #include #include #include diff --git a/document/src/vespa/document/select/CMakeLists.txt b/document/src/vespa/document/select/CMakeLists.txt index 8521c525171..5077c9f0494 100644 --- a/document/src/vespa/document/select/CMakeLists.txt +++ b/document/src/vespa/document/select/CMakeLists.txt @@ -1,26 +1,27 @@ # Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. vespa_add_library(document_select OBJECT SOURCES + bodyfielddetector.cpp branch.cpp + cloningvisitor.cpp compare.cpp constant.cpp + context.cpp doctype.cpp + gid_filter.cpp + invalidconstant.cpp operator.cpp - parser.cpp - result.cpp - value.cpp - valuenode.cpp orderingselector.cpp orderingspecification.cpp + parser.cpp + result.cpp + resultset.cpp resultlist.cpp - invalidconstant.cpp - bodyfielddetector.cpp simpleparser.cpp - resultset.cpp traversingvisitor.cpp - cloningvisitor.cpp - context.cpp - gid_filter.cpp + value.cpp + valuenode.cpp + valuenodes.cpp AFTER document_documentconfig ) diff --git a/document/src/vespa/document/select/bodyfielddetector.cpp b/document/src/vespa/document/select/bodyfielddetector.cpp index d0ddd0043ef..2b4c9890e45 100644 --- a/document/src/vespa/document/select/bodyfielddetector.cpp +++ b/document/src/vespa/document/select/bodyfielddetector.cpp @@ -1,15 +1,12 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "bodyfielddetector.h" +#include "valuenodes.h" #include #include #include -#include -#include "valuenode.h" -namespace document { - -namespace select { +namespace document::select { void BodyFieldDetector::detectFieldType(const FieldValueNode *expr, @@ -35,10 +32,8 @@ BodyFieldDetector::detectFieldType(const FieldValueNode *expr, void BodyFieldDetector::visitFieldValueNode(const FieldValueNode& expr) { - _repo.forEachDocumentType( - *makeClosure(this, &BodyFieldDetector::detectFieldType, &expr)); + _repo.forEachDocumentType(*makeClosure(this, &BodyFieldDetector::detectFieldType, &expr)); } -} // namespace select -} // namespace document +} diff --git a/document/src/vespa/document/select/cloningvisitor.cpp b/document/src/vespa/document/select/cloningvisitor.cpp index 84188788416..c0a45b758d5 100644 --- a/document/src/vespa/document/select/cloningvisitor.cpp +++ b/document/src/vespa/document/select/cloningvisitor.cpp @@ -1,7 +1,7 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "cloningvisitor.h" -#include "valuenode.h" +#include "valuenodes.h" #include "branch.h" #include "compare.h" #include "constant.h" diff --git a/document/src/vespa/document/select/gid_filter.cpp b/document/src/vespa/document/select/gid_filter.cpp index cb194452ead..7630053c16f 100644 --- a/document/src/vespa/document/select/gid_filter.cpp +++ b/document/src/vespa/document/select/gid_filter.cpp @@ -1,15 +1,13 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "gid_filter.h" #include "node.h" -#include "parser.h" #include "visitor.h" -#include "valuenode.h" +#include "valuenodes.h" #include "compare.h" #include "branch.h" #include -namespace document { -namespace select { +namespace document::select { namespace { @@ -156,5 +154,4 @@ GidFilter::GidFilter(const Node& ast_root) { } -} // select -} // document +} diff --git a/document/src/vespa/document/select/orderingselector.cpp b/document/src/vespa/document/select/orderingselector.cpp index 32a1f0a8adf..4195a6c28a2 100644 --- a/document/src/vespa/document/select/orderingselector.cpp +++ b/document/src/vespa/document/select/orderingselector.cpp @@ -2,18 +2,16 @@ #include "orderingselector.h" #include "node.h" -#include "valuenode.h" +#include "valuenodes.h" #include "visitor.h" #include "compare.h" #include "branch.h" -#include #include -#include namespace document { -using namespace document::select; +using namespace select; namespace { /** diff --git a/document/src/vespa/document/select/simpleparser.h b/document/src/vespa/document/select/simpleparser.h index e6457c3dec7..c52aed0f367 100644 --- a/document/src/vespa/document/select/simpleparser.h +++ b/document/src/vespa/document/select/simpleparser.h @@ -2,17 +2,11 @@ #pragma once -#include #include "node.h" -#include "valuenode.h" +#include "valuenodes.h" #include "operator.h" -#include -namespace document { - -namespace select { - -namespace simple { +namespace document::select::simple { class Parser { public: @@ -89,9 +83,4 @@ private: const BucketIdFactory & _bucketIdFactory; }; - - -} // simple -} // select -} // parser - +} diff --git a/document/src/vespa/document/select/traversingvisitor.cpp b/document/src/vespa/document/select/traversingvisitor.cpp index 7f85d8b7ebb..2f2468e5afc 100644 --- a/document/src/vespa/document/select/traversingvisitor.cpp +++ b/document/src/vespa/document/select/traversingvisitor.cpp @@ -1,13 +1,11 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "traversingvisitor.h" -#include "valuenode.h" +#include "valuenodes.h" #include "branch.h" #include "compare.h" -namespace document { - -namespace select { +namespace document::select { void TraversingVisitor::visitAndBranch(const And &expr) @@ -127,5 +125,3 @@ TraversingVisitor::visitInvalidValueNode(const InvalidValueNode &) } } - -} diff --git a/document/src/vespa/document/select/valuenode.cpp b/document/src/vespa/document/select/valuenode.cpp index f463c0e3288..79b795ca76f 100644 --- a/document/src/vespa/document/select/valuenode.cpp +++ b/document/src/vespa/document/select/valuenode.cpp @@ -1,41 +1,12 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "valuenode.h" -#include "visitor.h" -#include "parser.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +namespace document::select { -#include -LOG_SETUP(".document.select.valuenode"); - -namespace document { - -namespace select { - -namespace { - static const std::regex FIELD_NAME_REGEX("^([_A-Za-z][_A-Za-z0-9]*).*"); -} - -namespace { - bool documentTypeEqualsName(const DocumentType& type, const vespalib::stringref& name) - { - if (type.getName() == name) return true; - for (std::vector::const_iterator it - = type.getInheritedTypes().begin(); - it != type.getInheritedTypes().end(); ++it) - { - if (documentTypeEqualsName(**it, name)) return true; - } - return false; - } +std::unique_ptr +ValueNode::traceValue(const Context &context, std::ostream &out) const { + return defaultTrace(getValue(context), out); } std::unique_ptr @@ -45,1146 +16,5 @@ ValueNode::defaultTrace(std::unique_ptr val, std::ostream& out) const return std::move(val); } -InvalidValueNode::InvalidValueNode(const vespalib::stringref & name) - : _name(name) -{ } - - -void -InvalidValueNode::visit(Visitor &visitor) const -{ - visitor.visitInvalidValueNode(*this); -} - - -void -InvalidValueNode::print(std::ostream& out, bool verbose, - const std::string& indent) const -{ - (void) verbose; (void) indent; - if (hadParentheses()) out << '('; - out << _name; - if (hadParentheses()) out << ')'; -} - -NullValueNode::NullValueNode(const vespalib::stringref & name) - : _name(name) -{ } - - -void -NullValueNode::visit(Visitor &visitor) const -{ - visitor.visitNullValueNode(*this); -} - - -void -NullValueNode::print(std::ostream& out, bool verbose, - const std::string& indent) const -{ - (void) verbose; (void) indent; - if (hadParentheses()) out << '('; - out << _name; - if (hadParentheses()) out << ')'; -} - -StringValueNode::StringValueNode(const vespalib::stringref & val) - : _value(val) -{ -} - - -void -StringValueNode::visit(Visitor &visitor) const -{ - visitor.visitStringValueNode(*this); -} - - -void -StringValueNode::print(std::ostream& out, bool verbose, - const std::string& indent) const -{ - (void) verbose; (void) indent; - if (hadParentheses()) out << '('; - out << "\"" << StringUtil::escape(_value) << "\""; - if (hadParentheses()) out << ')'; -} - - -void -IntegerValueNode::visit(Visitor &visitor) const -{ - visitor.visitIntegerValueNode(*this); -} - - -void -IntegerValueNode::print(std::ostream& out, bool verbose, - const std::string& indent) const -{ - (void) verbose; (void) indent; - if (hadParentheses()) out << '('; - out << _value; - if (hadParentheses()) out << ')'; -} - -int64_t -CurrentTimeValueNode::getValue() const -{ - struct timeval mytime; - gettimeofday(&mytime, 0); - return mytime.tv_sec; -} - - -void -CurrentTimeValueNode::visit(Visitor &visitor) const -{ - visitor.visitCurrentTimeValueNode(*this); -} - - -void -CurrentTimeValueNode::print(std::ostream& out, bool verbose, - const std::string& indent) const -{ - (void) verbose; (void) indent; - out << "now()"; -} - -std::unique_ptr -VariableValueNode::getValue(const Context& context) const { - return context.getValue(_value); -} - -void -VariableValueNode::visit(Visitor &visitor) const -{ - visitor.visitVariableValueNode(*this); -} - - -void -VariableValueNode::print(std::ostream& out, bool verbose, - const std::string& indent) const -{ - (void) verbose; (void) indent; - if (hadParentheses()) out << '('; - out << "$" << _value; - if (hadParentheses()) out << ')'; -} - - -void -FloatValueNode::visit(Visitor &visitor) const -{ - visitor.visitFloatValueNode(*this); -} - - -void -FloatValueNode::print(std::ostream& out, bool verbose, - const std::string& indent) const -{ - (void) verbose; (void) indent; - if (hadParentheses()) out << '('; - out << _value; - if (hadParentheses()) out << ')'; -} - -FieldValueNode::FieldValueNode(const vespalib::string& doctype, - const vespalib::string& fieldExpression) - : _doctype(doctype), - _fieldExpression(fieldExpression), - _fieldName(extractFieldName(fieldExpression)) -{ -} - -FieldValueNode::FieldValueNode(const FieldValueNode &) = default; -FieldValueNode & FieldValueNode::operator = (const FieldValueNode &) = default; - -FieldValueNode::~FieldValueNode() {} -vespalib::string -FieldValueNode::extractFieldName(const std::string & fieldExpression) { - std::smatch match; - - if (std::regex_match(fieldExpression, match, FIELD_NAME_REGEX) && match[1].matched) { - return vespalib::string(match[1].first, match[1].second); - } - - throw ParsingFailedException("Fatal: could not extract field name from field expression '" + fieldExpression + "'"); -} - -namespace { - -class IteratorHandler : public fieldvalue::IteratorHandler { -public: - IteratorHandler(); - ~IteratorHandler(); - bool hasSingleValue() const; - std::unique_ptr getSingleValue(); - const std::vector &getValues(); - -private: - std::unique_ptr _firstValue; - std::vector _values; - - void onPrimitive(uint32_t fid, const Content &fv) override; - std::unique_ptr getInternalValue(const FieldValue &fval) const; -}; - -IteratorHandler::IteratorHandler() { } -IteratorHandler::~IteratorHandler() { } - -bool -IteratorHandler::hasSingleValue() const { - return _firstValue.get() && (_values.size() == 0); -} - -std::unique_ptr -IteratorHandler::getSingleValue() { - return std::move(_firstValue); -} - -const std::vector& -IteratorHandler::getValues() { - if (_firstValue.get()) { - _values.insert(_values.begin(), ArrayValue::VariableValue(fieldvalue::VariableMap(), Value::SP(_firstValue.release()))); - } - - return _values; -} - -void -IteratorHandler::onPrimitive(uint32_t fid, const Content& fv) { - (void) fid; - if (!_firstValue && getVariables().empty()) { - _firstValue = getInternalValue(fv.getValue()); - } else { - _values.emplace_back(getVariables(), Value::SP(getInternalValue(fv.getValue()).release())); - } -} - -std::unique_ptr -IteratorHandler::getInternalValue(const FieldValue& fval) const -{ - switch(fval.getClass().id()) { - case document::IntFieldValue::classId: - { - const IntFieldValue& val(dynamic_cast(fval)); - return std::make_unique(val.getAsInt(), false); - } - case document::ByteFieldValue::classId: - { - const ByteFieldValue& val(dynamic_cast(fval)); - return std::make_unique(val.getAsByte(), false); - } - case LongFieldValue::classId: - { - const LongFieldValue& val(dynamic_cast(fval)); - return std::make_unique(val.getAsLong(), false); - } - case FloatFieldValue::classId: - { - const FloatFieldValue& val(dynamic_cast(fval)); - return std::make_unique(val.getAsFloat()); - } - case DoubleFieldValue::classId: - { - const DoubleFieldValue& val(dynamic_cast(fval)); - return std::make_unique(val.getAsDouble()); - } - case StringFieldValue::classId: - { - const StringFieldValue& val(dynamic_cast(fval)); - return std::make_unique(val.getAsString()); - } - case ArrayFieldValue::classId: - { - const ArrayFieldValue& val(dynamic_cast(fval)); - if (val.size() == 0) { - return std::make_unique(); - } else { - std::vector values; - // TODO: Array comparison. - return std::make_unique(values); - } - } - case StructFieldValue::classId: - { - const StructFieldValue& val(dynamic_cast(fval)); - if (val.empty()) { - return std::make_unique(); - } else { - StructValue::ValueMap values; - for (StructFieldValue::const_iterator it(val.begin()); it != val.end(); ++it) { - FieldValue::UP fv(val.getValue(it.field())); - values[it.field().getName()] = Value::SP(getInternalValue(*fv).release()); - } - return std::make_unique(values); - } - } - case MapFieldValue::classId: - { - const MapFieldValue& val(static_cast(fval)); - if (val.isEmpty()) { - return std::make_unique(); - } else { - std::vector values; - // TODO: Map comparison - return std::make_unique(values); - } - } - } - LOG(warning, "Tried to use unsupported datatype %s in field comparison", - fval.getDataType()->toString().c_str()); - return std::make_unique(); -} - -} - -void -FieldValueNode::initFieldPath(const DocumentType& type) const { - if (_fieldPath.size() == 0) { - FieldPath::UP path(type.buildFieldPath(_fieldExpression)); - if (!path.get()) { - throw FieldNotFoundException( - vespalib::make_string("Could not create field path for doc type: '%s' field: '%s'", - type.toString().c_str(), _fieldExpression.c_str()), - VESPA_STRLOC); - } - _fieldPath = *path; - } -} - -std::unique_ptr -FieldValueNode::getValue(const Context& context) const -{ - if (context._doc == NULL) { - return std::unique_ptr(new InvalidValue()); - } - - const Document& doc = *context._doc; - - if (!documentTypeEqualsName(doc.getType(), _doctype)) { - return std::unique_ptr(new InvalidValue()); - } - try{ - initFieldPath(doc.getType()); - - IteratorHandler handler; - doc.iterateNested(_fieldPath.getFullRange(), handler); - - if (handler.hasSingleValue()) { - return handler.getSingleValue(); - } else { - const std::vector& values = handler.getValues(); - - if (values.size() == 0) { - return std::unique_ptr(new NullValue()); - } else { - return std::unique_ptr(new ArrayValue(handler.getValues())); - } - } - } catch (vespalib::IllegalArgumentException& e) { - LOG(warning, "Caught exception while fetching field from document: %s", e.what()); - return std::unique_ptr(new InvalidValue()); - } catch (FieldNotFoundException& e) { - LOG(warning, "Tried to compare to field %s, not found in document type", _fieldExpression.c_str()); - return std::unique_ptr(new InvalidValue()); - } -} - -void -FieldValueNode::visit(Visitor &visitor) const -{ - visitor.visitFieldValueNode(*this); -} - - -void -FieldValueNode::print(std::ostream& out, bool verbose, - const std::string& indent) const -{ - (void) verbose; (void) indent; - if (hadParentheses()) out << '('; - out << _doctype << "." << _fieldExpression; - if (hadParentheses()) out << ')'; -} - - -std::unique_ptr -FieldValueNode::traceValue(const Context &context, std::ostream& out) const -{ - if (context._doc == NULL) { - return defaultTrace(getValue(context), out); - } - const Document &doc(*context._doc); - if (!documentTypeEqualsName(doc.getType(), _doctype)) { - out << "Document is of type " << doc.getType() << " which isn't a " - << _doctype << " document, thus resolving invalid.\n"; - return std::unique_ptr(new InvalidValue()); - } - try{ - initFieldPath(doc.getType()); - - IteratorHandler handler; - doc.iterateNested(_fieldPath.getFullRange(), handler); - - if (handler.hasSingleValue()) { - return handler.getSingleValue(); - } else { - const std::vector& values = handler.getValues(); - - if (values.size() == 0) { - return std::unique_ptr(new NullValue()); - } else { - return std::unique_ptr(new ArrayValue(handler.getValues())); - } - } - } catch (FieldNotFoundException& e) { - LOG(warning, "Tried to compare to field %s, not found in document type", - _fieldExpression.c_str()); - out << "Field not found in document type " << doc.getType() - << ". Returning invalid.\n"; - return std::unique_ptr(new InvalidValue()); - } -} - -IdValueNode::IdValueNode(const BucketIdFactory& bucketIdFactory, - const vespalib::stringref & name, const vespalib::stringref & type, - int widthBits, int divisionBits) - : _bucketIdFactory(bucketIdFactory), - _id(name), - _typestring(type), - _type(ALL), - _widthBits(widthBits), - _divisionBits(divisionBits) -{ - if (type.length() > 2) switch (type[0]) { - case 'b': _type = BUCKET; - break; - case 'n': _type = NS; - break; - case 'g': - if (type[1] == 'r') { - _type = GROUP; - } else if (type[1] == 'i') { - _type = GID; - } - break; - case 's': { - if (type[1] == 'c') { _type = SCHEME; } else { _type = SPEC; } - break; - } - case 't': - _type = TYPE; - break; - case 'u': - _type = USER; - break; - case 'o': - _type = ORDER; - break; - } -} - - -std::unique_ptr -IdValueNode::getValue(const Context& context) const -{ - if (context._doc != NULL) { - return getValue(context._doc->getId()); - } else if (context._docId != NULL) { - return getValue(*context._docId); - } else { - return getValue(context._docUpdate->getId()); - } -} - - -std::unique_ptr -IdValueNode::getValue(const DocumentId& id) const -{ - vespalib::string value; - switch (_type) { - case BUCKET: - return std::unique_ptr( - new IntegerValue( - _bucketIdFactory.getBucketId(id).getId(), true)); - case NS: - value = id.getScheme().getNamespace(); break; - case SCHEME: - value = id.getScheme().getTypeName(id.getScheme().getType()); - break; - case TYPE: - if (id.getScheme().hasDocType()) { - value = id.getScheme().getDocType(); - } else { - return std::unique_ptr(new InvalidValue); - } - break; - case SPEC: - value = id.getScheme().getNamespaceSpecific(); - break; - case ALL: - value = id.getScheme().toString(); - break; - case GROUP: - if (id.getScheme().hasGroup()) { - value = id.getScheme().getGroup(); - } else { - fprintf(stderr, "***** Returning invalid value for %s\n", - id.toString().c_str()); - return std::unique_ptr(new InvalidValue); - } - break; - case GID: - value = id.getGlobalId().toString(); - break; - case ORDER: - if (id.getScheme().getType() == IdString::ORDERDOC) { - const OrderDocIdString& ods( - static_cast(id.getScheme())); - if (ods.getWidthBits() == _widthBits - && ods.getDivisionBits() == _divisionBits) - { - return std::unique_ptr(new IntegerValue( - static_cast(id.getScheme()) - .getOrdering(), false)); - } - } - return std::unique_ptr(new InvalidValue()); - case USER: - if (id.getScheme().hasNumber()) { - return std::unique_ptr( - new IntegerValue(id.getScheme().getNumber(), false)); - } else { - return std::unique_ptr(new InvalidValue); - } - } - - return std::unique_ptr(new StringValue(value)); -} - - -std::unique_ptr -IdValueNode::traceValue(const Context& context, - std::ostream &out) const -{ - if (context._doc != NULL) { - return traceValue(context._doc->getId(), out); - } else if (context._docId != NULL) { - return traceValue(*context._docId, out); - } else { - return traceValue(context._docUpdate->getId(), out); - } -} - - -std::unique_ptr -IdValueNode::traceValue(const DocumentId& id, std::ostream& out) const -{ - vespalib::string value; - switch (_type) { - case BUCKET: - { - document::BucketId bucket(_bucketIdFactory.getBucketId(id)); - std::unique_ptr result( - new IntegerValue(bucket.getId(), true)); - out << "Found id.bucket specification. Resolved to " - << bucket.toString() << ".\n"; - return result; - } - case NS: - value = id.getScheme().getNamespace(); - out << "Resolved id.namespace to value\"" << value << "\".\n"; - break; - case SCHEME: - value = id.getScheme().getTypeName(id.getScheme().getType()); - out << "Resolved id.scheme to value\"" << value << "\".\n"; - break; - case TYPE: - if (id.getScheme().hasDocType()) { - value = id.getScheme().getDocType(); - out << "Resolved id.type to value\"" << value << "\".\n"; - } else { - out << "Could not resolve type of doc " << id << ".\n"; - return std::unique_ptr(new InvalidValue); - } - break; - case SPEC: - value = id.getScheme().getNamespaceSpecific(); - out << "Resolved id.specific to value\"" << value << "\".\n"; - break; - case ALL: - value = id.getScheme().toString(); - out << "Resolved id to \"" << value << "\".\n"; - break; - case GROUP: - if (id.getScheme().hasGroup()) { - value = id.getScheme().getGroup(); - out << "Resolved group of doc (type " << id.getScheme().getType() - << ") to \"" << value << "\".\n"; - } else { - out << "Can't resolve group of doc \"" << id << "\".\n"; - return std::unique_ptr(new InvalidValue); - } - break; - case GID: - value = id.getGlobalId().toString(); - out << "Resolved gid to \"" << value << "\".\n"; - break; - case ORDER: - if (id.getScheme().getType() == IdString::ORDERDOC) { - const OrderDocIdString& ods( - static_cast(id.getScheme())); - if (ods.getWidthBits() == _widthBits - && ods.getDivisionBits() == _divisionBits) - { - std::unique_ptr result(new IntegerValue( - static_cast(id.getScheme()) - .getOrdering(), false)); - out << "Resolved id.order to int " << *result << "\n"; - return result; - } - } - out << "Could not resolve id.order(" << _widthBits << ", " - << _divisionBits << ") of doc " << id << ".\n"; - return std::unique_ptr(new InvalidValue()); - case USER: - if (id.getScheme().hasNumber()) { - std::unique_ptr result( - new IntegerValue(id.getScheme().getNumber(), false)); - out << "Resolved user of doc type " << id.getScheme().getType() - << " to " << *result << ".\n"; - return result; - } else { - out << "Could not resolve user of doc " << id << ".\n"; - return std::unique_ptr(new InvalidValue); - } - } - - return std::unique_ptr(new StringValue(value)); -} - - -void -IdValueNode::visit(Visitor &visitor) const -{ - visitor.visitIdValueNode(*this); -} - - -void -IdValueNode::print(std::ostream& out, bool verbose, - const std::string& indent) const -{ - (void) verbose; (void) indent; - if (hadParentheses()) out << '('; - out << _id; - if (_type != ALL) { - out << '.' << _typestring; - } - if (_type == ORDER) { - out << "(" << _widthBits << "," << _divisionBits << ")"; - } - if (hadParentheses()) out << ')'; -} - -SearchColumnValueNode::SearchColumnValueNode( - const BucketIdFactory& bucketIdFactory, - const vespalib::stringref & name, int numColumns) - : _bucketIdFactory(bucketIdFactory), - _id(name), - _numColumns(numColumns), - _distribution(_numColumns, 16) -{ -} - -int64_t -SearchColumnValueNode::getValue(const BucketId& id) const -{ - return _distribution.getColumn(id); -} - - -std::unique_ptr -SearchColumnValueNode::getValue(const Context& context) const -{ - if (context._doc != NULL) { - return getValue(context._doc->getId()); - } else if (context._docId != NULL) { - return getValue(*context._docId); - } else { - return getValue(context._docUpdate->getId()); - } -} - - -std::unique_ptr -SearchColumnValueNode::getValue(const DocumentId& id) const -{ - return std::unique_ptr(new IntegerValue( - getValue(_bucketIdFactory.getBucketId(id)), false)); -} - - -std::unique_ptr -SearchColumnValueNode::traceValue(const Context& context, - std::ostream &out) const -{ - if (context._doc != NULL) { - return traceValue(context._doc->getId(), out); - } else if (context._docId != NULL) { - return traceValue(*context._docId, out); - } else { - return traceValue(context._docUpdate->getId(), out); - } -} - - -std::unique_ptr -SearchColumnValueNode::traceValue(const DocumentId& id, - std::ostream& out) const -{ - std::unique_ptr result(new IntegerValue( - getValue(_bucketIdFactory.getBucketId(id)), false)); - out << "Resolved search column of doc \"" << id << "\" to " << *result - << "\n"; - return result; -} - - -void -SearchColumnValueNode::visit(Visitor &visitor) const -{ - visitor.visitSearchColumnValueNode(*this); -} - - -void -SearchColumnValueNode::print(std::ostream& out, bool verbose, - const std::string& indent) const -{ - (void) verbose; (void) indent; - if (hadParentheses()) out << '('; - out << _id; - out << '.' << _numColumns; - if (hadParentheses()) out << ')'; -} - -namespace { - union HashUnion { - unsigned char _key[16]; - int64_t _hash[2]; - }; - int64_t hash(const void* data, uint32_t len) { - HashUnion hash; - fastc_md5sum((const unsigned char*) data, len, hash._key); - return hash._hash[0]; - } -} - -FunctionValueNode::FunctionValueNode(const vespalib::stringref & name, - std::unique_ptr src) - : _function(), - _funcname(name), - _source(std::move(src)) -{ - if (name == "lowercase") { - _function = LOWERCASE; - } else if (name == "hash") { - _function = HASH; - } else if (name == "abs") { - _function = ABS; - } else { - throw ParsingFailedException("No function '"+name+"' exist.", - VESPA_STRLOC); - } -} - -std::unique_ptr -FunctionValueNode::getValue(std::unique_ptr val) const -{ - switch (val->getType()) { - case Value::String: - { - StringValue& sval(static_cast(*val)); - if (_function == LOWERCASE) { - return std::unique_ptr(new StringValue( - vespalib::LowerCase::convert(sval.getValue()))); - } else if (_function == HASH) { - return std::unique_ptr(new IntegerValue( - hash(sval.getValue().c_str(), sval.getValue().size()), - false)); - } - break; - } - case Value::Float: - { - FloatValue& fval(static_cast(*val)); - if (_function == HASH) { - FloatValue::ValueType ffval = fval.getValue(); - return std::unique_ptr(new IntegerValue( - hash(&ffval, sizeof(ffval)), false)); - } else if (_function == ABS) { - FloatValue::ValueType ffval = fval.getValue(); - if (ffval < 0) ffval *= -1; - return std::unique_ptr(new FloatValue(ffval)); - } - break; - } - case Value::Integer: - { - IntegerValue& ival(static_cast(*val)); - if (_function == HASH) { - IntegerValue::ValueType iival = ival.getValue(); - return std::unique_ptr(new IntegerValue( - hash(&iival, sizeof(iival)), false)); - } else if (_function == ABS) { - IntegerValue::ValueType iival = ival.getValue(); - if (iival < 0) iival *= -1; - return std::unique_ptr(new IntegerValue(iival, false)); - } - break; - } - case Value::Bucket: - { - throw ParsingFailedException( - "No functioncalls are allowed on value of type bucket", - VESPA_STRLOC); - break; - } - - case Value::Array: break; - case Value::Struct: break; - case Value::Invalid: break; - case Value::Null: break; - } - return std::unique_ptr(new InvalidValue); -} - -std::unique_ptr -FunctionValueNode::traceValue(std::unique_ptr val, - std::ostream& out) const -{ - switch (val->getType()) { - case Value::String: - { - StringValue& sval(static_cast(*val)); - if (_function == LOWERCASE) { - std::unique_ptr result(new StringValue( - vespalib::LowerCase::convert(sval.getValue()))); - out << "Performed lowercase function on '" << sval - << "' => '" << *result << "'.\n"; - return result; - } else if (_function == HASH) { - std::unique_ptr result(new IntegerValue( - hash(sval.getValue().c_str(), sval.getValue().size()), - false)); - out << "Performed hash on string '" << sval << "' -> " - << *result << "\n"; - return result; - } - break; - } - case Value::Float: - { - FloatValue& fval(static_cast(*val)); - if (_function == HASH) { - FloatValue::ValueType ffval = fval.getValue(); - std::unique_ptr result(new IntegerValue( - hash(&ffval, sizeof(ffval)), false)); - out << "Performed hash on float " << ffval << " -> " << *result - << "\n"; - return result; - } else if (_function == ABS) { - FloatValue::ValueType ffval = fval.getValue(); - if (ffval < 0) ffval *= -1; - out << "Performed abs on float " << fval.getValue() << " -> " - << ffval << "\n"; - return std::unique_ptr(new FloatValue(ffval)); - } - break; - } - case Value::Integer: - { - IntegerValue& ival(static_cast(*val)); - if (_function == HASH) { - IntegerValue::ValueType iival = ival.getValue(); - std::unique_ptr result(new IntegerValue( - hash(&iival, sizeof(iival)), false)); - out << "Performed hash on float " << iival << " -> " << *result - << "\n"; - return result; - } else if (_function == ABS) { - IntegerValue::ValueType iival = ival.getValue(); - if (iival < 0) iival *= -1; - out << "Performed abs on integer " << ival.getValue() << " -> " - << iival << "\n"; - return std::unique_ptr(new IntegerValue(iival, false)); - } - break; - } - case Value::Bucket: break; - case Value::Array: break; - case Value::Struct: break; - case Value::Invalid: break; - case Value::Null: break; - } - out << "Cannot use function " << _function << " on a value of type " - << val->getType() << ". Resolving invalid.\n"; - return std::unique_ptr(new InvalidValue); -} - - -void -FunctionValueNode::visit(Visitor &visitor) const -{ - visitor.visitFunctionValueNode(*this); -} - - -void -FunctionValueNode::print(std::ostream& out, bool verbose, - const std::string& indent) const -{ - if (hadParentheses()) out << '('; - _source->print(out, verbose, indent); - out << '.' << _funcname << "()"; - if (hadParentheses()) out << ')'; -} - -ArithmeticValueNode::ArithmeticValueNode( - std::unique_ptr left, const vespalib::stringref & op, - std::unique_ptr right) - : _operator(), - _left(std::move(left)), - _right(std::move(right)) -{ - if (op.size() == 1) switch (op[0]) { - case '+': _operator = ADD; return; - case '-': _operator = SUB; return; - case '*': _operator = MUL; return; - case '/': _operator = DIV; return; - case '%': _operator = MOD; return; - } - throw ParsingFailedException( - "Arithmetic operator '"+op+"' does not exist.", VESPA_STRLOC); -} - -const char* -ArithmeticValueNode::getOperatorName() const -{ - switch (_operator) { - case ADD: return "+"; - case SUB: return "-"; - case MUL: return "*"; - case DIV: return "/"; - case MOD: return "%"; - } - return "UNKNOWN"; -} - - - -std::unique_ptr -ArithmeticValueNode::getValue(std::unique_ptr lval, - std::unique_ptr rval) const -{ - switch (_operator) { - case ADD: - { - if (lval->getType() == Value::String && - rval->getType() == Value::String) - { - StringValue& slval(static_cast(*lval)); - StringValue& srval(static_cast(*rval)); - return std::unique_ptr(new StringValue( - slval.getValue() + srval.getValue())); - } - } - case SUB: - case MUL: - case DIV: - { - if (lval->getType() == Value::Integer && - rval->getType() == Value::Integer) - { - IntegerValue& ilval(static_cast(*lval)); - IntegerValue& irval(static_cast(*rval)); - IntegerValue::ValueType res = 0; - switch (_operator) { - case ADD: res = ilval.getValue() + irval.getValue(); break; - case SUB: res = ilval.getValue() - irval.getValue(); break; - case MUL: res = ilval.getValue() * irval.getValue(); break; - case DIV: - if (irval.getValue() != 0) { - res = ilval.getValue() / irval.getValue(); - } else { - throw vespalib::IllegalArgumentException("Division by zero"); - } - break; - case MOD: assert(0); - } - return std::unique_ptr(new IntegerValue(res, false)); - } - NumberValue* nlval(dynamic_cast(lval.get())); - NumberValue* nrval(dynamic_cast(rval.get())); - if (nlval != 0 && nrval != 0) { - NumberValue::CommonValueType res = 0; - switch (_operator) { - case ADD: res = nlval->getCommonValue() - + nrval->getCommonValue(); break; - case SUB: res = nlval->getCommonValue() - - nrval->getCommonValue(); break; - case MUL: res = nlval->getCommonValue() - * nrval->getCommonValue(); break; - case DIV: - if (nrval->getCommonValue() != 0) { - res = nlval->getCommonValue() - / nrval->getCommonValue(); - } else { - throw vespalib::IllegalArgumentException("Division by zero"); - } - break; - case MOD: assert(0); - } - return std::unique_ptr(new FloatValue(res)); - } - } - case MOD: - { - if (lval->getType() == Value::Integer && - rval->getType() == Value::Integer) - { - IntegerValue& ilval(static_cast(*lval)); - IntegerValue& irval(static_cast(*rval)); - if (irval.getValue() != 0) { - return std::unique_ptr(new IntegerValue(ilval.getValue() % irval.getValue(), false)); - } else { - throw vespalib::IllegalArgumentException("Division by zero"); - } - } - } - } - return std::unique_ptr(new InvalidValue); -} - -std::unique_ptr -ArithmeticValueNode::traceValue(std::unique_ptr lval, - std::unique_ptr rval, - std::ostream& out) const -{ - switch (_operator) { - case ADD: - { - if (lval->getType() == Value::String && - rval->getType() == Value::String) - { - StringValue& slval(static_cast(*lval)); - StringValue& srval(static_cast(*rval)); - std::unique_ptr result(new StringValue( - slval.getValue() + srval.getValue())); - out << "Appended strings '" << slval << "' + '" << srval - << "' -> '" << *result << "'.\n"; - return result; - } - } - case SUB: - case MUL: - case DIV: - { - if (lval->getType() == Value::Integer && - rval->getType() == Value::Integer) - { - IntegerValue& ilval(static_cast(*lval)); - IntegerValue& irval(static_cast(*rval)); - IntegerValue::ValueType res = 0; - switch (_operator) { - case ADD: res = ilval.getValue() + irval.getValue(); break; - case SUB: res = ilval.getValue() - irval.getValue(); break; - case MUL: res = ilval.getValue() * irval.getValue(); break; - case DIV: res = ilval.getValue() / irval.getValue(); break; - case MOD: assert(0); - } - std::unique_ptr result(new IntegerValue(res, false)); - out << "Performed integer operation " << ilval << " " - << getOperatorName() << " " << irval << " = " << *result - << "\n"; - return result; - } - NumberValue* nlval(dynamic_cast(lval.get())); - NumberValue* nrval(dynamic_cast(lval.get())); - if (nlval != 0 && nrval != 0) { - NumberValue::CommonValueType res = 0; - switch (_operator) { - case ADD: res = nlval->getCommonValue() - + nrval->getCommonValue(); break; - case SUB: res = nlval->getCommonValue() - - nrval->getCommonValue(); break; - case MUL: res = nlval->getCommonValue() - * nrval->getCommonValue(); break; - case DIV: res = nlval->getCommonValue() - / nrval->getCommonValue(); break; - case MOD: assert(0); - } - std::unique_ptr result(new FloatValue(res)); - out << "Performed float operation " << nlval << " " - << getOperatorName() << " " << nrval << " = " << *result - << "\n"; - return result; - } - } - case MOD: - { - if (lval->getType() == Value::Integer && - rval->getType() == Value::Integer) - { - IntegerValue& ilval(static_cast(*lval)); - IntegerValue& irval(static_cast(*rval)); - std::unique_ptr result(new IntegerValue( - ilval.getValue() % irval.getValue(), false)); - out << "Performed integer operation " << ilval << " " - << getOperatorName() << " " << irval << " = " << *result - << "\n"; - return result; - } - } - } - out << "Failed to do operation " << getOperatorName() - << " on values of type " << lval->getType() << " and " - << rval->getType() << ". Resolving invalid.\n"; - return std::unique_ptr(new InvalidValue); -} - - -void -ArithmeticValueNode::visit(Visitor &visitor) const -{ - visitor.visitArithmeticValueNode(*this); -} - - -void -ArithmeticValueNode::print(std::ostream& out, bool verbose, - const std::string& indent) const -{ - if (hadParentheses()) out << '('; - _left->print(out, verbose, indent); - switch (_operator) { - case ADD: out << " + "; break; - case SUB: out << " - "; break; - case MUL: out << " * "; break; - case DIV: out << " / "; break; - case MOD: out << " % "; break; - } - _right->print(out, verbose, indent); - if (hadParentheses()) out << ')'; } -} // select -} // document diff --git a/document/src/vespa/document/select/valuenode.h b/document/src/vespa/document/select/valuenode.h index 8aae23cb1e4..f36085f769d 100644 --- a/document/src/vespa/document/select/valuenode.h +++ b/document/src/vespa/document/select/valuenode.h @@ -13,18 +13,11 @@ #pragma once #include "value.h" -#include "context.h" -#include -#include -#include -#include -namespace document { +namespace document::select { -class Document; -class Field; - -namespace select { +class Context; +class Visitor; class ValueNode : public Printable { @@ -38,17 +31,10 @@ public: void clearParentheses() { _parentheses = false; } bool hadParentheses() const { return _parentheses; } - virtual std::unique_ptr - getValue(const Context& context) const = 0; - - virtual std::unique_ptr - traceValue(const Context &context, std::ostream &out) const { - return defaultTrace(getValue(context), out); - } - - virtual void print(std::ostream& out, bool verbose, const std::string& indent) const override = 0; + virtual std::unique_ptr getValue(const Context& context) const = 0; virtual void visit(Visitor&) const = 0; virtual ValueNode::UP clone() const = 0; + virtual std::unique_ptr traceValue(const Context &context, std::ostream &out) const; private: bool _parentheses; // Set to true if parentheses was used around this part // Set such that we can recreate original query in print. @@ -64,324 +50,5 @@ protected: std::unique_ptr defaultTrace(std::unique_ptr val, std::ostream& out) const; }; -class InvalidValueNode : public ValueNode -{ - vespalib::string _name; -public: - InvalidValueNode(const vespalib::stringref & name); - - std::unique_ptr getValue(const Context&) const override { - return std::unique_ptr(new InvalidValue()); - } - - void print(std::ostream& out, bool verbose, const std::string& indent) const override; - void visit(Visitor& visitor) const override; - - ValueNode::UP clone() const override { - return wrapParens(new InvalidValueNode(_name)); - } -}; - -class NullValueNode : public ValueNode -{ - vespalib::string _name; -public: - NullValueNode(const vespalib::stringref & name); - - std::unique_ptr getValue(const Context&) const override { - return std::unique_ptr(new NullValue()); - } - - void print(std::ostream& out, bool verbose, const std::string& indent) const override; - - void visit(Visitor& visitor) const override; - - ValueNode::UP clone() const override { - return wrapParens(new NullValueNode(_name)); - } -}; - -class StringValueNode : public ValueNode -{ - vespalib::string _value; -public: - StringValueNode(const vespalib::stringref & val); - - const vespalib::string& getValue() const { return _value; } - - std::unique_ptr getValue(const Context&) const override { - return std::unique_ptr(new StringValue(_value)); - } - - void print(std::ostream& out, bool verbose, const std::string& indent) const override; - void visit(Visitor& visitor) const override; - - ValueNode::UP clone() const override { - return wrapParens(new StringValueNode(_value)); - } -}; - -class IntegerValueNode : public ValueNode -{ - int64_t _value; - bool _isBucketValue; -public: - IntegerValueNode(int64_t val, bool isBucketValue) - : _value(val), _isBucketValue(isBucketValue) {} - - int64_t getValue() const { return _value; } - - virtual std::unique_ptr getValue(const Context&) const override { - return std::unique_ptr(new IntegerValue(_value, _isBucketValue)); - } - - void print(std::ostream& out, bool verbose, const std::string& indent) const override; - void visit(Visitor& visitor) const override; - - ValueNode::UP clone() const override { - return wrapParens(new IntegerValueNode(_value, _isBucketValue)); - } -}; - -class CurrentTimeValueNode : public ValueNode -{ -public: - int64_t getValue() const; - - std::unique_ptr getValue(const Context&) const override { - return std::unique_ptr(new IntegerValue(getValue(), false)); - } - - void print(std::ostream& out, bool verbose, const std::string& indent) const override; - void visit(Visitor& visitor) const override; - - ValueNode::UP clone() const override { - return wrapParens(new CurrentTimeValueNode); - } -}; - -class VariableValueNode : public ValueNode -{ - vespalib::string _value; -public: - VariableValueNode(const vespalib::string & variableName) : _value(variableName) {} - - const vespalib::string& getVariableName() const { return _value; } - - std::unique_ptr getValue(const Context& context) const override; - void print(std::ostream& out, bool verbose, const std::string& indent) const override; - void visit(Visitor& visitor) const override; - - ValueNode::UP clone() const override { - return wrapParens(new VariableValueNode(_value)); - } -}; - -class FloatValueNode : public ValueNode -{ - double _value; -public: - FloatValueNode(double val) : _value(val) {} - - double getValue() const { return _value; } - - std::unique_ptr getValue(const Context&) const override { - return std::unique_ptr(new FloatValue(_value)); - } - - void print(std::ostream& out, bool verbose, const std::string& indent) const override; - void visit(Visitor& visitor) const override; - - ValueNode::UP clone() const override { - return wrapParens(new FloatValueNode(_value)); - } -}; - -class FieldValueNode : public ValueNode -{ - vespalib::string _doctype; - vespalib::string _fieldExpression; - vespalib::string _fieldName; - mutable FieldPath _fieldPath; - -public: - FieldValueNode(const vespalib::string& doctype, const vespalib::string& fieldExpression); - FieldValueNode(const FieldValueNode &); - FieldValueNode & operator = (const FieldValueNode &); - FieldValueNode(FieldValueNode &&) = default; - FieldValueNode & operator = (FieldValueNode &&) = default; - ~FieldValueNode(); - - const vespalib::string& getDocType() const { return _doctype; } - const vespalib::string& getRealFieldName() const { return _fieldName; } - const vespalib::string& getFieldName() const { return _fieldExpression; } - - std::unique_ptr getValue(const Context& context) const override; - std::unique_ptr traceValue(const Context &context, std::ostream& out) const override; - void print(std::ostream& out, bool verbose, const std::string& indent) const override; - void visit(Visitor& visitor) const override; - - ValueNode::UP clone() const override { - return wrapParens(new FieldValueNode(_doctype, _fieldExpression)); - } - - static vespalib::string extractFieldName(const std::string & fieldExpression); - -private: - - void initFieldPath(const DocumentType&) const; -}; - -class IdValueNode : public ValueNode -{ -public: - enum Type { SCHEME, NS, TYPE, USER, GROUP, GID, SPEC, BUCKET, ORDER, ALL }; - - IdValueNode(const BucketIdFactory& bucketIdFactory, - const vespalib::stringref & name, const vespalib::stringref & type, - int widthBits = -1, int divisionBits = -1); - - Type getType() const { return _type; } - - std::unique_ptr getValue(const Context& context) const override; - - std::unique_ptr getValue(const DocumentId& id) const; - - std::unique_ptr traceValue(const Context& context, std::ostream &out) const override; - - std::unique_ptr traceValue(const DocumentId& val, std::ostream& out) const; - - void print(std::ostream& out, bool verbose, const std::string& indent) const override; - - void visit(Visitor& visitor) const override; - - ValueNode::UP clone() const override { - return wrapParens(new IdValueNode(_bucketIdFactory, _id, _typestring, _widthBits, _divisionBits)); - } - - int getWidthBits() const { return _widthBits; } - int getDivisionBits() const { return _divisionBits; } - -private: - const BucketIdFactory& _bucketIdFactory; - vespalib::string _id; - vespalib::string _typestring; - Type _type; - int _widthBits; - int _divisionBits; -}; - -class SearchColumnValueNode : public ValueNode -{ -public: - SearchColumnValueNode(const BucketIdFactory& bucketIdFactory, - const vespalib::stringref & name, - int numColumns); - - int getColumns() { return _numColumns; } - - std::unique_ptr getValue(const Context& context) const override; - std::unique_ptr getValue(const DocumentId& id) const; - std::unique_ptr traceValue(const Context& context, std::ostream &out) const override; - std::unique_ptr traceValue(const DocumentId& val, std::ostream& out) const; - - int64_t getValue(const BucketId& bucketId) const; - void print(std::ostream& out, bool verbose, const std::string& indent) const override; - void visit(Visitor& visitor) const override; - - ValueNode::UP clone() const override { - return wrapParens(new SearchColumnValueNode(_bucketIdFactory, _id, _numColumns)); } -private: - const BucketIdFactory& _bucketIdFactory; - vespalib::string _id; - int _numColumns; - BucketDistribution _distribution; -}; - -class FunctionValueNode : public ValueNode -{ -public: - enum Function { LOWERCASE, HASH, ABS }; - - FunctionValueNode(const vespalib::stringref & name, std::unique_ptr src); - - Function getFunction() const { return _function; } - const vespalib::string &getFunctionName(void) const { return _funcname; } - - std::unique_ptr getValue(const Context& context) const override { - return getValue(_source->getValue(context)); - } - - std::unique_ptr traceValue(const Context &context, std::ostream& out) const override { - return traceValue(_source->getValue(context), out); - } - - void print(std::ostream& out, bool verbose, const std::string& indent) const override; - void visit(Visitor& visitor) const override; - - ValueNode::UP clone() const override { - return wrapParens(new FunctionValueNode(_funcname, _source->clone())); - } - - const ValueNode& getChild() const { return *_source; } - -private: - Function _function; - vespalib::string _funcname; - std::unique_ptr _source; - - virtual std::unique_ptr getValue(std::unique_ptr val) const; - virtual std::unique_ptr traceValue(std::unique_ptr val, - std::ostream& out) const; -}; - -class ArithmeticValueNode : public ValueNode -{ -public: - enum Operator { ADD, SUB, MUL, DIV, MOD }; - - ArithmeticValueNode(std::unique_ptr left, - const vespalib::stringref & op, - std::unique_ptr right); - - Operator getOperator() const { return _operator; } - const char* getOperatorName() const; - - std::unique_ptr - getValue(const Context& context) const override { - return getValue(_left->getValue(context), _right->getValue(context)); - } - - std::unique_ptr - traceValue(const Context &context, std::ostream& out) const override { - return traceValue(_left->getValue(context), _right->getValue(context), out); - } - - void print(std::ostream& out, bool verbose, const std::string& indent) const override; - void visit(Visitor& visitor) const override; - - ValueNode::UP clone() const override { - return wrapParens(new ArithmeticValueNode(_left->clone(), - getOperatorName(), - _right->clone())); - } - - const ValueNode& getLeft() const { return *_left; } - const ValueNode& getRight() const { return *_right; } - -private: - Operator _operator; - std::unique_ptr _left; - std::unique_ptr _right; - - virtual std::unique_ptr getValue(std::unique_ptr lval, - std::unique_ptr rval) const; - virtual std::unique_ptr traceValue(std::unique_ptr lval, - std::unique_ptr rval, - std::ostream&) const; -}; - -} // select -} // document diff --git a/document/src/vespa/document/select/valuenodes.cpp b/document/src/vespa/document/select/valuenodes.cpp new file mode 100644 index 00000000000..3a4edbef093 --- /dev/null +++ b/document/src/vespa/document/select/valuenodes.cpp @@ -0,0 +1,1183 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include "valuenodes.h" +#include "visitor.h" +#include "parser.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +LOG_SETUP(".document.select.valuenode"); + +namespace document::select { + +namespace { + static const std::regex FIELD_NAME_REGEX("^([_A-Za-z][_A-Za-z0-9]*).*"); +} + +namespace { + bool documentTypeEqualsName(const DocumentType& type, const vespalib::stringref& name) + { + if (type.getName() == name) return true; + for (std::vector::const_iterator it + = type.getInheritedTypes().begin(); + it != type.getInheritedTypes().end(); ++it) + { + if (documentTypeEqualsName(**it, name)) return true; + } + return false; + } +} + +InvalidValueNode::InvalidValueNode(const vespalib::stringref & name) + : _name(name) +{ } + + +void +InvalidValueNode::visit(Visitor &visitor) const +{ + visitor.visitInvalidValueNode(*this); +} + + +void +InvalidValueNode::print(std::ostream& out, bool verbose, + const std::string& indent) const +{ + (void) verbose; (void) indent; + if (hadParentheses()) out << '('; + out << _name; + if (hadParentheses()) out << ')'; +} + +NullValueNode::NullValueNode(const vespalib::stringref & name) + : _name(name) +{ } + + +void +NullValueNode::visit(Visitor &visitor) const +{ + visitor.visitNullValueNode(*this); +} + + +void +NullValueNode::print(std::ostream& out, bool verbose, + const std::string& indent) const +{ + (void) verbose; (void) indent; + if (hadParentheses()) out << '('; + out << _name; + if (hadParentheses()) out << ')'; +} + +StringValueNode::StringValueNode(const vespalib::stringref & val) + : _value(val) +{ +} + + +void +StringValueNode::visit(Visitor &visitor) const +{ + visitor.visitStringValueNode(*this); +} + + +void +StringValueNode::print(std::ostream& out, bool verbose, + const std::string& indent) const +{ + (void) verbose; (void) indent; + if (hadParentheses()) out << '('; + out << "\"" << StringUtil::escape(_value) << "\""; + if (hadParentheses()) out << ')'; +} + + +void +IntegerValueNode::visit(Visitor &visitor) const +{ + visitor.visitIntegerValueNode(*this); +} + + +void +IntegerValueNode::print(std::ostream& out, bool verbose, + const std::string& indent) const +{ + (void) verbose; (void) indent; + if (hadParentheses()) out << '('; + out << _value; + if (hadParentheses()) out << ')'; +} + +int64_t +CurrentTimeValueNode::getValue() const +{ + struct timeval mytime; + gettimeofday(&mytime, 0); + return mytime.tv_sec; +} + + +void +CurrentTimeValueNode::visit(Visitor &visitor) const +{ + visitor.visitCurrentTimeValueNode(*this); +} + + +void +CurrentTimeValueNode::print(std::ostream& out, bool verbose, + const std::string& indent) const +{ + (void) verbose; (void) indent; + out << "now()"; +} + +std::unique_ptr +VariableValueNode::getValue(const Context& context) const { + return context.getValue(_value); +} + +void +VariableValueNode::visit(Visitor &visitor) const +{ + visitor.visitVariableValueNode(*this); +} + + +void +VariableValueNode::print(std::ostream& out, bool verbose, + const std::string& indent) const +{ + (void) verbose; (void) indent; + if (hadParentheses()) out << '('; + out << "$" << _value; + if (hadParentheses()) out << ')'; +} + + +void +FloatValueNode::visit(Visitor &visitor) const +{ + visitor.visitFloatValueNode(*this); +} + + +void +FloatValueNode::print(std::ostream& out, bool verbose, + const std::string& indent) const +{ + (void) verbose; (void) indent; + if (hadParentheses()) out << '('; + out << _value; + if (hadParentheses()) out << ')'; +} + +FieldValueNode::FieldValueNode(const vespalib::string& doctype, + const vespalib::string& fieldExpression) + : _doctype(doctype), + _fieldExpression(fieldExpression), + _fieldName(extractFieldName(fieldExpression)) +{ +} + +FieldValueNode::FieldValueNode(const FieldValueNode &) = default; +FieldValueNode & FieldValueNode::operator = (const FieldValueNode &) = default; + +FieldValueNode::~FieldValueNode() {} +vespalib::string +FieldValueNode::extractFieldName(const std::string & fieldExpression) { + std::smatch match; + + if (std::regex_match(fieldExpression, match, FIELD_NAME_REGEX) && match[1].matched) { + return vespalib::string(match[1].first, match[1].second); + } + + throw ParsingFailedException("Fatal: could not extract field name from field expression '" + fieldExpression + "'"); +} + +namespace { + +class IteratorHandler : public fieldvalue::IteratorHandler { +public: + IteratorHandler(); + ~IteratorHandler(); + bool hasSingleValue() const; + std::unique_ptr getSingleValue(); + const std::vector &getValues(); + +private: + std::unique_ptr _firstValue; + std::vector _values; + + void onPrimitive(uint32_t fid, const Content &fv) override; + std::unique_ptr getInternalValue(const FieldValue &fval) const; +}; + +IteratorHandler::IteratorHandler() { } +IteratorHandler::~IteratorHandler() { } + +bool +IteratorHandler::hasSingleValue() const { + return _firstValue.get() && (_values.size() == 0); +} + +std::unique_ptr +IteratorHandler::getSingleValue() { + return std::move(_firstValue); +} + +const std::vector& +IteratorHandler::getValues() { + if (_firstValue.get()) { + _values.insert(_values.begin(), ArrayValue::VariableValue(fieldvalue::VariableMap(), Value::SP(_firstValue.release()))); + } + + return _values; +} + +void +IteratorHandler::onPrimitive(uint32_t fid, const Content& fv) { + (void) fid; + if (!_firstValue && getVariables().empty()) { + _firstValue = getInternalValue(fv.getValue()); + } else { + _values.emplace_back(getVariables(), Value::SP(getInternalValue(fv.getValue()).release())); + } +} + +std::unique_ptr +IteratorHandler::getInternalValue(const FieldValue& fval) const +{ + switch(fval.getClass().id()) { + case document::IntFieldValue::classId: + { + const IntFieldValue& val(dynamic_cast(fval)); + return std::make_unique(val.getAsInt(), false); + } + case document::ByteFieldValue::classId: + { + const ByteFieldValue& val(dynamic_cast(fval)); + return std::make_unique(val.getAsByte(), false); + } + case LongFieldValue::classId: + { + const LongFieldValue& val(dynamic_cast(fval)); + return std::make_unique(val.getAsLong(), false); + } + case FloatFieldValue::classId: + { + const FloatFieldValue& val(dynamic_cast(fval)); + return std::make_unique(val.getAsFloat()); + } + case DoubleFieldValue::classId: + { + const DoubleFieldValue& val(dynamic_cast(fval)); + return std::make_unique(val.getAsDouble()); + } + case StringFieldValue::classId: + { + const StringFieldValue& val(dynamic_cast(fval)); + return std::make_unique(val.getAsString()); + } + case ArrayFieldValue::classId: + { + const ArrayFieldValue& val(dynamic_cast(fval)); + if (val.size() == 0) { + return std::make_unique(); + } else { + std::vector values; + // TODO: Array comparison. + return std::make_unique(values); + } + } + case StructFieldValue::classId: + { + const StructFieldValue& val(dynamic_cast(fval)); + if (val.empty()) { + return std::make_unique(); + } else { + StructValue::ValueMap values; + for (StructFieldValue::const_iterator it(val.begin()); it != val.end(); ++it) { + FieldValue::UP fv(val.getValue(it.field())); + values[it.field().getName()] = Value::SP(getInternalValue(*fv).release()); + } + return std::make_unique(values); + } + } + case MapFieldValue::classId: + { + const MapFieldValue& val(static_cast(fval)); + if (val.isEmpty()) { + return std::make_unique(); + } else { + std::vector values; + // TODO: Map comparison + return std::make_unique(values); + } + } + } + LOG(warning, "Tried to use unsupported datatype %s in field comparison", + fval.getDataType()->toString().c_str()); + return std::make_unique(); +} + +} + +void +FieldValueNode::initFieldPath(const DocumentType& type) const { + if (_fieldPath.size() == 0) { + FieldPath::UP path(type.buildFieldPath(_fieldExpression)); + if (!path.get()) { + throw FieldNotFoundException( + vespalib::make_string("Could not create field path for doc type: '%s' field: '%s'", + type.toString().c_str(), _fieldExpression.c_str()), + VESPA_STRLOC); + } + _fieldPath = *path; + } +} + +std::unique_ptr +FieldValueNode::getValue(const Context& context) const +{ + if (context._doc == NULL) { + return std::unique_ptr(new InvalidValue()); + } + + const Document& doc = *context._doc; + + if (!documentTypeEqualsName(doc.getType(), _doctype)) { + return std::unique_ptr(new InvalidValue()); + } + try{ + initFieldPath(doc.getType()); + + IteratorHandler handler; + doc.iterateNested(_fieldPath.getFullRange(), handler); + + if (handler.hasSingleValue()) { + return handler.getSingleValue(); + } else { + const std::vector& values = handler.getValues(); + + if (values.size() == 0) { + return std::unique_ptr(new NullValue()); + } else { + return std::unique_ptr(new ArrayValue(handler.getValues())); + } + } + } catch (vespalib::IllegalArgumentException& e) { + LOG(warning, "Caught exception while fetching field from document: %s", e.what()); + return std::unique_ptr(new InvalidValue()); + } catch (FieldNotFoundException& e) { + LOG(warning, "Tried to compare to field %s, not found in document type", _fieldExpression.c_str()); + return std::unique_ptr(new InvalidValue()); + } +} + +void +FieldValueNode::visit(Visitor &visitor) const +{ + visitor.visitFieldValueNode(*this); +} + + +void +FieldValueNode::print(std::ostream& out, bool verbose, + const std::string& indent) const +{ + (void) verbose; (void) indent; + if (hadParentheses()) out << '('; + out << _doctype << "." << _fieldExpression; + if (hadParentheses()) out << ')'; +} + + +std::unique_ptr +FieldValueNode::traceValue(const Context &context, std::ostream& out) const +{ + if (context._doc == NULL) { + return defaultTrace(getValue(context), out); + } + const Document &doc(*context._doc); + if (!documentTypeEqualsName(doc.getType(), _doctype)) { + out << "Document is of type " << doc.getType() << " which isn't a " + << _doctype << " document, thus resolving invalid.\n"; + return std::unique_ptr(new InvalidValue()); + } + try{ + initFieldPath(doc.getType()); + + IteratorHandler handler; + doc.iterateNested(_fieldPath.getFullRange(), handler); + + if (handler.hasSingleValue()) { + return handler.getSingleValue(); + } else { + const std::vector& values = handler.getValues(); + + if (values.size() == 0) { + return std::unique_ptr(new NullValue()); + } else { + return std::unique_ptr(new ArrayValue(handler.getValues())); + } + } + } catch (FieldNotFoundException& e) { + LOG(warning, "Tried to compare to field %s, not found in document type", + _fieldExpression.c_str()); + out << "Field not found in document type " << doc.getType() + << ". Returning invalid.\n"; + return std::unique_ptr(new InvalidValue()); + } +} + +IdValueNode::IdValueNode(const BucketIdFactory& bucketIdFactory, + const vespalib::stringref & name, const vespalib::stringref & type, + int widthBits, int divisionBits) + : _bucketIdFactory(bucketIdFactory), + _id(name), + _typestring(type), + _type(ALL), + _widthBits(widthBits), + _divisionBits(divisionBits) +{ + if (type.length() > 2) switch (type[0]) { + case 'b': _type = BUCKET; + break; + case 'n': _type = NS; + break; + case 'g': + if (type[1] == 'r') { + _type = GROUP; + } else if (type[1] == 'i') { + _type = GID; + } + break; + case 's': { + if (type[1] == 'c') { _type = SCHEME; } else { _type = SPEC; } + break; + } + case 't': + _type = TYPE; + break; + case 'u': + _type = USER; + break; + case 'o': + _type = ORDER; + break; + } +} + + +std::unique_ptr +IdValueNode::getValue(const Context& context) const +{ + if (context._doc != NULL) { + return getValue(context._doc->getId()); + } else if (context._docId != NULL) { + return getValue(*context._docId); + } else { + return getValue(context._docUpdate->getId()); + } +} + + +std::unique_ptr +IdValueNode::getValue(const DocumentId& id) const +{ + vespalib::string value; + switch (_type) { + case BUCKET: + return std::unique_ptr( + new IntegerValue( + _bucketIdFactory.getBucketId(id).getId(), true)); + case NS: + value = id.getScheme().getNamespace(); break; + case SCHEME: + value = id.getScheme().getTypeName(id.getScheme().getType()); + break; + case TYPE: + if (id.getScheme().hasDocType()) { + value = id.getScheme().getDocType(); + } else { + return std::unique_ptr(new InvalidValue); + } + break; + case SPEC: + value = id.getScheme().getNamespaceSpecific(); + break; + case ALL: + value = id.getScheme().toString(); + break; + case GROUP: + if (id.getScheme().hasGroup()) { + value = id.getScheme().getGroup(); + } else { + fprintf(stderr, "***** Returning invalid value for %s\n", + id.toString().c_str()); + return std::unique_ptr(new InvalidValue); + } + break; + case GID: + value = id.getGlobalId().toString(); + break; + case ORDER: + if (id.getScheme().getType() == IdString::ORDERDOC) { + const OrderDocIdString& ods( + static_cast(id.getScheme())); + if (ods.getWidthBits() == _widthBits + && ods.getDivisionBits() == _divisionBits) + { + return std::unique_ptr(new IntegerValue( + static_cast(id.getScheme()) + .getOrdering(), false)); + } + } + return std::unique_ptr(new InvalidValue()); + case USER: + if (id.getScheme().hasNumber()) { + return std::unique_ptr( + new IntegerValue(id.getScheme().getNumber(), false)); + } else { + return std::unique_ptr(new InvalidValue); + } + } + + return std::unique_ptr(new StringValue(value)); +} + + +std::unique_ptr +IdValueNode::traceValue(const Context& context, + std::ostream &out) const +{ + if (context._doc != NULL) { + return traceValue(context._doc->getId(), out); + } else if (context._docId != NULL) { + return traceValue(*context._docId, out); + } else { + return traceValue(context._docUpdate->getId(), out); + } +} + + +std::unique_ptr +IdValueNode::traceValue(const DocumentId& id, std::ostream& out) const +{ + vespalib::string value; + switch (_type) { + case BUCKET: + { + document::BucketId bucket(_bucketIdFactory.getBucketId(id)); + std::unique_ptr result( + new IntegerValue(bucket.getId(), true)); + out << "Found id.bucket specification. Resolved to " + << bucket.toString() << ".\n"; + return result; + } + case NS: + value = id.getScheme().getNamespace(); + out << "Resolved id.namespace to value\"" << value << "\".\n"; + break; + case SCHEME: + value = id.getScheme().getTypeName(id.getScheme().getType()); + out << "Resolved id.scheme to value\"" << value << "\".\n"; + break; + case TYPE: + if (id.getScheme().hasDocType()) { + value = id.getScheme().getDocType(); + out << "Resolved id.type to value\"" << value << "\".\n"; + } else { + out << "Could not resolve type of doc " << id << ".\n"; + return std::unique_ptr(new InvalidValue); + } + break; + case SPEC: + value = id.getScheme().getNamespaceSpecific(); + out << "Resolved id.specific to value\"" << value << "\".\n"; + break; + case ALL: + value = id.getScheme().toString(); + out << "Resolved id to \"" << value << "\".\n"; + break; + case GROUP: + if (id.getScheme().hasGroup()) { + value = id.getScheme().getGroup(); + out << "Resolved group of doc (type " << id.getScheme().getType() + << ") to \"" << value << "\".\n"; + } else { + out << "Can't resolve group of doc \"" << id << "\".\n"; + return std::unique_ptr(new InvalidValue); + } + break; + case GID: + value = id.getGlobalId().toString(); + out << "Resolved gid to \"" << value << "\".\n"; + break; + case ORDER: + if (id.getScheme().getType() == IdString::ORDERDOC) { + const OrderDocIdString& ods( + static_cast(id.getScheme())); + if (ods.getWidthBits() == _widthBits + && ods.getDivisionBits() == _divisionBits) + { + std::unique_ptr result(new IntegerValue( + static_cast(id.getScheme()) + .getOrdering(), false)); + out << "Resolved id.order to int " << *result << "\n"; + return result; + } + } + out << "Could not resolve id.order(" << _widthBits << ", " + << _divisionBits << ") of doc " << id << ".\n"; + return std::unique_ptr(new InvalidValue()); + case USER: + if (id.getScheme().hasNumber()) { + std::unique_ptr result( + new IntegerValue(id.getScheme().getNumber(), false)); + out << "Resolved user of doc type " << id.getScheme().getType() + << " to " << *result << ".\n"; + return result; + } else { + out << "Could not resolve user of doc " << id << ".\n"; + return std::unique_ptr(new InvalidValue); + } + } + + return std::unique_ptr(new StringValue(value)); +} + + +void +IdValueNode::visit(Visitor &visitor) const +{ + visitor.visitIdValueNode(*this); +} + + +void +IdValueNode::print(std::ostream& out, bool verbose, + const std::string& indent) const +{ + (void) verbose; (void) indent; + if (hadParentheses()) out << '('; + out << _id; + if (_type != ALL) { + out << '.' << _typestring; + } + if (_type == ORDER) { + out << "(" << _widthBits << "," << _divisionBits << ")"; + } + if (hadParentheses()) out << ')'; +} + +SearchColumnValueNode::SearchColumnValueNode( + const BucketIdFactory& bucketIdFactory, + const vespalib::stringref & name, int numColumns) + : _bucketIdFactory(bucketIdFactory), + _id(name), + _numColumns(numColumns), + _distribution(std::make_unique(_numColumns, 16)) +{ +} + +int64_t +SearchColumnValueNode::getValue(const BucketId& id) const +{ + return _distribution->getColumn(id); +} + + +std::unique_ptr +SearchColumnValueNode::getValue(const Context& context) const +{ + if (context._doc != NULL) { + return getValue(context._doc->getId()); + } else if (context._docId != NULL) { + return getValue(*context._docId); + } else { + return getValue(context._docUpdate->getId()); + } +} + + +std::unique_ptr +SearchColumnValueNode::getValue(const DocumentId& id) const +{ + return std::unique_ptr(new IntegerValue( + getValue(_bucketIdFactory.getBucketId(id)), false)); +} + + +std::unique_ptr +SearchColumnValueNode::traceValue(const Context& context, + std::ostream &out) const +{ + if (context._doc != NULL) { + return traceValue(context._doc->getId(), out); + } else if (context._docId != NULL) { + return traceValue(*context._docId, out); + } else { + return traceValue(context._docUpdate->getId(), out); + } +} + + +std::unique_ptr +SearchColumnValueNode::traceValue(const DocumentId& id, + std::ostream& out) const +{ + std::unique_ptr result(new IntegerValue( + getValue(_bucketIdFactory.getBucketId(id)), false)); + out << "Resolved search column of doc \"" << id << "\" to " << *result + << "\n"; + return result; +} + + +void +SearchColumnValueNode::visit(Visitor &visitor) const +{ + visitor.visitSearchColumnValueNode(*this); +} + + +void +SearchColumnValueNode::print(std::ostream& out, bool verbose, + const std::string& indent) const +{ + (void) verbose; (void) indent; + if (hadParentheses()) out << '('; + out << _id; + out << '.' << _numColumns; + if (hadParentheses()) out << ')'; +} + +namespace { + union HashUnion { + unsigned char _key[16]; + int64_t _hash[2]; + }; + int64_t hash(const void* data, uint32_t len) { + HashUnion hash; + fastc_md5sum((const unsigned char*) data, len, hash._key); + return hash._hash[0]; + } +} + +FunctionValueNode::FunctionValueNode(const vespalib::stringref & name, + std::unique_ptr src) + : _function(), + _funcname(name), + _source(std::move(src)) +{ + if (name == "lowercase") { + _function = LOWERCASE; + } else if (name == "hash") { + _function = HASH; + } else if (name == "abs") { + _function = ABS; + } else { + throw ParsingFailedException("No function '"+name+"' exist.", + VESPA_STRLOC); + } +} + +std::unique_ptr +FunctionValueNode::getValue(std::unique_ptr val) const +{ + switch (val->getType()) { + case Value::String: + { + StringValue& sval(static_cast(*val)); + if (_function == LOWERCASE) { + return std::unique_ptr(new StringValue( + vespalib::LowerCase::convert(sval.getValue()))); + } else if (_function == HASH) { + return std::unique_ptr(new IntegerValue( + hash(sval.getValue().c_str(), sval.getValue().size()), + false)); + } + break; + } + case Value::Float: + { + FloatValue& fval(static_cast(*val)); + if (_function == HASH) { + FloatValue::ValueType ffval = fval.getValue(); + return std::unique_ptr(new IntegerValue( + hash(&ffval, sizeof(ffval)), false)); + } else if (_function == ABS) { + FloatValue::ValueType ffval = fval.getValue(); + if (ffval < 0) ffval *= -1; + return std::unique_ptr(new FloatValue(ffval)); + } + break; + } + case Value::Integer: + { + IntegerValue& ival(static_cast(*val)); + if (_function == HASH) { + IntegerValue::ValueType iival = ival.getValue(); + return std::unique_ptr(new IntegerValue( + hash(&iival, sizeof(iival)), false)); + } else if (_function == ABS) { + IntegerValue::ValueType iival = ival.getValue(); + if (iival < 0) iival *= -1; + return std::unique_ptr(new IntegerValue(iival, false)); + } + break; + } + case Value::Bucket: + { + throw ParsingFailedException( + "No functioncalls are allowed on value of type bucket", + VESPA_STRLOC); + break; + } + + case Value::Array: break; + case Value::Struct: break; + case Value::Invalid: break; + case Value::Null: break; + } + return std::unique_ptr(new InvalidValue); +} + +std::unique_ptr +FunctionValueNode::traceValue(std::unique_ptr val, + std::ostream& out) const +{ + switch (val->getType()) { + case Value::String: + { + StringValue& sval(static_cast(*val)); + if (_function == LOWERCASE) { + std::unique_ptr result(new StringValue( + vespalib::LowerCase::convert(sval.getValue()))); + out << "Performed lowercase function on '" << sval + << "' => '" << *result << "'.\n"; + return result; + } else if (_function == HASH) { + std::unique_ptr result(new IntegerValue( + hash(sval.getValue().c_str(), sval.getValue().size()), + false)); + out << "Performed hash on string '" << sval << "' -> " + << *result << "\n"; + return result; + } + break; + } + case Value::Float: + { + FloatValue& fval(static_cast(*val)); + if (_function == HASH) { + FloatValue::ValueType ffval = fval.getValue(); + std::unique_ptr result(new IntegerValue( + hash(&ffval, sizeof(ffval)), false)); + out << "Performed hash on float " << ffval << " -> " << *result + << "\n"; + return result; + } else if (_function == ABS) { + FloatValue::ValueType ffval = fval.getValue(); + if (ffval < 0) ffval *= -1; + out << "Performed abs on float " << fval.getValue() << " -> " + << ffval << "\n"; + return std::unique_ptr(new FloatValue(ffval)); + } + break; + } + case Value::Integer: + { + IntegerValue& ival(static_cast(*val)); + if (_function == HASH) { + IntegerValue::ValueType iival = ival.getValue(); + std::unique_ptr result(new IntegerValue( + hash(&iival, sizeof(iival)), false)); + out << "Performed hash on float " << iival << " -> " << *result + << "\n"; + return result; + } else if (_function == ABS) { + IntegerValue::ValueType iival = ival.getValue(); + if (iival < 0) iival *= -1; + out << "Performed abs on integer " << ival.getValue() << " -> " + << iival << "\n"; + return std::unique_ptr(new IntegerValue(iival, false)); + } + break; + } + case Value::Bucket: break; + case Value::Array: break; + case Value::Struct: break; + case Value::Invalid: break; + case Value::Null: break; + } + out << "Cannot use function " << _function << " on a value of type " + << val->getType() << ". Resolving invalid.\n"; + return std::unique_ptr(new InvalidValue); +} + + +void +FunctionValueNode::visit(Visitor &visitor) const +{ + visitor.visitFunctionValueNode(*this); +} + + +void +FunctionValueNode::print(std::ostream& out, bool verbose, + const std::string& indent) const +{ + if (hadParentheses()) out << '('; + _source->print(out, verbose, indent); + out << '.' << _funcname << "()"; + if (hadParentheses()) out << ')'; +} + +ArithmeticValueNode::ArithmeticValueNode( + std::unique_ptr left, const vespalib::stringref & op, + std::unique_ptr right) + : _operator(), + _left(std::move(left)), + _right(std::move(right)) +{ + if (op.size() == 1) switch (op[0]) { + case '+': _operator = ADD; return; + case '-': _operator = SUB; return; + case '*': _operator = MUL; return; + case '/': _operator = DIV; return; + case '%': _operator = MOD; return; + } + throw ParsingFailedException( + "Arithmetic operator '"+op+"' does not exist.", VESPA_STRLOC); +} + +const char* +ArithmeticValueNode::getOperatorName() const +{ + switch (_operator) { + case ADD: return "+"; + case SUB: return "-"; + case MUL: return "*"; + case DIV: return "/"; + case MOD: return "%"; + } + return "UNKNOWN"; +} + + + +std::unique_ptr +ArithmeticValueNode::getValue(std::unique_ptr lval, + std::unique_ptr rval) const +{ + switch (_operator) { + case ADD: + { + if (lval->getType() == Value::String && + rval->getType() == Value::String) + { + StringValue& slval(static_cast(*lval)); + StringValue& srval(static_cast(*rval)); + return std::unique_ptr(new StringValue( + slval.getValue() + srval.getValue())); + } + } + case SUB: + case MUL: + case DIV: + { + if (lval->getType() == Value::Integer && + rval->getType() == Value::Integer) + { + IntegerValue& ilval(static_cast(*lval)); + IntegerValue& irval(static_cast(*rval)); + IntegerValue::ValueType res = 0; + switch (_operator) { + case ADD: res = ilval.getValue() + irval.getValue(); break; + case SUB: res = ilval.getValue() - irval.getValue(); break; + case MUL: res = ilval.getValue() * irval.getValue(); break; + case DIV: + if (irval.getValue() != 0) { + res = ilval.getValue() / irval.getValue(); + } else { + throw vespalib::IllegalArgumentException("Division by zero"); + } + break; + case MOD: assert(0); + } + return std::unique_ptr(new IntegerValue(res, false)); + } + NumberValue* nlval(dynamic_cast(lval.get())); + NumberValue* nrval(dynamic_cast(rval.get())); + if (nlval != 0 && nrval != 0) { + NumberValue::CommonValueType res = 0; + switch (_operator) { + case ADD: res = nlval->getCommonValue() + + nrval->getCommonValue(); break; + case SUB: res = nlval->getCommonValue() + - nrval->getCommonValue(); break; + case MUL: res = nlval->getCommonValue() + * nrval->getCommonValue(); break; + case DIV: + if (nrval->getCommonValue() != 0) { + res = nlval->getCommonValue() + / nrval->getCommonValue(); + } else { + throw vespalib::IllegalArgumentException("Division by zero"); + } + break; + case MOD: assert(0); + } + return std::unique_ptr(new FloatValue(res)); + } + } + case MOD: + { + if (lval->getType() == Value::Integer && + rval->getType() == Value::Integer) + { + IntegerValue& ilval(static_cast(*lval)); + IntegerValue& irval(static_cast(*rval)); + if (irval.getValue() != 0) { + return std::unique_ptr(new IntegerValue(ilval.getValue() % irval.getValue(), false)); + } else { + throw vespalib::IllegalArgumentException("Division by zero"); + } + } + } + } + return std::unique_ptr(new InvalidValue); +} + +std::unique_ptr +ArithmeticValueNode::traceValue(std::unique_ptr lval, + std::unique_ptr rval, + std::ostream& out) const +{ + switch (_operator) { + case ADD: + { + if (lval->getType() == Value::String && + rval->getType() == Value::String) + { + StringValue& slval(static_cast(*lval)); + StringValue& srval(static_cast(*rval)); + std::unique_ptr result(new StringValue( + slval.getValue() + srval.getValue())); + out << "Appended strings '" << slval << "' + '" << srval + << "' -> '" << *result << "'.\n"; + return result; + } + } + case SUB: + case MUL: + case DIV: + { + if (lval->getType() == Value::Integer && + rval->getType() == Value::Integer) + { + IntegerValue& ilval(static_cast(*lval)); + IntegerValue& irval(static_cast(*rval)); + IntegerValue::ValueType res = 0; + switch (_operator) { + case ADD: res = ilval.getValue() + irval.getValue(); break; + case SUB: res = ilval.getValue() - irval.getValue(); break; + case MUL: res = ilval.getValue() * irval.getValue(); break; + case DIV: res = ilval.getValue() / irval.getValue(); break; + case MOD: assert(0); + } + std::unique_ptr result(new IntegerValue(res, false)); + out << "Performed integer operation " << ilval << " " + << getOperatorName() << " " << irval << " = " << *result + << "\n"; + return result; + } + NumberValue* nlval(dynamic_cast(lval.get())); + NumberValue* nrval(dynamic_cast(lval.get())); + if (nlval != 0 && nrval != 0) { + NumberValue::CommonValueType res = 0; + switch (_operator) { + case ADD: res = nlval->getCommonValue() + + nrval->getCommonValue(); break; + case SUB: res = nlval->getCommonValue() + - nrval->getCommonValue(); break; + case MUL: res = nlval->getCommonValue() + * nrval->getCommonValue(); break; + case DIV: res = nlval->getCommonValue() + / nrval->getCommonValue(); break; + case MOD: assert(0); + } + std::unique_ptr result(new FloatValue(res)); + out << "Performed float operation " << nlval << " " + << getOperatorName() << " " << nrval << " = " << *result + << "\n"; + return result; + } + } + case MOD: + { + if (lval->getType() == Value::Integer && + rval->getType() == Value::Integer) + { + IntegerValue& ilval(static_cast(*lval)); + IntegerValue& irval(static_cast(*rval)); + std::unique_ptr result(new IntegerValue( + ilval.getValue() % irval.getValue(), false)); + out << "Performed integer operation " << ilval << " " + << getOperatorName() << " " << irval << " = " << *result + << "\n"; + return result; + } + } + } + out << "Failed to do operation " << getOperatorName() + << " on values of type " << lval->getType() << " and " + << rval->getType() << ". Resolving invalid.\n"; + return std::unique_ptr(new InvalidValue); +} + + +void +ArithmeticValueNode::visit(Visitor &visitor) const +{ + visitor.visitArithmeticValueNode(*this); +} + + +void +ArithmeticValueNode::print(std::ostream& out, bool verbose, + const std::string& indent) const +{ + if (hadParentheses()) out << '('; + _left->print(out, verbose, indent); + switch (_operator) { + case ADD: out << " + "; break; + case SUB: out << " - "; break; + case MUL: out << " * "; break; + case DIV: out << " / "; break; + case MOD: out << " % "; break; + } + _right->print(out, verbose, indent); + if (hadParentheses()) out << ')'; +} + +} + diff --git a/document/src/vespa/document/select/valuenodes.h b/document/src/vespa/document/select/valuenodes.h new file mode 100644 index 00000000000..98f80e2904a --- /dev/null +++ b/document/src/vespa/document/select/valuenodes.h @@ -0,0 +1,348 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +/** + * @class document::select::ValueNode + * @ingroup select + * + * @brief Node representing a value in the tree + * + * @author H�kon Humberset + * @date 2007-04-20 + * @version $Id$ + */ + +#pragma once + +#include "valuenode.h" +#include + +namespace document { + +class BucketDistribution; +class BucketIdFactory; +class DocumentId; +class BucketId; +class DocumentType; + +namespace select { + +class InvalidValueNode : public ValueNode +{ + vespalib::string _name; +public: + InvalidValueNode(const vespalib::stringref & name); + + std::unique_ptr getValue(const Context&) const override { + return std::unique_ptr(new InvalidValue()); + } + + void print(std::ostream& out, bool verbose, const std::string& indent) const override; + void visit(Visitor& visitor) const override; + + ValueNode::UP clone() const override { + return wrapParens(new InvalidValueNode(_name)); + } +}; + +class NullValueNode : public ValueNode +{ + vespalib::string _name; +public: + NullValueNode(const vespalib::stringref & name); + + std::unique_ptr getValue(const Context&) const override { + return std::unique_ptr(new NullValue()); + } + + void print(std::ostream& out, bool verbose, const std::string& indent) const override; + + void visit(Visitor& visitor) const override; + + ValueNode::UP clone() const override { + return wrapParens(new NullValueNode(_name)); + } +}; + +class StringValueNode : public ValueNode +{ + vespalib::string _value; +public: + StringValueNode(const vespalib::stringref & val); + + const vespalib::string& getValue() const { return _value; } + + std::unique_ptr getValue(const Context&) const override { + return std::unique_ptr(new StringValue(_value)); + } + + void print(std::ostream& out, bool verbose, const std::string& indent) const override; + void visit(Visitor& visitor) const override; + + ValueNode::UP clone() const override { + return wrapParens(new StringValueNode(_value)); + } +}; + +class IntegerValueNode : public ValueNode +{ + int64_t _value; + bool _isBucketValue; +public: + IntegerValueNode(int64_t val, bool isBucketValue) + : _value(val), _isBucketValue(isBucketValue) {} + + int64_t getValue() const { return _value; } + + virtual std::unique_ptr getValue(const Context&) const override { + return std::unique_ptr(new IntegerValue(_value, _isBucketValue)); + } + + void print(std::ostream& out, bool verbose, const std::string& indent) const override; + void visit(Visitor& visitor) const override; + + ValueNode::UP clone() const override { + return wrapParens(new IntegerValueNode(_value, _isBucketValue)); + } +}; + +class CurrentTimeValueNode : public ValueNode +{ +public: + int64_t getValue() const; + + std::unique_ptr getValue(const Context&) const override { + return std::unique_ptr(new IntegerValue(getValue(), false)); + } + + void print(std::ostream& out, bool verbose, const std::string& indent) const override; + void visit(Visitor& visitor) const override; + + ValueNode::UP clone() const override { + return wrapParens(new CurrentTimeValueNode); + } +}; + +class VariableValueNode : public ValueNode +{ + vespalib::string _value; +public: + VariableValueNode(const vespalib::string & variableName) : _value(variableName) {} + + const vespalib::string& getVariableName() const { return _value; } + + std::unique_ptr getValue(const Context& context) const override; + void print(std::ostream& out, bool verbose, const std::string& indent) const override; + void visit(Visitor& visitor) const override; + + ValueNode::UP clone() const override { + return wrapParens(new VariableValueNode(_value)); + } +}; + +class FloatValueNode : public ValueNode +{ + double _value; +public: + FloatValueNode(double val) : _value(val) {} + + double getValue() const { return _value; } + + std::unique_ptr getValue(const Context&) const override { + return std::unique_ptr(new FloatValue(_value)); + } + + void print(std::ostream& out, bool verbose, const std::string& indent) const override; + void visit(Visitor& visitor) const override; + + ValueNode::UP clone() const override { + return wrapParens(new FloatValueNode(_value)); + } +}; + +class FieldValueNode : public ValueNode +{ + vespalib::string _doctype; + vespalib::string _fieldExpression; + vespalib::string _fieldName; + mutable FieldPath _fieldPath; + +public: + FieldValueNode(const vespalib::string& doctype, const vespalib::string& fieldExpression); + FieldValueNode(const FieldValueNode &); + FieldValueNode & operator = (const FieldValueNode &); + FieldValueNode(FieldValueNode &&) = default; + FieldValueNode & operator = (FieldValueNode &&) = default; + ~FieldValueNode(); + + const vespalib::string& getDocType() const { return _doctype; } + const vespalib::string& getRealFieldName() const { return _fieldName; } + const vespalib::string& getFieldName() const { return _fieldExpression; } + + std::unique_ptr getValue(const Context& context) const override; + std::unique_ptr traceValue(const Context &context, std::ostream& out) const override; + void print(std::ostream& out, bool verbose, const std::string& indent) const override; + void visit(Visitor& visitor) const override; + + ValueNode::UP clone() const override { + return wrapParens(new FieldValueNode(_doctype, _fieldExpression)); + } + + static vespalib::string extractFieldName(const std::string & fieldExpression); + +private: + + void initFieldPath(const DocumentType&) const; +}; + +class IdValueNode : public ValueNode +{ +public: + enum Type { SCHEME, NS, TYPE, USER, GROUP, GID, SPEC, BUCKET, ORDER, ALL }; + + IdValueNode(const BucketIdFactory& bucketIdFactory, + const vespalib::stringref & name, const vespalib::stringref & type, + int widthBits = -1, int divisionBits = -1); + + Type getType() const { return _type; } + + std::unique_ptr getValue(const Context& context) const override; + + std::unique_ptr getValue(const DocumentId& id) const; + + std::unique_ptr traceValue(const Context& context, std::ostream &out) const override; + + std::unique_ptr traceValue(const DocumentId& val, std::ostream& out) const; + + void print(std::ostream& out, bool verbose, const std::string& indent) const override; + + void visit(Visitor& visitor) const override; + + ValueNode::UP clone() const override { + return wrapParens(new IdValueNode(_bucketIdFactory, _id, _typestring, _widthBits, _divisionBits)); + } + + int getWidthBits() const { return _widthBits; } + int getDivisionBits() const { return _divisionBits; } + +private: + const BucketIdFactory& _bucketIdFactory; + vespalib::string _id; + vespalib::string _typestring; + Type _type; + int _widthBits; + int _divisionBits; +}; + +class SearchColumnValueNode : public ValueNode +{ +public: + SearchColumnValueNode(const BucketIdFactory& bucketIdFactory, + const vespalib::stringref & name, + int numColumns); + + int getColumns() { return _numColumns; } + + std::unique_ptr getValue(const Context& context) const override; + std::unique_ptr getValue(const DocumentId& id) const; + std::unique_ptr traceValue(const Context& context, std::ostream &out) const override; + std::unique_ptr traceValue(const DocumentId& val, std::ostream& out) const; + + int64_t getValue(const BucketId& bucketId) const; + void print(std::ostream& out, bool verbose, const std::string& indent) const override; + void visit(Visitor& visitor) const override; + + ValueNode::UP clone() const override { + return wrapParens(new SearchColumnValueNode(_bucketIdFactory, _id, _numColumns)); +} + +private: + const BucketIdFactory& _bucketIdFactory; + vespalib::string _id; + int _numColumns; + std::unique_ptr _distribution; +}; + +class FunctionValueNode : public ValueNode +{ +public: + enum Function { LOWERCASE, HASH, ABS }; + + FunctionValueNode(const vespalib::stringref & name, std::unique_ptr src); + + Function getFunction() const { return _function; } + const vespalib::string &getFunctionName(void) const { return _funcname; } + + std::unique_ptr getValue(const Context& context) const override { + return getValue(_source->getValue(context)); + } + + std::unique_ptr traceValue(const Context &context, std::ostream& out) const override { + return traceValue(_source->getValue(context), out); + } + + void print(std::ostream& out, bool verbose, const std::string& indent) const override; + void visit(Visitor& visitor) const override; + + ValueNode::UP clone() const override { + return wrapParens(new FunctionValueNode(_funcname, _source->clone())); + } + + const ValueNode& getChild() const { return *_source; } + +private: + Function _function; + vespalib::string _funcname; + std::unique_ptr _source; + + virtual std::unique_ptr getValue(std::unique_ptr val) const; + virtual std::unique_ptr traceValue(std::unique_ptr val, + std::ostream& out) const; +}; + +class ArithmeticValueNode : public ValueNode +{ +public: + enum Operator { ADD, SUB, MUL, DIV, MOD }; + + ArithmeticValueNode(std::unique_ptr left, + const vespalib::stringref & op, + std::unique_ptr right); + + Operator getOperator() const { return _operator; } + const char* getOperatorName() const; + + std::unique_ptr + getValue(const Context& context) const override { + return getValue(_left->getValue(context), _right->getValue(context)); + } + + std::unique_ptr + traceValue(const Context &context, std::ostream& out) const override { + return traceValue(_left->getValue(context), _right->getValue(context), out); + } + + void print(std::ostream& out, bool verbose, const std::string& indent) const override; + void visit(Visitor& visitor) const override; + + ValueNode::UP clone() const override { + return wrapParens(new ArithmeticValueNode(_left->clone(), + getOperatorName(), + _right->clone())); + } + + const ValueNode& getLeft() const { return *_left; } + const ValueNode& getRight() const { return *_right; } + +private: + Operator _operator; + std::unique_ptr _left; + std::unique_ptr _right; + + virtual std::unique_ptr getValue(std::unique_ptr lval, + std::unique_ptr rval) const; + virtual std::unique_ptr traceValue(std::unique_ptr lval, + std::unique_ptr rval, + std::ostream&) const; +}; + +} // select +} // document diff --git a/fastos/src/vespa/fastos/time.h b/fastos/src/vespa/fastos/time.h index 97ebe21a3b5..1e37813a072 100644 --- a/fastos/src/vespa/fastos/time.h +++ b/fastos/src/vespa/fastos/time.h @@ -1,8 +1,6 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #pragma once -#include - /** * Interface to OS time functions. */ @@ -12,7 +10,7 @@ protected: /** * Destructor. No cleanup needed for base class. */ - virtual ~FastOS_TimeInterface(void) { } + virtual ~FastOS_TimeInterface() { } public: /** @@ -49,30 +47,26 @@ public: * Note: Only millisecond accuracy is guaranteed. * @param microsecs Number of microseconds to add. */ - void AddMicroSecs(double microsecs) - { SetMicroSecs(MicroSecs() + microsecs); } + void AddMicroSecs(double microsecs) { SetMicroSecs(MicroSecs() + microsecs); } /** * Add a specified number of milliseconds to the time. * @param millisecs Number of milliseconds to add. */ - void AddMilliSecs(double millisecs) - { SetMilliSecs(MilliSecs() + millisecs); } + void AddMilliSecs(double millisecs) { SetMilliSecs(MilliSecs() + millisecs); } /** * Subtract a specified number of microseconds from the time. * Note: Only millisecond accuracy is guaranteed. * @param microsecs Number of microseconds to subtract. */ - void SubtractMicroSecs(double microsecs) - { SetMicroSecs(MicroSecs() - microsecs); } + void SubtractMicroSecs(double microsecs) { SetMicroSecs(MicroSecs() - microsecs); } /** * Subtract a specified number of milliseconds from the time. * @param millisecs Number of milliseconds to subtract. */ - void SubtractMilliSecs(double millisecs) - { SetMilliSecs(MilliSecs() - millisecs); } + void SubtractMilliSecs(double millisecs) { SetMilliSecs(MilliSecs() - millisecs); } /** * Return the time in microseconds. @@ -133,7 +127,6 @@ public: virtual long int GetMicroSeconds() const = 0; }; - #include -typedef FastOS_UNIX_Time FASTOS_PREFIX(Time); +using FastOS_Time = FastOS_UNIX_Time; diff --git a/fastos/src/vespa/fastos/unix_time.cpp b/fastos/src/vespa/fastos/unix_time.cpp index 202ffe6d82a..6b6a8e58ffb 100644 --- a/fastos/src/vespa/fastos/unix_time.cpp +++ b/fastos/src/vespa/fastos/unix_time.cpp @@ -1,6 +1,7 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include +#include "time.h" +#include "types.h" double FastOS_UNIX_Time::MicroSecs() const @@ -96,3 +97,8 @@ FastOS_UNIX_Time::SetSecs(double secs) _time.tv_usec = - static_cast((- secs - (-_time.tv_sec)) * 1000000); } } + +void FastOS_UNIX_Time::SetNow() { + gettimeofday(&_time, NULL); +} + diff --git a/fastos/src/vespa/fastos/unix_time.h b/fastos/src/vespa/fastos/unix_time.h index dd6122bc463..5ae4916418a 100644 --- a/fastos/src/vespa/fastos/unix_time.h +++ b/fastos/src/vespa/fastos/unix_time.h @@ -89,9 +89,8 @@ public: void SetMilliSecs(double millisecs) override; void SetSecs(double secs) override; - void SetNow() override { gettimeofday(&_time, NULL); } + void SetNow() override; long int GetSeconds() const override { return _time.tv_sec; } long int GetMicroSeconds() const override { return _time.tv_usec; } }; - diff --git a/messagebus/src/vespa/messagebus/callstack.cpp b/messagebus/src/vespa/messagebus/callstack.cpp index 5311a75c3c5..44ae4190698 100644 --- a/messagebus/src/vespa/messagebus/callstack.cpp +++ b/messagebus/src/vespa/messagebus/callstack.cpp @@ -4,6 +4,7 @@ #include "message.h" #include "reply.h" #include "idiscardhandler.h" +#include namespace mbus { diff --git a/searchcore/src/tests/proton/common/selectpruner_test.cpp b/searchcore/src/tests/proton/common/selectpruner_test.cpp index 29ef6ef016c..0a181de39ec 100644 --- a/searchcore/src/tests/proton/common/selectpruner_test.cpp +++ b/searchcore/src/tests/proton/common/selectpruner_test.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff --git a/searchcore/src/vespa/searchcore/proton/common/attributefieldvaluenode.cpp b/searchcore/src/vespa/searchcore/proton/common/attributefieldvaluenode.cpp index d15eddb3ac4..10c2adfd1f2 100644 --- a/searchcore/src/vespa/searchcore/proton/common/attributefieldvaluenode.cpp +++ b/searchcore/src/vespa/searchcore/proton/common/attributefieldvaluenode.cpp @@ -3,6 +3,8 @@ #include "attributefieldvaluenode.h" #include "selectcontext.h" #include +#include + namespace proton { @@ -20,11 +22,10 @@ using search::attribute::BasicType; using search::attribute::CollectionType; using search::attribute::IAttributeVector; - AttributeFieldValueNode:: AttributeFieldValueNode(const vespalib::string& doctype, const vespalib::string& field, - const search::AttributeVector::SP &attribute) + const std::shared_ptr &attribute) : FieldValueNode(doctype, field), _attribute(attribute) { @@ -94,5 +95,11 @@ AttributeFieldValueNode::traceValue(const Context &context, } +document::select::ValueNode::UP +AttributeFieldValueNode::clone() const +{ + return wrapParens(new AttributeFieldValueNode(getDocType(), getFieldName(), _attribute)); +} + } // namespace proton diff --git a/searchcore/src/vespa/searchcore/proton/common/attributefieldvaluenode.h b/searchcore/src/vespa/searchcore/proton/common/attributefieldvaluenode.h index 38e532053d4..c0ffbaea987 100644 --- a/searchcore/src/vespa/searchcore/proton/common/attributefieldvaluenode.h +++ b/searchcore/src/vespa/searchcore/proton/common/attributefieldvaluenode.h @@ -1,38 +1,24 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #pragma once -#include -#include - -namespace proton -{ +#include +namespace search { class AttributeVector; } +namespace proton { class AttributeFieldValueNode : public document::select::FieldValueNode { - search::AttributeVector::SP _attribute; + using Context = document::select::Context; + std::shared_ptr _attribute; public: AttributeFieldValueNode(const vespalib::string& doctype, const vespalib::string& field, - const search::AttributeVector::SP &attribute); - - virtual std::unique_ptr - getValue(const document::select::Context &context) const override; + const std::shared_ptr &attribute); - virtual std::unique_ptr - traceValue(const document::select::Context &context, - std::ostream& out) const override; - - document::select::ValueNode::UP - clone() const override - { - return wrapParens(new AttributeFieldValueNode(getDocType(), - getFieldName(), - _attribute)); - } + std::unique_ptr getValue(const Context &context) const override; + std::unique_ptr traceValue(const Context &context, std::ostream& out) const override; + document::select::ValueNode::UP clone() const override; }; } // namespace proton - - diff --git a/searchcore/src/vespa/searchcore/proton/common/cachedselect.cpp b/searchcore/src/vespa/searchcore/proton/common/cachedselect.cpp index 861131642e4..9a15c257dcc 100644 --- a/searchcore/src/vespa/searchcore/proton/common/cachedselect.cpp +++ b/searchcore/src/vespa/searchcore/proton/common/cachedselect.cpp @@ -1,12 +1,11 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "cachedselect.h" -#include -#include #include "attributefieldvaluenode.h" +#include "selectpruner.h" #include +#include #include -#include "selectpruner.h" #include LOG_SETUP(".proton.common.cachedselect"); @@ -85,7 +84,7 @@ AttrVisitor::visitFieldValueNode(const FieldValueNode &expr) _valueNode = expr.clone(); return; } - AttributeVector::SP av(ag->getSP()); + std::shared_ptr av(ag->getSP()); if (av->getCollectionType() == CollectionType::SINGLE) { ++_svAttrs; AttrMap::iterator it(_amap.find(name)); diff --git a/searchcore/src/vespa/searchcore/proton/common/selectpruner.cpp b/searchcore/src/vespa/searchcore/proton/common/selectpruner.cpp index 001eb7d16f3..7e92be7507e 100644 --- a/searchcore/src/vespa/searchcore/proton/common/selectpruner.cpp +++ b/searchcore/src/vespa/searchcore/proton/common/selectpruner.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include using document::select::And; diff --git a/searchcore/src/vespa/searchcore/proton/common/selectpruner.h b/searchcore/src/vespa/searchcore/proton/common/selectpruner.h index 5d4bbc038b9..7b6c9954124 100644 --- a/searchcore/src/vespa/searchcore/proton/common/selectpruner.h +++ b/searchcore/src/vespa/searchcore/proton/common/selectpruner.h @@ -9,8 +9,9 @@ namespace search { class IAttributeManager; } -namespace proton -{ +namespace document { class DocumentTypeRepo; } + +namespace proton { class SelectPrunerBase { @@ -50,100 +51,36 @@ public: bool hasFields); SelectPruner(const SelectPruner *rhs); - - virtual - ~SelectPruner(); - - uint32_t - getFieldNodes() const - { - return _fieldNodes; - } - - uint32_t - getAttrFieldNodes() const - { - return _attrFieldNodes; - } - - const document::select::ResultSet & - getResultSet() const - { - return _resultSet; - } - - bool - isFalse() const; - - bool - isTrue() const; - - bool - isInvalid() const; - - bool - isConst() const; - - void - trace(std::ostream &t); - - void - process(const document::select::Node &node); + virtual ~SelectPruner(); + + uint32_t getFieldNodes() const { return _fieldNodes; } + uint32_t getAttrFieldNodes() const { return _attrFieldNodes; } + const document::select::ResultSet & getResultSet() const { return _resultSet; } + bool isFalse() const; + bool isTrue() const; + bool isInvalid() const; + bool isConst() const; + void trace(std::ostream &t); + void process(const document::select::Node &node); private: - virtual void - visitAndBranch(const document::select::And &expr) override; - - virtual void - visitComparison(const document::select::Compare &expr) override; - - virtual void - visitDocumentType(const document::select::DocType &expr) override; - - virtual void - visitNotBranch(const document::select::Not &expr) override; - - virtual void - visitOrBranch(const document::select::Or &expr) override; - - virtual void - visitArithmeticValueNode(const document::select::ArithmeticValueNode &expr) override; - - virtual void - visitFunctionValueNode(const document::select::FunctionValueNode &expr) override; - - virtual void - visitFieldValueNode(const document::select::FieldValueNode &expr) override; - - void - invertNode(); - - const document::select::Operator & - getOperator(const document::select::Operator &op); - - void - addNodeCount(const SelectPruner &rhs); - - void - setInvalidVal(); - - void - setInvalidConst(); - - void - setTernaryConst(bool val); - - void - resolveTernaryConst(bool wantInverted); - - bool - isInvalidVal() const; - - bool - isNullVal() const; - - void - swap(SelectPruner &rhs); + void visitAndBranch(const document::select::And &expr) override; + void visitComparison(const document::select::Compare &expr) override; + void visitDocumentType(const document::select::DocType &expr) override; + void visitNotBranch(const document::select::Not &expr) override; + void visitOrBranch(const document::select::Or &expr) override; + void visitArithmeticValueNode(const document::select::ArithmeticValueNode &expr) override; + void visitFunctionValueNode(const document::select::FunctionValueNode &expr) override; + void visitFieldValueNode(const document::select::FieldValueNode &expr) override; + void invertNode(); + const document::select::Operator &getOperator(const document::select::Operator &op); + void addNodeCount(const SelectPruner &rhs); + void setInvalidVal(); + void setInvalidConst(); + void setTernaryConst(bool val); + void resolveTernaryConst(bool wantInverted); + bool isInvalidVal() const; + bool isNullVal() const; + void swap(SelectPruner &rhs); }; } // namespace proton - diff --git a/storage/src/vespa/storage/persistence/fieldvisitor.cpp b/storage/src/vespa/storage/persistence/fieldvisitor.cpp index e67d15d4e91..6657a73543e 100644 --- a/storage/src/vespa/storage/persistence/fieldvisitor.cpp +++ b/storage/src/vespa/storage/persistence/fieldvisitor.cpp @@ -1,6 +1,8 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. // @author Vegard Sjonfjell -#include + +#include "fieldvisitor.h" +#include namespace storage { -- cgit v1.2.3