Esempio n. 1
0
 def testSelectWhat(self):
     self.assertQueryMatches(
         "SELECT proc.parent.pid AS ppid,"
         "proc.pid,"
         "'foo',"
         "asdate(proc.starttime),"
         "proc.fd[5]"
         "FROM pslist()",
         ast.Map(
             ast.Apply(ast.Var("pslist")),
             ast.Bind(
                 ast.Pair(
                     ast.Literal("ppid"),
                     ast.Resolve(
                         ast.Resolve(ast.Var("proc"),
                                     ast.Literal("parent")),
                         ast.Literal("pid"))),
                 ast.Pair(ast.Literal("pid"),
                          ast.Resolve(ast.Var("proc"), ast.Literal("pid"))),
                 ast.Pair(ast.Literal("column_2"), ast.Literal("foo")),
                 ast.Pair(
                     ast.Literal("asdate"),
                     ast.Apply(
                         ast.Var("asdate"),
                         ast.Resolve(ast.Var("proc"),
                                     ast.Literal("starttime")))),
                 ast.Pair(
                     ast.Literal("fd_5"),
                     ast.Select(
                         ast.Resolve(ast.Var("proc"), ast.Literal("fd")),
                         ast.Literal(5))))))
Esempio n. 2
0
    def testComplexSelect(self):
        query = ("(SELECT proc.parent.pid AS ppid, proc.pid FROM pslist(10) "
                 "WHERE COUNT(proc.open_files) > 10) and True")

        expected = ast.Intersection(
            ast.Map(
                ast.Filter(
                    ast.Apply(ast.Var("pslist"), ast.Literal(10)),
                    ast.StrictOrderedSet(
                        ast.Apply(
                            ast.Var("COUNT"),
                            ast.Resolve(ast.Var("proc"),
                                        ast.Literal("open_files"))),
                        ast.Literal(10))),
                ast.Bind(
                    ast.Pair(
                        ast.Literal("ppid"),
                        ast.Resolve(
                            ast.Resolve(ast.Var("proc"),
                                        ast.Literal("parent")),
                            ast.Literal("pid"))),
                    ast.Pair(ast.Literal("pid"),
                             ast.Resolve(ast.Var("proc"),
                                         ast.Literal("pid"))))),
            ast.Literal(True))

        self.assertQueryMatches(query, expected)
Esempio n. 3
0
    def select_limit(self, source_expression):
        """Match LIMIT take [OFFSET drop]."""
        start = self.tokens.matched.start

        # The expression right after LIMIT is the count to take.
        limit_count_expression = self.expression()

        # Optional OFFSET follows.
        if self.tokens.accept(grammar.select_offset):
            offset_start = self.tokens.matched.start
            offset_end = self.tokens.matched.end

            # Next thing is the count to drop.
            offset_count_expression = self.expression()

            # We have a new source expression, which is drop(count, original).
            offset_source_expression = ast.Apply(
                ast.Var("drop", start=offset_start, end=offset_end,
                        source=self.original),
                offset_count_expression,
                source_expression,
                start=offset_start, end=offset_count_expression.end,
                source=self.original)

            # Drop before taking, because obviously.
            source_expression = offset_source_expression

        limit_expression = ast.Apply(
            ast.Var("take", start=start, end=limit_count_expression.end,
                    source=self.original),
            limit_count_expression,
            source_expression,
            start=start, end=self.tokens.matched.end, source=self.original)

        return limit_expression
Esempio n. 4
0
    def application(self, func):
        """Parse the function application subgrammar.

        Function application can, conceptually, be thought of as a mixfix
        operator, similar to the way array subscripting works. However, it is
        not clear at this point whether we want to allow it to work as such,
        because doing so would permit queries to, at runtime, select methods
        out of an arbitrary object and then call them.

        While there is a function whitelist and preventing this sort of thing
        in the syntax isn't a security feature, it still seems like the
        syntax should make it clear what the intended use of application is.

        If we later decide to extend DottySQL to allow function application
        over an arbitrary LHS expression then that syntax would be a strict
        superset of the current syntax and backwards compatible.
        """
        start = self.tokens.matched.start
        if self.tokens.accept(common_grammar.rparen):
            # That was easy.
            return ast.Apply(func, start=start, end=self.tokens.matched.end,
                             source=self.original)

        arguments = [self.expression()]
        while self.tokens.accept(common_grammar.comma):
            arguments.append(self.expression())

        self.tokens.expect(common_grammar.rparen)
        return ast.Apply(func, *arguments, start=start,
                         end=self.tokens.matched.end, source=self.original)
