File: api.lisp

package info (click to toggle)
cl-qmynd 20140914-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 380 kB
  • ctags: 617
  • sloc: lisp: 3,852; makefile: 11
file content (132 lines) | stat: -rw-r--r-- 6,715 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;                                                                  ;;;
;;; Free Software published under an MIT-like license. See LICENSE   ;;;
;;;                                                                  ;;;
;;; Copyright (c) 2012-2013 Google, Inc.  All rights reserved.       ;;;
;;;                                                                  ;;;
;;; Original author: Alejandro SedeƱo                                ;;;
;;;                                                                  ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(in-package :qmynd-impl)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Connection entry-point
(defun mysql-connect (&key
			(host "localhost")
			(port 3306)
			(username "")
			(password "")
			database
			(compress nil)
			(ssl :unspecified)
			ssl-verify)
  "Connect to a MySQL over a network (AF_INET) socket and begin the MySQL Handshake.
   Returns a QMYND:MYSQL-CONNECTION object or signals a QMYND:MYSQL-ERROR.
   Accepts the following keyword arguments:
    HOST: The host to connect to. (default: \"localhost\")
    PORT: The port to connect to. (default: 3306)
    USERNAME: User to authenticate as.
    PASSWORD: Password to authenticate with.
    DATABASE: What database to use upon connecting. (default: nil)
    COMPRESS: Whether or not to use compression. (default: nil).
    SSL: Whether or not to use SSL. (default: :UNSPECIFIED)
                     T - Forces SSL (or error out if it's not available).
                   NIL - Disable SSL, even if it is available.
          :UNSPECIFIED - Opportunistic use of SSL.
    SSL-VERIFY: Whether or not to verify the SSL certificate presented by the server. (Default: nil)"
  ;; Open Socket
  (let* ((socket (usocket:socket-connect host port
                                         :protocol :stream
                                         :element-type '(unsigned-byte 8)))
         (connection (make-instance 'mysql-inet-connection
                                    :socket socket
                                    :stream (usocket:socket-stream socket)
                                    :default-schema database)))
    (mysql-connect-do-handshake connection username password database
				:compress compress
                                :ssl ssl
                                :ssl-verify ssl-verify)))

;;; AF_LOCAL sockets should really be folded into usocket. For now, just implement CCL and SBCL support.
#+(or ccl sbcl)
(defun mysql-local-connect (&key (path #P"/var/run/mysqld/mysqld.sock") (username "") (password "") database)
  "Connect to a MySQL over a local (AF_LOCAL) socket and begin the MySQL Handshake.
   Returns a QMYND:MYSQL-CONNECTION object or signals a QMYND:MYSQL-ERROR.
   Accepts the following keyword arguments:
    PATH: The path of the local socket to connect to. (default: #P\"/var/run/mysqld/mysqld.sock\")
    USERNAME: User to authenticate as.
    PASSWORD: Password to authenticate with.
    DATABASE: What database to use upon connecting. (default: nil)"
  ;; Open Socket
  (let* ((socket
           #+ccl (ccl:make-socket :address-family :file
                                  :connect :active
                                  :remote-filename path)
           #+sbcl (let ((socket (make-instance 'sb-bsd-sockets:local-socket
                                               :type :stream)))
                    (sb-bsd-sockets:socket-connect socket (etypecase path
                                                            (pathname (namestring path))
                                                            (string path)))
                    socket)
           )
         (connection (make-instance 'mysql-local-connection
                                    :socket socket
                                    :stream
                                    #+ccl socket
                                    #+sbcl (sb-bsd-sockets:socket-make-stream
                                            socket :input t
                                                   :output t
                                                   :element-type '(unsigned-byte 8))
                                    :default-schema database)))
    (mysql-connect-do-handshake connection username password database :ssl nil)))

(defmethod mysql-disconnect ((c mysql-base-connection))
  "Shut down a MySQL connection."
  (when (mysql-connection-connected c)
    (with-mysql-connection (c)
      (send-command-quit))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Simple SQL Queries
(defun mysql-query (connection query-string
		    &key row-fn (as-text nil) (result-type 'vector))
  "Send a SQL Query over the connection using the MySQL Text Protocol.
   For queries that return rows, returns two values:
    A vector of rows, each of which is a vector of columns.
    A vector of column descriptors.
   For queries that don't return rows, returns a QMYND:RESPONSE-OK-PACKET.
   May signal a QMYND:MYSQL-ERROR."
  (with-mysql-connection (connection)
    (send-command-query query-string
			:row-fn row-fn
			:as-text as-text
			:result-type result-type)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Prepared Statements
(defun mysql-statement-prepare (connection query-string)
  "Prepares a SQL Query using the MySQL Prepared Statement Protocol.
   Returns a QMYND:MYSQL-PREPARED-STATEMENT.
   NB: The QMYND:MYSQL-PREPARED-STATEMENT remembers the
       QMYND:MYSQL-CONNECTION it was prepared for."
  (with-mysql-connection (connection)
    (send-command-statement-prepare query-string)))

(defmethod mysql-statement-execute ((statement mysql-prepared-statement) &key parameters)
  "Executes a QMYND:MYSQL-PREPARED-STATEMENT.
   Accepts the following keyword arguments:
    PARAMETERS: a sequence of parameters for the placeholders in the prepared statement, if any."
  (let ((connection (mysql-prepared-statement-connection statement)))
    (unless connection (error 'invalid-prepared-statement))
    (with-mysql-connection (connection)
      (send-command-statement-execute statement :parameters parameters))))

(defmethod mysql-statement-close ((statement mysql-prepared-statement))
  "Deallocates and invalidates STATEMENT."
  (let ((connection (mysql-prepared-statement-connection statement)))
    (unless connection (error 'invalid-prepared-statement))
    (with-mysql-connection (connection)
      (send-command-statement-close statement)
      (mysql-connection-remove-stale-prepared-statements *mysql-connection*)
      (values))))