From f2e4c2c70344dd1a98593cfbe9256d1b3ed54f27 Mon Sep 17 00:00:00 2001
From: Boris Kolpackov <boris@codesynthesis.com>
Date: Fri, 12 Oct 2012 17:24:45 +0200
Subject: Completion of prepared query support

---
 common/prepared/driver.cxx | 276 ++++++++++++++++++++++++++++++++++++++++++++-
 common/prepared/makefile   |   2 +-
 common/prepared/test.hxx   |   7 ++
 3 files changed, 281 insertions(+), 4 deletions(-)

(limited to 'common/prepared')

diff --git a/common/prepared/driver.cxx b/common/prepared/driver.cxx
index 24a3788..6738e6b 100644
--- a/common/prepared/driver.cxx
+++ b/common/prepared/driver.cxx
@@ -5,7 +5,8 @@
 // Test prepared query functionality.
 //
 
-#include <memory>   // std::auto_ptr
+#include <memory>   // std::auto_ptr, std::unique_ptr
+#include <utility>  // std::move
 #include <cassert>
 #include <iostream>
 
@@ -13,6 +14,7 @@
 #include <odb/transaction.hxx>
 
 #include <common/common.hxx>
+#include <common/config.hxx> // HAVE_CXX11
 
 #include "test.hxx"
 #include "test-odb.hxx"
@@ -20,6 +22,26 @@
 using namespace std;
 using namespace odb::core;
 
