ruby-odbc 0.9998

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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