java.jdbc - Using DDL and Metadata
Contents
Using DDL
DDL operations can be executed using the db-do-commands
function. The general
approach is:
(jdbc/db-do-commands db-spec [sql-command-1 sql-command-2 .. sql-command-n])
The commands are executed as a single, batched statement, wrapped in a transaction. If you want to avoid the transaction, use this approach:
(jdbc/db-do-commands db-spec false [sql-command-1 sql-command-2 .. sql-command-n])
This is necessary for some databases that do not allow DDL operations to be wrapped in a transaction.
Creating tables
For the common operations of creating and dropping tables, java.jdbc
provides a
little assistance that recognizes :entities
so you can use keywords (or
strings) and have your chosen naming strategy applied, just as you can for
several of the SQL functions.
(jdbc/create-table-ddl :fruit
[[:name "varchar(32)" :primary :key]
[:appearance "varchar(32)"]
[:cost :int]
[:grade :real]]
{:table-spec "ENGINE=InnoDB"
:entities clojure.string/upper-case})
This will generate:
CREATE TABLE FRUIT
(NAME varchar(32) primary key,
APPEARANCE varchar(32),
COST int,
GRADE real) ENGINE=InnoDB
which you can pass to db-do-commands
.
create-table-ddl
also supports a conditional?
option which can be a simple
Boolean
, which, if true
, will add IF NOT EXISTS
before the table name. If
that syntax doesn't work for your database, you can pass a string that will be
used instead. If that isn't enough, you can pass a function of two arguments:
the first argument will be the table name and the second argument will be the
DDL string (this approach is needed for Microsoft SQL Server).
Dropping tables
Similarly there is a drop-table-ddl
function which takes a table name and an
optional :entities
option to generate DDL to drop a table.
(jdbc/drop-table-ddl :fruit) ; drop table fruit
(jdbc/drop-table-ddl :fruit {:entities clojure.string/upper-case}) ; drop table FRUIT
This will generate:
DROP TABLE FRUIT
drop-table-ddl
also supports a conditional?
option which can be a simple
Boolean
, which, if true
, will add IF EXISTS
before the table name. If
that syntax doesn't work for your database, you can pass a string that will be
used instead. If that isn't enough, you can pass a function of two arguments:
the first argument will be the table name and the second argument will be the
DDL string (this approach is needed for Microsoft SQL Server).
Accessing metadata
java.jdbc
provides two functions for working with database metadata:
with-db-metadata
for creating an active metadata object backed by an open connectionmetadata-result
for turning metadata results into Clojure data structures
For example:
(jdbc/with-db-metadata [md db-spec]
(jdbc/metadata-result (.getTables md nil nil nil (into-array ["TABLE" "VIEW"]))))
This returns a sequence of maps describing all the tables and views in the
current database. metadata-result
only transforms ResultSet
objects, other
results are returned as-is. metadata-result
can also accept an options map
containing :identifiers
and :as-arrays?
, like the query
function,
and those options control how the metatadata is transformed and/or returned.
Both with-db-metadata
and metadata-result
can accept an options hash map
which will be passed through various java.jdbc
functions (get-connections
for the former and result-set-seq
for the latter).