ruby-odbc 0.9998

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,146 @@
1
+ require 'mkmf'
2
+
3
+ def have_library_ex(lib, func="main", headers=nil)
4
+ checking_for "#{func}() in -l#{lib}" do
5
+ libs = append_library($libs, lib)
6
+ if !func.nil? && !func.empty? && COMMON_LIBS.include?(lib)
7
+ true
8
+ elsif try_func(func, libs, headers)
9
+ $libs = libs
10
+ true
11
+ else
12
+ false
13
+ end
14
+ end
15
+ end
16
+
17
+ def try_func_nolink(func, libs, headers = nil, &b)
18
+ headers = cpp_include(headers)
19
+ try_compile(<<"SRC", libs, &b)
20
+ #{COMMON_HEADERS}
21
+ #{headers}
22
+ /*top*/
23
+ int t() { void ((*volatile p)()); p = (void ((*)()))#{func}; return 0; }
24
+ SRC
25
+ end
26
+
27
+ def have_func_nolink(func, headers = nil, &b)
28
+ checking_for "#{func}()" do
29
+ if try_func_nolink(func, $libs, headers, &b)
30
+ $defs.push(format("-DHAVE_%s", func.upcase))
31
+ true
32
+ else
33
+ false
34
+ end
35
+ end
36
+ end
37
+
38
+ dir_config("odbc")
39
+ have_header("sql.h") || begin
40
+ puts "ERROR: sql.h not found"
41
+ exit 1
42
+ end
43
+ have_header("sqlext.h") || begin
44
+ puts "ERROR: sqlext.h not found"
45
+ exit 1
46
+ end
47
+ testdlopen = enable_config("dlopen", true)
48
+ begin
49
+ if PLATFORM !~ /(mingw|cygwin)/ then
50
+ header = "sqltypes.h"
51
+ else
52
+ header = ["windows.h", "sqltypes.h"]
53
+ end
54
+ if defined? have_type
55
+ have_type("SQLTCHAR", header)
56
+ else
57
+ throw
58
+ end
59
+ rescue
60
+ puts "WARNING: please check sqltypes.h for SQLTCHAR manually,"
61
+ puts "WARNING: if defined, modify CFLAGS in Makefile to contain"
62
+ puts "WARNING: the option -DHAVE_TYPE_SQLTCHAR"
63
+ end
64
+ begin
65
+ if PLATFORM !~ /(mingw|cygwin)/ then
66
+ header = "sqltypes.h"
67
+ else
68
+ header = ["windows.h", "sqltypes.h"]
69
+ end
70
+ if defined? have_type
71
+ have_type("SQLLEN", header)
72
+ else
73
+ throw
74
+ end
75
+ rescue
76
+ puts "WARNING: please check sqltypes.h for SQLLEN manually,"
77
+ puts "WARNING: if defined, modify CFLAGS in Makefile to contain"
78
+ puts "WARNING: the option -DHAVE_TYPE_SQLLEN"
79
+ end
80
+ begin
81
+ if PLATFORM !~ /(mingw|cygwin)/ then
82
+ header = "sqltypes.h"
83
+ else
84
+ header = ["windows.h", "sqltypes.h"]
85
+ end
86
+ if defined? have_type
87
+ have_type("SQLULEN", header)
88
+ else
89
+ throw
90
+ end
91
+ rescue
92
+ puts "WARNING: please check sqltypes.h for SQLULEN manually,"
93
+ puts "WARNING: if defined, modify CFLAGS in Makefile to contain"
94
+ puts "WARNING: the option -DHAVE_TYPE_SQLULEN"
95
+ end
96
+ $have_odbcinst_h = have_header("odbcinst.h")
97
+
98
+ if PLATFORM =~ /mswin32/ then
99
+ if !have_library_ex("odbc32", "SQLAllocConnect", "sql.h") ||
100
+ !have_library_ex("odbccp32", "SQLConfigDataSource", "odbcinst.h") ||
101
+ !have_library_ex("odbccp32", "SQLInstallerError", "odbcinst.h") ||
102
+ !have_library("user32", "CharUpper") then
103
+ puts "Can not locate odbc libraries"
104
+ exit 1
105
+ end
106
+ have_func("SQLConfigDataSourceW", "odbcinst.h")
107
+ have_func("SQLWriteFileDSNW", "odbcinst.h")
108
+ have_func("SQLReadFileDSNW", "odbcinst.h")
109
+ have_func("SQLInstallerError", "odbcinst.h")
110
+ have_func("SQLInstallerErrorW", "odbcinst.h")
111
+ # mingw untested !!!
112
+ elsif PLATFORM =~ /(mingw|cygwin)/ then
113
+ have_library("odbc32", "")
114
+ have_library("odbccp32", "")
115
+ have_library("user32", "")
116
+ elsif (testdlopen && PLATFORM !~ /(macos|darwin)/ && CONFIG["CC"] =~ /gcc/ && have_func("dlopen", "dlfcn.h") && have_library("dl", "dlopen")) then
117
+ $LDFLAGS+=" -Wl,-init -Wl,ruby_odbc_init -Wl,-fini -Wl,ruby_odbc_fini"
118
+ $CPPFLAGS+=" -DHAVE_SQLCONFIGDATASOURCE"
119
+ $CPPFLAGS+=" -DHAVE_SQLINSTALLERERROR"
120
+ $CPPFLAGS+=" -DUSE_DLOPEN_FOR_ODBC_LIBS"
121
+ # but test the UNICODE installer functions w/o linking
122
+ # in case we need to provide fwd declarations
123
+ have_func_nolink("SQLConfigDataSourceW", "odbcinst.h")
124
+ have_func_nolink("SQLWriteFileDSNW", "odbcinst.h")
125
+ have_func_nolink("SQLReadFileDSNW", "odbcinst.h")
126
+ have_func_nolink("SQLInstallerErrorW", "odbcinst.h")
127
+ else
128
+ have_library("odbc", "SQLAllocConnect") ||
129
+ have_library("iodbc", "SQLAllocConnect")
130
+ ($have_odbcinst_h &&
131
+ have_library("odbcinst", "SQLConfigDataSource")) ||
132
+ ($have_odbcinst_h &&
133
+ have_library("iodbcinst", "SQLConfigDataSource"))
134
+ $have_odbcinst_h &&
135
+ have_func("SQLConfigDataSourceW", "odbcinst.h")
136
+ $have_odbcinst_h &&
137
+ have_func("SQLWriteFileDSNW", "odbcinst.h")
138
+ $have_odbcinst_h &&
139
+ have_func("SQLReadFileDSNW", "odbcinst.h")
140
+ $have_odbcinst_h &&
141
+ have_func("SQLInstallerError", "odbcinst.h")
142
+ $have_odbcinst_h &&
143
+ have_func("SQLInstallerErrorW", "odbcinst.h")
144
+ end
145
+
146
+ create_makefile("odbc_utf8")
data/ext/utf8/init.c ADDED
@@ -0,0 +1,12 @@
1
+ /*
2
+ * Part of ODBC-Ruby binding
3
+ * Copyright (c) 2006-2007 Christian Werner <chw@ch-werner.de>
4
+ *
5
+ * See the file "COPYING" for information on usage
6
+ * and redistribution of this file and for a
7
+ * DISCLAIMER OF ALL WARRANTIES.
8
+ *
9
+ * $Id: init.c,v 1.2 2007/04/07 09:39:08 chw Exp chw $
10
+ */
11
+
12
+ #include "../init.c"
data/ext/utf8/odbc.c ADDED
@@ -0,0 +1,15 @@
1
+ /*
2
+ * ODBC-Ruby binding
3
+ * Copyright (c) 2001-2007 Christian Werner <chw@ch-werner.de>
4
+ *
5
+ * See the file "COPYING" for information on usage
6
+ * and redistribution of this file and for a
7
+ * DISCLAIMER OF ALL WARRANTIES.
8
+ *
9
+ * $Id: odbc.c,v 1.3 2007/04/07 09:39:08 chw Exp chw $
10
+ */
11
+
12
+ #define UNICODE
13
+ #define _UNICODE
14
+
15
+ #include "../odbc.c"
data/lib/cqgen.rb ADDED
@@ -0,0 +1,561 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # cqgen.rb - Poor man's C code generator to automatically
4
+ # make access wrappers for ODBC datasources.
5
+ #
6
+ # -------------------------------------------------------------------
7
+ # This file is part of "ODBC-Ruby binding"
8
+ #
9
+ # Copyright (c) 2006 Christian Werner <chw@ch-werner.de>
10
+ #
11
+ # See the file "COPYING" for information on usage
12
+ # and redistribution of this file and for a
13
+ # DISCLAIMER OF ALL WARRANTIES.
14
+ # -------------------------------------------------------------------
15
+ #
16
+ # Pre-requisites:
17
+ #
18
+ # * Ruby 1.6 or 1.8
19
+ # * Ruby/ODBC >= 0.996
20
+ # * Acesss to a ODBC datasource with properly
21
+ # loaded schema for the wrappers to generate
22
+ #
23
+ # -------------------------------------------------------------------
24
+ #
25
+ # Functions in this module
26
+ #
27
+ # cqgen DSName, UID, PWD, CFName, SQL, [ParmTypes, ParmNames]
28
+ #
29
+ # DSName: name of datasource to connect
30
+ # UID: user name on datasource
31
+ # PWD: password on datasource
32
+ # CFName: name for C function
33
+ # SQL: SQL text of one query yielding
34
+ # one result set
35
+ # ParmTypes: (optional, array) types for
36
+ # query parameters
37
+ # ParmNames: (optional, array) names for
38
+ # query parameters
39
+ #
40
+ # use this function to make C code for
41
+ # SELECT/UPDATE/DELETE/INSERT SQL statements.
42
+ # The "ParmTypes" is useful since many ODBC drivers
43
+ # cannot return the proper types in SQLDescribeParam().
44
+ #
45
+ # cqgen_test
46
+ # append test functions and skeleton test main()
47
+ # to end of C file
48
+ #
49
+ #
50
+ # cqgen_output c_name, h_name
51
+ # write C source code, 'c_name' for functions,
52
+ # 'h_name' for optional header file
53
+ #
54
+ # -------------------------------------------------------------------
55
+ #
56
+ # Specification file sample
57
+ #
58
+ # ---BOF---
59
+ # require 'cqgen'
60
+ # # simple query
61
+ # cqgen 'bla', '', '', "GetResults", %q{
62
+ # select * from results
63
+ # }
64
+ # # query with parameters using last DSN
65
+ # cqgen nil, nil, nil, "GetResultsGt", %q{
66
+ # select * from results where funfactor > ?
67
+ # }
68
+ # # update with parameters using other DSN
69
+ # cqgen 'bla2', '', '', "IncrFunFactor", %q{
70
+ # update results set funfactor = ? where funfactor < ?
71
+ # }, [ ODBC::SQL_INTEGER, ODBC::SQL_INTEGER ],
72
+ # [ "newfunfactor", "maxfunfactor" ]
73
+ # cqgen_test
74
+ # cqgen_output 'bla_wrap.c'
75
+ # ---EOF---
76
+ #
77
+ # Run this file with a command line like
78
+ #
79
+ # $ ruby sample-file
80
+ # $ cc -c bla_wrap.c
81
+ # or
82
+ # $ cc -o bla_wrap_test bla_wrap.c -DTEST_cqgen_all -lodbc
83
+ #
84
+ # Depending on the SQL text, cqgen writes one or more
85
+ # C functions and zero or one structure typedefs.
86
+ # The structure typedefs are merged when possible,
87
+ # thus you should write the least specific queries
88
+ # on top of the specification file.
89
+ #
90
+ # In the sample:
91
+ #
92
+ # * function GetResults_init to initiate the query
93
+ # * function GetResults to retrieve one result row
94
+ # * function GetResults_deinit to release resources
95
+ # associated with the query
96
+ # * struct RESULT_GetResults for representation of
97
+ # one result row
98
+ #
99
+ # * function GetResultsGt_init with one parameter par1
100
+ # * macro GetResultsGt aliased to GetResults
101
+ # (function reused from 1st query)
102
+ # * macro GetResultsGt_deinit aliased to GetResults_deinit
103
+ # (function reused from 1st query)
104
+ # * struct RESULT_GetResults for representation of
105
+ # one result row (struct name reused from 1st query)
106
+ #
107
+ # * function IncrFunFactor with two parameters named
108
+ # "newfunfactor" and "maxfunfactor" and an SQLINTEGER
109
+ # reference for the number of affected rows
110
+ #
111
+ # -------------------------------------------------------------------
112
+
113
+ require 'odbc'
114
+
115
+ $cqgen_dsn=nil
116
+ $cqgen_uid=nil
117
+ $cqgen_pwd=nil
118
+ $cqgen_simple_fns=Hash.new
119
+ $cqgen_stypes=Hash.new
120
+ $cqgen_h1=''
121
+ $cqgen_h2=''
122
+ $cqgen_c=''
123
+ $cqgen_ct1=''
124
+ $cqgen_ct2=''
125
+
126
+ def cqgen(dsn, uid, pwd, name, sql, parmtypes=nil, parmnames=nil)
127
+ dsn=$cqgen_dsn if dsn.nil?
128
+ uid=$cqgen_uid if uid.nil?
129
+ pwd=$cqgen_pwd if pwd.nil?
130
+ begin
131
+ conn=ODBC::connect(dsn, uid, pwd)
132
+ $cqgen_dsn=dsn
133
+ $cqgen_uid=uid
134
+ $cqgen_pwd=pwd
135
+ rescue Exception => err
136
+ $stderr.puts("connect for #{name} failed:\n")
137
+ $stderr.puts("\t#{err}\n")
138
+ return
139
+ end
140
+ sql = sql.strip
141
+ sql = sql.gsub(/[\r\n]+/, " ")
142
+ if sql.downcase =~ /where/
143
+ sql0=sql + " and 1=0"
144
+ else
145
+ sql0=sql + " where 1=0"
146
+ end
147
+ begin
148
+ stmt=conn.prepare(sql0)
149
+ if stmt.ncols < 1
150
+ stmt.execute
151
+ end
152
+ rescue Exception => err
153
+ $stderr.puts("SQL error for #{name}:\n")
154
+ $stderr.puts("\t#{err}\n")
155
+ return
156
+ end
157
+ if stmt.ncols > 0
158
+ fhead="SQLRETURN\n" + name + "_init(SQLHDBC hdbc, SQLHSTMT *hstmtRet"
159
+ fhead2="SQLRETURN\n" + name + "(SQLHSTMT hstmt"
160
+ flvars2="{\n SQLRETURN ret;\n INTERNAL_STMT *istmt;\n"
161
+ fbody2="\n istmt = (INTERNAL_STMT *) hstmt;\n"
162
+ fhead3="SQLRETURN\n" + name + "_deinit(SQLHSTMT hstmt)\n"
163
+ flvars3="{\n INTERNAL_STMT *istmt;\n"
164
+ fbody3="\n istmt = (INTERNAL_STMT *) hstmt;\n"
165
+ fbody3+=" if (istmt != NULL) {\n"
166
+ fbody3+="\tSQLFreeStmt(istmt->hstmt, SQL_DROP);\n"
167
+ fbody3+="\tfree(istmt);\n"
168
+ fbody3+=" }\n return SQL_SUCCESS;\n}\n\n"
169
+ else
170
+ fhead="SQLRETURN\n" + name + "(SQLHDBC hdbc"
171
+ fhead2=""
172
+ flvars2=""
173
+ fbody2=""
174
+ fhead3=""
175
+ flvars3=""
176
+ fbody3=""
177
+ end
178
+ flvars="{\n SQLRETURN ret;\n"
179
+ if stmt.ncols < 1
180
+ flvars+=" SQLHSTMT hstmt;\n"
181
+ end
182
+ fbody=""
183
+ flvarst="{\n SQLRETURN ret;\n"
184
+ fheadt="SQLRETURN\n" + name + "_test(SQLHDBC hdbc"
185
+ fbodyt=""
186
+ if stmt.ncols > 0
187
+ flvars+=" INTERNAL_STMT *istmt;\n SQLHSTMT hstmt;\n"
188
+ fbody+=" *hstmtRet = hstmt = SQL_NULL_HSTMT;\n"
189
+ fbody+=" ret = SQLAllocStmt(hdbc, &hstmt);\n"
190
+ fbody+=" if (!SQL_SUCCEEDED(ret)) {\n\treturn ret;\n }\n"
191
+ fbody+=" istmt = malloc(sizeof (INTERNAL_STMT));\n"
192
+ fbody+=" if (istmt == NULL) {\n\tSQLFreeStmt(hstmt, SQL_DROP);\n"
193
+ fbody+="\treturn SQL_ERROR;\n }\n"
194
+ fbody+=" istmt->hstmt = hstmt;\n"
195
+ fbody+=" istmt->result = NULL;\n"
196
+ fbody+=" *hstmtRet = (SQLHSTMT) istmt;\n"
197
+ flvarst+=" SQLHSTMT hstmt;\n"
198
+ fbodyt+=" ret = #{name}_init(hdbc, &hstmt"
199
+ else
200
+ fbodyt+=" ret = #{name}(hdbc"
201
+ end
202
+ pnum=1
203
+ stmt.parameters.each do |par|
204
+ if !parmtypes.nil?
205
+ ptype=parmtypes[pnum-1]
206
+ end
207
+ if ptype.nil?
208
+ ptype = par.type
209
+ end
210
+ if !parmnames.nil?
211
+ pname=parmnames[pnum-1]
212
+ end
213
+ if pname.nil?
214
+ pname="par#{pnum}"
215
+ end
216
+ case ptype
217
+ when ODBC::SQL_INTEGER
218
+ pdef=", SQLINTEGER *#{pname}"
219
+ fbody+=" #{pname}_len = sizeof (SQLINTEGER);\n";
220
+ fbody+=" ret = SQLBindParameter(hstmt, #{pnum}, SQL_PARAM_INPUT,"
221
+ fbody+=" SQL_C_LONG, SQL_INTEGER, #{par.precision}, #{par.scale},"
222
+ when ODBC::SQL_SMALLINT
223
+ pdef=", SQLSMALLINT *#{pname}"
224
+ fbody+=" #{pname}_len = sizeof (SQLSMALLINT);\n";
225
+ fbody+=" ret = SQLBindParameter(hstmt, #{pnum}, SQL_PARAM_INPUT,"
226
+ fbody+=" SQL_C_SHORT, SQL_SMALLINT, #{par.precision}, #{par.scale},"
227
+ when ODBC::SQL_FLOAT
228
+ pdef=", SQLDOUBLE *#{pname}"
229
+ fbody+=" #{pname}_len = sizeof (SQLDOUBLE);\n";
230
+ fbody+=" ret = SQLBindParameter(hstmt, #{pnum}, SQL_PARAM_INPUT,"
231
+ fbody+=" SQL_C_DOUBLE, SQL_FLOAT, #{par.precision}, #{par.scale},"
232
+ when ODBC::SQL_DOUBLE
233
+ pdef=", SQLDOUBLE *#{pname}"
234
+ fbody+=" #{pname}_len = sizeof (SQLDOUBLE);\n";
235
+ fbody+=" ret = SQLBindParameter(hstmt, #{pnum}, SQL_PARAM_INPUT,"
236
+ fbody+=" SQL_C_DOUBLE, SQL_DOUBLE, #{par.precision}, #{par.scale},"
237
+ else
238
+ pdef=", SQLCHAR *#{pname}"
239
+ fbody+=" #{pname}_len = #{pname} ? strlen(#{pname}) : SQL_NULL_DATA;\n";
240
+ fbody+=" ret = SQLBindParameter(hstmt, #{pnum}, SQL_PARAM_INPUT,"
241
+ fbody+=" SQL_C_CHAR, SQL_CHAR, #{par.precision}, #{par.scale},"
242
+ end
243
+ fbody+=" #{pname}, #{pname}_len, &#{pname}_len);\n"
244
+ fhead+=pdef
245
+ fheadt+=pdef
246
+ fbodyt+=", #{pname}"
247
+ flvars+=" SQLINTEGER #{pname}_len;\n"
248
+ if stmt.ncols > 0
249
+ fbody+=" if (!SQL_SUCCEEDED(ret)) {\n\treturn ret;\n }\n"
250
+ else
251
+ fbody+=" if (!SQL_SUCCEEDED(ret)) {\n\tgoto done;\n }\n"
252
+ end
253
+ pnum+=1
254
+ end
255
+ fheadt+=")\n"
256
+ if stmt.ncols < 1
257
+ fbodyt+= ", &rowCount"
258
+ end
259
+ fbodyt+=");\n"
260
+ if stmt.ncols > 0
261
+ fbodyt+=" if (!SQL_SUCCEEDED(ret)) {\n"
262
+ fbodyt+="\t#{name}_deinit(hstmt);\n\treturn ret;\n }\n"
263
+ end
264
+ struc=""
265
+ istruc=""
266
+ if stmt.ncols > 0
267
+ if pnum<=1
268
+ $cqgen_simple_fns["#{name}_test"]=1
269
+ end
270
+ fbody+=" ret = SQLPrepare(hstmt, \"#{sql}\", SQL_NTS);\n"
271
+ fbody+=" if (!SQL_SUCCEEDED(ret)) {\n\treturn ret;\n }\n"
272
+ fbody+=" ret = SQLExecute(hstmt);\n"
273
+ fbody+=" return ret;\n}\n\n"
274
+ struc+="typedef struct {\n"
275
+ fbody2+=" hstmt = istmt->hstmt;\n"
276
+ fbody2+=" if (result == istmt->result) {\n"
277
+ fbody2+="\tgoto doexec;\n }\n"
278
+ fbody2+=" istmt->result = NULL;\n"
279
+ fbodyt+=" do {\n"
280
+ fbodyt+="\tret = #{name}(hstmt, &result);\n"
281
+ fbodyt+="\tif (!SQL_SUCCEEDED(ret)) {\n\t break;\n\t}\n"
282
+ cols = stmt.columns(1)
283
+ coltable = Hash.new
284
+ cols.each do |col|
285
+ coltable[col.table => 1]
286
+ end
287
+ cnum=1
288
+ cols.each do |col|
289
+ if coltable.size > 1
290
+ cname=col.table+"_"+col.name
291
+ else
292
+ cname=col.name
293
+ end
294
+ case col.type
295
+ when ODBC::SQL_INTEGER
296
+ istruc+=" SQLLEN #{cname}_len;\n"
297
+ istruc+=" SQLINTEGER #{cname};\n"
298
+ fbody2+=" ret = SQLBindCol(hstmt, #{cnum}, SQL_C_LONG,"
299
+ fbody2+=" &result->#{cname}, sizeof (SQL_C_LONG),"
300
+ fbody2+=" &result->#{cname}_len);\n"
301
+ when ODBC::SQL_SMALLINT
302
+ istruc+=" SQLLEN #{cname}_len;\n"
303
+ istruc+=" SQLSMALLINT #{cname};\n"
304
+ fbody2+=" ret = SQLBindCol(hstmt, #{cnum}, SQL_C_SMALLINT,"
305
+ fbody2+=" &result->#{cname}, sizeof (SQL_C_SMALLINT),"
306
+ fbody2+=" &result->#{cname}_len);\n"
307
+ when ODBC::SQL_FLOAT
308
+ istruc+=" SQLLEN #{cname}_len;\n"
309
+ istruc+=" SQLDOUBLE #{cname};\n"
310
+ fbody2+=" ret = SQLBindCol(hstmt, #{cnum}, SQL_C_DOUBLE,"
311
+ fbody2+=" &result->#{cname}, sizeof (SQLDOUBLE),"
312
+ fbody2+=" &result->#{cname}_len);\n"
313
+ when ODBC::SQL_DOUBLE
314
+ istruc+=" SQLLEN #{cname}_len;\n"
315
+ istruc+=" SQLDOUBLE #{cname};\n"
316
+ fbody2+=" ret = SQLBindCol(hstmt, #{cnum}, SQL_C_DOUBLE,"
317
+ fbody2+=" &result->#{cname}, sizeof (SQL_C_DOUBLE),"
318
+ fbody2+=" &result->#{cname}_len);\n"
319
+ else
320
+ istruc+=" SQLLEN #{cname}_len;\n"
321
+ istruc+=" SQLCHAR #{cname}[#{col.length}];\n"
322
+ fbody2+=" ret = SQLBindCol(hstmt, #{cnum}, SQL_C_CHAR,"
323
+ fbody2+=" result->#{cname}, #{col.length},"
324
+ fbody2+=" &result->#{cname}_len);\n"
325
+ end
326
+ fbody2+=" if (!SQL_SUCCEEDED(ret)) {\n\treturn ret;\n }\n"
327
+ cnum+=1;
328
+ end
329
+ sname=$cqgen_stypes[istruc]
330
+ if sname.nil?
331
+ sname="RESULT_#{name}"
332
+ $cqgen_stypes[istruc]=sname
333
+ addstruct=true
334
+ else
335
+ addstruct=false
336
+ end
337
+ struc+="#{istruc}} #{sname};\n\n"
338
+ flvarst+=" #{sname} result;\n\n"
339
+ if addstruct
340
+ fhead2+=", #{sname} *result"
341
+ else
342
+ fbody2=""
343
+ flvars2=""
344
+ fbody3=""
345
+ flvars3=""
346
+ fname=sname.gsub(/^RESULT_/, "")
347
+ fhead2="#define\t\t#{name}\t#{fname}\n"
348
+ fhead3="#define\t\t#{name}_deinit\t#{fname}_deinit\n"
349
+ end
350
+ cnum=1
351
+ cols.each do |col|
352
+ if coltable.size > 1
353
+ cname=col.table+"_"+col.name
354
+ else
355
+ cname=col.name
356
+ end
357
+ case col.type
358
+ when ODBC::SQL_INTEGER
359
+ fmt='%ld'
360
+ when ODBC::SQL_SMALLINT
361
+ fmt='%d'
362
+ when ODBC::SQL_FLOAT
363
+ fmt='%g'
364
+ when ODBC::SQL_DOUBLE
365
+ fmt='%g'
366
+ else
367
+ fmt='%s'
368
+ end
369
+ fbodyt+="\tif (result.#{cname}_len != SQL_NULL_DATA) {\n"
370
+ fbodyt+="\t printf(\"#{sname}.#{cname}=#{fmt}\\n\",\n"
371
+ fbodyt+="\t\t result.#{cname});\n"
372
+ fbodyt+="\t} else {\n"
373
+ fbodyt+="\t printf(\"#{sname}.#{cname}=NULL\\n\");\n"
374
+ fbodyt+="\t}\n"
375
+ cnum+=1;
376
+ end
377
+ fbodyt+=" } while (SQL_SUCCEEDED(ret));\n"
378
+ fbodyt+=" #{name}_deinit(hstmt);\n"
379
+ else
380
+ fhead+=", SQLINTEGER *rowCountRet"
381
+ fbody=" if (!SQL_SUCCEEDED(ret)) {\n\tgoto done;\n }\n" + fbody
382
+ fbody=" ret = SQLAllocStmt(hdbc, &hstmt);\n" + fbody
383
+ fbody=" *rowCountRet = 0;\n" + fbody
384
+ fbody+=" ret = SQLExecDirect(hstmt, "
385
+ fbody+='"'+sql+'"'
386
+ fbody+=", SQL_NTS);\n"
387
+ fbody+=" if (!SQL_SUCCEEDED(ret)) {\n\tgoto done;\n }\n"
388
+ fbody+=" ret = SQLRowCount(hstmt, rowCountRet);\ndone:\n"
389
+ fbody+=" SQLFreeStmt(hstmt, SQL_DROP);\n return ret;\n}\n\n"
390
+ flvarst+=" SQLINTEGER rowCount;\n\n"
391
+ fbodyt+=" printf(\"#{name}_test rowCount=%ld\\n\", rowCount);\n"
392
+ end
393
+ if fbodyt.length > 0
394
+ fbodyt+=" return ret;\n"
395
+ fbodyt+="}\n"
396
+ end
397
+ fhead+=")\n"
398
+ if fbody2.length > 0
399
+ fhead2+=")\n"
400
+ fbody2+="doexec:\n"
401
+ fbody2+=" ret = SQLFetch(hstmt);\n"
402
+ fbody2+=" if (!SQL_SUCCEEDED(ret)) {\n\treturn ret;\n }\n"
403
+ fbody2+=" istmt->result = result;\n"
404
+ fbody2+=" return ret;\n}\n\n"
405
+ end
406
+ flvars+="\n"
407
+ stmt.drop
408
+ conn.disconnect
409
+ sql = sql.gsub(/[ \t]+/, " ")
410
+ sql = sql.gsub(/\/\*/, "")
411
+ sql = sql.gsub(/\*\//, "")
412
+ $cqgen_h1+="/* #{sql} */\n" if addstruct
413
+ $cqgen_h1+=struc if addstruct
414
+ $cqgen_h2+="/* #{sql} */\n"
415
+ tmp=fhead.gsub(/SQLRETURN\n/, "SQLRETURN\t");
416
+ $cqgen_h2+=tmp.gsub(/\)\n/, ");\n")
417
+ if fhead2.length > 0
418
+ tmp=fhead2.gsub(/SQLRETURN\n/, "SQLRETURN\t");
419
+ $cqgen_h2+=tmp.gsub(/\)\n/, ");\n")
420
+ end
421
+ if fhead3.length > 0
422
+ tmp=fhead3.gsub(/SQLRETURN\n/, "SQLRETURN\t");
423
+ $cqgen_h2+=tmp.gsub(/\)\n/, ");\n")
424
+ end
425
+ $cqgen_h2+="\n"
426
+ $cqgen_c+=fhead
427
+ $cqgen_c+=flvars
428
+ $cqgen_c+=fbody
429
+ $cqgen_c+=fhead2 unless fhead2 =~ /^#define/
430
+ $cqgen_c+=flvars2
431
+ $cqgen_c+=fbody2
432
+ $cqgen_c+=fhead3 unless fhead3 =~ /^#define/
433
+ $cqgen_c+=flvars3
434
+ $cqgen_c+=fbody3
435
+ $cqgen_ct1+="#if defined(TEST_#{name}) || defined(TEST_cqgen_all)\n"
436
+ $cqgen_ct1+=fheadt
437
+ $cqgen_ct1+=flvarst
438
+ $cqgen_ct1+=fbodyt
439
+ $cqgen_ct1+="#endif\n\n"
440
+ end
441
+
442
+ def cqgen_test
443
+ $cggen_dsn="" if $cqgen_dsn.nil?
444
+ $cggen_uid="" if $cqgen_uid.nil?
445
+ $cggen_pwd="" if $cqgen_pwd.nil?
446
+ test_calls=""
447
+ $cqgen_simple_fns.each_key do |name|
448
+ test_calls+=" printf(\"=== #{name} ===\\n\");\n"
449
+ test_calls+=" #{name}(hdbc);\n"
450
+ end
451
+ $cqgen_ct2=$cqgen_ct1
452
+ $cqgen_ct2+=%Q{
453
+ #ifdef TEST_cqgen_all
454
+ int
455
+ main(int argc, char **argv)
456
+ {
457
+ SQLHENV henv;
458
+ SQLHDBC hdbc;
459
+ SQLRETURN ret;
460
+
461
+ ret = SQLAllocEnv(&henv);
462
+ if (!SQL_SUCCEEDED(ret)) {
463
+ exit(1);
464
+ }
465
+ ret = SQLAllocConnect(henv, &hdbc);
466
+ if (!SQL_SUCCEEDED(ret)) {
467
+ exit(2);
468
+ }
469
+ ret = SQLConnect(hdbc,
470
+ \"#{$cqgen_dsn}\", SQL_NTS,
471
+ \"#{$cqgen_uid}\", SQL_NTS,
472
+ \"#{$cqgen_pwd}\", SQL_NTS);
473
+ if (!SQL_SUCCEEDED(ret)) {
474
+ exit(3);
475
+ }
476
+
477
+ /* ADD YOUR TEST CALLS HERE */
478
+ #{test_calls}
479
+ SQLDisconnect(hdbc);
480
+ SQLFreeConnect(hdbc);
481
+ SQLFreeEnv(henv);
482
+ return 0;
483
+ }
484
+ #endif
485
+
486
+ }
487
+ end
488
+
489
+ def cqgen_output(c_name=nil, h_name=nil)
490
+ h=''
491
+ h+="#include <stdio.h>\n"
492
+ h+="#include <stdlib.h>\n"
493
+ h+="#include <string.h>\n"
494
+ h+="#include <sqltypes.h>\n"
495
+ h+="#include <sql.h>\n"
496
+ h+="#include <sqlext.h>\n\n"
497
+ h+=$cqgen_h1
498
+ h+="\n"
499
+ h+=$cqgen_h2
500
+ if c_name.nil?
501
+ cf=$stdout
502
+ ctoclose=false
503
+ else
504
+ cf=File::open(c_name, 'w')
505
+ ctoclose=true
506
+ end
507
+ if h_name.nil?
508
+ hf=cf
509
+ htoclose=false
510
+ else
511
+ hf=File::open(h_name, 'w')
512
+ htoclose=true
513
+ hb=File::basename(h_name).gsub(/\W/, "_")
514
+ h="#ifndef _#{hb}\n#define _#{hb}\n\n#{h}\n#endif /* _#{hb} */\n"
515
+ end
516
+ hf.print(h)
517
+ c=''
518
+ if !h_name.nil? && (hf != cf)
519
+ c+="#include <stdio.h>\n"
520
+ c+="#include <stdlib.h>\n"
521
+ c+="#include <string.h>\n"
522
+ c+="#include <sqltypes.h>\n"
523
+ c+="#include <sql.h>\n"
524
+ c+="#include <sqlext.h>\n\n"
525
+ c+="#include \"#{h_name}\"\n\n"
526
+ end
527
+ c+=%Q{
528
+ typedef struct {
529
+ SQLHSTMT hstmt;
530
+ void *result;
531
+ } INTERNAL_STMT;
532
+
533
+
534
+ }
535
+ c+=$cqgen_c
536
+ c+=$cqgen_ct2
537
+ cf.print(c)
538
+ hf.close if htoclose
539
+ cf.close if ctoclose
540
+ $cqgen_h1=''
541
+ $cqgen_h2=''
542
+ $cqgen_c=''
543
+ $cqgen_ct1=''
544
+ $cqgen_ct2=''
545
+ $cqgen_simple_fns.clear
546
+ $cqgen_stypes.clear
547
+ end
548
+
549
+ # Run this code only when the file is the main program
550
+ if $0 == __FILE__
551
+ files=ARGV.flatten
552
+ ARGV.clear
553
+ files.each do |f|
554
+ begin
555
+ load f
556
+ rescue Exception => err
557
+ $stderr.puts("in file #{f}:\n")
558
+ $stderr.puts("\t#{err}\n")
559
+ end
560
+ end
561
+ end