query: Report data type for unary operators
authorMichael Hanselmann <hansmi@google.com>
Thu, 11 Oct 2012 08:44:12 +0000 (10:44 +0200)
committerMichael Hanselmann <hansmi@google.com>
Thu, 11 Oct 2012 09:23:54 +0000 (11:23 +0200)
All data kinds (used to restrict the data collected) referenced in a
filter can be requested once it's been “compiled”. However, the kinds
of fields used in boolean expressions (e.g. ["?", "xyz"]) were not
recorded. This patch changes the code accordingly and provides a unit
test update.

Signed-off-by: Michael Hanselmann <hansmi@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>

lib/query.py
test/ganeti.query_unittest.py

index b922bf9..01b434b 100644 (file)
@@ -269,13 +269,16 @@ class _FilterHints:
     if op != qlang.OP_OR:
       self._NeedAllNames()
 
-  def NoteUnaryOp(self, op): # pylint: disable=W0613
+  def NoteUnaryOp(self, op, datakind): # pylint: disable=W0613
     """Called when handling an unary operation.
 
     @type op: string
     @param op: Operator
 
     """
+    if datakind is not None:
+      self._datakinds.add(datakind)
+
     self._NeedAllNames()
 
   def NoteBinaryOp(self, op, datakind, name, value):
@@ -557,19 +560,22 @@ class _FilterCompilerHelper:
     """
     assert op_fn is None
 
-    if hints_fn:
-      hints_fn(op)
-
     if len(operands) != 1:
       raise errors.ParameterError("Unary operator '%s' expects exactly one"
                                   " operand" % op)
 
     if op == qlang.OP_TRUE:
-      (_, _, _, retrieval_fn) = self._LookupField(operands[0])
+      (_, datakind, _, retrieval_fn) = self._LookupField(operands[0])
+
+      if hints_fn:
+        hints_fn(op, datakind)
 
       op_fn = operator.truth
       arg = retrieval_fn
     elif op == qlang.OP_NOT:
+      if hints_fn:
+        hints_fn(op, None)
+
       op_fn = operator.not_
       arg = self._Compile(operands[0], level + 1)
     else:
index f1e848b..024102a 100755 (executable)
@@ -1521,6 +1521,19 @@ class TestQueryFilter(unittest.TestCase):
     self.assertEqual(q.RequestedData(), set([DK_B]))
     self.assertEqual(q.Query(data), [[]])
 
+    # Data type in boolean operator
+    q = query.Query(fielddefs, [], namefield="name",
+                    qfilter=["?", "name"])
+    self.assertTrue(q.RequestedNames() is None)
+    self.assertEqual(q.RequestedData(), set([DK_A]))
+    self.assertEqual(q.Query(data), [[], [], []])
+
+    q = query.Query(fielddefs, [], namefield="name",
+                    qfilter=["!", ["?", "name"]])
+    self.assertTrue(q.RequestedNames() is None)
+    self.assertEqual(q.RequestedData(), set([DK_A]))
+    self.assertEqual(q.Query(data), [])
+
   def testFilterContains(self):
     fielddefs = query._PrepareFieldList([
       (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),