diff --git a/tracfullblog/core.py b/tracfullblog/core.py
index a69ff3d..861a932 100644
--- a/tracfullblog/core.py
+++ b/tracfullblog/core.py
@@ -152,30 +152,31 @@ class FullBlogCore(Component):
     
     def get_bloginfotext(self):
         """ Retrieves the blog info text in sidebar from database. """
-        try:
+        sql = "SELECT value from system WHERE name='fullblog_infotext'"
+        if hasattr(self.env, 'db_query'):
+            rows = list(self.env.db_query(sql))
+        else:
             cnx = self.env.get_db_cnx()
             cursor = cnx.cursor()
-            cursor.execute("SELECT value from system " \
-                "WHERE name='fullblog_infotext'")
+            cursor.execute()
             rows = cursor.fetchall()
-            if rows:
-                return rows[0][0] # Only item in cursor (hopefully)
-            else:
-                return ''
-        except:
+        if rows:
+            return rows[0][0] # Only item in cursor (hopefully)
+        else:
             return ''
 
     def set_bloginfotext(self, text=''):
         """ Stores the blog info text in the database. """
-        try:
+        sql = "UPDATE system set value=%s WHERE name=%s"
+        args = (text, 'fullblog_infotext')
+        if hasattr(self.env, 'db_transaction'):
+            self.env.db_transaction(sql, args)
+        else:
             cnx = self.env.get_db_cnx()
             cursor = cnx.cursor()
-            cursor.execute("UPDATE system set value=%s " \
-                "WHERE name=%s", (text, 'fullblog_infotext'))
+            cursor.execute(sql, args)
             cnx.commit()
-            return True
-        except:
-            return False
+        return True
     
     def get_prev_next_posts(self, perm, post_name):
         """ Returns the name of the next and previous posts when compared with
diff --git a/tracfullblog/model.py b/tracfullblog/model.py
index e870549..92bf65a 100644
--- a/tracfullblog/model.py
+++ b/tracfullblog/model.py
@@ -37,12 +37,15 @@ def search_blog_posts(env, terms):
     Returns a list of tuples with:
         (name, version, publish_time, author, title, body) """
     assert terms
-    cnx = env.get_db_cnx()
-    cursor = cnx.cursor()
-    # SQL
+    # construct sql + args
     columns = ['bp1.name', 'bp1.title', 'bp1.body',
                'bp1.author', 'bp1.categories']
-    search_clause, args = search_to_sql(cnx, columns, terms)
+    if hasattr(env, 'db_query'):
+        with env.db_query as db:
+            search_clause, args = search_to_sql(db, columns, terms)
+    else:
+        db = env.get_db_cnx()
+        search_clause, args = search_to_sql(db, columns, terms)
     sql = "SELECT bp1.name, bp1.version, bp1.publish_time, bp1.author, " \
                "bp1.title, bp1.body " \
                "FROM fullblog_posts bp1," \
@@ -50,9 +53,14 @@ def search_blog_posts(env, terms):
                "FROM fullblog_posts GROUP BY name) bp2 " \
                "WHERE bp1.version = bp2.ver AND bp1.name = bp2.name " \
                "AND " + search_clause
-    env.log.debug("search_blog_posts() SQL: %r" % sql)
-    cursor.execute(sql, args)
-    # Return the items we have found
+    # perform search
+    if hasattr(env, 'db_query'):
+        cursor = env.db_query(sql, args)
+    else:
+        db = env.get_db_cnx()
+        cursor = db.cursor()
+        cursor.execute(sql, args)
+    # return found items
     return [(row[0], row[1], to_datetime(row[2], utc), row[3],
             row[4], row[5]) for row in cursor]
 