Esempio n. 5
0
 def testSelectWhereOrder(self):
     self.assertQueryMatches(
         "SELECT * FROM pslist() WHERE pid == 1 ORDER BY command DESC",
         ast.Apply(
             ast.Var("reverse"),
             ast.Sort(
                 ast.Filter(ast.Apply(ast.Var("pslist")),
                            ast.Equivalence(ast.Var("pid"),
                                            ast.Literal(1))),
                 ast.Var("command"))))
Esempio n. 6
0
    def testSelectLimit(self):
        self.assertQueryMatches(
            "SELECT * FROM pslist LIMIT 10",
            ast.Apply(ast.Var("take"), ast.Literal(10), ast.Var("pslist")))

        self.assertQueryMatches(
            "SELECT * FROM pslist LIMIT 10 OFFSET 5",
            ast.Apply(
                ast.Var("take"), ast.Literal(10),
                ast.Apply(ast.Var("drop"), ast.Literal(5), ast.Var("pslist"))))
Esempio n. 7
0
    def testSelectOrder(self):
        # Order expressions.
        self.assertQueryMatches(
            "SELECT * FROM pslist() ORDER BY pid",
            ast.Sort(ast.Apply(ast.Var("pslist")), ast.Var("pid")))

        self.assertQueryMatches(
            "SELECT * FROM pslist() ORDER BY pid DESC",
            ast.Apply(ast.Var("reverse"),
                      ast.Sort(ast.Apply(ast.Var("pslist")), ast.Var("pid"))))
Esempio n. 8
0
    def testSelectAny(self):
        self.assertQueryMatches("SELECT ANY FROM pslist()",
                                ast.Any(ast.Apply(ast.Var("pslist"))))

        # Shorthands for any should work.
        self.assertQueryMatches("SELECT ANY FROM pslist()",
                                ast.Any(ast.Apply(ast.Var("pslist"))))

        self.assertQueryMatches("ANY pslist()",
                                ast.Any(ast.Apply(ast.Var("pslist"))))

        # Any doesn't allow ORDER BY.
        self.assertQueryRaises("SELECT ANY FROM pslist() ORDER BY pid")
Esempio n. 9
0
    def select_order(self, source_expression):
        start = self.tokens.matched.start
        sort_expression = ast.Sort(source_expression, self.expression(),
                                   start=start, end=self.tokens.matched.end,
                                   source=self.original)

        if self.tokens.accept(grammar.select_asc):
            sort_expression.end = self.tokens.matched.end
            return sort_expression

        if self.tokens.accept(grammar.select_desc):
            # Descending sort uses the stdlib function 'reverse' on the sorted
            # results. Standard library's core functions should ALWAYS be
            # available.
            sort_expression = ast.Apply(
                ast.Var("reverse",
                        start=sort_expression.start,
                        end=self.tokens.matched.end,
                        source=self.original),
                sort_expression,
                start=sort_expression.start,
                end=self.tokens.matched.end,
                source=self.original)

        if self.tokens.accept(grammar.select_limit):
            return self.select_limit(sort_expression)

        if self.tokens.accept(grammar.select_limit):
            return self.select_limit(sort_expression)

        return sort_expression
Esempio n. 10
0
    def testApplication(self):
        self.assertQueryMatches(
            "f(x, y)", ast.Apply(ast.Var("f"), ast.Var("x"), ast.Var("y")))

        self.assertQueryRaises("f(x, ,)")
        self.assertQueryRaises("f(x, y")
        self.assertQueryRaises("f (x, y)")
Esempio n. 11
0
    def testBasicSelect(self):
        self.assertQueryMatches("SELECT * FROM pslist()",
                                ast.Apply(ast.Var("pslist")))

        # The dotty-like where doesn't exist. SQL keywords are not permitted
        # outside of a SELECT expression.
        self.assertQueryRaises("pslist where pid == 1")
Esempio n. 12
0
    def testOperatorPrecedence(self):
        # Prefix operator, like the unary minus sign, should respect operator
        # precedence order.
        self.assertQueryMatches(
            "-x + y",
            ast.Sum(ast.Product(ast.Literal(-1), ast.Var("x")), ast.Var("y")))

        self.assertQueryMatches(
            "not x and y",
            ast.Intersection(ast.Complement(ast.Var("x")), ast.Var("y")))

        self.assertQueryMatches(
            "x / -f(y) or not z(a, b)",
            ast.Union(
                ast.Quotient(
                    ast.Var("x"),
                    ast.Product(ast.Literal(-1),
                                ast.Apply(ast.Var("f"), ast.Var("y")))),
                ast.Complement(
                    ast.Apply(ast.Var("z"), ast.Var("a"), ast.Var("b")))))
