def make_delete_rv(t): noop = "noop" in t.parser.request.args # a new delete inner statement enforces that we only delete # things which we have the key for. if len(t) > 2 and t[2] == 'where': # delete the whole stream, gone. this also deletes the # data in the backend readingdb. if not noop: statement = "DELETE FROM stream" returning = "RETURNING id, uuid" else: statement = "SELECT uuid FROM stream" returning = "" return ext_deletor if not noop else ext_default, \ """%(statement)s WHERE id IN ( SELECT s.id FROM stream s, subscription sub WHERE (%(restrict)s) AND s.subscription_id = sub.id AND (%(auth)s) ) %(returning)s """ % { 'restrict': t[3].render(), 'auth': qg.build_authcheck(t.parser.request, forceprivate=True), 'statement': statement, 'returning': returning } else: # to make the return value right, we need to tweak the # where clause. we want to only select streams where # there's actually something to delete, since all of the # streams the where-clause hits will get returned. tag_clause = ast.Statement( ast.Statement.OP_OR, *[ast.Statement(ast.Statement.OP_HAS, tag) for tag in t[2]]) if len(t) > 3: where_clause = ast.Statement(ast.Statement.OP_AND, tag_clause, t[4]) else: # if there's no where clause, we only look at streams # with the right tag. where_clause = tag_clause # this alters the tags but doesn't touch the data del_tags = ', '.join(map(escape_string, t[2])) if not noop: statement = "UPDATE stream SET metadata = metadata - ARRAY[" + \ del_tags + "]" returning = "RETURNING id, uuid" else: statement = "SELECT id, uuid FROM stream" returning = "" q = statement + " WHERE id IN " + \ "(SELECT s.id FROM stream s, subscription sub " + \ "WHERE (" + where_clause.render() + ") AND s.subscription_id = sub.id AND " + \ qg.build_authcheck(t.parser.request, forceprivate=True) + ")" + returning return ext_tag_deletor, q
def p_statement_unary(t): """statement_unary : HAS LVALUE | CONTAINS QSTRING """ if t[1] == 'has': if t[2] == 'uuid': t[0] = ast.Statement(ast.Statement.OP_UUID) else: t[0] = ast.Statement(ast.Statement.OP_HAS, t[2]) elif t[1] == 'contains': t[0] = ast.Statement(ast.Statement.OP_CONTAINS, t[2])
def p_statement_binary(t): """statement_binary : LVALUE '=' QSTRING | LVALUE LIKE QSTRING | LVALUE TILDE QSTRING """ if t[1] == 'uuid': t[0] = ast.Statement(ast.Statement.OP_UUID, t[2], t[3]) else: if t[2] == '=': t[0] = ast.Statement(ast.Statement.OP_EQUALS, t[1], t[3]) elif t[2] == 'like': t[0] = ast.Statement(ast.Statement.OP_LIKE, t[1], t[3]) elif t[2] == '~': t[0] = ast.Statement(ast.Statement.OP_REGEX, t[1], t[3])
def p_statement(t): """statement : statement_unary | statement_binary | '(' statement ')' | statement AND statement | statement OR statement | NOT statement """ if len(t) == 2: t[0] = t[1] elif t[2] == 'and': t[0] = ast.Statement(ast.Statement.OP_AND, t[1], t[3]) elif t[2] == 'or': t[0] = ast.Statement(ast.Statement.OP_OR, t[1], t[3]) elif t[1] == 'not': t[0] = ast.Statement(ast.Statement.OP_NOT, t[2]) else: t[0] = t[2]
def make_set_rv(t): # build the query for a set expression if len(t) > 3: # if there is a where clause, grab it where_clause = t[4] else: # if no where clause, just do something fast that matches # everything where_clause = ast.Statement(ast.Statement.OP_UUID) noop = "noop" in t.parser.request.args # build a list of what tags we're updating, as well as the # name of the regex tag. We're currently not smart enough to # deal with more than one regex match in a set statement, due # to issues with back references. new_tags, regex_tag = build_setstring(t[2], where_clause) tag_list = [v[0] for v in t[2]] if regex_tag: tag_list.append(regex_tag) # if we're in noop mode, we need to tweak the SQL if not noop: command = "UPDATE stream SET metadata = metadata || " from_stmt = "" else: command = "SELECT uuid, " from_stmt = "FROM stream" # build the first part of the query that depends on if this is a noop q = "%(command)s %(hstore_expression)s %(from_stmt)s WHERE ID IN" % { "command": command, "hstore_expression": new_tags, "from_stmt": from_stmt } # the where caluse always looks the same q += "(SELECT s.id FROM stream s, subscription sub " + \ "WHERE (" + where_clause.render() + ") AND s.subscription_id = sub.id AND " + \ qg.build_authcheck(t.parser.request, forceprivate=True) + ") " if not noop: # return the list of modifications. if this was a noop we # get this for free. q += " RETURNING uuid, slice(metadata, ARRAY[" + \ ','.join((escape_string(v) for v in tag_list)) + "])" return lambda x: ext_set(tag_list, x), q
def p_statement_unary(t): """statement_unary : HAS LVALUE""" if t[1] == 'has': t[0] = ast.Statement(ast.Statement.OP_HAS, t[2])