diff --git a/examples/authors/sqlc.json b/examples/authors/sqlc.json
index 303e2b03a3..558ea97cbe 100644
--- a/examples/authors/sqlc.json
+++ b/examples/authors/sqlc.json
@@ -5,6 +5,9 @@
       "schema": "postgresql/schema.sql",
       "queries": "postgresql/query.sql",
       "engine": "postgresql",
+      "database": {
+        "url": "'postgresql://%s:%s@%s:%s/authors'.format([env.PG_USER, env.PG_PASSWORD, env.PG_HOST, env.PG_PORT])"
+      },
       "gen": {
         "go": {
           "package": "authors",
diff --git a/examples/batch/sqlc.json b/examples/batch/sqlc.json
index f56bad9b5d..b994f3b945 100644
--- a/examples/batch/sqlc.json
+++ b/examples/batch/sqlc.json
@@ -7,6 +7,9 @@
       "schema": "postgresql/schema.sql",
       "queries": "postgresql/query.sql",
       "engine": "postgresql",
+      "database": {
+        "url": "'postgresql://%s:%s@%s:%s/batch'.format([env.PG_USER, env.PG_PASSWORD, env.PG_HOST, env.PG_PORT])"
+      },
       "sql_package": "pgx/v4",
       "emit_json_tags": true,
       "emit_prepared_queries": true,
diff --git a/examples/booktest/sqlc.json b/examples/booktest/sqlc.json
index d4a0be3a59..c0176d1f23 100644
--- a/examples/booktest/sqlc.json
+++ b/examples/booktest/sqlc.json
@@ -6,7 +6,10 @@
       "path": "postgresql",
       "schema": "postgresql/schema.sql",
       "queries": "postgresql/query.sql",
-      "engine": "postgresql"
+      "engine": "postgresql",
+      "database": {
+        "url": "'postgresql://%s:%s@%s:%s/booktest'.format([env.PG_USER, env.PG_PASSWORD, env.PG_HOST, env.PG_PORT])"
+      }
     },
     {
       "name": "booktest",
diff --git a/examples/jets/db.go b/examples/jets/postgresql/db.go
similarity index 100%
rename from examples/jets/db.go
rename to examples/jets/postgresql/db.go
diff --git a/examples/jets/models.go b/examples/jets/postgresql/models.go
similarity index 100%
rename from examples/jets/models.go
rename to examples/jets/postgresql/models.go
diff --git a/examples/jets/query-building.sql b/examples/jets/postgresql/query-building.sql
similarity index 100%
rename from examples/jets/query-building.sql
rename to examples/jets/postgresql/query-building.sql
diff --git a/examples/jets/query-building.sql.go b/examples/jets/postgresql/query-building.sql.go
similarity index 100%
rename from examples/jets/query-building.sql.go
rename to examples/jets/postgresql/query-building.sql.go
diff --git a/examples/jets/schema.sql b/examples/jets/postgresql/schema.sql
similarity index 100%
rename from examples/jets/schema.sql
rename to examples/jets/postgresql/schema.sql
diff --git a/examples/jets/sqlc.json b/examples/jets/sqlc.json
index 0bca6f48df..7b15009422 100644
--- a/examples/jets/sqlc.json
+++ b/examples/jets/sqlc.json
@@ -2,11 +2,14 @@
   "version": "1",
   "packages": [
     {
-      "path": ".",
+      "path": "postgresql",
       "name": "jets",
-      "schema": "schema.sql",
-      "queries": "query-building.sql",
-      "engine": "postgresql"
+      "schema": "postgresql/schema.sql",
+      "queries": "postgresql/query-building.sql",
+      "engine": "postgresql",
+      "database": {
+        "url": "'postgresql://%s:%s@%s:%s/jets'.format([env.PG_USER, env.PG_PASSWORD, env.PG_HOST, env.PG_PORT])"
+      }
     }
   ]
 }
diff --git a/examples/kotlin/sqlc.json b/examples/kotlin/sqlc.json
index 720f77ab88..284b76ec91 100644
--- a/examples/kotlin/sqlc.json
+++ b/examples/kotlin/sqlc.json
@@ -39,8 +39,8 @@
       ]
     },
     {
-      "schema": "src/main/resources/jets/schema.sql",
-      "queries": "src/main/resources/jets/query-building.sql",
+      "schema": "src/main/resources/jets/postgresql/schema.sql",
+      "queries": "src/main/resources/jets/postgresql/query-building.sql",
       "engine": "postgresql",
       "codegen": [
         {
diff --git a/examples/ondeck/sqlc.json b/examples/ondeck/sqlc.json
index 7ad4bb3fc4..f3ae36698c 100644
--- a/examples/ondeck/sqlc.json
+++ b/examples/ondeck/sqlc.json
@@ -7,6 +7,9 @@
       "schema": "postgresql/schema",
       "queries": "postgresql/query",
       "engine": "postgresql",
+      "database": {
+        "url": "'postgresql://%s:%s@%s:%s/ondeck'.format([env.PG_USER, env.PG_PASSWORD, env.PG_HOST, env.PG_PORT])"
+      },
       "emit_json_tags": true,
       "emit_prepared_queries": true,
       "emit_interface": true
diff --git a/examples/python/sqlc.json b/examples/python/sqlc.json
index cb84d83503..29d3cc8464 100644
--- a/examples/python/sqlc.json
+++ b/examples/python/sqlc.json
@@ -44,8 +44,8 @@
       ]
     },
     {
-      "schema": "../jets/schema.sql",
-      "queries": "../jets/query-building.sql",
+      "schema": "../jets/postgresql/schema.sql",
+      "queries": "../jets/postgresql/query-building.sql",
       "engine": "postgresql",
       "codegen": [
         {
diff --git a/go.mod b/go.mod
index 5be6701acc..2cec9d1909 100644
--- a/go.mod
+++ b/go.mod
@@ -12,6 +12,7 @@ require (
 	github.com/google/go-cmp v0.5.9
 	github.com/jackc/pgconn v1.14.0
 	github.com/jackc/pgx/v4 v4.18.1
+	github.com/jackc/pgx/v5 v5.4.1
 	github.com/jinzhu/inflection v1.0.0
 	github.com/lib/pq v1.10.9
 	github.com/mattn/go-sqlite3 v1.14.17
@@ -25,7 +26,10 @@ require (
 	gopkg.in/yaml.v3 v3.0.1
 )
 
-require github.com/stoewer/go-strcase v1.2.0 // indirect
+require (
+	github.com/rogpeppe/go-internal v1.10.0 // indirect
+	github.com/stoewer/go-strcase v1.2.0 // indirect
+)
 
 require (
 	github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect
@@ -45,10 +49,10 @@ require (
 	go.uber.org/atomic v1.9.0 // indirect
 	go.uber.org/multierr v1.7.0 // indirect
 	go.uber.org/zap v1.19.1 // indirect
-	golang.org/x/crypto v0.6.0 // indirect
+	golang.org/x/crypto v0.9.0 // indirect
 	golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
-	golang.org/x/net v0.9.0 // indirect
-	golang.org/x/sys v0.7.0 // indirect
+	golang.org/x/net v0.10.0 // indirect
+	golang.org/x/sys v0.8.0 // indirect
 	golang.org/x/text v0.9.0 // indirect
 	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
 	gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
diff --git a/go.sum b/go.sum
index fd624928ef..5926d85c7e 100644
--- a/go.sum
+++ b/go.sum
@@ -92,6 +92,8 @@ github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQ
 github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
 github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0=
 github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE=
+github.com/jackc/pgx/v5 v5.4.1 h1:oKfB/FhuVtit1bBM3zNRRsZ925ZkMN3HXL+LgLUM9lE=
+github.com/jackc/pgx/v5 v5.4.1/go.mod h1:q6iHT8uDNXWiFNOlRqJzBTaSH3+2xCXkokxHZC5qWFY=
 github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
 github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
 github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
@@ -102,6 +104,7 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
 github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
@@ -119,7 +122,6 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
 github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
 github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
 github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
-github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
 github.com/pganalyze/pg_query_go/v4 v4.2.1 h1:id/vuyIQccb9f6Yx3pzH5l4QYrxE3v6/m8RPlgMrprc=
 github.com/pganalyze/pg_query_go/v4 v4.2.1/go.mod h1:aEkDNOXNM5j0YGzaAapwJ7LB3dLNj+bvbWcLv1hOVqA=
 github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
@@ -139,6 +141,8 @@ github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qq
 github.com/riza-io/grpc-go v0.2.0 h1:2HxQKFVE7VuYstcJ8zqpN84VnAoJ4dCL6YFhJewNcHQ=
 github.com/riza-io/grpc-go v0.2.0/go.mod h1:2bDvR9KkKC3KhtlSHfR3dAXjUMT86kg4UfWFyVGWqi8=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
+github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
 github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
 github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
 github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
@@ -205,8 +209,9 @@ golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWP
 golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
 golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
+golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
+golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
 golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
 golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@@ -222,8 +227,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
-golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
-golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
+golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -246,8 +251,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
-golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -295,7 +300,7 @@ google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs
 google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
 gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
diff --git a/internal/cmd/vet.go b/internal/cmd/vet.go
index d9f69901d8..f034b057aa 100644
--- a/internal/cmd/vet.go
+++ b/internal/cmd/vet.go
@@ -9,14 +9,18 @@ import (
 	"path/filepath"
 	"runtime/trace"
 	"strings"
+	"time"
 
 	"github.com/google/cel-go/cel"
+	"github.com/google/cel-go/ext"
+	"github.com/jackc/pgx/v5"
 	"github.com/spf13/cobra"
 
 	"github.com/kyleconroy/sqlc/internal/config"
 	"github.com/kyleconroy/sqlc/internal/debug"
 	"github.com/kyleconroy/sqlc/internal/opts"
 	"github.com/kyleconroy/sqlc/internal/plugin"
+	"github.com/kyleconroy/sqlc/internal/sql/ast"
 )
 
 var ErrFailedChecks = errors.New("failed checks")
@@ -59,6 +63,7 @@ func Vet(ctx context.Context, e Env, dir, filename string, stderr io.Writer) err
 
 	env, err := cel.NewEnv(
 		cel.StdLib(),
+		ext.Strings(ext.StringsVersion(1)),
 		cel.Types(
 			&plugin.VetConfig{},
 			&plugin.VetQuery{},
@@ -71,7 +76,7 @@ func Vet(ctx context.Context, e Env, dir, filename string, stderr io.Writer) err
 		),
 	)
 	if err != nil {
-		return fmt.Errorf("new env; %s", err)
+		return fmt.Errorf("new env: %s", err)
 	}
 
 	checks := map[string]cel.Program{}
@@ -99,62 +104,181 @@ func Vet(ctx context.Context, e Env, dir, filename string, stderr io.Writer) err
 		msgs[c.Name] = c.Msg
 	}
 
-	errored := true
-	for _, sql := range conf.SQL {
-		combo := config.Combine(*conf, sql)
+	dbenv, err := cel.NewEnv(
+		cel.StdLib(),
+		ext.Strings(ext.StringsVersion(1)),
+		cel.Variable("env",
+			cel.MapType(cel.StringType, cel.StringType),
+		),
+	)
+	if err != nil {
+		return fmt.Errorf("new dbenv; %s", err)
+	}
 
-		// TODO: This feels like a hack that will bite us later
-		joined := make([]string, 0, len(sql.Schema))
-		for _, s := range sql.Schema {
-			joined = append(joined, filepath.Join(dir, s))
+	c := checker{
+		Checks: checks,
+		Conf:   conf,
+		Dbenv:  dbenv,
+		Dir:    dir,
+		Env:    env,
+		Envmap: map[string]string{},
+		Msgs:   msgs,
+		Stderr: stderr,
+	}
+	errored := false
+	for _, sql := range conf.SQL {
+		if err := c.checkSQL(ctx, sql); err != nil {
+			if !errors.Is(err, ErrFailedChecks) {
+				fmt.Fprintf(stderr, "%s\n", err)
+			}
+			errored = true
 		}
-		sql.Schema = joined
+	}
+	if errored {
+		return ErrFailedChecks
+	}
+	return nil
+}
+
+type checker struct {
+	Checks map[string]cel.Program
+	Conf   *config.Config
+	Dbenv  *cel.Env
+	Dir    string
+	Env    *cel.Env
+	Envmap map[string]string
+	Msgs   map[string]string
+	Stderr io.Writer
+}
 
-		joined = make([]string, 0, len(sql.Queries))
-		for _, q := range sql.Queries {
-			joined = append(joined, filepath.Join(dir, q))
+// Determine if a query can be prepared based on the engine and the statement
+// type.
+func prepareable(sql config.SQL, raw *ast.RawStmt) bool {
+	if sql.Engine == config.EnginePostgreSQL {
+		// TOOD: Add support for MERGE and VALUES stmts
+		switch raw.Stmt.(type) {
+		case *ast.DeleteStmt:
+			return true
+		case *ast.InsertStmt:
+			return true
+		case *ast.SelectStmt:
+			return true
+		case *ast.UpdateStmt:
+			return true
+		default:
+			return false
 		}
-		sql.Queries = joined
+	}
+	return false
+}
+
+func (c *checker) checkSQL(ctx context.Context, sql config.SQL) error {
+	// TODO: Create a separate function for this logic so we can
+	combo := config.Combine(*c.Conf, sql)
+
+	// TODO: This feels like a hack that will bite us later
+	joined := make([]string, 0, len(sql.Schema))
+	for _, s := range sql.Schema {
+		joined = append(joined, filepath.Join(c.Dir, s))
+	}
+	sql.Schema = joined
+
+	joined = make([]string, 0, len(sql.Queries))
+	for _, q := range sql.Queries {
+		joined = append(joined, filepath.Join(c.Dir, q))
+	}
+	sql.Queries = joined
+
+	var name string
+	parseOpts := opts.Parser{
+		Debug: debug.Debug,
+	}
+
+	result, failed := parse(ctx, name, c.Dir, sql, combo, parseOpts, c.Stderr)
+	if failed {
+		return ErrFailedChecks
+	}
 
-		var name string
-		parseOpts := opts.Parser{
-			Debug: debug.Debug,
+	// TODO: Add MySQL support
+	var pgconn *pgx.Conn
+	if sql.Engine == config.EnginePostgreSQL && sql.Database != nil {
+		ast, issues := c.Dbenv.Compile(sql.Database.URL)
+		if issues != nil && issues.Err() != nil {
+			return fmt.Errorf("type-check error: database url %s", issues.Err())
+		}
+		prg, err := c.Dbenv.Program(ast)
+		if err != nil {
+			return fmt.Errorf("program construction error: database url %s", err)
+		}
+		// Populate the environment variable map if it is empty
+		if len(c.Envmap) == 0 {
+			for _, e := range os.Environ() {
+				k, v, _ := strings.Cut(e, "=")
+				c.Envmap[k] = v
+			}
+		}
+		out, _, err := prg.Eval(map[string]any{
+			"env": c.Envmap,
+		})
+		if err != nil {
+			return fmt.Errorf("expression error: %s", err)
+		}
+		dburl, ok := out.Value().(string)
+		if !ok {
+			return fmt.Errorf("expression returned non-string value: %v", out.Value())
 		}
+		fmt.Println("URL", dburl)
+		conn, err := pgx.Connect(ctx, dburl)
+		if err != nil {
+			return fmt.Errorf("database: connection error: %s", err)
+		}
+		if err := conn.Ping(ctx); err != nil {
+			return fmt.Errorf("database: connection error: %s", err)
+		}
+		defer conn.Close(ctx)
+		pgconn = conn
+	}
 
-		result, failed := parse(ctx, name, dir, sql, combo, parseOpts, stderr)
-		if failed {
-			return nil
+	errored := false
+	req := codeGenRequest(result, combo)
+	cfg := vetConfig(req)
+	for i, query := range req.Queries {
+		original := result.Queries[i]
+		if pgconn != nil && prepareable(sql, original.RawStmt) {
+			name := fmt.Sprintf("sqlc_vet_%d_%d", time.Now().Unix(), i)
+			_, err := pgconn.Prepare(ctx, name, query.Text)
+			if err != nil {
+				fmt.Fprintf(c.Stderr, "%s: error preparing %s: %s\n", query.Filename, query.Name, err)
+				errored = true
+				continue
+			}
 		}
-		req := codeGenRequest(result, combo)
-		cfg := vetConfig(req)
-		for _, query := range req.Queries {
-			q := vetQuery(query)
-			for _, name := range sql.Rules {
-				prg, ok := checks[name]
-				if !ok {
-					return fmt.Errorf("type-check error: a check with the name '%s' does not exist", name)
-				}
-				out, _, err := prg.Eval(map[string]any{
-					"query":  q,
-					"config": cfg,
-				})
-				if err != nil {
-					return err
-				}
-				tripped, ok := out.Value().(bool)
-				if !ok {
-					return fmt.Errorf("expression returned non-bool: %s", err)
-				}
-				if tripped {
-					// TODO: Get line numbers in the output
-					msg := msgs[name]
-					if msg == "" {
-						fmt.Fprintf(stderr, query.Filename+": %s: %s\n", q.Name, name, msg)
-					} else {
-						fmt.Fprintf(stderr, query.Filename+": %s: %s: %s\n", q.Name, name, msg)
-					}
-					errored = true
+		q := vetQuery(query)
+		for _, name := range sql.Rules {
+			prg, ok := c.Checks[name]
+			if !ok {
+				return fmt.Errorf("type-check error: a check with the name '%s' does not exist", name)
+			}
+			out, _, err := prg.Eval(map[string]any{
+				"query":  q,
+				"config": cfg,
+			})
+			if err != nil {
+				return err
+			}
+			tripped, ok := out.Value().(bool)
+			if !ok {
+				return fmt.Errorf("expression returned non-bool value: %v", out.Value())
+			}
+			if tripped {
+				// TODO: Get line numbers in the output
+				msg := c.Msgs[name]
+				if msg == "" {
+					fmt.Fprintf(c.Stderr, "%s: %s: %s\n", query.Filename, q.Name, name)
+				} else {
+					fmt.Fprintf(c.Stderr, "%s: %s: %s: %s\n", query.Filename, q.Name, name, msg)
 				}
+				errored = true
 			}
 		}
 	}
diff --git a/internal/compiler/parse.go b/internal/compiler/parse.go
index 9ac5cc855a..b108acc492 100644
--- a/internal/compiler/parse.go
+++ b/internal/compiler/parse.go
@@ -126,6 +126,7 @@ func (c *Compiler) parseQuery(stmt ast.Node, src string, o opts.Parser) (*Query,
 		return nil, err
 	}
 	return &Query{
+		RawStmt:         raw,
 		Cmd:             cmd,
 		Comments:        comments,
 		Name:            name,
diff --git a/internal/compiler/query.go b/internal/compiler/query.go
index c3e754cc04..e77f555dbd 100644
--- a/internal/compiler/query.go
+++ b/internal/compiler/query.go
@@ -51,6 +51,9 @@ type Query struct {
 
 	// Needed for CopyFrom
 	InsertIntoTable *ast.TableName
+
+	// Needed for vet
+	RawStmt *ast.RawStmt
 }
 
 type Parameter struct {
diff --git a/internal/config/config.go b/internal/config/config.go
index 9acadd8355..1d7df3111e 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"encoding/json"
 	"errors"
-	"fmt"
 	"io"
 
 	"gopkg.in/yaml.v3"
@@ -69,6 +68,10 @@ type Project struct {
 	ID string `json:"id" yaml:"id"`
 }
 
+type Database struct {
+	URL string `json:"url" yaml:"url"`
+}
+
 type Cloud struct {
 	Organization string `json:"organization" yaml:"organization"`
 	Project      string `json:"project" yaml:"project"`
@@ -105,6 +108,7 @@ type SQL struct {
 	Engine               Engine    `json:"engine,omitempty" yaml:"engine"`
 	Schema               Paths     `json:"schema" yaml:"schema"`
 	Queries              Paths     `json:"queries" yaml:"queries"`
+	Database             *Database `json:"database" yaml:"database"`
 	StrictFunctionChecks bool      `json:"strict_function_checks" yaml:"strict_function_checks"`
 	StrictOrderBy        *bool     `json:"strict_order_by" yaml:"strict_order_by"`
 	Gen                  SQLGen    `json:"gen" yaml:"gen"`
@@ -204,19 +208,6 @@ func ParseConfig(rd io.Reader) (Config, error) {
 	}
 }
 
-func Validate(c *Config) error {
-	for _, sql := range c.SQL {
-		sqlGo := sql.Gen.Go
-		if sqlGo == nil {
-			continue
-		}
-		if sqlGo.EmitMethodsWithDBArgument && sqlGo.EmitPreparedQueries {
-			return fmt.Errorf("invalid config: emit_methods_with_db_argument and emit_prepared_queries settings are mutually exclusive")
-		}
-	}
-	return nil
-}
-
 type CombinedSettings struct {
 	Global    Config
 	Package   SQL
diff --git a/internal/config/v_one.go b/internal/config/v_one.go
index 273413aea4..122fe835d3 100644
--- a/internal/config/v_one.go
+++ b/internal/config/v_one.go
@@ -20,6 +20,7 @@ type V1GenerateSettings struct {
 type v1PackageSettings struct {
 	Name                      string     `json:"name" yaml:"name"`
 	Engine                    Engine     `json:"engine,omitempty" yaml:"engine"`
+	Database                  *Database  `json:"database,omitempty" yaml:"database"`
 	Path                      string     `json:"path" yaml:"path"`
 	Schema                    Paths      `json:"schema" yaml:"schema"`
 	Queries                   Paths      `json:"queries" yaml:"queries"`
@@ -138,9 +139,10 @@ func (c *V1GenerateSettings) Translate() Config {
 			pkg.StrictOrderBy = &defaultValue
 		}
 		conf.SQL = append(conf.SQL, SQL{
-			Engine:  pkg.Engine,
-			Schema:  pkg.Schema,
-			Queries: pkg.Queries,
+			Engine:   pkg.Engine,
+			Database: pkg.Database,
+			Schema:   pkg.Schema,
+			Queries:  pkg.Queries,
 			Gen: SQLGen{
 				Go: &SQLGo{
 					EmitInterface:             pkg.EmitInterface,
diff --git a/internal/config/validate.go b/internal/config/validate.go
new file mode 100644
index 0000000000..4810a32eb3
--- /dev/null
+++ b/internal/config/validate.go
@@ -0,0 +1,21 @@
+package config
+
+import "fmt"
+
+func Validate(c *Config) error {
+	for _, sql := range c.SQL {
+		sqlGo := sql.Gen.Go
+		if sqlGo == nil {
+			continue
+		}
+		if sqlGo.EmitMethodsWithDBArgument && sqlGo.EmitPreparedQueries {
+			return fmt.Errorf("invalid config: emit_methods_with_db_argument and emit_prepared_queries settings are mutually exclusive")
+		}
+		if sql.Database != nil {
+			if sql.Database.URL == "" {
+				return fmt.Errorf("invalid config: database must have a non-empty URL")
+			}
+		}
+	}
+	return nil
+}
diff --git a/internal/endtoend/vet_test.go b/internal/endtoend/vet_test.go
new file mode 100644
index 0000000000..94108107dc
--- /dev/null
+++ b/internal/endtoend/vet_test.go
@@ -0,0 +1,67 @@
+//go:build examples
+// +build examples
+
+package main
+
+import (
+	"bytes"
+	"context"
+	"os"
+	"path/filepath"
+	"testing"
+
+	"github.com/kyleconroy/sqlc/internal/cmd"
+	"github.com/kyleconroy/sqlc/internal/sqltest"
+)
+
+func findSchema(t *testing.T, path string) string {
+	t.Helper()
+	schemaFile := filepath.Join(path, "postgresql", "schema.sql")
+	if _, err := os.Stat(schemaFile); !os.IsNotExist(err) {
+		return schemaFile
+	}
+	schemaDir := filepath.Join(path, "postgresql", "schema")
+	if _, err := os.Stat(schemaDir); !os.IsNotExist(err) {
+		return schemaDir
+	}
+	t.Fatalf("error: can't find schema files in %s", path)
+	return ""
+}
+
+func TestExamplesVet(t *testing.T) {
+	t.Parallel()
+	ctx := context.Background()
+
+	examples, err := filepath.Abs(filepath.Join("..", "..", "examples"))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	files, err := os.ReadDir(examples)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, replay := range files {
+		if !replay.IsDir() {
+			continue
+		}
+		tc := replay.Name()
+		t.Run(tc, func(t *testing.T) {
+			t.Parallel()
+			path := filepath.Join(examples, tc)
+
+			if tc != "kotlin" && tc != "python" {
+				sqltest.CreatePostgreSQLDatabase(t, tc, []string{
+					findSchema(t, path),
+				})
+			}
+
+			var stderr bytes.Buffer
+			err := cmd.Vet(ctx, cmd.Env{}, path, "", &stderr)
+			if err != nil {
+				t.Fatalf("sqlc vet failed: %s %s", err, stderr.String())
+			}
+		})
+	}
+}
diff --git a/internal/sqltest/postgres.go b/internal/sqltest/postgres.go
index 3968b6bddb..ad58e2c019 100644
--- a/internal/sqltest/postgres.go
+++ b/internal/sqltest/postgres.go
@@ -28,6 +28,86 @@ func id() string {
 	return string(b)
 }
 
+// Disable random new schema
+// Override database name
+func CreatePostgreSQLDatabase(t *testing.T, newDB string, migrations []string) *sql.DB {
+	t.Helper()
+
+	pgUser := os.Getenv("PG_USER")
+	pgHost := os.Getenv("PG_HOST")
+	pgPort := os.Getenv("PG_PORT")
+	pgPass := os.Getenv("PG_PASSWORD")
+	pgDB := os.Getenv("PG_DATABASE")
+
+	if pgUser == "" {
+		pgUser = "postgres"
+	}
+
+	if pgPass == "" {
+		pgPass = "mysecretpassword"
+	}
+
+	if pgPort == "" {
+		pgPort = "5432"
+	}
+
+	if pgHost == "" {
+		pgHost = "127.0.0.1"
+	}
+
+	if pgDB == "" {
+		pgDB = "dinotest"
+	}
+
+	source := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable", pgUser, pgPass, pgHost, pgPort, pgDB)
+	t.Logf("db: %s", source)
+
+	db, err := sql.Open("postgres", source)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer db.Close()
+
+	var exists bool
+	dberr := db.QueryRow(`SELECT true FROM pg_database WHERE datname = $1`, newDB).Scan(&exists)
+	if dberr != nil && dberr != sql.ErrNoRows {
+		t.Fatal(err)
+	}
+
+	if !exists {
+		if _, err := db.Exec("CREATE DATABASE " + newDB); err != nil {
+			t.Fatal(err)
+		}
+	} else {
+		t.Logf("database '%s' exists, not creating", newDB)
+	}
+
+	newSource := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable", pgUser, pgPass, pgHost, pgPort, newDB)
+	t.Logf("newdb: %s", newSource)
+
+	sdb, err := sql.Open("postgres", newSource)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !exists {
+		files, err := sqlpath.Glob(migrations)
+		if err != nil {
+			t.Fatal(err)
+		}
+		for _, f := range files {
+			blob, err := os.ReadFile(f)
+			if err != nil {
+				t.Fatal(err)
+			}
+			if _, err := sdb.Exec(string(blob)); err != nil {
+				t.Fatalf("%s: %s", filepath.Base(f), err)
+			}
+		}
+	}
+	return sdb
+}
+
 func PostgreSQL(t *testing.T, migrations []string) (*sql.DB, func()) {
 	t.Helper()