+struct params
+{
+  unsigned short age;
+  std::string name;
+};
+
+static void
+query_factory (const char* name, connection& c)
+{
+  typedef odb::query<person> query;
+
+  auto_ptr<params> p (new params);
+  prepared_query<person> pq (
+    c.prepare_query<person> (
+      name,
+      query::age > query::_ref (p->age) &&
+      query::name != query::_ref (p->name)));
+  c.cache_query (pq, p);
+}
+
 int
 main (int argc, char* argv[])
 {
@@ -47,14 +69,14 @@ main (int argc, char* argv[])
     typedef odb::prepared_query<person> prep_query;
     typedef odb::result<person> result;
 
-    // Simple case: uncached query.
+    // Uncached query.
     //
     {
       transaction t (db->begin ());
 
       unsigned short age (90);
       prep_query pq (
-        t.connection ().prepare_query<person> (
+        db->prepare_query<person> (
           "person-age-query",
           query::age > query::_ref (age)));
 
@@ -64,6 +86,254 @@ main (int argc, char* argv[])
         assert (size (r) == i);
       }
 
+      age = 90;
+      result r (pq.execute ());
+      result::iterator i (r.begin ());
+      assert (i != r.end () && i->name_ == "John First" && i->age_ == 91);
+      assert (++i == r.end ());
+
+      t.commit ();
+    }
+
+    // Cached query without parameters.
+    //
+    {
+      for (unsigned short i (1); i < 6; ++i)
+      {
+        transaction t (db->begin ());
+
+        prep_query pq (db->lookup_query<person> ("person-val-age-query"));
+
+        if (!pq)
+        {
+          assert (i == 1);
+          pq = db->prepare_query<person> (
+            "person-val-age-query",
+            query::age > 90);
+          db->cache_query (pq);
+          prep_query pq1 (db->lookup_query<person> ("person-val-age-query"));
+        }
+        else if (i == 2)
+        {
+          try
+          {
+            db->cache_query (pq);
+            assert (false);
+          }
+          catch (const odb::prepared_already_cached&)
+          {
+          }
+        }
+
+        result r (pq.execute ());
+        assert (size (r) == 1);
+
+        t.commit ();
+      }
+    }
+
+    // Cached query with parameters.
+    //
+    {
+      for (unsigned short i (1); i < 6; ++i)
+      {
+        transaction t (db->begin ());
+
+        unsigned short* age;
+        prep_query pq (db->lookup_query<person> ("person-ref-age-query", age));
+
+        if (!pq)
+        {
+          assert (i == 1);
+
+#ifdef HAVE_CXX11
+          unique_ptr<unsigned short> p (new unsigned short);
+#else
+          auto_ptr<unsigned short> p (new unsigned short);
+#endif
+          age = p.get ();
+          pq = db->prepare_query<person> (
+            "person-ref-age-query",
+            query::age > query::_ref (*age));
+
+#ifdef HAVE_CXX11
+          db->cache_query (pq, move (p));
+#else
+          db->cache_query (pq, p);
+#endif
+        }
+        else if (i == 2)
+        {
+          // Object type mismatch.
+          //
+          try
+          {
+            db->lookup_query<int> ("person-ref-age-query", age);
+            assert (false);
+          }
+          catch (const odb::prepared_type_mismatch&)
+          {
+          }
+
+          // Parameters type mismatch.
+          //
+          try
+          {
+            int* age;
+            db->lookup_query<person> ("person-ref-age-query", age);
+            assert (false);
+          }
+          catch (const odb::prepared_type_mismatch&)
+          {
+          }
+        }
+
+        *age = 100 - i * 10;
+        result r (pq.execute ());
+        assert (size (r) == i);
+
+        t.commit ();
+      }
+    }
+
+    // Cached query with factory.
+    //
+    {
+      db->query_factory ("person-params-query", &query_factory);
+
+      for (unsigned int i (1); i < 6; ++i)
+      {
+        transaction t (db->begin ());
+
+        params* p;
+        prep_query pq (db->lookup_query<person> ("person-params-query", p));
+        assert (pq);
+
+        p->age = 100 - i * 10;
+        p->name = "John First";
+        result r (pq.execute ());
+        assert (size (r) == i - 1);
+
+        t.commit ();
+      }
+
+      db->query_factory ("person-params-query", 0);
+    }
+
+    // Cached query with wildcard factory.
+    //
+    {
+      db->query_factory ("", &query_factory);
+
+      for (unsigned int i (1); i < 6; ++i)
+      {
+        transaction t (db->begin ());
+
+        params* p;
+        prep_query pq (db->lookup_query<person> ("person-params-query-1", p));
+        assert (pq);
+
+        p->age = 100 - i * 10;
+        p->name = "John First";
+        result r (pq.execute ());
+        assert (size (r) == i - 1);
+
+        t.commit ();
+      }
+
+      db->query_factory ("", 0);
+    }
+
+    // Cached query with lambda factory.
+    //
+#ifdef HAVE_CXX11
+    {
+      db->query_factory (
+        "person-params-query-2",
+        [] (const char* name, connection& c)
+        {
+            auto_ptr<params> p (new params);
+            prepared_query<person> pq (
+              c.prepare_query<person> (
+                name,
+                query::age > query::_ref (p->age) &&
+                query::name != query::_ref (p->name)));
+            c.cache_query (pq, p);
+        });
+
+      for (unsigned int i (1); i < 6; ++i)
+      {
+        transaction t (db->begin ());
+
+        params* p;
+        prep_query pq (db->lookup_query<person> ("person-params-query-2", p));
+        assert (pq);
+
+        p->age = 100 - i * 10;
+        p->name = "John First";
+        result r (pq.execute ());
+        assert (size (r) == i - 1);
+
+        t.commit ();
+      }
+
+      db->query_factory ("person-params-query-2", 0);
+    }
+#endif
+
+    // View prepared query.
+    //
+    {
+      typedef odb::query<person_view> query;
+      typedef odb::prepared_query<person_view> prep_query;
+      typedef odb::result<person_view> result;
+
+      transaction t (db->begin ());
+
+      unsigned short age (90);
+      prep_query pq (
+        db->prepare_query<person_view> (
+          "person-view-age-query",
+          query::age > query::_ref (age)));
+
+      for (unsigned short i (1); i < 6; ++i, age -= 10)
+      {
+        result r (pq.execute ());
+        assert (size (r) == i);
+      }
+
+      age = 90;
+      result r (pq.execute ());
+      result::iterator i (r.begin ());
+      assert (i != r.end () && i->name == "John First" && i->age == 91);
+      assert (++i == r.end ());
+
+      t.commit ();
+    }
+
+    // By-ref parameter image growth.
+    //
+    {
+      transaction t (db->begin ());
+
+      string name;
+      prep_query pq (
+        db->prepare_query<person> (
+          "person-name-query",
+          query::name != query::_ref (name)));
+
+      {
+        name = "John First";
+        result r (pq.execute ());
+        assert (size (r) == 4);
+      }
+
+      {
+        name.assign (2048, 'x');
+        result r (pq.execute ());
+        assert (size (r) == 5);
+      }
+
       t.commit ();
     }
   }
diff --git a/common/prepared/makefile b/common/prepared/makefile
index 6da88d3..4126b54 100644
--- a/common/prepared/makefile
+++ b/common/prepared/makefile
@@ -35,7 +35,7 @@ gen  := $(addprefix $(out_base)/,$(genf))
 $(gen): $(odb)
 $(gen): odb := $(odb)
 $(gen) $(dist): export odb_options += --database $(db_id) --generate-schema \
---generate-query --omit-unprepared --table-prefix prepared_
+--generate-query --generate-prepared --omit-unprepared --table-prefix prepared_
 $(gen): cpp_options := -I$(src_base)
 $(gen): $(common.l.cpp-options)
 
diff --git a/common/prepared/test.hxx b/common/prepared/test.hxx
index 734b138..7ea0ce8 100644
--- a/common/prepared/test.hxx
+++ b/common/prepared/test.hxx
@@ -23,4 +23,11 @@ struct person
   unsigned short age_;
 };
 
+#pragma db view object(person)
+struct person_view
+{
+  std::string name;
+  unsigned short age;
+};
+
 #endif // TEST_HXX
-- 
cgit v1.1