Пример #1
0
    def _rewriter_table(self):
        rewriter_table = sql.default_rewriter_table()

        #
        # Timestamp binary minus operator.
        #
        rewriter_table[Prototype("-", (Timestamp, Timestamp), Real)] = \
            lambda arg0, arg1: "EXTRACT(EPOCH FROM (%s) - (%s))" % (arg0, arg1)

        #
        # Functions.
        #
        rewriter_table[Prototype("covers", (Geometry, Geometry), Boolean)] = \
            sql.binary_function_rewriter("ST_Covers")

        rewriter_table[Prototype("intersects", (Geometry, Geometry), Boolean)] = \
            sql.binary_function_rewriter("ST_Intersects")

        rewriter_table[Prototype("is_source_of", (UUID,), Boolean)] = \
            lambda arg0: "EXISTS (SELECT 1 FROM %s WHERE source_uuid = %s.uuid AND uuid = (%s))" % \
            (self._link_table_name, self._core_table_name, arg0)

        rewriter_table[Prototype("is_derived_from", (UUID,), Boolean)] = \
            lambda arg0: "EXISTS (SELECT 1 FROM %s WHERE uuid = %s.uuid AND source_uuid = (%s))" % \
            (self._link_table_name, self._core_table_name, arg0)

        rewriter_table[Prototype("has_tag", (Text,), Boolean)] = \
            lambda arg0: "EXISTS (SELECT 1 FROM %s WHERE uuid = %s.uuid AND tag = (%s))" % \
            (self._tag_table_name, self._core_table_name, arg0)

        rewriter_table[Prototype("now", (), Timestamp)] = \
            sql.as_is("now() AT TIME ZONE 'UTC'")

        return rewriter_table
Пример #2
0
    def _rewriter_table(self):
        rewriter_table = sql.default_rewriter_table()

        #
        # Timestamp binary minus operator.
        #
        rewriter_table[Prototype("-", (Timestamp, Timestamp), Real)] = \
            lambda arg0, arg1: "(julianday(%s) - julianday(%s)) * 86400.0" % (arg0, arg1)

        #
        # Enable escape sequences with the LIKE operator
        #
        rewriter_table[Prototype("~=", (Text, Text), Boolean)] = \
            lambda arg0, arg1: "(%s) LIKE (%s) ESCAPE '\\'" % (arg0, arg1)

        #
        # Functions.
        #
        rewriter_table[Prototype("covers", (Geometry, Geometry), Boolean)] = \
            sql.binary_function_rewriter("ST_Covers")

        rewriter_table[Prototype("intersects", (Geometry, Geometry), Boolean)] = \
            sql.binary_function_rewriter("ST_Intersects")

        rewriter_table[Prototype("is_source_of", (UUID,), Boolean)] = \
            lambda arg0: "EXISTS (SELECT 1 FROM %s WHERE source_uuid = %s.uuid AND uuid = (%s))" % \
            (self._link_table_name, self._core_table_name, arg0)

        rewriter_table[Prototype("is_derived_from", (UUID,), Boolean)] = \
            lambda arg0: "EXISTS (SELECT 1 FROM %s WHERE uuid = %s.uuid AND source_uuid = (%s))" % \
            (self._link_table_name, self._core_table_name, arg0)

        rewriter_table[Prototype("has_tag", (Text,), Boolean)] = \
            lambda arg0: "EXISTS (SELECT 1 FROM %s WHERE uuid = %s.uuid AND tag = (%s))" % \
            (self._tag_table_name, self._core_table_name, arg0)

        rewriter_table[Prototype("now", (), Timestamp)] = \
            sql.as_is("datetime(\"now\")")

        return rewriter_table
Пример #3
0
    def visit_FunctionCall(self, visitable):
        # Resolve the type of the function arguments.
        for argument in visitable.arguments:
            self.visit(argument)

        prototype = Prototype(visitable.name, [argument.type for argument in visitable.arguments])

        try:
            prototypes = function_table.resolve(prototype)
        except KeyError:
            prototypes = []

        if not prototypes:
            raise Error("undefined function: \"%s\"" % prototype)

        if len(prototypes) > 1:
            raise InternalError("cannot uniquely resolve function: \"%s\"" % prototype)

        prototype = prototypes[0]
        visitable.prototype = prototype
        visitable.type = prototype.return_type
Пример #4
0
from muninn.exceptions import *
from muninn.function import Prototype, FunctionTable
from muninn.schema import *
from muninn.visitor import Visitor

