annotate base/charm/database-functions.lisp @ 258:aac79c0ac1b9

add within-short-bar-p, and use this to correctly calculate the ioi-from-bar of anacruses
author Jamie Forth <j.forth@gold.ac.uk>
date Thu, 24 Feb 2011 18:50:38 +0000
parents b5ffec94ae6d
children
rev   line source
j@253 1 (cl:in-package #:amuse-charm)
j@253 2
j@253 3 ;;;=====================================================================
j@253 4 ;;; API for inserting and retrieving constituents
j@253 5 ;;;=====================================================================
j@253 6
j@253 7 (defun store-charm-constituent (constituent database)
j@253 8 "Given a charm-constituent, store it in the database (after first
j@253 9 checking for a previously added identical constituent - this needs
j@253 10 doing properly), and then update the database related
j@253 11 slots (identifier, owner, version, and timestamps).
j@253 12
j@253 13 FIXME: What to do about constituent start and duration slots?
j@253 14 Currently all implementations use integer time in the database, but
j@253 15 then typically convert to a real number line in Lisp, e.g. geerdes
j@253 16 divides by the MIDI timebase. So what should the start and duration
j@253 17 slots mean? Should they be the real values or the database integer
j@253 18 values? If the latter, then each implementation should provide a
j@253 19 'convert-to-integer-time' function. Or the other extreme, do we
j@253 20 specify these database columns as string so that we can store what
j@253 21 ever we want (e.g. Lisp ratios instead of forcing conversion to
j@253 22 floating point). For the moment, I'm ignoring this."
j@253 23 (unless nil ;(constituent-header-exists-p constituent database)
j@253 24 (%insert-new-constituent constituent database)
j@253 25 (format t "New constituent added: id ~A."
j@253 26 (id constituent))
j@253 27 (identifier constituent)))
j@253 28
j@253 29 (defun get-charm-constituent (constituent-identifier database)
j@253 30 (let ((header (%get-constituent-header constituent-identifier
j@253 31 database)))
j@253 32 (destructuring-bind (parent ext-properties int-properties owner
j@253 33 version creation-timestamp
j@253 34 deletion-timestamp) header
j@253 35 (make-standard-charm-constituent (%get-constituent-particles
j@253 36 constituent-identifier parent
j@253 37 database) parent
j@253 38 ext-properties int-properties
j@253 39 :constituent-identifier
j@253 40 constituent-identifier
j@253 41 :owner owner
j@253 42 :version version
j@253 43 :creation-timestamp creation-timestamp
j@253 44 :deletion-timestamp
j@253 45 deletion-timestamp))))
j@253 46
j@253 47 ;; (defun cache-charm-particles (charm-constituent)
j@253 48 ;; "This could/should also re-compute the time and duration slots. Or,
j@253 49 ;; unless we can come up with a general way of storing these values in
j@253 50 ;; the constituent headers."
j@253 51 ;; (%cache-charm-particles (implementation-package (parent-identifier
j@253 52 ;; charm-constituent))
j@253 53 ;; charm-constituent))
j@253 54
j@253 55 ;(defun delete-constituent (constituent-identifier database)
j@253 56
j@253 57
j@253 58 (defun constituent-header-exists-p (constituent database)
j@253 59 (with-slots (time interval extrinsic-properties
j@253 60 intrinsic-properties)
j@253 61 constituent
j@253 62 (let ((exists
j@253 63 (car
j@253 64 (clsql:query (format nil "
j@253 65 SELECT constituent_header_exists(~S, ~S, '~A', '~A')"
j@253 66 time
j@253 67 interval
j@253 68 (object->db-string
j@253 69 extrinsic-properties)
j@253 70 (object->db-string
j@253 71 intrinsic-properties))
j@253 72 :database database
j@253 73 :flatp t
j@253 74 :field-names nil))))
j@253 75 (if (eq exists 1)
j@253 76 (progn (setf exists t)
j@253 77 (format t "Constituent header exists.~%"))
j@253 78 (progn (setf exists nil)
j@253 79 (format t "Constituent header does not exist.~%")))
j@253 80 exists)))
j@253 81
j@253 82 ;(defun constituent-particle-list-exists-p (constituent) nil)
j@253 83
j@253 84
j@253 85 ;;;=====================================================================
j@253 86 ;;; Helper functions
j@253 87 ;;;=====================================================================
j@253 88
j@253 89 (defun %insert-new-constituent (constituent database)
j@253 90 "Constituent-identifier, owner, version, and timestamps are added as
j@253 91 side effects."
j@253 92 (clsql:with-transaction (:database database)
j@253 93 (%insert-constituent-header constituent database)
j@253 94 (%insert-particles constituent database)))
j@253 95
j@253 96 (defun %insert-constituent-header (constituent database)
j@253 97 (with-slots (parent extrinsic-properties intrinsic-properties)
j@253 98 constituent
j@253 99 (clsql:execute-command (concatenate 'string "
j@253 100 INSERT INTO charm_constituent_headers SET
j@253 101 implementation_id := (SELECT get_impl_id('" (implementation-namestring
j@253 102 parent) "')),
j@253 103 parent_id := " (princ-to-string (id parent)) ",
j@253 104 ext_properties := '" (object->db-string extrinsic-properties) "',
j@253 105 int_properties := '" (object->db-string intrinsic-properties) "';")
j@253 106 :database database)
j@253 107 (%update-header-slots constituent database)))
j@253 108
j@253 109 (defun %update-header-slots (constituent database)
j@253 110 (let ((db-row-data (clsql:query "
j@253 111 SELECT last_insert_id(), owner, version, creation_timestamp, deletion_timestamp
j@253 112 FROM charm_constituent_headers
j@253 113 WHERE constituent_id = last_insert_id();"
j@253 114 :database database
j@253 115 :flatp t
j@253 116 :field-names nil)))
j@253 117 (destructuring-bind (const-id own ver create delete) (car db-row-data)
j@253 118 (setf (identifier constituent) (make-charm-constituent-identifier
j@253 119 const-id)
j@253 120 (owner constituent) own
j@253 121 (version constituent) ver
j@253 122 (creation-timestamp constituent) create
j@253 123 (deletion-timestamp constituent) delete)))
j@253 124 constituent)
j@253 125
j@253 126 (defgeneric %insert-particles (constituent database))
j@253 127
j@253 128 (defmethod %insert-particles ((constituent standard-charm-event-constituent)
j@253 129 database)
j@253 130 (if (write-particles constituent)
j@253 131 (clsql:execute-command
j@253 132 "LOAD DATA LOCAL INFILE '/tmp/particles'
j@253 133 INTO TABLE charm_constituent_particles"
j@253 134 :database database)
j@253 135 (error "file not written"))
j@253 136 (delete-file "/tmp/particles"))
j@253 137
j@253 138 (defmethod %insert-particles ((constituent standard-charm-constituent)
j@253 139 database)
j@253 140 (sequence:dosequence (particle constituent t)
j@253 141 (store-charm-constituent particle database)))
j@253 142
j@253 143 (defun write-particles (constituent)
j@253 144 (with-open-file (particle-stream (pathname "/tmp/particles")
j@253 145 :direction :output
j@253 146 :if-exists :supersede)
j@253 147 (loop for particle in (%list-slot-sequence-data constituent)
j@253 148 do (write-sequence (concatenate
j@253 149 'string ;;FIXME SET @constituent_id server side?
j@253 150 (princ-to-string (id constituent))
j@253 151 '(#\tab)
j@253 152 (princ-to-string (id particle))
j@253 153 '(#\tab)
j@253 154 (object->db-string (identifier particle)) ; type
j@253 155 '(#\tab)
j@253 156 "1" ; version - defaults to 1
j@253 157 '(#\nl))
j@253 158 particle-stream)
j@253 159 finally (return t))))
j@253 160
j@253 161
j@253 162 ;;;=====================================================================
j@253 163 ;;; Retrieving
j@253 164 ;;;=====================================================================
j@253 165
j@253 166 (defun %get-constituent-header (constituent-identifier database)
j@253 167 "Basic low-level retrieval of constituents. Just takes an identifier
j@253 168 and returns a header without any checking of version or deletion
j@253 169 fields."
j@253 170 (let ((header-row (clsql:query (concatenate 'string "
j@253 171 SELECT implementation_name, parent_id, ext_properties, int_properties,
j@253 172 owner, version, creation_timestamp, deletion_timestamp
j@253 173 FROM charm_constituent_headers
j@253 174 LEFT JOIN amuse_implementations
j@253 175 USING (implementation_id)
j@253 176 WHERE constituent_id = " (princ-to-string (id constituent-identifier)))
j@253 177 :flatp t
j@253 178 :field-names nil
j@253 179 :database database)))
j@253 180 (%init-header (car header-row))))
j@253 181
j@253 182 (defun %init-header (header-row)
j@253 183 (destructuring-bind (impl-name parent ext-properties int-properties
j@253 184 owner version creation-timestamp
j@253 185 deletion-timestamp) header-row
j@253 186 (setf ext-properties (make-charm-property-list (read-from-string
j@253 187 ext-properties)))
j@253 188 (setf int-properties (make-charm-property-list (read-from-string
j@253 189 int-properties)))
j@253 190 (setf impl-name (find-package impl-name))
j@253 191 (setf parent
j@253 192 (get-charm-parent
j@253 193 (make-charm-parent-identifier impl-name parent)))
j@253 194 ;; FIXME: probable should turn timestamps into objects
j@253 195 (list parent ext-properties int-properties owner version
j@253 196 creation-timestamp deletion-timestamp)))
j@253 197
j@253 198 (defun %get-constituent-particles (constituent-identifier parent
j@253 199 database)
j@253 200 (let ((particle-rows (clsql:query (concatenate 'string "
j@253 201 SELECT particle_id, version_added, version_removed
j@253 202 FROM charm_constituent_particles
j@253 203 WHERE constituent_id = " (princ-to-string
j@253 204 (id constituent-identifier)))
j@253 205 :database database
j@253 206 :flatp t
j@253 207 :field-names nil)))
j@253 208 (%init-particle-rows particle-rows parent)))
j@253 209
j@253 210 (defun %init-particle-rows (particle-rows parent)
j@253 211 (let ((impl-package (implementation-package parent)))
j@253 212 (loop for row in particle-rows
j@253 213 collect (make-charm-particle-identifier impl-package (car row))
j@253 214 into particles
j@253 215 finally (return particles))))
j@253 216
j@253 217 ;; (defun %init-particle-rows (particle-rows parent)
j@253 218 ;; "An alternative to above - would select-events-by-ids be useful?"
j@253 219 ;; (select-events-by-ids parent
j@253 220 ;; (loop for row in particle-rows
j@253 221 ;; collect (car row)
j@253 222 ;; into ids
j@253 223 ;; finally (return ids))))