1 ! Copyright (C) 2007 Chris Double.
\r
2 ! See http://factorcode.org/license.txt for BSD license.
\r
3 USING: kernel alien alien.syntax combinators alien.c-types
\r
4 strings sequences namespaces words math threads ;
\r
7 "odbc" "odbc32.dll" "stdcall" add-library
\r
11 TYPEDEF: void* usb_dev_handle*
\r
12 TYPEDEF: short SQLRETURN
\r
13 TYPEDEF: short SQLSMALLINT
\r
14 TYPEDEF: short* SQLSMALLINT*
\r
15 TYPEDEF: ushort SQLUSMALLINT
\r
16 TYPEDEF: uint* SQLUINTEGER*
\r
17 TYPEDEF: int SQLINTEGER
\r
18 TYPEDEF: char SQLCHAR
\r
19 TYPEDEF: char* SQLCHAR*
\r
20 TYPEDEF: void* SQLHANDLE
\r
21 TYPEDEF: void* SQLHANDLE*
\r
22 TYPEDEF: void* SQLHENV
\r
23 TYPEDEF: void* SQLHDBC
\r
24 TYPEDEF: void* SQLHSTMT
\r
25 TYPEDEF: void* SQLHWND
\r
26 TYPEDEF: void* SQLPOINTER
\r
28 : SQL-HANDLE-ENV ( -- number ) 1 ; inline
\r
29 : SQL-HANDLE-DBC ( -- number ) 2 ; inline
\r
30 : SQL-HANDLE-STMT ( -- number ) 3 ; inline
\r
31 : SQL-HANDLE-DESC ( -- number ) 4 ; inline
\r
33 : SQL-NULL-HANDLE ( -- alien ) f ; inline
\r
35 : SQL-ATTR-ODBC-VERSION ( -- number ) 200 ; inline
\r
37 : SQL-OV-ODBC2 ( -- number ) 2 <alien> ; inline
\r
38 : SQL-OV-ODBC3 ( -- number ) 3 <alien> ; inline
\r
40 : SQL-SUCCESS ( -- number ) 0 ; inline
\r
41 : SQL-SUCCESS-WITH-INFO ( -- number ) 1 ; inline
\r
42 : SQL-NO-DATA-FOUND ( -- number ) 100 ; inline
\r
44 : SQL-DRIVER-NOPROMPT ( -- number ) 0 ; inline
\r
45 : SQL-DRIVER-PROMPT ( -- number ) 2 ; inline
\r
47 : SQL-C-DEFAULT ( -- number ) 99 ; inline
\r
51 SYMBOL: SQL-LONGVARCHAR
\r
53 SYMBOL: SQL-WCHARVAR
\r
54 SYMBOL: SQL-WLONGCHARVAR
\r
56 SYMBOL: SQL-SMALLINT
\r
66 SYMBOL: SQL-VARBINARY
\r
67 SYMBOL: SQL-LONGVARBINARY
\r
68 SYMBOL: SQL-TYPE-DATE
\r
69 SYMBOL: SQL-TYPE-TIME
\r
70 SYMBOL: SQL-TYPE-TIMESTAMP
\r
71 SYMBOL: SQL-TYPE-UTCDATETIME
\r
72 SYMBOL: SQL-TYPE-UTCTIME
\r
73 SYMBOL: SQL-INTERVAL-MONTH
\r
74 SYMBOL: SQL-INTERVAL-YEAR
\r
75 SYMBOL: SQL-INTERVAL-YEAR-TO-MONTH
\r
76 SYMBOL: SQL-INTERVAL-DAY
\r
77 SYMBOL: SQL-INTERVAL-HOUR
\r
78 SYMBOL: SQL-INTERVAL-MINUTE
\r
79 SYMBOL: SQL-INTERVAL-SECOND
\r
80 SYMBOL: SQL-INTERVAL-DAY-TO-HOUR
\r
81 SYMBOL: SQL-INTERVAL-DAY-TO-MINUTE
\r
82 SYMBOL: SQL-INTERVAL-DAY-TO-SECOND
\r
83 SYMBOL: SQL-INTERVAL-HOUR-TO-MINUTE
\r
84 SYMBOL: SQL-INTERVAL-HOUR-TO-SECOND
\r
85 SYMBOL: SQL-INTERVAL-MINUTE-TO-SECOND
\r
87 SYMBOL: SQL-TYPE-UNKNOWN
\r
89 : convert-sql-type ( number -- symbol )
\r
91 { [ dup 1 = ] [ drop SQL-CHAR ] }
\r
92 { [ dup 12 = ] [ drop SQL-VARCHAR ] }
\r
93 { [ dup -1 = ] [ drop SQL-LONGVARCHAR ] }
\r
94 { [ dup -8 = ] [ drop SQL-WCHAR ] }
\r
95 { [ dup -9 = ] [ drop SQL-WCHARVAR ] }
\r
96 { [ dup -10 = ] [ drop SQL-WLONGCHARVAR ] }
\r
97 { [ dup 3 = ] [ drop SQL-DECIMAL ] }
\r
98 { [ dup 5 = ] [ drop SQL-SMALLINT ] }
\r
99 { [ dup 2 = ] [ drop SQL-NUMERIC ] }
\r
100 { [ dup 4 = ] [ drop SQL-INTEGER ] }
\r
101 { [ dup 7 = ] [ drop SQL-REAL ] }
\r
102 { [ dup 6 = ] [ drop SQL-FLOAT ] }
\r
103 { [ dup 8 = ] [ drop SQL-DOUBLE ] }
\r
104 { [ dup -7 = ] [ drop SQL-BIT ] }
\r
105 { [ dup -6 = ] [ drop SQL-TINYINT ] }
\r
106 { [ dup -5 = ] [ drop SQL-BIGINT ] }
\r
107 { [ dup -2 = ] [ drop SQL-BINARY ] }
\r
108 { [ dup -3 = ] [ drop SQL-VARBINARY ] }
\r
109 { [ dup -4 = ] [ drop SQL-LONGVARBINARY ] }
\r
110 { [ dup 91 = ] [ drop SQL-TYPE-DATE ] }
\r
111 { [ dup 92 = ] [ drop SQL-TYPE-TIME ] }
\r
112 { [ dup 93 = ] [ drop SQL-TYPE-TIMESTAMP ] }
\r
113 { [ t ] [ drop SQL-TYPE-UNKNOWN ] }
\r
116 : succeeded? ( n -- bool )
\r
117 #! Did the call succeed (SQL-SUCCESS or SQL-SUCCESS-WITH-INFO)
\r
119 { [ dup SQL-SUCCESS = ] [ drop t ] }
\r
120 { [ dup SQL-SUCCESS-WITH-INFO = ] [ drop t ] }
\r
121 { [ t ] [ drop f ] }
\r
124 FUNCTION: SQLRETURN SQLAllocHandle ( SQLSMALLINT handleType, SQLHANDLE inputHandle, SQLHANDLE* outputHandlePtr ) ;
\r
125 FUNCTION: SQLRETURN SQLSetEnvAttr ( SQLHENV environmentHandle, SQLINTEGER attribute, SQLPOINTER valuePtr, SQLINTEGER stringLength ) ;
\r
126 FUNCTION: SQLRETURN SQLDriverConnect ( SQLHDBC connectionHandle, SQLHWND windowHandle, SQLCHAR* inConnectionString, SQLSMALLINT stringLength, SQLCHAR* outConnectionString, SQLSMALLINT bufferLength, SQLSMALLINT* stringLength2Ptr, SQLUSMALLINT driverCompletion ) ;
\r
127 FUNCTION: SQLRETURN SQLDisconnect ( SQLHDBC connectionHandle ) ;
\r
128 FUNCTION: SQLRETURN SQLPrepare ( SQLHSTMT statementHandle, SQLCHAR* statementText, SQLINTEGER length ) ;
\r
129 FUNCTION: SQLRETURN SQLExecute ( SQLHSTMT statementHandle ) ;
\r
130 FUNCTION: SQLRETURN SQLFreeHandle ( SQLSMALLINT handleType, SQLHANDLE handle ) ;
\r
131 FUNCTION: SQLRETURN SQLFetch ( SQLHSTMT statementHandle ) ;
\r
132 FUNCTION: SQLRETURN SQLNumResultCols ( SQLHSTMT statementHandle, SQLSMALLINT* columnCountPtr ) ;
\r
133 FUNCTION: SQLRETURN SQLDescribeCol ( SQLHSTMT statementHandle, SQLSMALLINT columnNumber, SQLCHAR* columnName, SQLSMALLINT bufferLength, SQLSMALLINT* nameLengthPtr, SQLSMALLINT* dataTypePtr, SQLUINTEGER* columnSizePtr, SQLSMALLINT* decimalDigitsPtr, SQLSMALLINT* nullablePtr ) ;
\r
134 FUNCTION: SQLRETURN SQLGetData ( SQLHSTMT statementHandle, SQLUSMALLINT columnNumber, SQLSMALLINT targetType, SQLPOINTER targetValuePtr, SQLINTEGER bufferLength, SQLINTEGER* strlen_or_indPtr ) ;
\r
136 : alloc-handle ( type parent -- handle )
\r
137 f <void*> [ SQLAllocHandle ] keep swap succeeded? [
\r
143 : alloc-env-handle ( -- handle )
\r
144 SQL-HANDLE-ENV SQL-NULL-HANDLE alloc-handle ;
\r
146 : alloc-dbc-handle ( env -- handle )
\r
147 SQL-HANDLE-DBC swap alloc-handle ;
\r
149 : alloc-stmt-handle ( dbc -- handle )
\r
150 SQL-HANDLE-STMT swap alloc-handle ;
\r
152 : temp-string ( length -- byte-array length )
\r
153 [ CHAR: \space <string> string>char-alien ] keep ;
\r
155 : odbc-init ( -- env )
\r
158 SQL-ATTR-ODBC-VERSION SQL-OV-ODBC3 0 SQLSetEnvAttr
\r
159 succeeded? [ "odbc-init failed" throw ] unless
\r
162 : odbc-connect ( env dsn -- dbc )
\r
163 >r alloc-dbc-handle dup r>
\r
164 f swap dup length 1024 temp-string 0 <short> SQL-DRIVER-NOPROMPT
\r
165 SQLDriverConnect succeeded? [ "odbc-connect failed" throw ] unless ;
\r
167 : odbc-disconnect ( dbc -- )
\r
168 SQLDisconnect succeeded? [ "odbc-disconnect failed" throw ] unless ;
\r
170 : odbc-prepare ( dbc string -- statement )
\r
171 >r alloc-stmt-handle dup r> dup length SQLPrepare succeeded? [ "odbc-prepare failed" throw ] unless ;
\r
173 : odbc-free-statement ( statement -- )
\r
174 SQL-HANDLE-STMT swap SQLFreeHandle succeeded? [ "odbc-free-statement failed" throw ] unless ;
\r
176 : odbc-execute ( statement -- )
\r
177 SQLExecute succeeded? [ "odbc-execute failed" throw ] unless ;
\r
179 : odbc-next-row ( statement -- bool )
\r
180 SQLFetch succeeded? ;
\r
182 : odbc-number-of-columns ( statement -- number )
\r
183 0 <short> [ SQLNumResultCols succeeded? ] keep swap [
\r
189 TUPLE: column nullable digits size type name number ;
\r
193 : odbc-describe-column ( statement n -- column )
\r
195 1024 CHAR: \space <string> string>char-alien dup >r
\r
202 SQLDescribeCol succeeded? [
\r
206 r> *short convert-sql-type
\r
207 r> alien>char-string
\r
210 r> drop r> drop r> drop r> drop r> drop r> drop
\r
211 "odbc-describe-column failed" throw
\r
214 : dereference-type-pointer ( byte-array column -- object )
\r
216 { [ dup SQL-CHAR = ] [ drop alien>char-string ] }
\r
217 { [ dup SQL-VARCHAR = ] [ drop alien>char-string ] }
\r
218 { [ dup SQL-LONGVARCHAR = ] [ drop alien>char-string ] }
\r
219 { [ dup SQL-WCHAR = ] [ drop alien>char-string ] }
\r
220 { [ dup SQL-WCHARVAR = ] [ drop alien>char-string ] }
\r
221 { [ dup SQL-WLONGCHARVAR = ] [ drop alien>char-string ] }
\r
222 { [ dup SQL-SMALLINT = ] [ drop *short ] }
\r
223 { [ dup SQL-INTEGER = ] [ drop *long ] }
\r
224 { [ dup SQL-REAL = ] [ drop *float ] }
\r
225 { [ dup SQL-FLOAT = ] [ drop *double ] }
\r
226 { [ dup SQL-DOUBLE = ] [ drop *double ] }
\r
227 { [ dup SQL-TINYINT = ] [ drop *char ] }
\r
228 { [ dup SQL-BIGINT = ] [ drop *longlong ] }
\r
229 { [ t ] [ nip [ "Unknown SQL Type: " % word-name % ] "" make ] }
\r
232 TUPLE: field value column ;
\r
236 : odbc-get-field ( statement column -- field )
\r
237 dup column? [ dupd odbc-describe-column ] unless dup >r column-number
\r
239 8192 CHAR: \space <string> string>char-alien dup >r
\r
241 f SQLGetData succeeded? [
\r
242 r> r> [ dereference-type-pointer ] keep <field>
\r
245 "SQLGetData Failed for Column: " %
\r
247 " of type: " % dup column-type word-name %
\r
248 ] "" make swap <field>
\r
251 : odbc-get-row-fields ( statement -- seq )
\r
253 dup odbc-number-of-columns [
\r
254 1+ odbc-get-field field-value ,
\r
258 : (odbc-get-all-rows) ( statement -- )
\r
259 dup odbc-next-row [ dup odbc-get-row-fields , yield (odbc-get-all-rows) ] [ drop ] if ;
\r
261 : odbc-get-all-rows ( statement -- seq )
\r
262 [ (odbc-get-all-rows) ] { } make ;
\r
264 : odbc-query ( string dsn -- result )
\r
265 odbc-init swap odbc-connect [
\r
268 dup odbc-get-all-rows
\r
269 swap odbc-free-statement
\r
270 ] keep odbc-disconnect ;