#
# Table of all supported operators and functions
#
type_map = {
    UUID: Boolean,
}
function_table = FunctionTable(type_map=type_map)
#
# Logical operators
#
function_table.add(Prototype("not", (Boolean, ), Boolean))
function_table.add(Prototype("and", (Boolean, Boolean), Boolean))
function_table.add(Prototype("or", (Boolean, Boolean), Boolean))
#
# Membership operators
#
function_table.add(Prototype("in", (Integer, Sequence), Boolean))
function_table.add(Prototype("in", (Long, Sequence), Boolean))
function_table.add(Prototype("in", (Real, Sequence), Boolean))
function_table.add(Prototype("in", (Text, Sequence), Boolean))
function_table.add(Prototype("not in", (Integer, Sequence), Boolean))
function_table.add(Prototype("not in", (Long, Sequence), Boolean))
function_table.add(Prototype("not in", (Real, Sequence), Boolean))
function_table.add(Prototype("not in", (Text, Sequence), Boolean))
#
# Comparison operators
Пример #5
0
def default_rewriter_table():
    #
    # Table of all supported operators and functions that can be rewritten in standard SQL and without backend specific
    # knowledge. NB. This is a subset of the set of all supported operators and functions. Database specific backends
    # should add custom implementations of the operators and functions not implemented here.
    #
    rewriter_table = {}

    #
    # Logical operators
    #
    rewriter_table[Prototype("not", (Boolean,), Boolean)] = unary_operator_rewriter("NOT")
    rewriter_table[Prototype("and", (Boolean, Boolean), Boolean)] = binary_operator_rewriter("AND")
    rewriter_table[Prototype("or", (Boolean, Boolean), Boolean)] = binary_operator_rewriter("OR")

    #
    # Membership operators
    #
    in_rewriter = membership_operator_rewriter("in")
    rewriter_table[Prototype("in", (Integer, Sequence), Boolean)] = in_rewriter
    rewriter_table[Prototype("in", (Long, Sequence), Boolean)] = in_rewriter
    rewriter_table[Prototype("in", (Real, Sequence), Boolean)] = in_rewriter
    rewriter_table[Prototype("in", (Text, Sequence), Boolean)] = in_rewriter
    not_in_rewriter = membership_operator_rewriter("not in")
    rewriter_table[Prototype("not in", (Integer, Sequence), Boolean)] = not_in_rewriter
    rewriter_table[Prototype("not in", (Long, Sequence), Boolean)] = not_in_rewriter
    rewriter_table[Prototype("not in", (Real, Sequence), Boolean)] = not_in_rewriter
    rewriter_table[Prototype("not in", (Text, Sequence), Boolean)] = not_in_rewriter

    #
    # Comparison operators
    #
    eq_rewriter = binary_operator_rewriter("=")
    rewriter_table[Prototype("==", (Long, Long), Boolean)] = eq_rewriter
    rewriter_table[Prototype("==", (Long, Integer), Boolean)] = eq_rewriter
    rewriter_table[Prototype("==", (Integer, Long), Boolean)] = eq_rewriter
    rewriter_table[Prototype("==", (Integer, Integer), Boolean)] = eq_rewriter
    rewriter_table[Prototype("==", (Real, Real), Boolean)] = eq_rewriter
    rewriter_table[Prototype("==", (Real, Long), Boolean)] = eq_rewriter
    rewriter_table[Prototype("==", (Long, Real), Boolean)] = eq_rewriter
    rewriter_table[Prototype("==", (Real, Integer), Boolean)] = eq_rewriter
    rewriter_table[Prototype("==", (Integer, Real), Boolean)] = eq_rewriter
    rewriter_table[Prototype("==", (Boolean, Boolean), Boolean)] = eq_rewriter
    rewriter_table[Prototype("==", (Text, Text), Boolean)] = eq_rewriter
    rewriter_table[Prototype("==", (Timestamp, Timestamp), Boolean)] = eq_rewriter
    rewriter_table[Prototype("==", (UUID, UUID), Boolean)] = eq_rewriter

    ne_rewriter = binary_operator_rewriter("!=")
    rewriter_table[Prototype("!=", (Long, Long), Boolean)] = ne_rewriter
    rewriter_table[Prototype("!=", (Long, Integer), Boolean)] = ne_rewriter
    rewriter_table[Prototype("!=", (Integer, Long), Boolean)] = ne_rewriter
    rewriter_table[Prototype("!=", (Integer, Integer), Boolean)] = ne_rewriter
    rewriter_table[Prototype("!=", (Real, Real), Boolean)] = ne_rewriter
    rewriter_table[Prototype("!=", (Real, Long), Boolean)] = ne_rewriter
    rewriter_table[Prototype("!=", (Long, Real), Boolean)] = ne_rewriter
    rewriter_table[Prototype("!=", (Real, Integer), Boolean)] = ne_rewriter
    rewriter_table[Prototype("!=", (Integer, Real), Boolean)] = ne_rewriter
    rewriter_table[Prototype("!=", (Boolean, Boolean), Boolean)] = ne_rewriter
    rewriter_table[Prototype("!=", (Text, Text), Boolean)] = ne_rewriter
    rewriter_table[Prototype("!=", (Timestamp, Timestamp), Boolean)] = ne_rewriter
    rewriter_table[Prototype("!=", (UUID, UUID), Boolean)] = ne_rewriter

    lt_rewriter = binary_operator_rewriter("<")
    rewriter_table[Prototype("<", (Long, Long), Boolean)] = lt_rewriter
    rewriter_table[Prototype("<", (Long, Integer), Boolean)] = lt_rewriter
    rewriter_table[Prototype("<", (Integer, Long), Boolean)] = lt_rewriter
    rewriter_table[Prototype("<", (Integer, Integer), Boolean)] = lt_rewriter
    rewriter_table[Prototype("<", (Real, Real), Boolean)] = lt_rewriter
    rewriter_table[Prototype("<", (Real, Long), Boolean)] = lt_rewriter
    rewriter_table[Prototype("<", (Long, Real), Boolean)] = lt_rewriter
    rewriter_table[Prototype("<", (Real, Integer), Boolean)] = lt_rewriter
    rewriter_table[Prototype("<", (Integer, Real), Boolean)] = lt_rewriter
    rewriter_table[Prototype("<", (Text, Text), Boolean)] = lt_rewriter
    rewriter_table[Prototype("<", (Timestamp, Timestamp), Boolean)] = lt_rewriter

    gt_rewriter = binary_operator_rewriter(">")
    rewriter_table[Prototype(">", (Long, Long), Boolean)] = gt_rewriter
    rewriter_table[Prototype(">", (Long, Integer), Boolean)] = gt_rewriter
    rewriter_table[Prototype(">", (Integer, Long), Boolean)] = gt_rewriter
    rewriter_table[Prototype(">", (Integer, Integer), Boolean)] = gt_rewriter
    rewriter_table[Prototype(">", (Real, Real), Boolean)] = gt_rewriter
    rewriter_table[Prototype(">", (Real, Long), Boolean)] = gt_rewriter
    rewriter_table[Prototype(">", (Long, Real), Boolean)] = gt_rewriter
    rewriter_table[Prototype(">", (Real, Integer), Boolean)] = gt_rewriter
    rewriter_table[Prototype(">", (Integer, Real), Boolean)] = gt_rewriter
    rewriter_table[Prototype(">", (Text, Text), Boolean)] = gt_rewriter
    rewriter_table[Prototype(">", (Timestamp, Timestamp), Boolean)] = gt_rewriter

    le_rewriter = binary_operator_rewriter("<=")
    rewriter_table[Prototype("<=", (Long, Long), Boolean)] = le_rewriter
    rewriter_table[Prototype("<=", (Long, Integer), Boolean)] = le_rewriter
    rewriter_table[Prototype("<=", (Integer, Long), Boolean)] = le_rewriter
    rewriter_table[Prototype("<=", (Integer, Integer), Boolean)] = le_rewriter
    rewriter_table[Prototype("<=", (Real, Real), Boolean)] = le_rewriter
    rewriter_table[Prototype("<=", (Real, Long), Boolean)] = le_rewriter
    rewriter_table[Prototype("<=", (Long, Real), Boolean)] = le_rewriter
    rewriter_table[Prototype("<=", (Real, Integer), Boolean)] = le_rewriter
    rewriter_table[Prototype("<=", (Integer, Real), Boolean)] = le_rewriter
    rewriter_table[Prototype("<=", (Text, Text), Boolean)] = le_rewriter
    rewriter_table[Prototype("<=", (Timestamp, Timestamp), Boolean)] = le_rewriter

    ge_rewriter = binary_operator_rewriter(">=")
    rewriter_table[Prototype(">=", (Long, Long), Boolean)] = ge_rewriter
    rewriter_table[Prototype(">=", (Long, Integer), Boolean)] = ge_rewriter
    rewriter_table[Prototype(">=", (Integer, Long), Boolean)] = ge_rewriter
    rewriter_table[Prototype(">=", (Integer, Integer), Boolean)] = ge_rewriter
    rewriter_table[Prototype(">=", (Real, Real), Boolean)] = ge_rewriter
    rewriter_table[Prototype(">=", (Real, Long), Boolean)] = ge_rewriter
    rewriter_table[Prototype(">=", (Long, Real), Boolean)] = ge_rewriter
    rewriter_table[Prototype(">=", (Real, Integer), Boolean)] = ge_rewriter
    rewriter_table[Prototype(">=", (Integer, Real), Boolean)] = ge_rewriter
    rewriter_table[Prototype(">=", (Text, Text), Boolean)] = ge_rewriter
    rewriter_table[Prototype(">=", (Timestamp, Timestamp), Boolean)] = ge_rewriter

    rewriter_table[Prototype("~=", (Text, Text), Boolean)] = binary_operator_rewriter("LIKE")

    #
    # Arithmetic operators.
    #
    plus_rewriter = unary_operator_rewriter("+")
    rewriter_table[Prototype("+", (Long,), Long)] = plus_rewriter
    rewriter_table[Prototype("+", (Integer,), Integer)] = plus_rewriter
    rewriter_table[Prototype("+", (Real,), Real)] = plus_rewriter

    minus_rewriter = unary_operator_rewriter("-")
    rewriter_table[Prototype("-", (Long,), Long)] = minus_rewriter
    rewriter_table[Prototype("-", (Integer,), Integer)] = minus_rewriter
    rewriter_table[Prototype("-", (Real,), Real)] = minus_rewriter

    add_rewriter = binary_operator_rewriter("+")
    rewriter_table[Prototype("+", (Long, Long), Long)] = add_rewriter
    rewriter_table[Prototype("+", (Long, Integer), Long)] = add_rewriter
    rewriter_table[Prototype("+", (Integer, Long), Long)] = add_rewriter
    rewriter_table[Prototype("+", (Integer, Integer), Integer)] = add_rewriter
    rewriter_table[Prototype("+", (Real, Real), Real)] = add_rewriter
    rewriter_table[Prototype("+", (Real, Long), Real)] = add_rewriter
    rewriter_table[Prototype("+", (Long, Real), Real)] = add_rewriter
    rewriter_table[Prototype("+", (Real, Integer), Real)] = add_rewriter
    rewriter_table[Prototype("+", (Integer, Real), Real)] = add_rewriter

    subtract_rewriter = binary_operator_rewriter("-")
    rewriter_table[Prototype("-", (Long, Long), Long)] = subtract_rewriter
    rewriter_table[Prototype("-", (Long, Integer), Long)] = subtract_rewriter
    rewriter_table[Prototype("-", (Integer, Long), Long)] = subtract_rewriter
    rewriter_table[Prototype("-", (Integer, Integer), Integer)] = subtract_rewriter
    rewriter_table[Prototype("-", (Real, Real), Real)] = subtract_rewriter
    rewriter_table[Prototype("-", (Real, Long), Real)] = subtract_rewriter
    rewriter_table[Prototype("-", (Long, Real), Real)] = subtract_rewriter
    rewriter_table[Prototype("-", (Real, Integer), Real)] = subtract_rewriter
    rewriter_table[Prototype("-", (Integer, Real), Real)] = subtract_rewriter

    multiply_rewriter = binary_operator_rewriter("*")
    rewriter_table[Prototype("*", (Long, Long), Long)] = multiply_rewriter
    rewriter_table[Prototype("*", (Long, Integer), Long)] = multiply_rewriter
    rewriter_table[Prototype("*", (Integer, Long), Long)] = multiply_rewriter
    rewriter_table[Prototype("*", (Integer, Integer), Integer)] = multiply_rewriter
    rewriter_table[Prototype("*", (Real, Real), Real)] = multiply_rewriter
    rewriter_table[Prototype("*", (Real, Long), Real)] = multiply_rewriter
    rewriter_table[Prototype("*", (Long, Real), Real)] = multiply_rewriter
    rewriter_table[Prototype("*", (Real, Integer), Real)] = multiply_rewriter
    rewriter_table[Prototype("*", (Integer, Real), Real)] = multiply_rewriter

    divide_rewriter = binary_operator_rewriter("/")
    rewriter_table[Prototype("/", (Long, Long), Long)] = divide_rewriter
    rewriter_table[Prototype("/", (Long, Integer), Long)] = divide_rewriter
    rewriter_table[Prototype("/", (Integer, Long), Long)] = divide_rewriter
    rewriter_table[Prototype("/", (Integer, Integer), Integer)] = divide_rewriter
    rewriter_table[Prototype("/", (Real, Real), Real)] = divide_rewriter
    rewriter_table[Prototype("/", (Real, Long), Real)] = divide_rewriter
    rewriter_table[Prototype("/", (Long, Real), Real)] = divide_rewriter
    rewriter_table[Prototype("/", (Real, Integer), Real)] = divide_rewriter
    rewriter_table[Prototype("/", (Integer, Real), Real)] = divide_rewriter

    #
    # Functions.
    #
    rewriter_table[Prototype("covers", (Timestamp, Timestamp, Timestamp, Timestamp), Boolean)] = \
        lambda left0, right0, left1, right1: "(%s) >= (%s) AND (%s) >= (%s) AND (%s) >= (%s) AND (%s) <= (%s)" % \
        (right0, left0, right1, left1, left1, left0, right1, right0)

    rewriter_table[Prototype("intersects", (Timestamp, Timestamp, Timestamp, Timestamp), Boolean)] = \
        lambda left0, right0, left1, right1: "(%s) >= (%s) AND (%s) >= (%s) AND (%s) >= (%s) AND (%s) <= (%s)" % \
        (right0, left0, right1, left1, right0, left1, left0, right1)

    return rewriter_table
