--- a/server/ssplanner.py Tue Oct 25 13:51:27 2011 +0200
+++ b/server/ssplanner.py Tue Oct 25 14:03:52 2011 +0200
@@ -103,28 +103,26 @@
When select has nothing selected, search in origrqlst for restriction that
should be considered.
"""
+ if origrqlst.where is not None and not select.selection:
+ # no selection, append one randomly by searching for a relation which is
+ # neither a type restriction (is) nor an eid specification (not neged
+ # eid with constant node)
+ for rel in origrqlst.where.iget_nodes(Relation):
+ if rel.neged(strict=True) or not (
+ rel.is_types_restriction() or
+ (rel.r_type == 'eid'
+ and isinstance(rel.get_variable_parts()[1], Constant))):
+ select.append_selected(rel.children[0].copy(select))
+ break
+ else:
+ return
if select.selection:
if origrqlst.where is not None:
select.set_where(origrqlst.where.copy(select))
+ if getattr(origrqlst, 'having', None):
+ select.set_having([sq.copy(select) for sq in origrqlst.having])
return select
- if origrqlst.where is None:
- return
- for rel in origrqlst.where.iget_nodes(Relation):
- # search for a relation which is neither a type restriction (is) nor an
- # eid specification (not neged eid with constant node
- if rel.neged(strict=True) or not (
- rel.is_types_restriction() or
- (rel.r_type == 'eid'
- and isinstance(rel.get_variable_parts()[1], Constant))):
- break
- else:
- return
- select.set_where(origrqlst.where.copy(select))
- if not select.selection:
- # no selection, append one randomly
- select.append_selected(rel.children[0].copy(select))
- return select
-
+ return None
class SSPlanner(object):
"""SingleSourcePlanner: build execution plan for rql queries
@@ -204,38 +202,40 @@
steps = []
for etype, var in rqlst.main_variables:
step = DeleteEntitiesStep(plan)
- step.children += self._sel_variable_step(plan, rqlst.solutions,
- rqlst.where, etype, var)
+ step.children += self._sel_variable_step(plan, rqlst, etype, var)
steps.append(step)
for relation in rqlst.main_relations:
step = DeleteRelationsStep(plan, relation.r_type)
- step.children += self._sel_relation_steps(plan, rqlst.solutions,
- rqlst.where, relation)
+ step.children += self._sel_relation_steps(plan, rqlst, relation)
steps.append(step)
return steps
- def _sel_variable_step(self, plan, solutions, restriction, etype, varref):
+ def _sel_variable_step(self, plan, rqlst, etype, varref):
"""handle the selection of variables for a delete query"""
select = Select()
varref = varref.copy(select)
select.defined_vars = {varref.name: varref.variable}
select.append_selected(varref)
- if restriction is not None:
- select.set_where(restriction.copy(select))
+ if rqlst.where is not None:
+ select.set_where(rqlst.where.copy(select))
+ if getattr(rqlst, 'having', None):
+ select.set_having([x.copy(select) for x in rqlst.having])
if etype != 'Any':
select.add_type_restriction(varref.variable, etype)
- return self._select_plan(plan, select, solutions)
+ return self._select_plan(plan, select, rqlst.solutions)
- def _sel_relation_steps(self, plan, solutions, restriction, relation):
+ def _sel_relation_steps(self, plan, rqlst, relation):
"""handle the selection of relations for a delete query"""
select = Select()
lhs, rhs = relation.get_variable_parts()
select.append_selected(lhs.copy(select))
select.append_selected(rhs.copy(select))
select.set_where(relation.copy(select))
- if restriction is not None:
- select.add_restriction(restriction.copy(select))
- return self._select_plan(plan, select, solutions)
+ if rqlst.where is not None:
+ select.set_where(rqlst.where.copy(select))
+ if getattr(rqlst, 'having', None):
+ select.set_having([x.copy(select) for x in rqlst.having])
+ return self._select_plan(plan, select, rqlst.solutions)
def build_set_plan(self, plan, rqlst):
"""get an execution plan from an SET RQL query"""
--- a/server/test/unittest_querier.py Tue Oct 25 13:51:27 2011 +0200
+++ b/server/test/unittest_querier.py Tue Oct 25 14:03:52 2011 +0200
@@ -1227,6 +1227,26 @@
self.assertRaises(QueryError, self.execute, "SET X nom 'toto', X has_text 'tutu' WHERE X is Personne")
self.assertRaises(QueryError, self.execute, "SET X login 'tutu', X eid %s" % cnx.user(self.session).eid)
+ # HAVING on write queries test #############################################
+
+ def test_update_having(self):
+ peid1 = self.execute("INSERT Personne Y: Y nom 'hop', Y tel 1")[0][0]
+ peid2 = self.execute("INSERT Personne Y: Y nom 'hop', Y tel 2")[0][0]
+ rset = self.execute("SET X tel 3 WHERE X tel TEL HAVING TEL&1=1")
+ self.assertEqual(tuplify(rset.rows), [(peid1, 3)])
+
+ def test_insert_having(self):
+ self.skip('unsupported yet')
+ self.execute("INSERT Personne Y: Y nom 'hop', Y tel 1")[0][0]
+ with self.debugged('DBG_SQL'):
+ self.assertFalse(self.execute("INSERT Personne Y: Y nom 'hop', Y tel 2 WHERE X tel XT HAVING XT&2=2"))
+ self.assertTrue(self.execute("INSERT Personne Y: Y nom 'hop', Y tel 2 WHERE X tel XT HAVING XT&1=1"))
+
+ def test_delete_having(self):
+ self.execute("INSERT Personne Y: Y nom 'hop', Y tel 1")[0][0]
+ self.assertFalse(self.execute("DELETE Personne Y WHERE X tel XT HAVING XT&2=2"))
+ self.assertTrue(self.execute("DELETE Personne Y WHERE X tel XT HAVING XT&1=1"))
+
# upassword encryption tests #################################################
def test_insert_upassword(self):