r9115: new deb package
[clsql.git] / sql / table.lisp
1 ;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
2 ;;;; *************************************************************************
3 ;;;;
4 ;;;; $Id$
5 ;;;;
6 ;;;; The CLSQL Functional Data Definition Language (FDDL)
7 ;;;; including functions for schema manipulation. Currently supported
8 ;;;; SQL objects include tables, views, indexes, attributes and
9 ;;;; sequences.
10 ;;;;
11 ;;;; This file is part of CLSQL.
12 ;;;;
13 ;;;; CLSQL users are granted the rights to distribute and use this software
14 ;;;; as governed by the terms of the Lisp Lesser GNU Public License
15 ;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
16 ;;;; *************************************************************************
17
18 (in-package #:clsql-sys)
19
20
21 ;; Utilities
22
23 (defun database-identifier (name)
24   (sql-escape (etypecase name
25                 (string
26                  (string-upcase name))
27                 (sql-ident
28                  (sql-output name))
29                 (symbol
30                  (sql-output name)))))
31
32
33 ;; Tables 
34
35 (defun create-table (name description &key (database *default-database*)
36                           (constraints nil))
37   "Create a table called NAME, in DATABASE which defaults to
38 *DEFAULT-DATABASE*, containing the attributes in DESCRIPTION which is
39 a list containing lists of attribute-name and type information pairs."
40   (let* ((table-name (etypecase name 
41                        (symbol (sql-expression :attribute name))
42                        (string (sql-expression :attribute (make-symbol name)))
43                        (sql-ident name)))
44          (stmt (make-instance 'sql-create-table
45                               :name table-name
46                               :columns description
47                               :modifiers constraints)))
48     (execute-command stmt :database database)))
49
50 (defun drop-table (name &key (if-does-not-exist :error)
51                         (database *default-database*))
52   "Drops table NAME from DATABASE which defaults to
53 *DEFAULT-DATABASE*. If the table does not exist and IF-DOES-NOT-EXIST
54 is :ignore then DROP-TABLE returns nil whereas an error is signalled
55 if IF-DOES-NOT-EXIST is :error."
56   (let ((table-name (database-identifier name)))
57     (ecase if-does-not-exist
58       (:ignore
59        (unless (table-exists-p table-name :database database)
60          (return-from drop-table nil)))
61       (:error
62        t))
63     (let ((expr (concatenate 'string "DROP TABLE " table-name)))
64       (execute-command expr :database database))))
65
66 (defun list-tables (&key (owner nil) (database *default-database*))
67   "List all tables in DATABASE which defaults to
68 *DEFAULT-DATABASE*. If OWNER is nil, only user-owned tables are
69 considered. This is the default. If OWNER is :all , all tables are
70 considered. If OWNER is a string, this denotes a username and only
71 tables owned by OWNER are considered. Table names are returned as a
72 list of strings."
73   (database-list-tables database :owner owner))
74
75 (defun table-exists-p (name &key (owner nil) (database *default-database*))
76   "Test for existence of an SQL table called NAME in DATABASE which
77 defaults to *DEFAULT-DATABASE*. If OWNER is nil, only user-owned
78 tables are considered. This is the default. If OWNER is :all , all
79 tables are considered. If OWNER is a string, this denotes a username
80 and only tables owned by OWNER are considered. Table names are
81 returned as a list of strings."
82   (when (member (database-identifier name)
83                 (list-tables :owner owner :database database)
84                 :test #'string-equal)
85     t))
86
87
88 ;; Views 
89
90 (defun create-view (name &key as column-list (with-check-option nil)
91                          (database *default-database*))
92   "Creates a view called NAME using the AS query and the optional
93 COLUMN-LIST and WITH-CHECK-OPTION. The COLUMN-LIST argument is a list
94 of columns to add to the view. The WITH-CHECK-OPTION adds 'WITH CHECK
95 OPTION' to the resulting SQL. The default value of WITH-CHECK-OPTION
96 is NIL. The default value of DATABASE is *DEFAULT-DATABASE*."
97   (let* ((view-name (etypecase name 
98                       (symbol (sql-expression :attribute name))
99                       (string (sql-expression :attribute (make-symbol name)))
100                       (sql-ident name)))
101          (stmt (make-instance 'sql-create-view
102                               :name view-name
103                               :column-list column-list
104                               :query as
105                               :with-check-option with-check-option)))
106     (execute-command stmt :database database)))
107
108 (defun drop-view (name &key (if-does-not-exist :error)
109                        (database *default-database*))
110   "Deletes view NAME from DATABASE which defaults to
111 *DEFAULT-DATABASE*. If the view does not exist and IF-DOES-NOT-EXIST
112 is :ignore then DROP-VIEW returns nil whereas an error is signalled if
113 IF-DOES-NOT-EXIST is :error."
114   (let ((view-name (database-identifier name)))
115     (ecase if-does-not-exist
116       (:ignore
117        (unless (view-exists-p view-name :database database)
118          (return-from drop-view)))
119       (:error
120        t))
121     (let ((expr (concatenate 'string "DROP VIEW " view-name)))
122       (execute-command expr :database database))))
123
124 (defun list-views (&key (owner nil) (database *default-database*))
125   "List all views in DATABASE which defaults to *DEFAULT-DATABASE*. If
126 OWNER is nil, only user-owned views are considered. This is the
127 default. If OWNER is :all , all views are considered. If OWNER is a
128 string, this denotes a username and only views owned by OWNER are
129 considered. View names are returned as a list of strings."
130   (database-list-views database :owner owner))
131
132 (defun view-exists-p (name &key (owner nil) (database *default-database*))
133   "Test for existence of an SQL view called NAME in DATABASE which
134 defaults to *DEFAULT-DATABASE*. If OWNER is nil, only user-owned views
135 are considered. This is the default. If OWNER is :all , all views are
136 considered. If OWNER is a string, this denotes a username and only
137 views owned by OWNER are considered. View names are returned as a list
138 of strings."
139   (when (member (database-identifier name)
140                 (list-views :owner owner :database database)
141                 :test #'string-equal)
142     t))
143
144
145 ;; Indexes 
146
147 (defun create-index (name &key on (unique nil) attributes
148                           (database *default-database*))
149   "Creates an index called NAME on the table specified by ON. The
150 attributes of the table to index are given by ATTRIBUTES. Setting
151 UNIQUE to T includes UNIQUE in the SQL index command, specifying that
152 the columns indexed must contain unique values. The default value of
153 UNIQUE is nil. The default value of DATABASE is *DEFAULT-DATABASE*."
154   (let* ((index-name (database-identifier name))
155          (table-name (database-identifier on))
156          (attributes (mapcar #'database-identifier (listify attributes)))
157          (stmt (format nil "CREATE ~A INDEX ~A ON ~A (~{~A~^, ~})"
158                        (if unique "UNIQUE" "")
159                        index-name table-name attributes)))
160     (execute-command stmt :database database)))
161
162 (defun drop-index (name &key (if-does-not-exist :error)
163                         (on nil)
164                         (database *default-database*))
165   "Deletes index NAME from table FROM in DATABASE which defaults to
166 *DEFAULT-DATABASE*. If the index does not exist and IF-DOES-NOT-EXIST
167 is :ignore then DROP-INDEX returns nil whereas an error is signalled
168 if IF-DOES-NOT-EXIST is :error. The argument ON allows the optional
169 specification of a table to drop the index from."
170   (let ((index-name (database-identifier name)))
171     (ecase if-does-not-exist
172       (:ignore
173        (unless (index-exists-p index-name :database database)
174          (return-from drop-index)))
175       (:error t))
176     (unless (db-use-column-on-drop-index? (database-underlying-type database))
177       (setq on nil))
178     (execute-command (format nil "DROP INDEX ~A~A" index-name
179                              (if (null on) ""
180                                  (concatenate 'string " ON "
181                                               (database-identifier on))))
182                      :database database)))
183
184 (defun list-indexes (&key (owner nil) (database *default-database*))
185   "List all indexes in DATABASE, which defaults to
186 *default-database*. If OWNER is :all , all indexs are considered. If
187 OWNER is a string, this denotes a username and only indexs owned by
188 OWNER are considered. Index names are returned as a list of strings."
189   (database-list-indexes database :owner owner))
190
191 (defun list-table-indexes (table &key (owner nil)
192                                       (database *default-database*))
193   "List all indexes in DATABASE for a TABLE, which defaults to
194 *default-database*. If OWNER is :all , all indexs are considered. If
195 OWNER is a string, this denotes a username and only indexs owned by
196 OWNER are considered. Index names are returned as a list of strings."
197   (database-list-table-indexes (database-identifier table)
198                                database :owner owner))
199   
200 (defun index-exists-p (name &key (owner nil) (database *default-database*))
201   "Test for existence of an index called NAME in DATABASE which
202 defaults to *DEFAULT-DATABASE*. If OWNER is :all , all indexs are
203 considered. If OWNER is a string, this denotes a username and only
204 indexs owned by OWNER are considered. Index names are returned as a
205 list of strings."
206   (when (member (database-identifier name)
207                 (list-indexes :owner owner :database database)
208                 :test #'string-equal)
209     t))
210
211 ;; Attributes 
212
213 (defun list-attributes (name &key (owner nil) (database *default-database*))
214   "List the attributes of a attribute called NAME in DATABASE which
215 defaults to *DEFAULT-DATABASE*. If OWNER is nil, only user-owned
216 attributes are considered. This is the default. If OWNER is :all , all
217 attributes are considered. If OWNER is a string, this denotes a
218 username and only attributes owned by OWNER are considered. Attribute
219 names are returned as a list of strings. Attributes are returned as a
220 list of strings."
221   (database-list-attributes (database-identifier name) database :owner owner))
222
223 (defun attribute-type (attribute table &key (owner nil)
224                                  (database *default-database*))
225   "Return the field type of the ATTRIBUTE in TABLE.  The optional
226 keyword argument DATABASE specifies the database to query, defaulting
227 to *DEFAULT-DATABASE*. If OWNER is nil, only user-owned attributes are
228 considered. This is the default. If OWNER is :all , all attributes are
229 considered. If OWNER is a string, this denotes a username and only
230 attributes owned by OWNER are considered. Attribute names are returned
231 as a list of strings. Attributes are returned as a list of strings."
232   (database-attribute-type (database-identifier attribute)
233                            (database-identifier table)
234                            database
235                            :owner owner))
236
237 (defun list-attribute-types (table &key (owner nil)
238                                    (database *default-database*))
239   "Returns type information for the attributes in TABLE from DATABASE
240 which has a default value of *default-database*. If OWNER is nil, only
241 user-owned attributes are considered. This is the default. If OWNER is
242 :all, all attributes are considered. If OWNER is a string, this
243 denotes a username and only attributes owned by OWNER are
244 considered. Returns a list in which each element is a list (attribute
245 datatype). Attribute is a string denoting the atribute name. Datatype
246 is the vendor-specific type returned by ATTRIBUTE-TYPE."
247   (mapcar #'(lambda (type)
248               (list type (attribute-type type table :database database
249                                          :owner owner)))
250           (list-attributes table :database database :owner owner)))
251
252 ;(defun add-attribute (table attribute &key (database *default-database*))
253 ;  (database-add-attribute table attribute database))
254
255 ;(defun rename-attribute (table oldatt newname
256 ;                               &key (database *default-database*))
257 ;  (error "(rename-attribute ~a ~a ~a ~a) is not implemented"
258 ;         table oldatt newname database))
259
260
261 ;; Sequences 
262
263 (defun create-sequence (name &key (database *default-database*))
264   "Create a sequence called NAME in DATABASE which defaults to
265 *DEFAULT-DATABASE*."
266   (let ((sequence-name (database-identifier name)))
267     (database-create-sequence sequence-name database))
268   (values))
269
270 (defun drop-sequence (name &key (if-does-not-exist :error)
271                            (database *default-database*))
272   "Drops sequence NAME from DATABASE which defaults to
273 *DEFAULT-DATABASE*. If the sequence does not exist and
274 IF-DOES-NOT-EXIST is :ignore then DROP-SEQUENCE returns nil whereas an
275 error is signalled if IF-DOES-NOT-EXIST is :error."
276   (let ((sequence-name (database-identifier name)))
277     (ecase if-does-not-exist
278       (:ignore
279        (unless (sequence-exists-p sequence-name :database database)
280          (return-from drop-sequence)))
281       (:error t))
282     (database-drop-sequence sequence-name database))
283   (values))
284
285 (defun list-sequences (&key (owner nil) (database *default-database*))
286   "List all sequences in DATABASE, which defaults to
287 *default-database*. If OWNER is nil, only user-owned sequences are
288 considered. This is the default. If OWNER is :all , all sequences are
289 considered. If OWNER is a string, this denotes a username and only
290 sequences owned by OWNER are considered. Sequence names are returned
291 as a list of strings."
292   (database-list-sequences database :owner owner))
293
294 (defun sequence-exists-p (name &key (owner nil)
295                                (database *default-database*))
296   "Test for existence of a sequence called NAME in DATABASE which
297 defaults to *DEFAULT-DATABASE*."
298   (when (member (database-identifier name)
299                 (list-sequences :owner owner :database database)
300                 :test #'string-equal)
301     t))
302   
303 (defun sequence-next (name &key (database *default-database*))
304   "Return the next value in the sequence NAME in DATABASE."
305   (database-sequence-next (database-identifier name) database))
306
307 (defun set-sequence-position (name position &key (database *default-database*))
308   "Explicitly set the the position of the sequence NAME in DATABASE to
309 POSITION."
310   (database-set-sequence-position (database-identifier name) position database))
311
312 (defun sequence-last (name &key (database *default-database*))
313   "Return the last value of the sequence NAME in DATABASE."
314   (database-sequence-last (database-identifier name) database))