Пример #6
0
    def build_summary_query(self, where='', parameters=None, aggregates=None, group_by=None, group_by_tag=False,
                            having=None, order_by=None):
        aggregates = aggregates or []
        group_by = group_by or []
        order_by = order_by or []
        if group_by_tag:
            group_by = group_by + ['tag']
        result_fields = group_by + ['count'] + aggregates
        join_set = set(item.split('.')[0] for item in group_by)

        # Parse the WHERE clause.
        where_clause, where_parameters = '', {}
        if where:
            ast = parse_and_analyze(where, self._namespace_schemas, parameters)
            visitor = _WhereExpressionVisitor(self._rewriter_table, self._column_name, self._named_placeholder)
            where_expr, where_parameters, where_namespaces = visitor.do_visit(ast)
            if where_expr:
                join_set.update(where_namespaces)
                where_clause = 'WHERE %s' % where_expr

        # Generate the GROUP BY clause.
        group_by_clause = ''
        group_by_list = [str(i) for i in range(1, len(group_by) + 1)]
        if group_by_list:
            group_by_clause = 'GROUP BY %s' % ', '.join(group_by_list)

        # Generate the HAVING clause
        having_clause = ''
        if having is not None:
            ast = parse_and_analyze(having, self._namespace_schemas, parameters, having=True)
            visitor = _WhereExpressionVisitor(self._rewriter_table, self._column_name, self._named_placeholder, visitor if where else None)
            having_expr, having_parameters, _ = visitor.do_visit(ast)
            where_parameters.update(having_parameters)
            having_clause = 'HAVING %s' % having_expr

        # Parse the ORDER BY clause.
        order_by_clause = ''
        order_by_list = []
        for item in order_by:
            direction = 'DESC' if item.startswith('-') else 'ASC'
            name = item[1:] if item.startswith('+') or item.startswith('-') else item
            Identifier(name, self._namespace_schemas)  # check if the identifier is valid
            if name not in result_fields:
                raise Error("cannot order result by %r; field is not present in result" % name)
            order_by_list.append('"%s" %s' % (name, direction))
        order_by_list += [str(i) for i in range(1, len(group_by) + 1)]
        if order_by_list:
            order_by_clause = 'ORDER BY %s' % ', '.join(order_by_list)

        # Generate the SELECT clause.
        select_list = []
        # group by fields
        for item in group_by:
            item = Identifier(item, self._namespace_schemas)
            column_name = self._column_name(item.namespace, item.identifier)
            group_by_functions = GROUP_BY_FUNCTIONS.get(item.muninn_type)
            if not group_by_functions:  # item.muninn_type not in (Text, Boolean, Long, Integer):
                if item.muninn_type:
                    raise Error("property %r of type %r cannot be part of the group_by field specification" %
                                (item.property_name, item.muninn_type.name()))
                else:
                    raise Error("property %r cannot be part of the group_by field specification" %
                                (item.property_name, ))
            if item.subscript not in group_by_functions:
                if item.subscript:
                    allowed_message = "; it can be one of %r" % group_by_functions if group_by_functions != [None] \
                        else ""
                    raise Error(("group field specification subscript %r of %r is not allowed" + allowed_message) %
                                (item.subscript, item.canonical))
                else:
                    raise Error("property %r of type %r must specify a subscript (one of %r) to be part of the "
                                "group_by field specification" % (item.property_name, item.muninn_type.name(),
                                                                  group_by_functions))
            if item.subscript:
                column_name = self._rewriter_property(column_name, item.subscript)
            select_list.append('%s AS "%s"' % (column_name, item.canonical))
        # aggregated fields
        select_list.append('COUNT(*) AS count')  # always aggregate row count
        for item in aggregates:
            item = Identifier(item, self._namespace_schemas)
            join_set.add(item.namespace)

            if not AGGREGATE_FUNCTIONS.get(item.muninn_type):
                raise Error("property %r of type %r cannot be part of the summary field specification" %
                            (item.property_name, item.muninn_type.name()))
            elif item.subscript not in AGGREGATE_FUNCTIONS[item.muninn_type]:
                if item.subscript:
                    raise Error("summary field specification subscript %r of %r should be one of %r" %
                                (item.subscript, item.canonical, AGGREGATE_FUNCTIONS[item.muninn_type]))
                else:
                    raise Error("summary field specification %r must specify a subscript (one of %r)" %
                                (item.canonical, AGGREGATE_FUNCTIONS[item.muninn_type]))
            if item.property_name == 'core.validity_duration':
                start_column = self._column_name(item.namespace, 'validity_start')
                stop_column = self._column_name(item.namespace, 'validity_stop')
                column_name = self._rewriter_table[Prototype('-', (Timestamp, Timestamp), Real)](stop_column,
                                                                                                 start_column)
            else:
                column_name = self._column_name(item.namespace, item.identifier)
            select_list.append('%s(%s) AS "%s"' % (item.subscript.upper(), column_name, item.canonical))
        select_clause = 'SELECT %s' % ', '.join(select_list)

        # Generate the FROM clause.
        from_clause = 'FROM %s' % self._table_name('core')

        join_set.discard('core')
        for namespace in join_set:
            from_clause = '%s LEFT JOIN %s USING (uuid)' % (from_clause, self._table_name(namespace))

        # Generate the complete query.
        query = '%s\n%s' % (select_clause, from_clause)
        if where_clause:
            query = '%s\n%s' % (query, where_clause)
        if group_by_clause:
            query = '%s\n%s' % (query, group_by_clause)
        if having_clause:
            query = '%s\n%s' % (query, having_clause)
        if order_by_clause:
            query = '%s\n%s' % (query, order_by_clause)

        return query, where_parameters, result_fields