Esempio n. 13
0
    def testListLiterals(self):
        self.assertQueryMatches(
            "[1, 2, 3]",
            ast.Tuple(ast.Literal(1), ast.Literal(2), ast.Literal(3)))

        # Empty list literals should work.
        self.assertQueryMatches("[]", ast.Tuple())

        # Arbitrary AST should now be allowed in lists.
        self.assertQueryMatches(
            "[x, f(x)]",
            ast.Tuple(ast.Var("x"), ast.Apply(ast.Var("f"), ast.Var("x"))))
Esempio n. 14
0
    def testBuiltins(self):
        self.assertQueryMatches(
            "filter(pslist(), proc.pid == 1)",
            ast.Filter(
                ast.Apply(ast.Var("pslist")),
                ast.Equivalence(
                    ast.Resolve(ast.Var("proc"), ast.Literal("pid")),
                    ast.Literal(1))))

        self.assertQueryMatches(
            "map(pslist(), [proc.pid, proc['command']])",
            ast.Map(
                ast.Apply(ast.Var("pslist")),
                ast.Tuple(ast.Resolve(ast.Var("proc"), ast.Literal("pid")),
                          ast.Select(ast.Var("proc"),
                                     ast.Literal("command")))))

        self.assertQueryMatches(
            "bind(x: 1, y: 2)",
            ast.Bind(ast.Pair(ast.Var("x"), ast.Literal(1)),
                     ast.Pair(ast.Var("y"), ast.Literal(2))))

        self.assertQueryRaises("bind (x: 1, y: 2)")
Esempio n. 15
0
    def testKVPairs(self):
        self.assertQueryMatches("x: y", ast.Pair(ast.Var("x"), ast.Var("y")))

        # KV pairs are used in named function arguments:
        self.assertQueryMatches(
            "f(10, 'strings': ['foo', 'bar'])",
            ast.Apply(
                ast.Var("f"), ast.Literal(10),
                ast.Pair(ast.Literal("strings"),
                         ast.Tuple(ast.Literal("foo"), ast.Literal("bar")))))

        # They can also appear in repeated values, forming a logical dictionary:
        self.assertQueryMatches(
            "('foo': foo, 'bar': bar)",
            ast.Repeat(ast.Pair(ast.Literal("foo"), ast.Var("foo")),
                       ast.Pair(ast.Literal("bar"), ast.Var("bar"))))
Esempio n. 16
0
    def testFullSelect(self):
        query = ("SELECT proc.parent.pid AS ppid_column, proc.pid"
                 " FROM pslist(pid: 10, ppid: 20)"
                 " WHERE count(proc.open_files) > 10"
                 " ORDER BY proc.command DESC"
                 " LIMIT 10 - 9 OFFSET add(5, 10)")

        expected = ast.Map(
            ast.Apply(
                ast.Var("take"), ast.Difference(ast.Literal(10),
                                                ast.Literal(9)),
                ast.Apply(
                    ast.Var("drop"),
                    ast.Apply(ast.Var("add"), ast.Literal(5), ast.Literal(10)),
                    ast.Apply(
                        ast.Var("reverse"),
                        ast.Sort(
                            ast.Filter(
                                ast.Apply(
                                    ast.Var("pslist"),
                                    ast.Pair(ast.Var("pid"), ast.Literal(10)),
                                    ast.Pair(ast.Var("ppid"),
                                             ast.Literal(20))),
                                ast.StrictOrderedSet(
                                    ast.Literal(10),
                                    ast.Apply(
                                        ast.Var("count"),
                                        ast.Resolve(
                                            ast.Var("proc"),
                                            ast.Literal("open_files"))),
                                )),
                            ast.Resolve(ast.Var("proc"),
                                        ast.Literal("command")))))),
            ast.Bind(
                ast.Pair(
                    ast.Literal("ppid_column"),
                    ast.Resolve(
                        ast.Resolve(ast.Var("proc"), ast.Literal("parent")),
                        ast.Literal("pid"))),
                ast.Pair(ast.Literal("pid"),
                         ast.Resolve(ast.Var("proc"), ast.Literal("pid")))))

        self.assertQueryMatches(query, expected)
Esempio n. 17
0
 def testReverse(self):
     query = q.Query(
         ast.Apply(
             ast.Var("reverse"),
             ast.Repeat(ast.Literal(1), ast.Literal(2), ast.Literal(3))))
     self.assertEqual(solve.solve(query, {}).value, repeated.meld(3, 2, 1))
Esempio n. 18
0
 def testSelectAnyWhere(self):
     self.assertQueryMatches(
         "SELECT ANY FROM pslist() WHERE pid == 1",
         ast.Any(ast.Apply(ast.Var("pslist")),
                 ast.Equivalence(ast.Var("pid"), ast.Literal(1))))