Update-slots-from-instance now throws an exception if it generates an update without...
[clsql.git] / sql / sequences.lisp
1 ;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
2 ;;;; *************************************************************************
3 ;;;;
4 ;;;; Generic sequence implementation. Backends should use native sequences if
5 ;;;; are available.
6 ;;;;
7 ;;;; This file is part of CLSQL.
8 ;;;;
9 ;;;; CLSQL users are granted the rights to distribute and use this software
10 ;;;; as governed by the terms of the Lisp Lesser GNU Public License
11 ;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
12 ;;;; *************************************************************************
13
14 (in-package #:clsql-sys)
15
16 (defclass generic-database (database)
17   ()
18   (:documentation "Encapsulate same behavior across backends."))
19
20
21 ;;; Sequence functions
22
23 (defun %sequence-name-to-table (sequence-name database)
24   (concatenate 'string
25                (convert-to-db-default-case "_CLSQL_SEQ_" database)
26                (sql-escape sequence-name)))
27
28 (defun %table-name-to-sequence-name (table-name database)
29   (and (>= (length table-name) 11)
30        (string-equal (subseq table-name 0 11)
31                      (convert-to-db-default-case "_CLSQL_SEQ_" database))
32        (subseq table-name 11)))
33
34 (defmethod database-create-sequence (sequence-name database)
35   (let ((table-name (%sequence-name-to-table sequence-name database)))
36     (database-execute-command
37      (concatenate 'string "CREATE TABLE " table-name
38                   " (last_value int NOT NULL PRIMARY KEY, increment_by int, min_value int, is_called char(1))")
39      database)
40     (database-execute-command
41      (concatenate 'string "INSERT INTO " table-name
42                   " VALUES (1,1,1,'f')")
43      database)))
44
45 (defmethod database-drop-sequence (sequence-name database)
46   (database-execute-command
47    (concatenate 'string "DROP TABLE " (%sequence-name-to-table sequence-name database))
48    database))
49
50 (defmethod database-list-sequences (database &key (owner nil))
51   (declare (ignore owner))
52   (mapcan #'(lambda (s)
53               (let ((sn (%table-name-to-sequence-name s database)))
54                 (and sn (list sn))))
55           (database-list-tables-and-sequences database)))
56
57 (defmethod database-set-sequence-position (sequence-name position database)
58   (database-execute-command
59    (format nil "UPDATE ~A SET last_value=~A,is_called='t'"
60            (%sequence-name-to-table sequence-name database)
61            position)
62    database)
63   position)
64
65 (defmethod database-sequence-next (sequence-name database)
66   (without-interrupts
67    (let* ((table-name (%sequence-name-to-table sequence-name database))
68           (tuple
69            (car (database-query
70                  (concatenate 'string "SELECT last_value,is_called FROM "
71                               table-name)
72                  database :auto nil))))
73      (cond
74        ((char-equal (schar (second tuple) 0) #\f)
75         (database-execute-command
76          (format nil "UPDATE ~A SET is_called='t'" table-name)
77          database)
78         (car tuple))
79        (t
80         (let ((new-pos (1+ (car tuple))))
81          (database-execute-command
82           (format nil "UPDATE ~A SET last_value=~D" table-name new-pos)
83           database)
84          new-pos))))))
85
86 (defmethod database-sequence-last (sequence-name database)
87   (without-interrupts
88    (caar (database-query
89           (concatenate 'string "SELECT last_value FROM "
90                        (%sequence-name-to-table sequence-name database))
91           database :auto nil))))