Пример #7
0
    def _rewriter_table(self):
        rewriter_table = sql.default_rewriter_table()

        #
        # Timestamp binary minus operator.
        #
        rewriter_table[Prototype("-", (Timestamp, Timestamp), Real)] = \
            lambda arg0, arg1: "(julianday(%s) - julianday(%s)) * 86400.0" % (arg0, arg1)

        #
        # Enable escape sequences with the LIKE operator
        #
        rewriter_table[Prototype("~=", (Text, Text), Boolean)] = \
            lambda arg0, arg1: "(%s) LIKE (%s) ESCAPE '\\'" % (arg0, arg1)

        #
        # Functions.
        #
        rewriter_table[Prototype("covers", (Geometry, Geometry), Boolean)] = \
            lambda arg0, arg1: "(ST_Covers(%s, %s)=1)" % (arg0, arg1)

        rewriter_table[Prototype("intersects", (Geometry, Geometry), Boolean)] = \
            lambda arg0, arg1: "(ST_Intersects(%s, %s)=1)" % (arg0, arg1)

        rewriter_table[Prototype("is_source_of", (UUID,), Boolean)] = \
            lambda arg0: "EXISTS (SELECT 1 FROM %s WHERE source_uuid = %s.uuid AND uuid = (%s))" % \
            (self._link_table_name, self._core_table_name, arg0)

        def is_source_of_subquery(where_expr, where_namespaces):
            joins = ''
            for namespace in where_namespaces:
                joins = "%s INNER JOIN %s USING (uuid)" % (
                    joins, self._table_name(namespace))

            return "{core}.uuid in (SELECT {link}.source_uuid FROM {core} {joins} " \
                "INNER JOIN {link} on {link}.uuid = {core}.uuid WHERE {where})".format(
                    core=self._core_table_name, link=self._link_table_name, joins=joins,
                    where=where_expr)

        rewriter_table[Prototype("is_source_of", (Boolean, ),
                                 Boolean)] = is_source_of_subquery

        rewriter_table[Prototype("is_derived_from", (UUID,), Boolean)] = \
            lambda arg0: "EXISTS (SELECT 1 FROM %s WHERE uuid = %s.uuid AND source_uuid = (%s))" % \
            (self._link_table_name, self._core_table_name, arg0)

        def is_derived_from_subquery(where_expr, where_namespaces):
            joins = ''
            for namespace in where_namespaces:
                joins = "%s INNER JOIN %s USING (uuid)" % (
                    joins, self._table_name(namespace))

            return "{core}.uuid in (SELECT {link}.uuid FROM {core} {joins} " \
                "INNER JOIN {link} on {link}.source_uuid = {core}.uuid WHERE {where})".format(
                    core=self._core_table_name, link=self._link_table_name, joins=joins,
                    where=where_expr)

        rewriter_table[Prototype("is_derived_from", (Boolean, ),
                                 Boolean)] = is_derived_from_subquery

        rewriter_table[Prototype("has_tag", (Text,), Boolean)] = \
            lambda arg0: "EXISTS (SELECT 1 FROM %s WHERE uuid = %s.uuid AND tag = (%s))" % \
            (self._tag_table_name, self._core_table_name, arg0)

        rewriter_table[Prototype("now", (), Timestamp)] = \
            sql.as_is("datetime(\"now\")")

        def is_defined_rewriter(arg):
            namespace_name = arg.split('.')
            if len(namespace_name) == 1:
                return 'EXISTS (SELECT 1 FROM %s WHERE uuid = %s.uuid)' % \
                    (arg, self._core_table_name)
            else:
                return "(%s) IS NOT NULL" % arg

        rewriter_table[Prototype("is_defined", (Long, ),
                                 Boolean)] = is_defined_rewriter
        rewriter_table[Prototype("is_defined", (Integer, ),
                                 Boolean)] = is_defined_rewriter
        rewriter_table[Prototype("is_defined", (Real, ),
                                 Boolean)] = is_defined_rewriter
        rewriter_table[Prototype("is_defined", (Boolean, ),
                                 Boolean)] = is_defined_rewriter
        rewriter_table[Prototype("is_defined", (Text, ),
                                 Boolean)] = is_defined_rewriter
        rewriter_table[Prototype("is_defined", (Namespace, ),
                                 Boolean)] = is_defined_rewriter
        rewriter_table[Prototype("is_defined", (Timestamp, ),
                                 Boolean)] = is_defined_rewriter
        rewriter_table[Prototype("is_defined", (UUID, ),
                                 Boolean)] = is_defined_rewriter
        rewriter_table[Prototype("is_defined", (Geometry, ),
                                 Boolean)] = is_defined_rewriter

        return rewriter_table
