CREATE-VIEW and DROP-VIEW

Marcus Pearce <[email protected]> Sun, 7 Mar 2004 22:48:24 +0000 (GMT)
Newsgroups gmane.lisp.uncommon-sql
Message-ID <[email protected]>
The following patch implements create-view and drop-view as specified in
the CommonSQL reference manual. The following simple example uses the
database described in the usql tutorial:

USER> (sql:create-view [lenins-group]
                 :column-list '([forename] [surname] [email])
                 :as [select [first-name] [last-name] [email]
                             :from [employee]
                             :where [= [managerid] 1]])
USER> (sql:select [forename] [surname] [email] :from [lenins-group])
(("Josef" "Stalin" "[email protected]"))
USER> (sql:drop-view [lenins-group])
USER>

Drop-view tests whether the supplied view actually exists using the
generic functions DATABASE-VIEWP and DATABASE-LIST-VIEWS (in
dbms-interface.lisp). The patch contains corresponding methods for
postgresql (in postgresql-sql.lisp) but not for the oracle or mysql
backends since I don't use those.

Cheers,
Marcus
--

cvs server: Diffing .
cvs server: Diffing dbms
cvs server: Diffing dbms/mysql
cvs server: Diffing dbms/oracle
cvs server: Diffing dbms/postgresql
Index: dbms/postgresql/postgresql-sql.lisp
===================================================================
RCS file: /cvs/usql/dbms/postgresql/postgresql-sql.lisp,v
retrieving revision 1.41
diff -u -r1.41 postgresql-sql.lisp
--- dbms/postgresql/postgresql-sql.lisp	2003/03/26 17:11:21	1.41
+++ dbms/postgresql/postgresql-sql.lisp	2004/03/07 20:54:04
@@ -359,6 +359,26 @@
 ;;(defmethod database-add-attribute (table attribute database)
 ;;  (let ((attname (slot-value attribute 'name)

+(defmethod database-list-views ((database postgresql-database)
+                                &key (system-views nil))
+  (let ((res (select [viewname] :from [pg_views] :flatp t :database database)))
+    (if (not system-views)
+        (remove-if #'(lambda (view) (equal (subseq view 0 3) "pg_")) res)
+        res)))
+
+(defmethod database-viewp ((database postgresql-database) name)
+  (let ((tref (etypecase name
+                (string (string-upcase name))
+                (sql-sys::sql-ident
+                 (sql name))
+                (symbol
+                 (sql-escape (sql name))))))
+    (when (and tref
+               (member (string-upcase (subseq tref 0 (min (length tref) (1- *max-identifier-length*))))
+                       (mapcar #'string-upcase
+                               (database-list-views database :system-views t))
+                       :test #'equal))
+      t)))

 (defmethod database-output-sql ((expr sql-sys::sql-typecast-exp) (database postgresql-database))
   (with-slots (sql-sys::modifier sql-sys::components)
cvs server: Diffing debian
cvs server: Diffing doc
cvs server: Diffing doc/refguide
cvs server: Diffing sql
Index: sql/classes.lisp
===================================================================
RCS file: /cvs/usql/sql/classes.lisp,v
retrieving revision 1.59
diff -u -r1.59 classes.lisp
--- sql/classes.lisp	2002/12/05 17:37:14	1.59
+++ sql/classes.lisp	2004/03/07 20:54:05
@@ -678,7 +678,28 @@
           (write-string (car modifier) *sql-stream*)))
       (write-char #\) *sql-stream*)))
   t)
-
+
+
+;; CREATE VIEW
+
+(defclass sql-create-view (%sql-expression)
+  ((name :initarg :name :initform nil)
+   (column-list :initarg :column-list :initform nil)
+   (query :initarg :query :initform nil)
+   (with-check-option :initarg :with-check-option :initform nil))
+  (:documentation "An SQL CREATE VIEW statement."))
+
+(defmethod output-sql ((stmt sql-create-view) &optional database)
+  (with-slots (name column-list query with-check-option) stmt
+    (write-string "CREATE VIEW " *sql-stream*)
+    (output-sql name database)
+    (when column-list (write-string " " *sql-stream*)
+          (output-sql (listify column-list) database))
+    (write-string " AS " *sql-stream*)
+    (output-sql query database)
+    (when with-check-option (write-string " WITH CHECK OPTION" *sql-stream*))))
+
+
 ;; Keep a hashtable for mapping symbols to sql generator functions,
 ;; for use by the bracketed reader syntax.

Index: sql/dbms-interface.lisp
===================================================================
RCS file: /cvs/usql/sql/dbms-interface.lisp,v
retrieving revision 1.12
diff -u -r1.12 dbms-interface.lisp
--- sql/dbms-interface.lisp	2003/01/03 05:24:08	1.12
+++ sql/dbms-interface.lisp	2004/03/07 20:54:05
@@ -120,4 +120,11 @@
 (defgeneric oid (object)
   (:documentation "Return the unique ID of a database object."))

+(defgeneric database-viewp (database view-name)
+  (:documentation
+   "If view with given name VIEW-NAME exists in DATABASE, returns true."))
+
+(defgeneric database-list-views (database &key system-views)
+  (:documentation "List all views in the given database"))
+
 )                                       ; eval-when
Index: sql/package.lisp
===================================================================
RCS file: /cvs/usql/sql/package.lisp,v
retrieving revision 1.39
diff -u -r1.39 package.lisp
--- sql/package.lisp	2002/10/30 21:47:58	1.39
+++ sql/package.lisp	2004/03/07 20:54:05
@@ -65,6 +65,8 @@
      "DATABASE-GET-TYPE-SPECIFIER"
      "DATABASE-LIST-TABLES"
      "DATABASE-TABLEP"
+     "DATABASE-LIST-VIEWS"
+     "DATABASE-VIEWP"
      "DATABASE-LIST-INDEXES"
      "DATABASE-INDEXP"
      "DATABASE-LIST-SEQUENCES"
Index: sql/table.lisp
===================================================================
RCS file: /cvs/usql/sql/table.lisp,v
retrieving revision 1.24
diff -u -r1.24 table.lisp
--- sql/table.lisp	2002/08/06 14:46:01	1.24
+++ sql/table.lisp	2004/03/07 20:54:06
@@ -111,3 +111,43 @@
 (defun rename-attribute (table oldatt newname
 			       &key (database *default-database*))
   (error "(rename-attribute ~a ~a ~a ~a) is not implemented" table oldatt newname database))
+
+(defun create-view (name &key column-list as (with-check-option nil)
+                         (database *default-database*))
+  "The CREATE-VIEW function creates a view called NAME using the AS
+query and the optional COLUMN-LIST and WITH-CHECK-OPTION. The
+COLUMN-LIST argument is a list of columns to add to the view. The
+WITH-CHECK-OPTION adds 'WITH CHECK OPTION' to the resulting SQL. The
+default value of WITH-CHECK-OPTION is NIL. The default value of
+DATABASE is *default-database*."
+  (execute-command
+   (make-instance 'sql-sys::sql-create-view
+                  :name name
+                  :column-list column-list
+                  :query as
+                  :with-check-option with-check-option)
+   :database database)
+  (values))
+
+(defun drop-view (name &key (database *default-database*)
+                       (if-does-not-exist :error))
+  "Deletes view NAME from DATABASE which defaults to *default-database*."
+  (let ((view-name (etypecase name
+                     (string name)
+                     (sql-sys::sql-ident (sql-sys::generate-sql name)))))
+    (case if-does-not-exist
+      (:ignore (unless (viewp view-name) (return-from drop-view)))
+      (t
+       (execute-command (concatenate 'string "DROP VIEW " view-name)
+                        :database database)))
+    (values)))
+
+(defun viewp (view-name &key (database *default-database*))
+  (database-viewp database view-name))
+
+(defun list-views (&key (database *default-database*)
+                        (system-views nil))
+  "Returns a list of strings representing views in DATABASE which
+defaults to *default-database*. If SYSTEM-VIEWS is true, then non-user
+views are included as well."
+  (database-list-views database :system-views system-views))
cvs server: Diffing sql/tests