teradata-cli 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ #
2
+ # $Id: exception.rb 7 2010-03-04 16:54:09Z tdaoki $
3
+ #
4
+ # Copyright (C) 2009,2010 Teradata Japan, LTD.
5
+ #
6
+ # This program is free software.
7
+ # You can distribute/modify this program under the terms of
8
+ # the GNU LGPL2, Lesser General Public License version 2.
9
+ #
10
+
11
+ module Teradata
12
+
13
+ class Error < StandardError; end
14
+
15
+ end
@@ -0,0 +1,184 @@
1
+ #
2
+ # $Id: utils.rb 7 2010-03-04 16:54:09Z tdaoki $
3
+ #
4
+ # Copyright (C) 2009,2010 Teradata Japan, LTD.
5
+ #
6
+ # This program is free software.
7
+ # You can distribute/modify this program under the terms of
8
+ # the GNU LGPL2, Lesser General Public License version 2.
9
+ #
10
+
11
+ require 'teradata/exception'
12
+
13
+ module Teradata
14
+
15
+ class BadLogonString < Error; end
16
+
17
+ class LogonString
18
+ def LogonString.intern(arg)
19
+ arg.kind_of?(LogonString) ? arg : LogonString.parse(arg.to_s)
20
+ end
21
+
22
+ def LogonString.parse(str)
23
+ m = %r<\A(?:([^/\s]+)/)?(\w+),(\w+)(?:,('.*'))?\z>.match(str) or
24
+ raise BadLogonString, "bad logon string: #{str.inspect}"
25
+ new(* m.captures)
26
+ end
27
+
28
+ def initialize(tdpid, user, password, account = nil)
29
+ @tdpid = tdpid
30
+ @user = user
31
+ @password = password
32
+ @account = account
33
+ end
34
+
35
+ attr_reader :tdpid
36
+ attr_reader :user
37
+ attr_reader :password
38
+ attr_reader :account
39
+
40
+ def to_s
41
+ "#{@tdpid ? @tdpid + '/' : ''}#{@user},#{@password}#{@account ? ',' + @account : ''}"
42
+ end
43
+
44
+ def safe_string
45
+ "#{@tdpid ? @tdpid + '/' : ''}#{@user},****#{@account ? ',' + @account : ''}"
46
+ end
47
+
48
+ def inspect
49
+ "\#<#{self.class} #{to_s}>"
50
+ end
51
+ end
52
+
53
+ class SessionCharset
54
+ def SessionCharset.intern(arg)
55
+ arg.kind_of?(SessionCharset) ? arg : SessionCharset.new(arg.to_s)
56
+ end
57
+
58
+ def initialize(name)
59
+ @name = name
60
+ end
61
+
62
+ attr_reader :name
63
+ alias to_s name
64
+
65
+ if defined?(::Encoding) # M17N
66
+ def encoding
67
+ case @name
68
+ when /UTF8/i then Encoding::UTF_8
69
+ when /KANJISJIS_0S/i then Encoding::Windows_31J
70
+ when /KANJIEUC_0U/i then Encoding::EUC_JP
71
+ when /ASCII/i then Encoding::US_ASCII
72
+ else
73
+ raise ArgumentError, "could not convert session charset to encoding name: #{sc.inspect}"
74
+ end
75
+ end
76
+ else
77
+ def encoding
78
+ nil
79
+ end
80
+ end
81
+ end
82
+
83
+ module MetadataUtils
84
+ def adjust_list_size(list, size)
85
+ if list.size > size
86
+ list[0...size]
87
+ else
88
+ list.push nil while list.size < size
89
+ list
90
+ end
91
+ end
92
+ end
93
+
94
+ SESSION_ATTRIBUTES = [
95
+ :user_name,
96
+ :account_name,
97
+ :logon_date,
98
+ :logon_time,
99
+ :current_database,
100
+ :collation,
101
+ :character_set,
102
+ :transaction_semantics,
103
+ :current_dateform,
104
+ :timezone,
105
+ :default_character_type,
106
+ :export_latin,
107
+ :export_unicode,
108
+ :export_unicode_adjust,
109
+ :export_kanjisjis,
110
+ :export_graphic,
111
+ :default_date_format,
112
+ :radix_separator,
113
+ :group_separator,
114
+ :grouping_rule,
115
+ :currency_radix_separator,
116
+ :currency_graphic_rule,
117
+ :currency_grouping_rule,
118
+ :currency_name,
119
+ :currency,
120
+ :iso_currency,
121
+ :dual_currency_name,
122
+ :dual_currency,
123
+ :dual_iso_currency,
124
+ :default_byteint_format,
125
+ :default_integer_format,
126
+ :default_smallint_format,
127
+ :default_numeric_format,
128
+ :default_real_format,
129
+ :default_time_format,
130
+ :default_timestamp_format,
131
+ :current_role,
132
+ :logon_account,
133
+ :profile,
134
+ :ldap,
135
+ :audit_trail_id,
136
+ :current_isolation_level,
137
+ :default_bigint_format,
138
+ :query_band
139
+ ]
140
+
141
+ SessionInfo = Struct.new(*SESSION_ATTRIBUTES)
142
+
143
+ class SessionInfo # reopen
144
+ extend MetadataUtils
145
+
146
+ def SessionInfo.for_record(rec)
147
+ new(* adjust_list_size(rec.to_a, SESSION_ATTRIBUTES.size))
148
+ end
149
+ end
150
+
151
+ module SQLUtils
152
+ private
153
+
154
+ def sql_int(n)
155
+ return 'NULL' unless n
156
+ n
157
+ end
158
+
159
+ alias int sql_int
160
+
161
+ def sql_string(str)
162
+ return 'NULL' unless str
163
+ "'" + str.gsub(/'/, "''") + "'"
164
+ end
165
+
166
+ alias string sql_string
167
+
168
+ def sql_date(d)
169
+ return 'NULL' unless d
170
+ "DATE '#{d.strftime('%Y-%m-%d')}'"
171
+ end
172
+
173
+ alias date sql_date
174
+
175
+ def sql_timestamp(t)
176
+ return 'NULL' unless t
177
+ "TIMESTAMP '#{t.strftime('%Y-%m-%d %H:%M:%S')}'"
178
+ end
179
+
180
+ alias timestamp sql_timestamp
181
+ end
182
+
183
+
184
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'teradata/cli/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "teradata-cli"
8
+ spec.version = Teradata::Cli::VERSION
9
+ spec.authors = ["Giuseppe Privitera"]
10
+ spec.email = ["priviterag@gmail.com"]
11
+ spec.description = %q{ruby extension for Teradata Cliv2}
12
+ spec.summary = %q{ruby extension for Teradata Cliv2}
13
+ spec.homepage = "https://github.com/priviterag/teradata-cli"
14
+ spec.license = "LGPL2"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.extensions = ["ext/teradata/cli/extconf.rb"]
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.3"
23
+ spec.add_development_dependency "rake"
24
+ end
data/test/all ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ basedir = File.dirname($0)
4
+ $LOAD_PATH.unshift basedir
5
+ Dir.glob("#{basedir}/test_*.rb") do |test_case|
6
+ load test_case
7
+ end
@@ -0,0 +1,99 @@
1
+ module RubyCLITestUtils
2
+
3
+ def logon_string
4
+ s = ENV['TEST_LOGON_STRING'] or raise ArgumentError, "environ TEST_LOGON_STRING not given"
5
+ Teradata::LogonString.parse(s)
6
+ end
7
+
8
+ def playpen_string
9
+ s = ENV['TEST_PLAYPEN_STRING']
10
+ s == '' ? nil : "#{s}"
11
+ end
12
+
13
+ def env_string
14
+ s = ENV['TEST_ENV_STRING']
15
+ s == '' ? nil : "#{s}"
16
+ end
17
+
18
+ def get_table_name(name)
19
+ "#{playpen_string ? playpen_string + '.' : ''}#{env_string ? env_string + '_' : ''}#{name}"
20
+ end
21
+
22
+ def connect(*args)
23
+ options = {}
24
+ unless args.empty?
25
+ charset, internal = args
26
+ options[:session_charset] = charset if charset
27
+ options[:internal_encoding] = internal if internal
28
+ end
29
+ Teradata::Connection.open(logon_string, options) {|conn|
30
+ begin
31
+ @conn = conn
32
+ yield conn
33
+ ensure
34
+ @conn = nil
35
+ end
36
+ }
37
+ end
38
+
39
+ def using_test_table(name = "#{get_table_name('t')}", conn = @conn, &block)
40
+ unless conn
41
+ connect {|_conn| using_test_table(name, _conn, &block) }
42
+ return
43
+ end
44
+ using_table(name, 'x INTEGER, y INTEGER', conn) do |n|
45
+ %w(1,2 3,4 5,6).each do |values|
46
+ insert n, values, conn
47
+ end
48
+ yield n
49
+ end
50
+ end
51
+
52
+ def using_table(name, fields, conn = @conn, &block)
53
+ unless conn
54
+ connect {|_conn| using_table(name, fields, _conn, &block) }
55
+ return
56
+ end
57
+ drop_table_force name, conn
58
+ conn.execute_update "CREATE TABLE #{name} (#{fields});"
59
+ begin
60
+ yield name
61
+ ensure
62
+ drop_table_force name, conn
63
+ end
64
+ end
65
+
66
+ def create_table(name, fields, conn = @conn)
67
+ conn.execute_update "CREATE TABLE #{name} (#{fields});"
68
+ end
69
+
70
+ ERR_OBJECT_NOT_EXIST = 3807
71
+ ERR_INDEX_NOT_EXIST = 3526
72
+
73
+ def drop_table_force(name, conn = @conn)
74
+ drop_table name, conn
75
+ rescue Teradata::SQLError => err
76
+ raise err unless err.code == ERR_OBJECT_NOT_EXIST
77
+ end
78
+
79
+ def drop_table(name, conn = @conn)
80
+ drop 'TABLE', name, conn
81
+ end
82
+
83
+ def drop(type, name, conn = @conn)
84
+ conn.execute_update "DROP #{type} #{name};"
85
+ end
86
+
87
+ def delete(table, conn = @conn)
88
+ conn.execute_update "DELETE FROM #{table};"
89
+ end
90
+
91
+ def insert(table, values, conn = @conn)
92
+ conn.execute_update "INSERT INTO #{table} (#{values});"
93
+ end
94
+
95
+ def select(table, conn = @conn)
96
+ conn.entries "SELECT * FROM #{table} ORDER BY 1;"
97
+ end
98
+
99
+ end
@@ -0,0 +1,298 @@
1
+ require 'teradata'
2
+ require 'test/unit'
3
+ libdir = File.dirname(__FILE__)
4
+ $LOAD_PATH.unshift libdir unless $LOAD_PATH.include?(libdir)
5
+ require 'rubyclitestutils'
6
+
7
+ class Test_Connection < Test::Unit::TestCase
8
+
9
+ include RubyCLITestUtils
10
+
11
+ def test_s_open
12
+ begin
13
+ conn = Teradata::Connection.open(logon_string)
14
+ assert_instance_of Teradata::Connection, conn
15
+ assert_equal false, conn.closed?
16
+ ensure
17
+ begin
18
+ conn.close
19
+ rescue
20
+ end
21
+ assert_equal true, conn.closed?
22
+ end
23
+
24
+ Teradata::Connection.open(logon_string) {|c| assert_instance_of(Teradata::Connection, c); assert_equal(false, c.closed?)}
25
+ assert_equal true, conn.closed?
26
+ end
27
+
28
+ def test_execute_update
29
+ connect {
30
+ drop_table_force "#{get_table_name('t')}"
31
+ x = @conn.execute_update("CREATE TABLE #{get_table_name('t')} (x INTEGER);")
32
+ assert_instance_of Teradata::ResultSet, x
33
+ assert_equal true, x.closed?
34
+ }
35
+ end
36
+
37
+ def test_txn
38
+ using_table("#{get_table_name('t')}", "x INTEGER, y INTEGER") {|name|
39
+ @conn.execute_update "BEGIN TRANSACTION;"
40
+ @conn.execute_update "INSERT INTO #{name} (x,y) VALUES (1,2);"
41
+ @conn.execute_update "INSERT INTO #{name} (x,y) VALUES (3,4);"
42
+ @conn.execute_update "END TRANSACTION;"
43
+ recs = @conn.entries("SELECT * FROM #{name} ORDER BY 1;")
44
+ assert_equal 2, recs.size
45
+
46
+ begin
47
+ @conn.execute_update "BEGIN TRANSACTION;"
48
+ @conn.execute_update "DELETE FROM #{name};"
49
+ @conn.execute_update "ABORT;"
50
+ rescue Teradata::UserAbort
51
+ end
52
+ recs = @conn.entries("SELECT * FROM #{name} ORDER BY 1;")
53
+ assert_equal 2, recs.size
54
+ assert_equal 1, recs[0][:x]
55
+ }
56
+ end
57
+
58
+ def test_execute_query
59
+ using_test_table {|name|
60
+ _test_single_rs name, @conn
61
+ _test_single_rs2 name, @conn
62
+ _test_multiple_rs name, @conn
63
+ }
64
+ end
65
+
66
+ def _test_single_rs(name, conn)
67
+ buf = []
68
+ conn.execute_query("SELECT * FROM #{name} ORDER BY 1") {|rs|
69
+ assert_instance_of Teradata::ResultSet, rs
70
+ rs.each do |rec|
71
+ buf.push rec
72
+ end
73
+ }
74
+ assert_equal 3, buf.size
75
+ assert_instance_of Teradata::Record, buf[0]
76
+ assert_equal 1, buf[0][:x]
77
+ assert_equal 2, buf[0][:y]
78
+ assert_instance_of Teradata::Record, buf[1]
79
+ assert_equal 3, buf[1][:x]
80
+ assert_equal 4, buf[1][:y]
81
+ assert_instance_of Teradata::Record, buf[2]
82
+ assert_equal 5, buf[2][:x]
83
+ assert_equal 6, buf[2][:y]
84
+ end
85
+
86
+ def _test_single_rs2(name, conn)
87
+ buf = []
88
+ num_rs = 0
89
+ conn.execute_query("SELECT * FROM #{name} ORDER BY 1") {|sets|
90
+ assert_instance_of Teradata::ResultSet, sets
91
+ sets.each_result_set do |rs|
92
+ num_rs += 1
93
+ assert_instance_of Teradata::ResultSet, rs
94
+ rs.each do |rec|
95
+ buf.push rec
96
+ end
97
+ end
98
+ }
99
+ assert_equal 1, num_rs
100
+ assert_equal 3, buf.size
101
+ buf.each do |r|
102
+ assert_instance_of Teradata::Record, r
103
+ end
104
+ assert_equal [1,2], [buf[0][:x], buf[0][:y]]
105
+ assert_equal [3,4], [buf[1][:x], buf[1][:y]]
106
+ assert_equal [5,6], [buf[2][:x], buf[2][:y]]
107
+ end
108
+
109
+ def _test_multiple_rs(name, conn)
110
+ buf = []
111
+ num_rs = 0
112
+ conn.execute_query(
113
+ "SELECT * FROM #{name} ORDER BY 1;
114
+ SELECT * FROM #{name} ORDER BY 1 DESC;") {|sets|
115
+ assert_instance_of Teradata::ResultSet, sets
116
+ sets.each_result_set do |rs|
117
+ num_rs += 1
118
+ assert_instance_of Teradata::ResultSet, rs
119
+ rs.each do |rec|
120
+ buf.push rec
121
+ end
122
+ end
123
+ }
124
+ assert_equal 2, num_rs
125
+ assert_equal 6, buf.size
126
+ buf.each do |r|
127
+ assert_instance_of Teradata::Record, r
128
+ end
129
+ assert_equal [1,2], [buf[0][:x], buf[0][:y]]
130
+ assert_equal [3,4], [buf[1][:x], buf[1][:y]]
131
+ assert_equal [5,6], [buf[2][:x], buf[2][:y]]
132
+ assert_equal [5,6], [buf[3][:x], buf[3][:y]]
133
+ assert_equal [3,4], [buf[4][:x], buf[4][:y]]
134
+ assert_equal [1,2], [buf[5][:x], buf[5][:y]]
135
+ end
136
+
137
+ def test_execute_query_without_block
138
+ using_test_table {|name|
139
+ rs = @conn.execute_query("SELECT * FROM #{get_table_name('t')} ORDER BY 1;")
140
+
141
+ recs = []
142
+ rs.each do |rec|
143
+ recs.push rec
144
+ end
145
+ assert_equal 3, recs.size
146
+ assert_equal 1, recs[0][:x]
147
+ assert_equal 6, recs[2][:y]
148
+
149
+ recs = rs.entries
150
+ assert_equal 3, recs.size
151
+ assert_equal 1, recs[0][:x]
152
+ assert_equal 6, recs[2][:y]
153
+ }
154
+ end
155
+
156
+ def test_entries
157
+ using_test_table {|name|
158
+ recs = @conn.entries("SELECT * FROM #{name} ORDER BY 1;")
159
+ assert_equal 3, recs.size
160
+ assert_equal 1, recs[0][:x]
161
+ assert_equal 6, recs[2][:y]
162
+ }
163
+ end
164
+
165
+ # Teradata hates "\n", check it.
166
+ def test_line_terms
167
+ using_test_table {|name|
168
+ recs = @conn.entries("SELECT *\nFROM #{name} \n ORDER BY 1;")
169
+ assert_equal 3, recs.size
170
+
171
+ assert_nothing_thrown {
172
+ @conn.execute_update "INSERT INTO #{name}\n(x,y)\nVALUES \n (7,8);"
173
+ }
174
+ recs = @conn.entries("SELECT *\nFROM #{name} \n ORDER BY 1;")
175
+ assert_equal 4, recs.size
176
+ }
177
+ end
178
+
179
+ # connection/request intersection test
180
+ def test_duplicated_connections
181
+ assert_nothing_thrown {
182
+ connect {|c1|
183
+ connect {|c2|
184
+ drop_table_force "#{get_table_name('t')}", c1
185
+ c2.execute_update "CREATE TABLE #{get_table_name('t')} (x INTEGER);"
186
+ drop_table_force "#{get_table_name('t')}", c1
187
+ c2.execute_update "CREATE TABLE #{get_table_name('t')} (x INTEGER);"
188
+ drop_table_force "#{get_table_name('t')}", c1
189
+ }
190
+ }
191
+ }
192
+ end
193
+
194
+ def test_tables
195
+ db = playpen_string
196
+ connect {|conn|
197
+ # assert_equal [], @conn.tables(db)
198
+ using_test_table(get_table_name('t1')) {
199
+ using_test_table(get_table_name('t2')) {
200
+ list = @conn.tables(db)
201
+ assert(list.include? Teradata::Table.new(db, 't1'))
202
+ assert(list.include? Teradata::Table.new(db, 't2'))
203
+ }}
204
+ }
205
+ end
206
+
207
+ def test_views
208
+ db = playpen_string
209
+ using_test_table do
210
+ using_view("#{get_table_name('v')}", 'select 1 as i') do
211
+ assert(@conn.views(db).include? Teradata::View.new(db, 'v'))
212
+ end
213
+ end
214
+ end
215
+
216
+ def test_objects
217
+ db = playpen_string
218
+ connect do
219
+ # assert_equal [], @conn.objects(db)
220
+ using_test_table(get_table_name('t')) do
221
+ using_view("#{get_table_name('v')}", 'select 1 as i') do
222
+ objects = @conn.objects(db)
223
+ assert(objects.include? Teradata::Table.new(db, 't'))
224
+ assert(objects.include? Teradata::View.new(db, 'v'))
225
+ end
226
+ end
227
+ end
228
+ end
229
+
230
+ def using_view(name, query, conn = @conn)
231
+ drop_view_force name, conn
232
+ begin
233
+ conn.execute_update "CREATE VIEW #{name} AS #{query}"
234
+ yield name
235
+ ensure
236
+ drop_view_force name, conn
237
+ end
238
+ end
239
+
240
+ def drop_view_force(name, conn = @conn)
241
+ conn.execute_update "DROP VIEW #{name}"
242
+ rescue Teradata::SQLError
243
+ end
244
+
245
+ def test_info
246
+ connect {
247
+ info = @conn.info
248
+ assert_instance_of Teradata::SessionInfo, info
249
+ assert_equal logon_string.user.downcase, info.user_name.downcase
250
+ }
251
+ end
252
+
253
+ def test_column
254
+ db = playpen_string
255
+ using_table("#{get_table_name('t')}", "x INTEGER, y INTEGER") do
256
+ col = @conn.column(Teradata::Table.new(db, 't'), 'x')
257
+ assert_instance_of Teradata::Column, col
258
+ assert_equal 'x', col.column_name.strip.downcase
259
+ end
260
+ end
261
+
262
+ def test_transaction
263
+ connect {|conn|
264
+ using_test_table("#{get_table_name('t')}") {|table|
265
+ n_records = count(table, conn)
266
+
267
+ # transaction fails #1
268
+ assert_raise(RuntimeError) {
269
+ conn.transaction {
270
+ conn.query "DELETE FROM #{table}"
271
+ raise RuntimeError, "USER ABORT"
272
+ }
273
+ }
274
+ assert_equal n_records, count(table, conn)
275
+
276
+ # transaction fails #2
277
+ assert_raise(Teradata::UserAbort) {
278
+ conn.transaction {
279
+ conn.query "DELETE FROM #{table}"
280
+ conn.abort
281
+ }
282
+ }
283
+ assert_equal n_records, count(table, conn)
284
+
285
+ # transaction success
286
+ conn.transaction {
287
+ conn.query "DELETE FROM #{table}"
288
+ }
289
+ assert_equal 0, count(table, conn)
290
+ }
291
+ }
292
+ end
293
+
294
+ def count(table, conn)
295
+ conn.entries("SELECT count(*) FROM #{table}").first[0]
296
+ end
297
+
298
+ end