;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*- ;;;; ************************************************************************* ;;;; ;;;; Generic sequence implementation. Backends should use native sequences if ;;;; are available. ;;;; ;;;; This file is part of CLSQL. ;;;; ;;;; CLSQL users are granted the rights to distribute and use this software ;;;; as governed by the terms of the Lisp Lesser GNU Public License ;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL. ;;;; ************************************************************************* (in-package #:clsql-sys) (defclass generic-database (database) () (:documentation "Encapsulate same behavior across backends.")) ;;; Sequence functions (defvar *old-sequence-names* nil "Should CLSQL use its old sequence naming scheme _CLSQL_SEQ_{table} instead of the current scheme {table}_CLSQL_SEQ") (defun %sequence-name-to-table (sequence-name database) (escaped (combine-database-identifiers (if *old-sequence-names* (list '_CLSQL_SEQ sequence-name) (list sequence-name 'CLSQL_SEQ)) database))) (defmethod database-create-sequence (sequence-name database) (let ((table-name (%sequence-name-to-table sequence-name database))) (database-execute-command (concatenate 'string "CREATE TABLE " table-name " (last_value int NOT NULL PRIMARY KEY, increment_by int, min_value int, is_called char(1))") database) (database-execute-command (concatenate 'string "INSERT INTO " table-name " VALUES (1,1,1,'f')") database))) (defmethod database-drop-sequence (sequence-name database) (database-execute-command (concatenate 'string "DROP TABLE " (%sequence-name-to-table sequence-name database)) database)) (defun %seq-name-key () (if *old-sequence-names* "_CLSQL_SEQ_" "_CLSQL_SEQ")) (defun %table-name-to-sequence-name (table-name) ;; if this was escaped it still should be, ;; if it wasnt it still shouldnt-be (check-type table-name string) (replace-all table-name (%seq-name-key) "")) (defmethod database-list-sequences (database &key (owner nil)) (declare (ignore owner)) (mapcan #'(lambda (s) (and (search (%seq-name-key) s :test #'string-equal) (list (%table-name-to-sequence-name s)))) (database-list-tables-and-sequences database))) (defmethod database-set-sequence-position (sequence-name position database) (database-execute-command (format nil "UPDATE ~A SET last_value=~A,is_called='t'" (%sequence-name-to-table sequence-name database) position) database) position) (defmethod database-sequence-next (sequence-name database) (without-interrupts (let* ((table-name (%sequence-name-to-table sequence-name database)) (tuple (car (database-query (concatenate 'string "SELECT last_value,is_called FROM " table-name) database :auto nil)))) (cond ((char-equal (schar (second tuple) 0) #\f) (database-execute-command (format nil "UPDATE ~A SET is_called='t'" table-name) database) (car tuple)) (t (let ((new-pos (1+ (car tuple)))) (database-execute-command (format nil "UPDATE ~A SET last_value=~D" table-name new-pos) database) new-pos)))))) (defmethod database-sequence-last (sequence-name database) (without-interrupts (caar (database-query (concatenate 'string "SELECT last_value FROM " (%sequence-name-to-table sequence-name database)) database :auto nil))))