teradata-cli 0.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/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in teradata-cli.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # Teradata::Cli
2
+
3
+ Teradata::Cli is an access module which allows Ruby scripts
4
+ to access Teradata RDBMS by CLIv2 interface.
5
+
6
+ It's based on the [Ruby/CLIv2](http://sourceforge.net/projects/rubycli/) library.
7
+
8
+
9
+ ## Requirements
10
+
11
+ CLIv2 (32bit / 64bit)
12
+ C compiler
13
+
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ gem 'teradata-cli'
20
+
21
+ And then execute:
22
+
23
+ $ bundle
24
+
25
+ Or install it yourself as:
26
+
27
+ $ gem install teradata-cli
28
+
29
+
30
+ ## Usage
31
+
32
+ Look the examples folder
33
+
34
+
35
+ ## Tests
36
+
37
+ $ export TEST_LOGON_STRING=dbc/user,password
38
+ $ ruby -Ilib:test test/all
39
+
40
+
41
+ ## Contributing
42
+
43
+ 1. Fork it
44
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
45
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
46
+ 4. Push to the branch (`git push origin my-new-feature`)
47
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/examples/query.rb ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Dispatches SQL query and shows result records.
4
+ #
5
+ # Usage:
6
+ # $ export LOGON_STRING=dbc/user,pass
7
+ # $ ruby example/query.rb 'SELECT * FROM x'
8
+ #
9
+
10
+ require 'teradata'
11
+ require 'logger'
12
+ require 'pp'
13
+
14
+ logon_string = ENV['LOGON_STRING']
15
+ unless logon_string
16
+ $stderr.puts "set environment variable LOGON_STRING"
17
+ exit 1
18
+ end
19
+
20
+ sql = ARGV[0]
21
+ unless sql
22
+ $stderr.puts "Usage: ruby #{File.basename($0)} QUERY"
23
+ exit 1
24
+ end
25
+
26
+ log = Logger.new($stderr)
27
+ log.sev_threshold = $DEBUG ? Logger::DEBUG : Logger::INFO
28
+
29
+ Teradata.connect(logon_string, :logger => log) {|conn|
30
+ conn.query(sql) {|result_sets|
31
+ result_sets.each_result_set do |rs|
32
+ pp rs
33
+ rs.each_record do |rec|
34
+ pp rec
35
+ end
36
+ end
37
+ }
38
+ }
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Show Query Bands of current sessions.
4
+ #
5
+ # Usage:
6
+ # $ export LOGON_STRING=dbc/user,pass
7
+ # $ ruby example/show-queryband.rb
8
+ #
9
+
10
+ require 'teradata'
11
+
12
+ logon_string = ENV['LOGON_STRING']
13
+ unless logon_string
14
+ $stderr.puts "set environment variable LOGON_STRING"
15
+ exit 1
16
+ end
17
+
18
+ Teradata.connect(logon_string) {|conn|
19
+ conn.query("SELECT * FROM dbc.sessionInfo") {|rs|
20
+ rs.each do |rec|
21
+ user = rec[:UserName].strip
22
+ band = rec[:QueryBand]
23
+ puts "#{user}\t#{band}"
24
+ end
25
+ }
26
+ }
@@ -0,0 +1,86 @@
1
+ require 'win32ole'
2
+ require 'fileutils'
3
+
4
+ class Excel
5
+
6
+ def Excel.open_worksheet(path, sheet_name, mode, &block)
7
+ open {|app| app.open_worksheet(path, sheet_name, mode, &block) }
8
+ end
9
+
10
+ def Excel.open_book(path, mode, &block)
11
+ open {|app| app.open_book(path, mode, &block) }
12
+ end
13
+
14
+ FileSystem = WIN32OLE.new('Scripting.FileSystemObject')
15
+
16
+ def Excel.open(visible = $DEBUG, &block)
17
+ new(visible, &block)
18
+ end
19
+
20
+ @@const_loaded = false
21
+
22
+ def initialize(visible = $DEBUG)
23
+ @app = WIN32OLE.new('Excel.Application')
24
+ unless @@const_loaded
25
+ WIN32OLE.const_load @app, Excel
26
+ @@const_loaded = true
27
+ end
28
+ @app.visible = true if visible
29
+ yield self if block_given?
30
+ ensure
31
+ quit if block_given? and @app
32
+ end
33
+
34
+ def quit
35
+ @app.quit
36
+ end
37
+
38
+ def open_book(path, mode)
39
+ begin
40
+ book = @app.workbooks.open(win_extend_path(path))
41
+ yield book
42
+ book.save if mode == 'w'
43
+ ensure
44
+ book.saved = true # avoid confirmation message
45
+ @app.workbooks.close
46
+ end
47
+ end
48
+
49
+ def open_worksheet(path, sheet_name, mode)
50
+ open_book(path, mode) {|book|
51
+ sheet = book.worksheets.item(1)
52
+ sheet.extend WorkSheetMethods
53
+ yield sheet
54
+ }
55
+ end
56
+
57
+ def win_extend_path(path)
58
+ FileSystem.getAbsolutePathName(path)
59
+ end
60
+ private :win_extend_path
61
+
62
+ module WorkSheetMethods
63
+ def [](y, x)
64
+ cell = cells().item(y, x)
65
+ if cell.mergeCells
66
+ cell.mergeArea.item(1, 1).value
67
+ else
68
+ cell.value
69
+ end
70
+ end
71
+
72
+ def []=(y, x, value)
73
+ cell = cells().item(y, x)
74
+ if cell.mergeCells
75
+ cell.mergeArea.item(1, 1).value = value
76
+ else
77
+ cell.value = value
78
+ end
79
+ end
80
+
81
+ def last_cell
82
+ cells().specialCells(Excel::XlLastCell)
83
+ end
84
+ end
85
+
86
+ end
@@ -0,0 +1,94 @@
1
+ require 'excel'
2
+ require 'fileutils'
3
+ require 'pp'
4
+ require 'teradata'
5
+
6
+ def main
7
+ logon_string, template, output = ARGV
8
+ usage_exit unless logon_string
9
+ usage_exit unless template
10
+ output ||= 'out.xls'
11
+
12
+ FileUtils.cp template, output
13
+ Excel.open(true) {|app|
14
+ app.open_worksheet(output, 'Sheet1', 'w') {|sheet|
15
+ fill_sheet sheet, logon_string
16
+ }
17
+ }
18
+ end
19
+
20
+ def fill_sheet(sheet, logon_string)
21
+ # Get SQL Cell
22
+ sql_cell = sheet.cells.find('%SQL')
23
+ p ['sql_cell', sql_cell.address]
24
+ sql = sql_cell.value.slice(/%SQL\s+(.*)/m, 1).strip
25
+ p sql
26
+
27
+ # Get Value Cells
28
+ value_cell = sheet.cells.find('%=', sql_cell)
29
+ p ['value', value_cell.address]
30
+ exprs = [expr_proc(value_cell)]
31
+ c = value_cell
32
+ while true
33
+ next_c = sheet.range(address(c.row.to_i, c.column.to_i + 1))
34
+ break unless /^%=/ =~ next_c.value
35
+ c = next_c
36
+ p ['value', c.address]
37
+ exprs.push expr_proc(c)
38
+ end
39
+ pp exprs
40
+
41
+ tmpl_range = sheet.range(value_cell.address + ':' + c.address)
42
+ xl = value_cell.column
43
+ xr = c.column
44
+ y = value_cell.row + 1
45
+
46
+ # Execute SQL and fill cells by data
47
+ Teradata.connect(logon_string) {|conn|
48
+ conn.query(sql) {|rs|
49
+ rs.each do |rec|
50
+ pp rec
51
+ values = exprs.map {|expr| expr.call(rec) }
52
+ pp values
53
+ tmpl_range.copy
54
+ sheet.range(address(y, xl) + ':' + address(y, xr)).insert Excel::XlShiftDown
55
+ sheet.range(address(y, xl) + ':' + address(y, xr)).value = values
56
+ y += 1
57
+ end
58
+ }
59
+ }
60
+
61
+ # remove metadata cells
62
+ tmpl_range.delete Excel::XlShiftUp
63
+ sheet.rows(sql_cell.row).delete
64
+ end
65
+
66
+ def usage_exit
67
+ $stderr.puts "Usage: #{$0} LOGON_STRING TEMPLATE [OUTPUT]"
68
+ exit 1
69
+ end
70
+
71
+ def expr_proc(cell)
72
+ expr = cell.value.slice(/%=(.*)/m, 1).strip
73
+ lambda {|_| eval(expr).to_s }
74
+ end
75
+
76
+ def address(row, col)
77
+ "$#{column_string(col)}$#{row}"
78
+ end
79
+
80
+ ALPHA = ('a'..'z').to_a
81
+
82
+ def column_string(col)
83
+ result = []
84
+ n = col - 1
85
+ while n >= 26
86
+ n, mod = n.divmod(26)
87
+ result.unshift mod
88
+ n -= 1
89
+ end
90
+ result.unshift n
91
+ result.map {|i| ALPHA[i] }.join('')
92
+ end
93
+
94
+ main
Binary file
@@ -0,0 +1,6 @@
1
+ require 'teradata'
2
+ Teradata.connect(ENV['LOGON_STRING']) {|conn|
3
+ conn.tables("tudemo").
4
+ select {|table| /_bak$/ =~ table.name }.
5
+ each {|table| conn.drop table }
6
+ }
@@ -0,0 +1,7 @@
1
+ require 'teradata'
2
+ Teradata.connect(ENV['LOGON_STRING']) {|conn|
3
+ conn.tables("tudemo").
4
+ sort_by {|table| -table.size }.
5
+ first(5).
6
+ each {|table| puts "#{table.name}\t#{table.size}" }
7
+ }
@@ -0,0 +1,197 @@
1
+ # $Id: bitdao.rb 184 2009-08-12 08:46:22Z aamine $
2
+
3
+ class BitDAO
4
+ module Error; end
5
+
6
+ class BaseError < ::StandardError
7
+ include Error
8
+ end
9
+
10
+ class IntegrityError < BaseError; end
11
+ class ObjectNotExist < BaseError; end
12
+
13
+ def error
14
+ @connection.error_class
15
+ end
16
+
17
+ def sql_error
18
+ @connection.sql_error_class
19
+ end
20
+
21
+ def initialize(log, connection)
22
+ @log = log
23
+ @connection = connection
24
+ end
25
+
26
+ def load_object(_class, sql)
27
+ list = load_objects(_class, sql)
28
+ if list.empty?
29
+ raise ObjectNotExist, "no record exist: #{_class}"
30
+ end
31
+ if list.size > 1
32
+ raise IntegrityError, "too many #{_class} loaded: #{list.size} for 1"
33
+ end
34
+ list.first
35
+ end
36
+
37
+ def load_objects(_class, sql)
38
+ @log.info(self.class) { "[SEL] #{sql}" }
39
+ result = []
40
+ @connection.execute_query(sql) {|rs|
41
+ rs.each_record do |rec|
42
+ result.push _class.for_record(self, rec)
43
+ end
44
+ }
45
+ @log.info(self.class) { "#{result.size} records" }
46
+ result
47
+ end
48
+
49
+ def exec_sql(sql, level = Logger::INFO)
50
+ @log.add(level, nil, self.class) { "[UPD] #{sql}" } if level
51
+ @connection.execute_update sql
52
+ end
53
+
54
+ def transaction
55
+ aborting = false
56
+ exec_sql "BEGIN TRANSACTION;"
57
+ begin
58
+ yield
59
+ rescue Teradata::CLI::UserAbort => err
60
+ aborting = true
61
+ raise err
62
+ ensure
63
+ if $@
64
+ begin
65
+ abort unless aborting
66
+ rescue Teradata::CLI::UserAbort # do not override original exception
67
+ end
68
+ else
69
+ exec_sql "END TRANSACTION;"
70
+ end
71
+ end
72
+ end
73
+
74
+ def abort
75
+ exec_sql "ABORT;"
76
+ end
77
+
78
+ private
79
+
80
+ def int(n)
81
+ return 'NULL' unless n
82
+ n
83
+ end
84
+
85
+ def string(str)
86
+ return 'NULL' unless str
87
+ "'" + str.gsub(/'/, "''") + "'"
88
+ end
89
+
90
+ def date(d)
91
+ return 'NULL' unless d
92
+ "DATE '#{d.strftime('%Y-%m-%d')}'"
93
+ end
94
+
95
+ def timestamp(t)
96
+ return 'NULL' unless t
97
+ "TIMESTAMP '#{t.strftime('%Y-%m-%d %H:%M:%S')}'"
98
+ end
99
+
100
+
101
+ def BitDAO.define(&block)
102
+ PersistentObject.define(&block)
103
+ end
104
+
105
+ class PersistentObject
106
+
107
+ def PersistentObject.define(&block)
108
+ c = Class.new(PersistentObject)
109
+ c.module_eval(&block)
110
+ c.define_initialize c.slots
111
+ c
112
+ end
113
+
114
+ def PersistentObject.slot(name, _class, column = nil)
115
+ attr_reader name
116
+ (@slots ||= []).push Slot.new(name, _class, column)
117
+ end
118
+
119
+ class << self
120
+ attr_reader :slots
121
+ end
122
+
123
+ class Slot
124
+ def initialize(name, _class, column)
125
+ @name = name
126
+ @class = _class
127
+ @column = column || name
128
+ end
129
+
130
+ attr_reader :name
131
+ attr_reader :column
132
+
133
+ def parse(s)
134
+ @class.parse(s)
135
+ end
136
+ end
137
+
138
+ def PersistentObject.sql_integer
139
+ SQLInteger.new
140
+ end
141
+
142
+ class SQLInteger
143
+ def parse(i)
144
+ i
145
+ end
146
+ end
147
+
148
+ def PersistentObject.sql_string
149
+ SQLString.new
150
+ end
151
+
152
+ class SQLString
153
+ # CHAR/VARCHAR field returns extra spaces, remove it always.
154
+ def parse(str)
155
+ str ? str.rstrip : nil
156
+ end
157
+ end
158
+
159
+ def PersistentObject.sql_date
160
+ SQLDate.new
161
+ end
162
+
163
+ def PersistentObject.sql_timestamp
164
+ SQLDate.new
165
+ end
166
+
167
+ class SQLDate
168
+ def parse(str)
169
+ # "2009-01-23"
170
+ Time.parse(str)
171
+ end
172
+ end
173
+
174
+ def PersistentObject.for_record(dao, rec)
175
+ unless rec.size >= @slots.size
176
+ raise DatabaseError, "wrong column number of record (#{rec.size} for #{@slots.size})"
177
+ end
178
+ obj = new(* @slots.map {|slot| slot.parse(rec[slot.column]) })
179
+ obj._dao = dao
180
+ obj
181
+ end
182
+
183
+ def PersistentObject.define_initialize(slots)
184
+ param_list = slots.map {|s| s.name }.join(', ')
185
+ ivar_list = slots.map {|s| "@#{s.name}" }.join(', ')
186
+ module_eval(<<-End, __FILE__, __LINE__ + 1)
187
+ def initialize(#{param_list})
188
+ #{ivar_list} = #{param_list}
189
+ end
190
+ End
191
+ end
192
+
193
+ attr_writer :_dao
194
+
195
+ end
196
+
197
+ end