r9336: 12 May 2004 Kevin Rosenberg (kevin@rosenberg.net)
[clsql.git] / sql / conditions.lisp
1 ;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
2 ;;;; *************************************************************************
3 ;;;; FILE IDENTIFICATION
4 ;;;;
5 ;;;; Name:          conditions.lisp
6 ;;;; Purpose:       Error conditions for high-level SQL interface
7 ;;;; Programmers:   Kevin M. Rosenberg based on
8 ;;;;                 Original code by Pierre R. Mai 
9 ;;;; Date Started:  Feb 2002
10 ;;;;
11 ;;;; $Id$
12 ;;;;
13 ;;;; This file, part of CLSQL, is Copyright (c) 2002-2004 by Kevin M. Rosenberg
14 ;;;; and Copyright (c) 1999-2001 by Pierre R. Mai
15 ;;;;
16 ;;;; CLSQL users are granted the rights to distribute and use this software
17 ;;;; as governed by the terms of the Lisp Lesser GNU Public License
18 ;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
19 ;;;; *************************************************************************
20
21 (in-package #:clsql-sys)
22
23 (defvar *backend-warning-behavior* :warn
24   "Action to perform on warning messages from backend. Default is to :warn. May also be
25 set to :error to signal an error or :ignore/nil to silently ignore the warning.")
26
27 ;;; Conditions
28 (define-condition clsql-condition ()
29   ())
30
31 (define-condition clsql-error (error clsql-condition)
32   ())
33
34 (define-condition clsql-simple-error (simple-condition clsql-error)
35   ())
36
37 (define-condition clsql-warning (warning clsql-condition)
38   ())
39
40 (define-condition clsql-simple-warning (simple-condition clsql-warning)
41   ())
42
43 (define-condition clsql-generic-error (clsql-error)
44   ((message :initarg :message
45             :reader clsql-generic-error-message))
46   (:report (lambda (c stream)
47              (format stream (clsql-generic-error-message c)))))
48
49 (define-condition clsql-invalid-spec-error (clsql-error)
50   ((connection-spec :initarg :connection-spec
51                     :reader clsql-invalid-spec-error-connection-spec)
52    (database-type :initarg :database-type
53                   :reader clsql-invalid-spec-error-database-type)
54    (template :initarg :template
55              :reader clsql-invalid-spec-error-template))
56   (:report (lambda (c stream)
57              (format stream "The connection specification ~A~%is invalid for database type ~A.~%The connection specification must conform to ~A"
58                      (clsql-invalid-spec-error-connection-spec c)
59                      (clsql-invalid-spec-error-database-type c)
60                      (clsql-invalid-spec-error-template c)))))
61
62 (defmacro check-connection-spec (connection-spec database-type template)
63   "Check the connection specification against the provided template,
64 and signal an clsql-invalid-spec-error if they don't match."
65   `(handler-case
66     (destructuring-bind ,template ,connection-spec 
67       (declare (ignore ,@(remove '&optional template)))
68       t)
69     (error () (error 'clsql-invalid-spec-error
70                      :connection-spec ,connection-spec
71                      :database-type ,database-type
72                      :template (quote ,template)))))
73
74 (define-condition clsql-access-error (clsql-error)
75   ((database-type :initarg :database-type
76                   :reader clsql-access-error-database-type)
77    (connection-spec :initarg :connection-spec
78                     :reader clsql-access-error-connection-spec)
79    (error :initarg :error :reader clsql-access-error-error))
80   (:report (lambda (c stream)
81              (format stream "While trying to access database ~A~%  using database-type ~A:~%  Error ~A~%  has occurred."
82                      (database-name-from-spec
83                       (clsql-access-error-connection-spec c)
84                       (clsql-access-error-database-type c))
85                      (clsql-access-error-database-type c)
86                      (clsql-access-error-error c)))))
87
88 (define-condition clsql-connect-error (clsql-access-error)
89   ((errno :initarg :errno :reader clsql-connect-error-errno))
90   (:report (lambda (c stream)
91              (format stream "While trying to connect to database ~A~%  using database-type ~A:~%  Error ~D / ~A~%  has occurred."
92                      (database-name-from-spec
93                       (clsql-access-error-connection-spec c)
94                       (clsql-access-error-database-type c))
95                      (clsql-access-error-database-type c)
96                      (clsql-connect-error-errno c)
97                      (clsql-access-error-error c)))))
98
99 (define-condition clsql-sql-error (clsql-error)
100   ((database :initarg :database :reader clsql-sql-error-database)
101    (message :initarg :message :initform nil :reader clsql-sql-error-message)
102    (expression :initarg :expression :initarg nil :reader clsql-sql-error-expression)
103    (errno :initarg :errno :initarg nil :reader clsql-sql-error-errno)
104    (error :initarg :error :initarg nil :reader clsql-sql-error-error))
105   (:report (lambda (c stream)
106              (if (clsql-sql-error-message c)
107                  (format stream "While accessing database ~A~%, Error~%  ~A~%  has occurred."
108                          (clsql-sql-error-database c)
109                          (clsql-sql-error-message c))
110                (format stream "While accessing database ~A~%  with expression ~S:~%  Error ~D / ~A~%  has occurred."
111                        (clsql-sql-error-database c)
112                        (clsql-sql-error-expression c)
113                        (clsql-sql-error-errno c)
114                        (clsql-sql-error-error c))))))
115
116 (define-condition clsql-database-warning (clsql-warning)
117   ((database :initarg :database :reader clsql-database-warning-database)
118    (message :initarg :message :reader clsql-database-warning-message))
119   (:report (lambda (c stream)
120              (format stream "While accessing database ~A~%  Warning: ~A~%  has occurred."
121                      (clsql-database-warning-database c)
122                      (clsql-database-warning-message c)))))
123
124 (define-condition clsql-exists-condition (clsql-condition)
125    ((old-db :initarg :old-db :reader clsql-exists-condition-old-db)
126     (new-db :initarg :new-db :reader clsql-exists-condition-new-db
127             :initform nil))
128    (:report (lambda (c stream)
129               (format stream "In call to ~S:~%" 'connect)
130               (cond
131                 ((null (clsql-exists-condition-new-db c))
132                  (format stream
133                          "  There is an existing connection ~A to database ~A."
134                          (clsql-exists-condition-old-db c)
135                          (database-name (clsql-exists-condition-old-db c))))
136                 ((eq (clsql-exists-condition-new-db c)
137                      (clsql-exists-condition-old-db c))
138                  (format stream
139                          "  Using existing connection ~A to database ~A."
140                          (clsql-exists-condition-old-db c)
141                          (database-name (clsql-exists-condition-old-db c))))
142                 (t
143                  (format stream
144                          "  Created new connection ~A to database ~A~%, although there is an existing connection (~A)."
145                          (clsql-exists-condition-new-db c)
146                          (database-name (clsql-exists-condition-new-db c))
147                          (clsql-exists-condition-old-db c)))))))
148
149 (define-condition clsql-exists-warning (clsql-exists-condition
150                                          clsql-warning)
151   ())
152
153 (define-condition clsql-exists-error (clsql-exists-condition
154                                        clsql-error)
155   ())
156
157 (define-condition clsql-closed-error (clsql-error)
158   ((database :initarg :database :reader clsql-closed-error-database))
159   (:report (lambda (c stream)
160              (format stream "The database ~A has already been closed."
161                      (clsql-closed-error-database c)))))
162
163 (define-condition clsql-no-database-error (clsql-error)
164   ((database :initarg :database :reader clsql-no-database-error-database))
165   (:report (lambda (c stream)
166              (format stream "~S is not a CLSQL database." 
167                      (clsql-no-database-error-database c)))))
168
169 (define-condition clsql-odbc-error (clsql-error)
170   ((odbc-message :initarg :odbc-message
171                  :reader clsql-odbc-error-message)
172    (sql-state :initarg :sql-state :initform nil
173               :reader clsql-odbc-error-sql-state))
174   (:report (lambda (c stream)
175              (format stream "[ODBC error] ~A; state: ~A"
176                      (clsql-odbc-error-message c)
177                      (clsql-odbc-error-sql-state c)))))
178
179 ;; Signal conditions
180
181
182 (defun signal-closed-database-error (database)
183   (cerror "Ignore this error and return nil."
184           'clsql-closed-error
185           :database database))
186
187 (defun signal-no-database-error (database)
188   (error 'clsql-no-database-error :database database))
189
190 (define-condition clsql-type-error (clsql-error clsql-condition)
191   ((slotname :initarg :slotname
192              :reader clsql-type-error-slotname)
193    (typespec :initarg :typespec
194              :reader clsql-type-error-typespec)
195    (value :initarg :value
196           :reader clsql-type-error-value))
197   (:report (lambda (c stream)
198              (format stream
199                      "Invalid value ~A in slot ~A, not of type ~A."
200                      (clsql-type-error-value c)
201                      (clsql-type-error-slotname c)
202                      (clsql-type-error-typespec c)))))
203
204 (define-condition clsql-sql-syntax-error (clsql-error)
205   ((reason :initarg :reason
206            :reader clsql-sql-syntax-error-reason))
207   (:report (lambda (c stream)
208              (format stream "Invalid SQL syntax: ~A"
209                      (clsql-sql-syntax-error-reason c)))))
210