r10922: 03 May 2006 Kevin Rosenberg <kevin@rosenberg.net>
authorKevin M. Rosenberg <kevin@rosenberg.net>
Wed, 3 May 2006 14:39:10 +0000 (14:39 +0000)
committerKevin M. Rosenberg <kevin@rosenberg.net>
Wed, 3 May 2006 14:39:10 +0000 (14:39 +0000)
        * Version 3.5.7
        * sql/time.lisp: Apply patch from Aleksandar Bakic to extended
        duration parsing and unparsing to include year and month.
        * clsql-uffi.asd, uffi/clsql-uffi-loader.lisp: Apply patch from Nathan Bird
        improving library search on Windows platform.
        * doc/ref-fdml.xml, /doc/TODO, tests/test-fdml.lisp, tests/test-init.lisp:
        Apply patch from Marcus Pearce documenting and testing :limit and :offset for SELECT

ChangeLog
clsql-uffi.asd
debian/changelog
doc/TODO
doc/ref-fdml.xml
sql/db-interface.lisp
sql/time.lisp
tests/test-fdml.lisp
tests/test-init.lisp
uffi/clsql-uffi-loader.lisp

index 87172f2f7f37366e89998dcd626533d1f23d05d5..9b213c84c5b41e35a2b5518781ca247997fe9d3b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+03 May 2006  Kevin Rosenberg <kevin@rosenberg.net>
+       * Version 3.5.7
+       * sql/time.lisp: Apply patch from Aleksandar Bakic to extended
+       duration parsing and unparsing to include year and month.
+       * clsql-uffi.asd, uffi/clsql-uffi-loader.lisp: Apply patch from Nathan Bird
+       improving library search on Windows platform.
+       * doc/ref-fdml.xml, /doc/TODO, tests/test-fdml.lisp, tests/test-init.lisp:
+       Apply patch from Marcus Pearce documenting and testing :limit and :offset for SELECT
+
 20 Mar 2006  Kevin Rosenberg <kevin@rosenberg.net>
        * Version 3.5.6
        * clsql-postgresql-socket.asd, 
index 48372a1cff433b5060ae08a564e0f355c5108045..19b9fb4ce44afbd342b35a4026c86998b9a6902f 100644 (file)
@@ -21,8 +21,9 @@
 (defpackage clsql-uffi-system (:use #:asdf #:cl))
 (in-package clsql-uffi-system)
 
-(defvar *library-file-dir* (append (pathname-directory *load-truename*)
-                                  (list "uffi")))
+(defvar *clsql-uffi-library-dir*
+  (merge-pathnames "uffi/"
+                  (make-pathname :name nil :type nil :defaults *load-truename*)))
 
 (defclass clsql-uffi-source-file (c-source-file)
   ())
@@ -43,7 +44,7 @@
              found
              (make-pathname :name (component-name c)
                             :type library-file-type
-                            :directory *library-file-dir*)))))
+                            :defaults *clsql-uffi-library-dir*)))))
 
 (defmethod perform ((o load-op) (c clsql-uffi-source-file))
   nil) ;;; library will be loaded by a loader file
