プロジェクト

全般

プロフィール

ErrataPage » sqlite3.scm

Yuumi Yoshida, 2008-06-04 22:15

 
1
;;;
2
;;;
3
;;;
4
(define-module dbd.sqlite3
5
  (use dbi)
6
  (use gauche.uvector)
7
  (use util.list)
8
  (use util.match)
9
  (use gauche.collection)
10
  (use gauche.sequence)
11
  (use util.relation)
12
  (export <sqlite3-driver>
13
	  <sqlite3-connection>
14
	  <sqlite3-result-set>
15
	  ))
16

    
17
(select-module dbd.sqlite3)
18
(dynamic-load "dbd_sqlite3")
19

    
20

    
21
(define-class <sqlite3-driver> (<dbi-driver>) 
22
  ())
23

    
24
(define-class <sqlite3-connection> (<dbi-connection>)
25
  ((%handle :init-keyword :handle :init-value #f)))
26

    
27
(define-class <sqlite3-result-set> (<relation> <collection>)
28
  ((%handle :init-keyword :handle :init-value #f)
29
   (%prev :init-keyword :prev :init-value #f)
30
   (field-names :init-keyword :field-names :init-value #f)
31
   (rows        :init-form #f)))
32

    
33
(define-condition-type <sqlite3-error> <dbi-error> #f 
34
  (error-code))
35

    
36

    
37
(define	(sqlite3-step result-set)
38
  (let1 v (sqlite-c-stmt-step (slot-ref result-set '%handle))
39
    (slot-set! result-set '%prev v)
40
    v))
41

    
42
(define (sqlite3-execute db query)
43
  (let ((stmt (make-sqlite-stmt))
44
	(result-set (make <sqlite3-result-set>)))
45
    (if (sqlite-c-execute db stmt query)
46
	(begin (slot-set! result-set '%handle stmt)
47
	       (slot-set! result-set 'field-names (sqlite-c-stmt-column-names stmt))
48
	       result-set)
49
	#f)))
50

    
51
(define-method dbi-make-connection ((d <sqlite3-driver>)
52
				    (options <string>)
53
				    (option-alist <list>)
54
				    . args)
55
  (let* ((db-name (match option-alist
56
		    (((maybe-db . #t) . rest) maybe-db)
57
		    (else (assoc-ref option-alist "db" #f))))
58
	 (conn (make <sqlite3-connection>)))
59
    (with-error-handler (lambda (e) (error <dbi-error> :message "SQLite3 open failed"))
60
			(lambda () (slot-set! conn '%handle (sqlite-c-open db-name))))
61
    conn))
62

    
63

    
64
(define-method dbi-execute-using-connection ((c <sqlite3-connection>)
65
					     (q <dbi-query>)
66
					     params)
67
  (let* ((handle (slot-ref c '%handle))
68
	 (query-string (apply (slot-ref q 'prepared) params))
69
	 (result #f))
70
;    	(print query-string)
71
    (with-error-handler (lambda (e) (error <dbi-error> :message (slot-ref e 'message)))
72
			(lambda () (set! result (sqlite3-execute handle query-string))))
73
    (if result
74
	(begin (sqlite3-step result)
75
	       result)
76
       (errorf <dbi-error> :error-message (sqlite-c-error-message handle)
77
		"SQLite3 query failed: ~a" (sqlite-c-error-message handle)))))
78

    
79

    
80
(define-method dbi-close ((result-set <sqlite3-result-set>))
81
  (sqlite-c-stmt-finish (slot-ref result-set '%handle)))
82

    
83
(define-method dbi-close ((c <sqlite3-connection>))
84
  (with-error-handler
85
    (lambda (e) (error <dbi-error> :message (slot-ref e 'message)))
86
    (cut sqlite-c-close (slot-ref c '%handle))))
87

    
88

    
89
(define-method dbi-open? ((c <sqlite3-connection>))
90
	(not (sqlite-c-closed-p (slot-ref c '%handle))))
91

    
92
(define-method dbi-escape-sql ((c <sqlite3-connection>) str)
93
	(sqlite-c-escape-string str))
94

    
95
;; (define-method call-with-iterator ((r <sqlite3-result-set>) proc . option)
96
;;   (let*	((prev #f)
97
;; 	 (end? (cut sqlite-c-stmt-end-p (slot-ref r '%handle)))
98
;; 	 (next (lambda ()
99
;; 		 (set! prev (slot-ref r '%prev))
100
;; 		 (with-error-handler (lambda (e)
101
;; 				       (error <dbi-error> :message (slot-ref e 'message)))
102
;; 				     (cut sqlite3-step r))
103
;; 		 prev)))
104
;;     (proc end? next)))
105

    
106
(define (get-all-rows r)
107
  (let loop ((rows (list (slot-ref r '%prev))))
108
    (let1 row (sqlite3-step r)
109
      (if row
110
	  (loop (cons row rows))
111
	  (reverse! rows)))))
112

    
113
(define-method call-with-iterator ((r <sqlite3-result-set>) proc . option)
114
  (unless (dbi-open? r)
115
    (error <dbi-error> "<sqlite3-result> already closed:" r))
116
  (unless (ref r 'rows)
117
    (set! (ref r 'rows) (get-all-rows r)))
118
  (call-with-iterator (ref r 'rows) proc))
119

    
120
(define-method relation-rows ((r <sqlite3-result-set>))
121
  (slot-ref r 'rows))
122

    
123
(define-method relation-column-names ((result-set <sqlite3-result-set>))
124
  (ref result-set 'field-names))
125

    
126
(define-method relation-accessor ((result-set <sqlite3-result-set>))
127
  (let1 columns (ref result-set 'field-names)
128
    (lambda (row column . maybe-default)
129
      (cond ((find-index (cut string=? <> column) columns)
130
	     => (cut vector-ref row <>))
131
	    ((pair? maybe-default) (car maybe-default))
132
	    (else (error "invalud column name:" column))))))
133

    
134
(provide "dbd/sqlite3")
    (1-1/1)