@@ -62,16 +70,24 @@ def search_blog_comments(env, terms):
     Returns a list of tuples with:
         (post_name, comment_number, comment, comment_author, comment_time) """
     assert terms
-    cnx = env.get_db_cnx()
-    cursor = cnx.cursor()
-    # SQL
+    # construct sql + args
     columns = ['author', 'comment']
-    search_clause, args = search_to_sql(cnx, columns, terms)
+    if hasattr(env, 'db_query'):
+        with env.db_query as db:
+            search_clause, args = search_to_sql(db, columns, terms)
+    else:
+        db = env.get_db_cnx()
+        search_clause, args = search_to_sql(db, columns, terms)
     sql = "SELECT name, number, comment, author, time " \
           "FROM fullblog_comments WHERE " + search_clause
-    env.log.debug("search_blog_comments() SQL: %r" % sql)
-    cursor.execute(sql, args)
-    # Return the items we have found
+    # perform search
+    if hasattr(env, 'db_query'):
+        cursor = env.db_query(sql, args)
+    else:
+        db = env.get_db_cnx()
+        cursor = db.cursor()
+        cursor.execute(sql, args)
+    # return found items
     return [(row[0], row[1], row[2], row[3], to_datetime(row[4], utc))
             for row in cursor]
 
@@ -93,39 +109,49 @@ def get_blog_posts(env, category='', author='', from_dt=None, to_dt=None,
         (name, version, time, author, title, body, category_list)
     Use 'name' and 'version' to instantiate BlogPost objects."""
 
-    cnx = env.get_db_cnx()
-    cursor = cnx.cursor()
+    # Get db.like() text for reuse
+    if hasattr(env, 'db_query'):
+        with env.db_query as db:
+            db_like = db.like()
+    else:
+        db = env.get_db_cnx()
+        db_like = db.like()
 
-    # Build the list of WHERE restrictions
+    # Build SQL with list of WHERE restrictions
     time_field = 'bp1.publish_time'
     join_operation = ",(SELECT name, max(version) AS ver " \
                      "FROM fullblog_posts GROUP BY name) bp2 " \
                      "WHERE bp1.version = bp2.ver AND bp1.name = bp2.name "
     where_clause = ""
-    where_values = None
+    args = None
     if all_versions:
         time_field = 'bp1.version_time'
         join_operation = ""
