     (throw (IllegalArgumentException. (format "'not' takes exactly one argument, but %d were supplied" (count terms)))))
   (negate-term* ops (first terms)))
 
-(def fact-columns #{"certname" "name" "value"})
-
-(def resource-columns #{"certname" "catalog" "resource" "type" "title" "tags" "exported" "sourcefile" "sourceline"})
-
-(def node-columns #{"name" "deactivated"})
-
-(def selectable-columns
-  {:resource resource-columns
-   :fact fact-columns
-   :node node-columns})
+;; This map's keys are the queryable fields for facts, and the values are the
+;;  corresponding table names where the fields reside
+(def fact-columns {"certname" "certname_facts"
+                   "name"     "certname_facts"
+                   "value"    "certname_facts"})
+
+;; This map's keys are the queryable fields for resources, and the values are the
+;;  corresponding table names where the fields reside
+(def resource-columns {"certname"   "certname_catalogs"
+                       "catalog"    "catalog_resources"
+                       "resource"   "catalog_resources"
+                       "type"       "catalog_resources"
+                       "title"      "catalog_resources"
+                       "tags"       "catalog_resources"
+                       "exported"   "catalog_resources"
+                       "sourcefile" "catalog_resources"
+                       "sourceline" "catalog_resources"})
+
+;; This map's keys are the queryable fields for nodes, and the values are the
+;;  corresponding table names where the fields reside
+(def node-columns {"name"         "certnames"
+                   "deactivated"  "certnames"})
+
+(defn column-map->sql
+  "Helper function that converts one of our column maps to a SQL string suitable
+  for use in a SELECT"
+  [col-map]
+  (string/join ", "
+    (for [[field table] col-map]
+      (str table "." field))))
+
+
+(def queryable-fields
+  {:resource (keyset resource-columns)
+   :fact     (keyset fact-columns)
+   :node     (keyset node-columns)})
 
 (def subquery->type
   {"select-resources" :resource

;;
(ns com.puppetlabs.puppetdb.query
  (:require [clojure.string :as string])
  (:use [com.puppetlabs.utils :only [parse-number]]
        [com.puppetlabs.puppetdb.scf.storage :only [db-serialize sql-as-numeric sql-array-query-string sql-regexp-match sql-regexp-array-match]]
        [com.puppetlabs.jdbc :only [valid-jdbc-query?]]
        [clojure.core.match :only [match]]))

         (coll? subquery)]
   :post [(map? %)
          (string? (:where %))]}
  (when-not (get-in queryable-fields [kind field])
    (throw (IllegalArgumentException. (format "Can't match on unknown %s field '%s' for 'in'. Acceptable fields are: %s" (name kind) field (string/join ", " (sort (queryable-fields kind)))))))
  (when-not (= (first subquery) "extract")
    (throw (IllegalArgumentException. (format "The subquery argument of 'in' must be an 'extract', not '%s'" (first subquery)))))
  (let [{:keys [where] :as compiled-subquery} (compile-term ops subquery)]