@@ -59,9 +60,7 @@
     (unless (zerop (run-shell-command
                    #-freebsd "cd ~A; make"
                    #+freebsd "cd ~A; gmake"
-                   (namestring (make-pathname :name nil
-                                              :type nil
-                                              :directory *library-file-dir*))))
+                   (namestring *clsql-uffi-library-dir*)))
       (error 'operation-error :component c :operation o))))
 
 (defmethod operation-done-p ((o compile-op) (c clsql-uffi-source-file))
index 9ac6c70d1974a6e5dd3ca63117ab9d44be56a26d..ce66a8cb859f330617369d597dd189df981a464f 100644 (file)
@@ -1,3 +1,9 @@
+cl-sql (3.5.7-1) unstable; urgency=low
+
+  * New upstream
+
+ -- Kevin M. Rosenberg <kmr@debian.org>  Wed,  3 May 2006 07:50:05 -0600
+
 cl-sql (3.5.6-3) unstable; urgency=low
 
   * Rebuild to update library dependencies (closes: 361849)
index 3a4dae93697e0c61e27ef2615e5acf35b22773c3..36b1fd6a86994be0d6f85a5b9b309d639a1b497f 100644 (file)
--- a/doc/TODO
+++ b/doc/TODO
@@ -12,8 +12,7 @@ DOCUMENTATION TO DO LIST
  - SQL operators: group-by, limit, not-null, ==, is, having, the, uplike,
    view-class, coalesce, except, exists, substring, concat 
 
- - SELECT: additional keyword arguments accepted include :LIMIT, :OFFSET, 
-   :INNER-JOIN and :ON. 
+ - SELECT: additional keyword arguments accepted include :INNER-JOIN and :ON. 
 
 4. Documenting lower level, non-CommonSQL functions (some of this is already 
    done). 
index c512cdb020f9d0829e16bfe5396a1d7a26f52e51..a5162ff6c1b3801e054353b6bd28556e2d053d4d 100644 (file)
@@ -1188,6 +1188,22 @@ ID FORENAME   SURNAME   EMAIL
             </para>
           </listitem>
         </varlistentry>
+        <varlistentry>
+          <term><parameter>limit</parameter></term>
+          <listitem>
+            <para>
+              A non-negative integer. 
+            </para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><parameter>offset</parameter></term>
+          <listitem>
+            <para>
+              A non-negative integer. 
+            </para>
+          </listitem>
+        </varlistentry>
         <varlistentry>
           <term><parameter>order-by</parameter></term>
           <listitem>
@@ -1341,8 +1357,8 @@ ID FORENAME   SURNAME   EMAIL
         specified lisp type. The keyword arguments
         <parameter>all</parameter>, <parameter>distinct</parameter>,
         <parameter>from</parameter>, <parameter>group-by</parameter>,
-        <parameter>having</parameter>,
-        <parameter>order-by</parameter>,
+        <parameter>having</parameter>, <parameter>limit</parameter>, 
+        <parameter>offset</parameter>, <parameter>order-by</parameter>,
         <parameter>set-operation</parameter> and
         <parameter>where</parameter> are used to specify, using the
         symbolic SQL syntax, the corresponding components of the SQL
@@ -1423,7 +1439,7 @@ ID FORENAME   SURNAME   EMAIL
                        :result-types :auto)
 => (10)
 
-(clsql:select [avg [height]] :from [employee] :flatp t :field-names nil)
+(select [avg [height]] :from [employee] :flatp t :field-names nil)
 => (1.58999584d0)
 
 (select [emplid] [last-name] :from [employee] :where [= [emplid] 1]) 
@@ -1442,13 +1458,21 @@ ID FORENAME   SURNAME   EMAIL
                  :flatp t)
 => (1 2 3 4)
 
-(clsql:select [emplid] :from [employee] 
-                       :where [in [emplid] '(1 2 3 4)]
-                       :flatp t 
-                       :order-by [emplid] 
-                       :field-names nil)
+(select [emplid] :from [employee] 
+        :where [in [emplid] '(1 2 3 4)]
+        :flatp t 
+        :order-by [emplid] 
+        :field-names nil)
 => (1 2 3 4)
 
+(select [emplid] :from [employee] 
+        :order-by [emplid]
+        :limit 5 
+        :offset 3
+        :field-names nil
+        :flatp t)
+=> (4 5 6 7 8)
+
 (select [first-name] [last-name] :from [employee] 
         :field-names nil 
         :order-by '(([first-name] :asc) ([last-name] :desc)))
index 298214ae0cdcfd9c734f9428942212bf1c5a7c6b..10b25d93defb0bbd1c1325561669b4c271c723b8 100644 (file)
@@ -476,4 +476,4 @@ for foreign libraries \(in addition to the default places).")
 (defun push-library-path (path)
   "Adds the pathspec PATH \(which should denote a directory) to
 the list *FOREIGN-LIBRARY-SEARCH-PATHS*."
-  (push path *foreign-library-search-paths*))
\ No newline at end of file
+  (pushnew path *foreign-library-search-paths* :test #'equal))
index e04525889f54d301f4a428488d304e1cb37a7395..22fd87be14bee56b044ac62ce0df6f9dfc100a42 100644 (file)
   (let ((second (duration-second duration))
         (minute (duration-minute duration))
         (hour (duration-hour duration))
-        (day (duration-day duration)))
-    (format nil "P~dD~dH~dM~dS" day hour minute second)))
+        (day (duration-day duration))
+       (month (duration-month duration))
+       (year (duration-year duration)))
+    (format nil "P~dY~dM~dD~dH~dM~dS" year month day hour minute second)))
 
 
 ;; ------------------------------------------------------------
