Major rewrite of table/column name output escaping system wide.
[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   (escaped
25    (combine-database-identifiers
26     (list sequence-name 'CLSQL_SEQ)
27     database)))
28
29 (defmethod database-create-sequence (sequence-name database)
30   (let ((table-name (%sequence-name-to-table sequence-name database)))
31     (database-execute-command
32      (concatenate 'string "CREATE TABLE " table-name
33                   " (last_value int NOT NULL PRIMARY KEY, increment_by int, min_value int, is_called char(1))")
34      database)
35     (database-execute-command
36      (concatenate 'string "INSERT INTO " table-name
37                   " VALUES (1,1,1,'f')")
38      database)))
39
40 (defmethod database-drop-sequence (sequence-name database)
41   (database-execute-command
42    (concatenate 'string "DROP TABLE " (%sequence-name-to-table sequence-name database))
43    database))
44
45 (defun %table-name-to-sequence-name (table-name)
46   ;; if this was escaped it still should be,
47   ;; if it wasnt it still shouldnt-be
48   (check-type table-name string)
49   (replace-all table-name "_CLSQL_SEQ" ""))
50
51 (defmethod database-list-sequences (database &key (owner nil))
52   (declare (ignore owner))
53   (mapcan #'(lambda (s)
54               (and (search "_CLSQL_SEQ" s :test #'string-equal)
55                    (list (%table-name-to-sequence-name s))))
56           (database-list-tables-and-sequences database)))
57
58 (defmethod database-set-sequence-position (sequence-name position database)
59   (database-execute-command
60    (format nil "UPDATE ~A SET last_value=~A,is_called='t'"
61            (%sequence-name-to-table sequence-name database)
62            position)
63    database)
64   position)
65
66 (defmethod database-sequence-next (sequence-name database)
67   (without-interrupts
68    (let* ((table-name (%sequence-name-to-table sequence-name database))
69           (tuple
70            (car (database-query
71                  (concatenate 'string "SELECT last_value,is_called FROM "
72                               table-name)
73                  database :auto nil))))
74      (cond
75        ((char-equal (schar (second tuple) 0) #\f)
76         (database-execute-command
77          (format nil "UPDATE ~A SET is_called='t'" table-name)
78          database)
79         (car tuple))
80        (t
81         (let ((new-pos (1+ (car tuple))))
82          (database-execute-command
83           (format nil "UPDATE ~A SET last_value=~D" table-name new-pos)
84           database)
85          new-pos))))))
86
87 (defmethod database-sequence-last (sequence-name database)
88   (without-interrupts
89    (caar (database-query
90           (concatenate 'string "SELECT last_value FROM "
91                        (%sequence-name-to-table sequence-name database))
92           database :auto nil))))