-    args = [category and ("bp1.categories "+cnx.like(), "%"+category+"%"),
+    clauses = [category and ("bp1.categories "+db_like, "%"+category+"%"),
             author and ("bp1.author=%s", author) or None,
             from_dt and (time_field+">%s", to_timestamp(from_dt)) or None,
             to_dt and (time_field+"<%s", to_timestamp(to_dt)) or None]
-    args = [arg for arg in args if arg]  # Ignore the None values
-    if args:
+    clauses = [arg for arg in clauses if arg]  # Ignore the None values
+    if clauses:
         where_start = "AND "
         if not join_operation:
             where_start = "WHERE "
-        where_clause = where_start + " AND ".join([arg[0] for arg in args])
-        where_values = tuple([arg[1] for arg in args])
-
-    # Run the SQL
+        where_clause = where_start + " AND ".join([arg[0] for arg in clauses])
+        args = tuple([arg[1] for arg in clauses])
     sql = "SELECT bp1.name, bp1.version, bp1.publish_time, bp1.author, " \
                "bp1.title, bp1.body, bp1.categories " \
                "FROM fullblog_posts bp1 " \
                + join_operation + where_clause \
                + " ORDER BY bp1.publish_time DESC"
-    env.log.debug("get_blog_posts() SQL: %r (%r)" % (sql, where_values))
-    cursor.execute(sql, where_values)
+
+    # Execute SQL
+    if hasattr(env, 'db_query'):
+        with env.db_query as db:
+            cursor = env.db_query(sql, args)
+    else:
+        db = env.get_db_cnx()
+        cursor = db.cursor()
+        cursor.execute(sql, args)
 
     # Return the rows
     blog_posts = []
@@ -150,23 +176,25 @@ def get_blog_comments(env, post_name='', from_dt=None, to_dt=None):
         sorted(comments, key=itemgetter(4), reverse=True) """
 
     # Build the list of WHERE restrictions
-    args = [post_name and ("name=%s", post_name) or None,
+    clauses = [post_name and ("name=%s", post_name) or None,
             from_dt and ("time>%s", to_timestamp(from_dt)) or None,
             to_dt and ("time<%s", to_timestamp(to_dt)) or None]
-    args = [arg for arg in args if arg]
+    clauses = [arg for arg in clauses if arg]
     where_clause = ""
-    where_values = None
-    if args:
-        where_clause = "WHERE " + " AND ".join([arg[0] for arg in args])
-        where_values = tuple([arg[1] for arg in args])
-
-    # Do the SELECT
-    cnx = env.get_db_cnx()
-    cursor = cnx.cursor()
+    args = None
+    if clauses:
+        where_clause = "WHERE " + " AND ".join([arg[0] for arg in clauses])
+        args = tuple([arg[1] for arg in clauses])
     sql = "SELECT name, number, comment, author, time " \
             "FROM fullblog_comments " + where_clause
-    env.log.debug("get_blog_comments() SQL: %r (%r)" % (sql, where_values))
-    cursor.execute(sql, where_values or None)
+
+    # Do the SELECT
+    if hasattr(env, 'db_query'):
+        cursor = env.db_query(sql, args)
+    else:    
+        db = env.get_db_cnx()
+        cursor = db.cursor()
+        cursor.execute(sql, args)
 
     # Return the items we have found
     return [(row[0], row[1], row[2], row[3], to_datetime(row[4], utc))
@@ -175,13 +203,16 @@ def get_blog_comments(env, post_name='', from_dt=None, to_dt=None):
 def get_blog_resources(env):
     """ Returns a list of resource instances of existing blog posts (current
     version). The list is ordered by publish_time (newest first). """
-    cnx = env.get_db_cnx()
-    cursor = cnx.cursor()
     sql = "SELECT bp1.name FROM fullblog_posts bp1, " \
           "(SELECT name, max(version) AS ver FROM fullblog_posts " \
           "GROUP BY name) bp2 WHERE bp1.name = bp2.name AND " \
           "bp1.version = ver ORDER BY bp1.publish_time DESC"
-    cursor.execute(sql)
+    if hasattr(env, 'db_query'):
+        cursor = env.db_query(sql)
+    else:
+        db = env.get_db_cnx()
+        cursor = db.cursor()
+        cursor.execute(sql)
     blog_realm = Resource('blog')
     return [blog_realm(id=post[0], version=0) for post in cursor]
 
@@ -279,42 +310,53 @@ class BlogComment(object):
         if warnings or verify_only:
             return warnings
         # No problems (we think), try to save.
-        cnx = self.env.get_db_cnx()
-        cursor = cnx.cursor()
         self.env.log.debug("Creating blog comment number %d for %r" % (
                 number, self.post_name))
-        cursor.execute("INSERT INTO fullblog_comments "
-                "VALUES (%s, %s, %s, %s, %s)", (self.post_name,
-                number, comment, author, to_timestamp(self.time)) )
-        cnx.commit()
+        sql = "INSERT INTO fullblog_comments VALUES (%s, %s, %s, %s, %s)"
+        args = (self.post_name, number, comment, author,
+                to_timestamp(self.time))
+        if hasattr(self.env, 'db_transaction'):
+            self.env.db_transaction(sql, args)
+        else:
+            db = self.env.get_db_cnx()
+            cursor = db.cursor()
+            cursor.execute(sql, args)
+            db.commit()
         self._load_comment(number)
         return warnings
     
     def delete(self):
         if not self.post_name or not self.number:
             return False
-        cnx = self.env.get_db_cnx()
-        cursor = cnx.cursor()
         self.env.log.debug("Deleting blog comment number %d for %r" % (
                 self.number, self.post_name))
-        cursor.execute("DELETE FROM fullblog_comments "
-                "WHERE name=%s AND number=%s",  (
-                self.post_name, self.number))
-        cnx.commit()
+        sql = "DELETE FROM fullblog_comments WHERE name=%s AND number=%s"
+        args = (self.post_name, self.number)
+        if hasattr(self.env, 'db_transaction'):
+            self.env.db_transaction(sql, args)
+        else:
+            db = self.env.get_db_cnx()
+            cursor = db.cursor()
+            cursor.execute(sql, args)
+            db.commit()
         return True
 
     # Internal methods
     
     def _load_comment(self, number):
         """ Loads a comment from database if found. """
-        cnx = self.env.get_db_cnx()
-        cursor = cnx.cursor()
         self.env.log.debug("Fetching blog comment number %d for %r" % (
                 number, self.post_name))
-        cursor.execute("SELECT comment, author, time "
-                "FROM fullblog_comments "
-                "WHERE name=%s AND number=%s",
-                (self.post_name, number))
+        sql = "SELECT comment, author, time " \
+                "FROM fullblog_comments " \
+                "WHERE name=%s AND number=%s"
+        args = (self.post_name, number)
+        if hasattr(self.env, 'db_query'):
+            cursor = self.env.db_query(sql, args)
+        else:
+            db = self.env.get_db_cnx()
+            cursor = db.cursor()
+            cursor.execute(sql, args)
         for row in cursor:
             self.number = number
             self.comment = row[0]
@@ -326,13 +368,17 @@ class BlogComment(object):
     def _next_comment_number(self):
         """ Function that returns the next available comment number.
         If no blog post exists (can't attach comment), it returns 0. """
-        cnx = self.env.get_db_cnx()
-        cursor = cnx.cursor()
-        cursor.execute("SELECT number FROM fullblog_comments "
-            "WHERE name=%s", (self.post_name,))
-        cmts = sorted([row[0] for row in cursor])
-        if cmts:
-            return cmts[-1] + 1 # Add 1 for next free
+        sql = "SELECT number FROM fullblog_comments WHERE name=%s"
+        args = (self.post_name,)
+        if hasattr(self.env, 'db_query'):
+            cursor = self.env.db_query(sql, args)
+        else:
+            db = self.env.get_db_cnx()
+            cursor = db.cursor()
+            cursor.execute(sql, args)
+        comments = sorted([row[0] for row in cursor])
+        if comments:
+            return comments[-1] + 1 # Add 1 for next free
         # No item found - need to double-check to find out why
         bp = BlogPost(self.env, self.post_name)
         if bp.get_versions():
@@ -396,16 +442,19 @@ class BlogPost(object):
             version = self.versions[-1] + 1
         self.env.log.debug("Saving new version %d of blog post %r "
                 "from author %r" % (version, self.name, version_author))
-        cnx = self.env.get_db_cnx()
-        cursor = cnx.cursor()
-        cursor.execute("INSERT INTO fullblog_posts "
-                "(name, version, title, body, publish_time, version_time, "
-                "version_comment, version_author, author, categories) "
-                "VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
-                (self.name, version, self.title, self.body,
+        sql = "INSERT INTO fullblog_posts " \
+                "(name, version, title, body, publish_time, version_time, " \
+                "version_comment, version_author, author, categories) " \
+                "VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"
+        args = (self.name, version, self.title, self.body,
                 to_timestamp(self.publish_time), version_time,
-                version_comment, version_author, self.author, self.categories))
-        cnx.commit()
+                version_comment, version_author, self.author, self.categories)
+        if hasattr(self.env, 'db_transaction'):
+            self.env.db_transaction(sql, args)
+        else:
+            db = self.env.get_db_cnx()
+            cursor = db.cursor()
+            cursor.execute(sql, args)
         self._load_post(version)
         return warnings
     
@@ -432,32 +481,42 @@ class BlogPost(object):
         """ Deletes a specific version, or if none is provided
         then all versions will be deleted. If all (or just one version exists) it
         will also delete all comments and any attachments attached to the post. """
-        cnx = self.env.get_db_cnx()
-        cursor = cnx.cursor()
         if version:
-            cursor.execute("DELETE FROM fullblog_posts "
-                    "WHERE name=%s AND version=%s",
-                    (self.name, version))
+            sql = "DELETE FROM fullblog_posts WHERE name=%s AND version=%s"
+            args = (self.name, version)
         else:
-            cursor.execute("DELETE FROM fullblog_posts "
-                    "WHERE name=%s", (self.name,))
-        cnx.commit()
+            sql = "DELETE FROM fullblog_posts WHERE name=%s"
+            args = (self.name,)
+        if hasattr(self.env, 'db_transaction'):
+            self.env.db_transaction(sql, args)
+            db = None
+        else:
+            db = self.env.get_db_cnx()
+            cursor = db.cursor()
+            cursor.execute(sql, args)
+            db.commit()
         if not len(self.get_versions()):
             # Delete comments
             for comment in self.get_comments():
                 comment.delete()
             # Delete attachments
-            Attachment.delete_all(self.env, 'blog', self.name, cnx)
-            cnx.commit()
+            if db is not None:
+                Attachment.delete_all(self.env, 'blog', self.name, db)
+            else:
+                Attachment.delete_all(self.env, 'blog', self.name)
         return True
     
     def get_versions(self):
         """ Returns a sorted list of versions stored for the blog post.
         Returns empty list ([]) if no versions exists. """
-        cnx = self.env.get_db_cnx()
-        cursor = cnx.cursor()
-        cursor.execute("SELECT version from fullblog_posts "
-                "WHERE name=%s", (self.name,) )
+        sql = "SELECT version from fullblog_posts WHERE name=%s"
+        args = (self.name,)
+        if hasattr(self.env, 'db_query'):
+            cursor = self.env.db_query(sql, args)
+        else:
+            db = self.env.get_db_cnx()
+            cursor = db.cursor()
+            cursor.execute(sql, args)
         self.versions = sorted([row[0] for row in cursor])
         return self.versions
         
@@ -482,13 +541,17 @@ class BlogPost(object):
             # No blog post with the name exists
             return {}
         version = version or self.versions[-1]
-        cnx = self.env.get_db_cnx()
-        cursor = cnx.cursor()
-        cursor.execute("SELECT title, body, publish_time, version_time, "
-                "version_comment, version_author, author, categories "
-                "FROM fullblog_posts "
-                "WHERE name=%s AND version=%s",
-                (self.name, version) )
+        sql = "SELECT title, body, publish_time, version_time, " \
+              "version_comment, version_author, author, categories " \
+              "FROM fullblog_posts " \
+              "WHERE name=%s AND version=%s"
+        args = (self.name, version)
+        if hasattr(self.env, 'db_query'):
+            cursor = self.env.db_query(sql, args)
+        else:
+            db = self.env.get_db_cnx()
+            cursor = db.cursor()
+            cursor.execute(sql, args)
         fields = {}
         for row in cursor:
             fields['version'] = version
diff --git a/tracfullblog/tags.py b/tracfullblog/tags.py
index dbead0e..7b91850 100644
--- a/tracfullblog/tags.py
+++ b/tracfullblog/tags.py
@@ -27,9 +27,6 @@ class FullBlogTagSystem(Component):
         if 'TAGS_VIEW' not in req.perm or 'BLOG_VIEW' not in req.perm:
             return
 
-        db = self.env.get_db_cnx()
-        cursor = db.cursor()
-
         args = []
         constraints = []
         sql = "SELECT bp1.name, bp1.categories, bp1.version " \
@@ -46,8 +43,14 @@ class FullBlogTagSystem(Component):
         if constraints:
             sql += " AND " + " AND ".join(constraints)
         sql += " ORDER BY bp1.name"
-        self.env.log.debug(sql)
-        cursor.execute(sql, args)
+
+        if hasattr(self.env, 'db_query'):
+            cursor = self.env.db_query(sql, args)
+        else:
+            db = self.env.get_db_cnx()
+            cursor = db.cursor()
+            cursor.execute(sql, args)
+
         for row in cursor:
             post_name, categories = row[0], set(_parse_categories(row[1]))
             if not tags or categories.intersection(tags):
diff --git a/tracfullblog/templates/fullblog.rss b/tracfullblog/templates/fullblog.rss
index 079eda7..9c71519 100644
--- a/tracfullblog/templates/fullblog.rss
+++ b/tracfullblog/templates/fullblog.rss
@@ -2,7 +2,6 @@
 <rss version="2.0" xmlns:py="http://genshi.edgewall.org/"
                    xmlns:dc="http://purl.org/dc/elements/1.1/"
                    xmlns:xi="http://www.w3.org/2001/XInclude">
-  <xi:include href="macros.rss" />
   <channel>
     <title>${project.name} - Blog</title>
     <link>${abs_href.blog()}</link>
diff --git a/tracfullblog/templates/fullblog_archive.html b/tracfullblog/templates/fullblog_archive.html
index 214d180..d3f44e4 100644
--- a/tracfullblog/templates/fullblog_archive.html
+++ b/tracfullblog/templates/fullblog_archive.html
@@ -5,7 +5,6 @@
       xmlns:py="http://genshi.edgewall.org/"
       xmlns:xi="http://www.w3.org/2001/XInclude">
   <xi:include href="layout.html" />
-  <xi:include href="macros.html" />
   <head>
     <title>Blog Archive</title>
     <meta name="ROBOTS" content="NOINDEX" />
diff --git a/tracfullblog/templates/fullblog_delete.html b/tracfullblog/templates/fullblog_delete.html
index 686d8cb..d403a84 100644
--- a/tracfullblog/templates/fullblog_delete.html
+++ b/tracfullblog/templates/fullblog_delete.html
@@ -5,7 +5,6 @@
       xmlns:py="http://genshi.edgewall.org/"
       xmlns:xi="http://www.w3.org/2001/XInclude">
   <xi:include href="layout.html" />
-  <xi:include href="macros.html" />
   <head>
     <title>Blog : Delete</title>
   </head>
diff --git a/tracfullblog/templates/fullblog_edit.html b/tracfullblog/templates/fullblog_edit.html
index 28ef32c..cef720c 100644
--- a/tracfullblog/templates/fullblog_edit.html
+++ b/tracfullblog/templates/fullblog_edit.html
@@ -5,7 +5,6 @@
       xmlns:py="http://genshi.edgewall.org/"
       xmlns:xi="http://www.w3.org/2001/XInclude">
   <xi:include href="layout.html" />
-  <xi:include href="macros.html" />
   <head>
     <title>Edit Blog Post</title>
   </head>
diff --git a/tracfullblog/templates/fullblog_post.rss b/tracfullblog/templates/fullblog_post.rss
index 8c11178..a556926 100644
--- a/tracfullblog/templates/fullblog_post.rss
+++ b/tracfullblog/templates/fullblog_post.rss
@@ -2,7 +2,6 @@
 <rss version="2.0" xmlns:py="http://genshi.edgewall.org/"
                    xmlns:dc="http://purl.org/dc/elements/1.1/"
                    xmlns:xi="http://www.w3.org/2001/XInclude">
-  <xi:include href="macros.rss" />
   <channel py:with="bp = blog_post">
     <title>${project.name} - Blog: ${bp.title}</title>
     <link>${abs_href.blog(bp.name)}</link>
diff --git a/tracfullblog/templates/fullblog_view.html b/tracfullblog/templates/fullblog_view.html
index 4c090bf..4269067 100644
--- a/tracfullblog/templates/fullblog_view.html
+++ b/tracfullblog/templates/fullblog_view.html
@@ -5,7 +5,7 @@
       xmlns:py="http://genshi.edgewall.org/"
       xmlns:xi="http://www.w3.org/2001/XInclude">
   <xi:include href="layout.html" />
-  <xi:include href="macros.html" />
+  <xi:include href="macros.html"><xi:fallback /></xi:include>
   <head>
     <title>Blog${defined('blog_post') and ': ' + blog_post.title \
                 or req.args.get('blog_path') and defined('blog_list_title') \
@@ -45,7 +45,15 @@
                   <input type="submit" value="${_('Edit post')}" accesskey="e" />
                 </div>
               </form>
-              ${attach_file_form(blog_attachments)}
+              <py:choose test="defined('attach_file_form')">
+                <py:when test="True">
+                  ${attach_file_form(blog_attachments)}
+                </py:when>
+                <py:when test="False">
+                  <xi:include href="attach_file_form.html"
+                              py:with="alist=blog_attachments"/>
+                </py:when>
+              </py:choose>
               <form method="get" action="${href.blog('delete', blog_post.name)}"
                     py:if="'BLOG_DELETE' in perm(blog_post.resource)">
                 <div>
@@ -57,7 +65,15 @@
           </py:if>
         
           <!--! List attachments -->
-          ${list_of_attachments(blog_attachments, compact=True)}
+          <py:choose test="defined('list_of_attachments')">
+            <py:when test="True">
+              ${list_of_attachments(blog_attachments, compact=True)}
+            </py:when>
+            <py:when test="False">
+              <xi:include href="list_of_attachments.html"
+                          py:with="alist=blog_attachments; compact=True"/>
+            </py:when>
+          </py:choose>
 
           <!--! View comments -->
           <div id="comments" py:with="blog_comments = blog_post.get_comments()">
