ruby-odbc 0.9998
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +53 -0
- data/ChangeLog +283 -0
- data/GPL +340 -0
- data/MANIFEST +23 -0
- data/README +110 -0
- data/doc/odbc.html +1315 -0
- data/ext/extconf.rb +112 -0
- data/ext/init.c +197 -0
- data/ext/odbc.c +7905 -0
- data/ext/utf8/extconf.rb +146 -0
- data/ext/utf8/init.c +12 -0
- data/ext/utf8/odbc.c +15 -0
- data/lib/cqgen.rb +561 -0
- data/ruby-odbc.gemspec +16 -0
- data/test/00connect.rb +1 -0
- data/test/10create_table.rb +1 -0
- data/test/20insert.rb +6 -0
- data/test/30select.rb +69 -0
- data/test/40update.rb +4 -0
- data/test/50drop_table.rb +3 -0
- data/test/70close.rb +1 -0
- data/test/test.rb +32 -0
- data/test/utf8/test.rb +32 -0
- metadata +80 -0
data/ext/utf8/extconf.rb
ADDED
@@ -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
|