Пример #8
0
    def _rewriter_table(self):
        rewriter_table = sql.default_rewriter_table()

        #
        # Timestamp binary minus operator.
        #
        rewriter_table[Prototype("-", (Timestamp, Timestamp), Real)] = \
            lambda arg0, arg1: "EXTRACT(EPOCH FROM (%s) - (%s))" % (arg0, arg1)

        #
        # Functions.
        #
        rewriter_table[Prototype("covers", (Geometry, Geometry), Boolean)] = \
            sql.binary_function_rewriter("ST_Covers")

        rewriter_table[Prototype("intersects", (Geometry, Geometry), Boolean)] = \
            sql.binary_function_rewriter("ST_Intersects")

        rewriter_table[Prototype("is_source_of", (UUID,), Boolean)] = \
            lambda arg0: "EXISTS (SELECT 1 FROM %s WHERE source_uuid = %s.uuid AND uuid = (%s))" % \
            (self._link_table_name, self._core_table_name, arg0)

        def is_source_of_subquery(where_expr, where_namespaces):
            joins = ''
            for namespace in where_namespaces:
                joins = "%s INNER JOIN %s USING (uuid)" % (
                    joins, self._table_name(namespace))

            return "{core}.uuid in (SELECT {link}.source_uuid FROM {core} {joins} " \
                "INNER JOIN {link} on {link}.uuid = {core}.uuid WHERE {where})".format(
                    core=self._core_table_name, link=self._link_table_name, joins=joins,
                    where=where_expr)

        rewriter_table[Prototype("is_source_of", (Boolean, ),
                                 Boolean)] = is_source_of_subquery

        rewriter_table[Prototype("is_derived_from", (UUID,), Boolean)] = \
            lambda arg0: "EXISTS (SELECT 1 FROM %s WHERE uuid = %s.uuid AND source_uuid = (%s))" % \
            (self._link_table_name, self._core_table_name, arg0)

        def is_derived_from_subquery(where_expr, where_namespaces):
            joins = ''
            for namespace in where_namespaces:
                joins = "%s INNER JOIN %s USING (uuid)" % (
                    joins, self._table_name(namespace))

            return "{core}.uuid in (SELECT {link}.uuid FROM {core} {joins} " \
                "INNER JOIN {link} on {link}.source_uuid = {core}.uuid WHERE {where})".format(
                    core=self._core_table_name, link=self._link_table_name, joins=joins,
                    where=where_expr)

        rewriter_table[Prototype("is_derived_from", (Boolean, ),
                                 Boolean)] = is_derived_from_subquery

        rewriter_table[Prototype("has_tag", (Text,), Boolean)] = \
            lambda arg0: "EXISTS (SELECT 1 FROM %s WHERE uuid = %s.uuid AND tag = (%s))" % \
            (self._tag_table_name, self._core_table_name, arg0)

        rewriter_table[Prototype("now", (), Timestamp)] = \
            sql.as_is("now() AT TIME ZONE 'UTC'")

        def is_defined_rewriter(arg):
            namespace_name = arg.split('.')
            if len(namespace_name) == 1:
                return 'EXISTS (SELECT 1 FROM %s WHERE uuid = %s.uuid)' % \
                    (self._table_name(arg), self._core_table_name)
            else:
                return "(%s) IS NOT NULL" % arg

        rewriter_table[Prototype("is_defined", (Long, ),
                                 Boolean)] = is_defined_rewriter
        rewriter_table[Prototype("is_defined", (Integer, ),
                                 Boolean)] = is_defined_rewriter
        rewriter_table[Prototype("is_defined", (Real, ),
                                 Boolean)] = is_defined_rewriter
        rewriter_table[Prototype("is_defined", (Boolean, ),
                                 Boolean)] = is_defined_rewriter
        rewriter_table[Prototype("is_defined", (Text, ),
                                 Boolean)] = is_defined_rewriter
        rewriter_table[Prototype("is_defined", (Namespace, ),
                                 Boolean)] = is_defined_rewriter
        rewriter_table[Prototype("is_defined", (Timestamp, ),
                                 Boolean)] = is_defined_rewriter
        rewriter_table[Prototype("is_defined", (UUID, ),
                                 Boolean)] = is_defined_rewriter
        rewriter_table[Prototype("is_defined", (Geometry, ),
                                 Boolean)] = is_defined_rewriter

        return rewriter_table
