kemen-ruby-odbc 0.1
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.
- data/COPYING +53 -0
- data/ChangeLog +317 -0
- data/GPL +340 -0
- data/MANIFEST +23 -0
- data/README +110 -0
- data/doc/odbc.html +1340 -0
- data/ext/extconf.rb +122 -0
- data/ext/init.c +197 -0
- data/ext/odbc.c +8441 -0
- data/ext/utf8/extconf.rb +156 -0
- data/ext/utf8/init.c +12 -0
- data/ext/utf8/odbc.c +17 -0
- data/kemen-ruby-odbc.gemspec +16 -0
- data/lib/cqgen.rb +561 -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 +92 -0
data/ext/utf8/extconf.rb
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
if ! defined? PLATFORM
|
4
|
+
PLATFORM = RUBY_PLATFORM
|
5
|
+
end
|
6
|
+
|
7
|
+
def have_library_ex(lib, func="main", headers=nil)
|
8
|
+
checking_for "#{func}() in -l#{lib}" do
|
9
|
+
libs = append_library($libs, lib)
|
10
|
+
if !func.nil? && !func.empty? && COMMON_LIBS.include?(lib)
|
11
|
+
true
|
12
|
+
elsif try_func(func, libs, headers)
|
13
|
+
$libs = libs
|
14
|
+
true
|
15
|
+
else
|
16
|
+
false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def try_func_nolink(func, libs, headers = nil, &b)
|
22
|
+
headers = cpp_include(headers)
|
23
|
+
try_compile(<<"SRC", libs, &b)
|
24
|
+
#{COMMON_HEADERS}
|
25
|
+
#{headers}
|
26
|
+
/*top*/
|
27
|
+
int t() { void ((*volatile p)()); p = (void ((*)()))#{func}; return 0; }
|
28
|
+
SRC
|
29
|
+
end
|
30
|
+
|
31
|
+
def have_func_nolink(func, headers = nil, &b)
|
32
|
+
checking_for "#{func}()" do
|
33
|
+
if try_func_nolink(func, $libs, headers, &b)
|
34
|
+
$defs.push(format("-DHAVE_%s", func.upcase))
|
35
|
+
true
|
36
|
+
else
|
37
|
+
false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
dir_config("odbc")
|
43
|
+
have_header("sql.h") || begin
|
44
|
+
puts "ERROR: sql.h not found"
|
45
|
+
exit 1
|
46
|
+
end
|
47
|
+
have_header("sqlext.h") || begin
|
48
|
+
puts "ERROR: sqlext.h not found"
|
49
|
+
exit 1
|
50
|
+
end
|
51
|
+
testdlopen = enable_config("dlopen", false)
|
52
|
+
begin
|
53
|
+
if PLATFORM !~ /(mingw|cygwin)/ then
|
54
|
+
header = "sqltypes.h"
|
55
|
+
else
|
56
|
+
header = ["windows.h", "sqltypes.h"]
|
57
|
+
end
|
58
|
+
if defined? have_type
|
59
|
+
have_type("SQLTCHAR", header)
|
60
|
+
else
|
61
|
+
throw
|
62
|
+
end
|
63
|
+
rescue
|
64
|
+
puts "WARNING: please check sqltypes.h for SQLTCHAR manually,"
|
65
|
+
puts "WARNING: if defined, modify CFLAGS in Makefile to contain"
|
66
|
+
puts "WARNING: the option -DHAVE_TYPE_SQLTCHAR"
|
67
|
+
end
|
68
|
+
begin
|
69
|
+
if PLATFORM !~ /(mingw|cygwin)/ then
|
70
|
+
header = "sqltypes.h"
|
71
|
+
else
|
72
|
+
header = ["windows.h", "sqltypes.h"]
|
73
|
+
end
|
74
|
+
if defined? have_type
|
75
|
+
have_type("SQLLEN", header)
|
76
|
+
else
|
77
|
+
throw
|
78
|
+
end
|
79
|
+
rescue
|
80
|
+
puts "WARNING: please check sqltypes.h for SQLLEN manually,"
|
81
|
+
puts "WARNING: if defined, modify CFLAGS in Makefile to contain"
|
82
|
+
puts "WARNING: the option -DHAVE_TYPE_SQLLEN"
|
83
|
+
end
|
84
|
+
begin
|
85
|
+
if PLATFORM !~ /(mingw|cygwin)/ then
|
86
|
+
header = "sqltypes.h"
|
87
|
+
else
|
88
|
+
header = ["windows.h", "sqltypes.h"]
|
89
|
+
end
|
90
|
+
if defined? have_type
|
91
|
+
have_type("SQLULEN", header)
|
92
|
+
else
|
93
|
+
throw
|
94
|
+
end
|
95
|
+
rescue
|
96
|
+
puts "WARNING: please check sqltypes.h for SQLULEN manually,"
|
97
|
+
puts "WARNING: if defined, modify CFLAGS in Makefile to contain"
|
98
|
+
puts "WARNING: the option -DHAVE_TYPE_SQLULEN"
|
99
|
+
end
|
100
|
+
$have_odbcinst_h = have_header("odbcinst.h")
|
101
|
+
|
102
|
+
if PLATFORM =~ /mswin32/ then
|
103
|
+
if !have_library_ex("odbc32", "SQLAllocConnect", "sql.h") ||
|
104
|
+
!have_library_ex("odbccp32", "SQLConfigDataSource", "odbcinst.h") ||
|
105
|
+
!have_library_ex("odbccp32", "SQLInstallerError", "odbcinst.h") ||
|
106
|
+
!have_library("user32", "CharUpper") then
|
107
|
+
puts "Can not locate odbc libraries"
|
108
|
+
exit 1
|
109
|
+
end
|
110
|
+
have_func("SQLConfigDataSourceW", "odbcinst.h")
|
111
|
+
have_func("SQLWriteFileDSNW", "odbcinst.h")
|
112
|
+
have_func("SQLReadFileDSNW", "odbcinst.h")
|
113
|
+
have_func("SQLInstallerError", "odbcinst.h")
|
114
|
+
have_func("SQLInstallerErrorW", "odbcinst.h")
|
115
|
+
# mingw untested !!!
|
116
|
+
elsif PLATFORM =~ /(mingw|cygwin)/ then
|
117
|
+
have_library("odbc32", "")
|
118
|
+
have_library("odbccp32", "")
|
119
|
+
have_library("user32", "")
|
120
|
+
have_func("SQLConfigDataSourceW", "odbcinst.h")
|
121
|
+
have_func("SQLWriteFileDSNW", "odbcinst.h")
|
122
|
+
have_func("SQLReadFileDSNW", "odbcinst.h")
|
123
|
+
have_func("SQLInstallerError", "odbcinst.h")
|
124
|
+
have_func("SQLInstallerErrorW", "odbcinst.h")
|
125
|
+
elsif (testdlopen && PLATFORM !~ /(macos|darwin)/ && CONFIG["CC"] =~ /gcc/ && have_func("dlopen", "dlfcn.h") && have_library("dl", "dlopen")) then
|
126
|
+
$LDFLAGS+=" -Wl,-init -Wl,ruby_odbc_init -Wl,-fini -Wl,ruby_odbc_fini"
|
127
|
+
$CPPFLAGS+=" -DHAVE_SQLCONFIGDATASOURCE"
|
128
|
+
$CPPFLAGS+=" -DHAVE_SQLINSTALLERERROR"
|
129
|
+
$CPPFLAGS+=" -DUSE_DLOPEN_FOR_ODBC_LIBS"
|
130
|
+
# but test the UNICODE installer functions w/o linking
|
131
|
+
# in case we need to provide fwd declarations
|
132
|
+
have_func_nolink("SQLConfigDataSourceW", "odbcinst.h")
|
133
|
+
have_func_nolink("SQLWriteFileDSNW", "odbcinst.h")
|
134
|
+
have_func_nolink("SQLReadFileDSNW", "odbcinst.h")
|
135
|
+
have_func_nolink("SQLInstallerErrorW", "odbcinst.h")
|
136
|
+
else
|
137
|
+
$CPPFLAGS+=" -DUNICODE -D_UNICODE"
|
138
|
+
have_library("odbc", "SQLAllocConnect") ||
|
139
|
+
have_library("iodbc", "SQLAllocConnect")
|
140
|
+
($have_odbcinst_h &&
|
141
|
+
have_library("odbcinst", "SQLConfigDataSource")) ||
|
142
|
+
($have_odbcinst_h &&
|
143
|
+
have_library("iodbcinst", "SQLConfigDataSource"))
|
144
|
+
$have_odbcinst_h &&
|
145
|
+
have_func("SQLConfigDataSourceW", "odbcinst.h")
|
146
|
+
$have_odbcinst_h &&
|
147
|
+
have_func("SQLWriteFileDSNW", "odbcinst.h")
|
148
|
+
$have_odbcinst_h &&
|
149
|
+
have_func("SQLReadFileDSNW", "odbcinst.h")
|
150
|
+
$have_odbcinst_h &&
|
151
|
+
have_func("SQLInstallerError", "odbcinst.h")
|
152
|
+
$have_odbcinst_h &&
|
153
|
+
have_func("SQLInstallerErrorW", "odbcinst.h")
|
154
|
+
end
|
155
|
+
|
156
|
+
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,17 @@
|
|
1
|
+
/*
|
2
|
+
* ODBC-Ruby binding
|
3
|
+
* Copyright (c) 2001-2011 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.6 2011/01/15 08:02:55 chw Exp chw $
|
10
|
+
*/
|
11
|
+
|
12
|
+
#undef UNICODE
|
13
|
+
#undef _UNICODE
|
14
|
+
#define UNICODE
|
15
|
+
#define _UNICODE
|
16
|
+
|
17
|
+
#include "../odbc.c"
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'date'
|
2
|
+
spec = Gem::Specification.new do |s|
|
3
|
+
s.name = "kemen-ruby-odbc"
|
4
|
+
s.version = "0.1"
|
5
|
+
s.date = Date.today.to_s
|
6
|
+
s.author = "Christian Werner"
|
7
|
+
s.email = "chw @nospam@ ch-werner.de"
|
8
|
+
s.summary = "Fork of ruby-odbc-0.99994 - ODBC binding for Ruby"
|
9
|
+
s.homepage = "http://www.ch-werner.de/rubyodbc"
|
10
|
+
s.files = Dir.glob("**/*")
|
11
|
+
s.require_paths << 'lib'
|
12
|
+
s.test_files = Dir.glob('tests/*.rb')
|
13
|
+
s.has_rdoc = false
|
14
|
+
s.extra_rdoc_files = ["README", "COPYING", "ChangeLog", "GPL", "doc/odbc.html"]
|
15
|
+
s.extensions = ["ext/extconf.rb", "ext/utf8/extconf.rb"]
|
16
|
+
end
|
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
|