@@ -878,10 +880,10 @@ with the given options"
   (third (mjd-to-gregorian (time-mjd (get-time)))))
 
 (defun current-month ()
-  (second (mjd-to-gregorian (time-mjd (get-time)))))
+  (first (mjd-to-gregorian (time-mjd (get-time)))))
 
 (defun current-day ()
-  (first (mjd-to-gregorian (time-mjd (get-time)))))
+  (second (mjd-to-gregorian (time-mjd (get-time)))))
 
 (defun parse-date-time (string)
   "parses date like 08/08/01, 8.8.2001, eg"
@@ -1002,6 +1004,8 @@ with the given options"
         (minute (duration-minute duration))
         (hour (duration-hour duration))
         (day (duration-day duration))
+       (month (duration-month duration))
+       (year (duration-year duration))
         (return (null stream))
         (stream (or stream (make-string-output-stream))))
     (ecase precision
@@ -1013,10 +1017,20 @@ with the given options"
        (setf second 0))
       (:second
        t))
-    (if (= 0 day hour minute)
+    (if (= 0 year month day hour minute)
         (format stream "0 minutes")
         (let ((sent? nil))
+         (when (< 0 year)
+           (format stream "~d year~p" year year)
+           (setf sent? t))
+         (when (< 0 month)
+           (when sent?
+             (write-char #\Space stream))
+           (format stream "~d month~p" month month)
+           (setf sent? t))
           (when (< 0 day)
+           (when sent?
+             (write-char #\Space stream))
             (format stream "~d day~p" day day)
             (setf sent? t))
           (when (< 0 hour)
@@ -1201,42 +1215,64 @@ Will throw a hissy fit if the date string is a duration. Will ignore any precisi
 
 
 (defvar *iso-8601-duration-delimiters*
-  '((#\D . :days)
+  '((#\Y . :years)
+    (#\D . :days)
     (#\H . :hours)
-    (#\M . :minutes)
+    (#\M . :months/minutes)
     (#\S . :seconds)))
 
 (defun iso-8601-delimiter (elt)
   (cdr (assoc elt *iso-8601-duration-delimiters*)))
 
-(defun iso-8601-duration-subseq (string start)
-  (let* ((pos (position-if #'iso-8601-delimiter string :start start))
-        (number (when pos (parse-integer (subseq string start pos)
-                                          :junk-allowed t))))
+(defun iso-8601-duration-subseq (string end)
+  (let* ((pos (position-if #'iso-8601-delimiter string :end end :from-end t))
+        (pos2 (when pos
+                (position-if-not #'digit-char-p string :end pos :from-end t)))
+        (number (when pos2
+                  (parse-integer
+                   (subseq string (1+ pos2) pos) :junk-allowed t))))
     (when number
       (values number
              (1+ pos)
+             (1+ pos2)
              (iso-8601-delimiter (aref string pos))))))
 
 (defun parse-iso-8601-duration (string)
   "return a wall-time from a duration string"
   (block parse
-    (let ((days 0) (secs 0) (hours 0) (minutes 0) (index 1))
+    (let ((years 0)
+         (months 0)
+         (days 0)
+         (secs 0)
+         (hours 0)
+         (minutes 0)
+         (index (length string))
+         (months/minutes nil))
       (loop
        (multiple-value-bind (duration next-index duration-type)
            (iso-8601-duration-subseq string index)
          (case duration-type
+          (:years
+           (incf years duration))
+          (:months/minutes
+           (if months/minutes
+               (incf months duration)
+               (progn
+                 (setq months/minutes t)
+                 (incf minutes duration))))
+           (:days
+           (setq months/minutes t)
+            (incf days duration))
            (:hours
+           (setq months/minutes t)
             (incf hours duration))
-           (:minutes
-            (incf minutes duration))
            (:seconds
             (incf secs duration))
-           (:days
-            (incf days duration))
            (t
-            (return-from parse (make-duration :day days :hour hours
-                                              :minute minutes :second secs))))
+            (return-from parse
+             (make-duration
+              :year years :month months :day days :hour hours
+              :minute minutes :second secs))))
          (setf index next-index))))))
 
 ;; e.g. 2000-11-11 00:00:00-06
index d2606c14b4419f038d8d0eecbb6a6d4a107af670..0fbcb17a9756b6695f46851bc20ae2b09d1679e9 100644 (file)
   "foo\\bar\\baz"  "foo\\bar\\baz" "foo\\bar\\baz" "foo\\bar\\baz" 
   "foo\\bar\\baz" "foo\\bar\\baz"))
 
+(deftest :fdml/select/37
+    (clsql:select [emplid] :from [employee] 
+                  :order-by [emplid]
+                  :limit 5 
+                  :field-names nil
+                  :flatp t)
+  (1 2 3 4 5))
+
+(deftest :fdml/select/38
+    (clsql:select [emplid] :from [employee] 
+                  :order-by [emplid]
+                  :limit 5 
+                  :offset 3
+                  :field-names nil
+                  :flatp t)
+  (4 5 6 7 8))
+
 (deftest :fdml/do-query/1
     (let ((result '()))
     (clsql:do-query ((name) [select [last-name] :from [employee]
index d745ff0698e3823e4b2c7881d7f760e25eaac0a8..5cdcb78115516fe16e53bea8497bb2bdba9a2879 100644 (file)
           ((and (eq *test-database-underlying-type* :mssql)
                 (clsql-sys:in test :fdml/select/9))
            (push (cons test "mssql uses integer math for AVG") skip-tests))
+          ((and (not (member *test-database-underlying-type* 
+                             '(:postgresql :mysql :sqlite3)))
+                (clsql-sys:in test :fdml/select/37 :fdml/select/38))
+           (push (cons test "LIMIT keyword not supported in SELECT") skip-tests))
          (t
           (push test-form test-forms)))))
       (values (nreverse test-forms) (nreverse skip-tests))))
 
-
 (defun rapid-load (type &optional (position 0))
   "Rapid load for interactive testing."
   (when *default-database*
index 1655ed27cc29ebd5f6baf8d3f4e46f8ce7fd7311..084f66ae160fded631dbe9e4e33d623844c3d511 100644 (file)
 (in-package #:clsql-uffi)
 
 (defun find-and-load-foreign-library (filenames &key module supporting-libraries (errorp t))
-  (setq filenames (if (listp filenames) filenames (list filenames))
-        filenames
-          (append
-           (loop for search-path in clsql:*foreign-library-search-paths*
-                 nconc (loop for filename in filenames
-                             collect (merge-pathnames filename search-path)))
-           filenames))
-  (or (loop for type in (uffi:foreign-library-types)
-            for suffix = (make-pathname :type type)
-            thereis (loop for filename in filenames
-                          thereis (handler-case
-                                    (uffi:load-foreign-library (merge-pathnames filename suffix)
-                                                               :module module
-                                                               :supporting-libraries supporting-libraries)
-                                    (error (c)
-                                      (warn "~A" c)
-                                      nil))))
-      (when errorp
-       (error "Couldn't load foreign librar~@P ~{~S~^, ~}. (searched ~S)"
-               (length filenames) filenames
-              'clsql:*foreign-library-search-paths*))))
+  "Attempt to load a foreign library. This will search for any of the filenames, as
+well as any of the filenames in any of the clsql:*foreign-library-search-paths*"
+  (setq filenames (if (listp filenames) filenames (list filenames)))
+
+  (flet ((try-load (testpath)
+          (handler-case
+              (uffi:load-foreign-library testpath
+                                         :module module
+                                         :supporting-libraries supporting-libraries)
+            (error (c) (warn "~A" c) nil))))
+    (or
+     (loop for type in (uffi:foreign-library-types)
+          thereis
+          (loop for name in filenames
+                for pn = (make-pathname :name name :type type)
+                thereis (or
+                         (loop for search-path in clsql:*foreign-library-search-paths*
+                               thereis (try-load (merge-pathnames pn search-path)))
+                         (try-load pn))))
+     (when errorp
+       (error "Couldn't load foreign librar~@P ~{~S~^, ~}. (searched ~S)"
+             (length filenames) filenames
+             'clsql:*foreign-library-search-paths*)))))
 
 (defvar *clsql-uffi-library-filenames*
-    (list #+(or 64bit x86-64) "clsql_uffi64"
-          #+(or 64bit x86-64) (make-pathname :name "clsql_uffi64"
-                                             :directory clsql-uffi-system::*library-file-dir*)
-          "clsql_uffi"
-          (make-pathname :name "clsql_uffi"
-                         :directory clsql-uffi-system::*library-file-dir*)))
+  (list #+(or 64bit x86-64) "clsql_uffi64"
+       "clsql_uffi"))
 
 (defvar *clsql-uffi-supporting-libraries* '("c")
   "Used only by CMU. List of library flags needed to be passed to ld to
@@ -58,6 +56,7 @@ set to the right path before compiling or loading the system.")
   "T if foreign library was able to be loaded successfully")
 
 (defun load-uffi-foreign-library ()
+  (clsql:push-library-path clsql-uffi-system::*clsql-uffi-library-dir*)
   (find-and-load-foreign-library *clsql-uffi-library-filenames*
                                  :module "clsql-uffi"
                                  :supporting-libraries
@@ -65,4 +64,3 @@ set to the right path before compiling or loading the system.")
   (setq *uffi-library-loaded* t))
 
 (load-uffi-foreign-library)
-