Пример #9
0
    def build_summary_query(self,
                            where='',
                            parameters=None,
                            aggregates=None,
                            group_by=None,
                            group_by_tag=False,
                            order_by=None):
        # Namespaces that appear in the "where" expression are combined via inner joins. This ensures that only those
        # products that actually have a defined value for a given attribute will be considered by the "where"
        # expression. This also means that products that do not occur in all of the namespaces referred to in the
        # "where" expression will be ignored.
        #
        # Other namespaces are combined via (left) outer joins, with the core namespace as the leftmost namespace. This
        # ensures that attributes will be returned of any product that occurs in zero or more of the requested
        # namespaces.

        aggregates = aggregates or []
        if group_by_tag:
            group_by = group_by + ['tag']
        result_fields = group_by + ['count'] + aggregates
        outer_join_set, inner_join_set = set(
            item.split('.')[0] for item in group_by), set()

        # Parse the WHERE clause.
        where_clause, where_parameters = '', {}
        if where:
            ast = parse_and_analyze(where, self._namespace_schemas, parameters)
            visitor = _WhereExpressionVisitor(self._rewriter_table,
                                              self._column_name,
                                              self._named_placeholder)
            where_expr, where_parameters, where_namespaces = visitor.visit(ast)
            if where_expr:
                inner_join_set.update(where_namespaces)
                where_clause = 'WHERE %s' % where_expr

        # Generate the GROUP BY clause.
        group_by_clause = ''
        group_by_list = [str(i) for i in range(1, len(group_by) + 1)]
        if group_by_list:
            group_by_clause = 'GROUP BY %s' % ', '.join(group_by_list)

        # Parse the ORDER BY clause.
        order_by_clause = ''
        order_by_list = []
        for item in order_by:
            direction = 'DESC' if item.startswith('-') else 'ASC'
            name = item[1:] if item.startswith('+') or item.startswith(
                '-') else item
            Identifier(
                name,
                self._namespace_schemas)  # check if the identifier is valid
            if name not in result_fields:
                raise Error(
                    "cannot order result by %r; field is not present in result"
                    % name)
            order_by_list.append('"%s" %s' % (name, direction))
        order_by_list += [str(i) for i in range(1, len(group_by) + 1)]
        if order_by_list:
            order_by_clause = 'ORDER BY %s' % ', '.join(order_by_list)

        # Generate the SELECT clause.
        select_list = []
        # group by fields
        for item in group_by:
            item = Identifier(item, self._namespace_schemas)
            column_name = self._column_name(item.namespace, item.attribute)
            group_by_functions = GROUP_BY_FUNCTIONS.get(item.muninn_type)
            if not group_by_functions:  # item.muninn_type not in (Text, Boolean, Long, Integer):
                if item.muninn_type:
                    raise Error(
                        "property %r of type %r cannot be part of the group_by field specification"
                        % (item.property, item.muninn_type.name()))
                else:
                    raise Error(
                        "property %r cannot be part of the group_by field specification"
                        % (item.property, ))
            if item.subscript not in group_by_functions:
                if item.subscript:
                    allowed_message = "; it can be one of %r" % group_by_functions if group_by_functions != [
                        None
                    ] else ""
                    raise Error((
                        "group field specification subscript %r of %r is not allowed"
                        + allowed_message) % (item.subscript, item.canonical))
                else:
                    raise Error(
                        "property %r of type %r must specify a subscript (one of %r) to be part of the group_by field specification"
                        % (item.property, item.muninn_type.name(),
                           group_by_functions))
            if item.subscript:
                column_name = self._rewriter_property(column_name,
                                                      item.subscript)
            select_list.append('%s AS "%s"' % (column_name, item.canonical))
        # aggregated fields
        select_list.append('COUNT(*) AS count')  # always aggregate row count
        for item in aggregates:
            item = Identifier(item, self._namespace_schemas)
            if not AGGREGATE_FUNCTIONS.get(item.muninn_type):
                raise Error(
                    "property %r of type %r cannot be part of the summary field specification"
                    % (item.property, item.muninn_type.name()))
            elif item.subscript not in AGGREGATE_FUNCTIONS[item.muninn_type]:
                if item.subscript:
                    raise Error(
                        "summary field specification subscript %r of %r should be one of %r"
                        % (item.subscript, item.canonical,
                           AGGREGATE_FUNCTIONS[item.muninn_type]))
                else:
                    raise Error(
                        "summary field specification %r must specify a subscript (one of %r)"
                        % (item.canonical,
                           AGGREGATE_FUNCTIONS[item.muninn_type]))
            if item.property == 'core.validity_duration':
                start_column = self._column_name(item.namespace,
                                                 'validity_start')
                stop_column = self._column_name(item.namespace,
                                                'validity_stop')
                column_name = self._rewriter_table[Prototype(
                    '-', (Timestamp, Timestamp), Real)](stop_column,
                                                        start_column)
            else:
                column_name = self._column_name(item.namespace, item.attribute)
            select_list.append(
                '%s(%s) AS "%s"' %
                (item.subscript.upper(), column_name, item.canonical))
        select_clause = 'SELECT %s' % ', '.join(select_list)

        # Generate the FROM clause.
        from_clause = 'FROM %s' % self._table_name('core')

        outer_join_set.discard('core')
        inner_join_set.discard('core')
        for namespace in outer_join_set - inner_join_set:
            from_clause = '%s LEFT OUTER JOIN %s USING (uuid)' % (
                from_clause, self._table_name(namespace))
        for namespace in inner_join_set:
            from_clause = '%s INNER JOIN %s USING (uuid)' % (
                from_clause, self._table_name(namespace))

        # Generate the complete query.
        query = '%s\n%s' % (select_clause, from_clause)
        if where_clause:
            query = '%s\n%s' % (query, where_clause)
        if group_by_clause:
            query = '%s\n%s' % (query, group_by_clause)
        if order_by_clause:
            query = '%s\n%s' % (query, order_by_clause)

        return query, where_parameters, result_fields