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.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/COPYING +515 -0
- data/Gemfile +4 -0
- data/README.md +47 -0
- data/Rakefile +1 -0
- data/examples/query.rb +38 -0
- data/examples/show-queryband.rb +26 -0
- data/examples/tu/excel/excel.rb +86 -0
- data/examples/tu/excel/fill.rb +94 -0
- data/examples/tu/excel/template.xls +0 -0
- data/examples/tu/tusample1.rb +6 -0
- data/examples/tu/tusample2.rb +7 -0
- data/examples/tu/web/bitdao.rb +197 -0
- data/examples/tu/web/bitdao/teradata.rb +23 -0
- data/examples/tu/web/bitweb.rb +575 -0
- data/examples/tu/web/messages +0 -0
- data/examples/tu/web/server.rb +94 -0
- data/examples/tu/web/tdwalker.rb +42 -0
- data/examples/tu/web/template/database/show +56 -0
- data/examples/tu/web/template/footer +2 -0
- data/examples/tu/web/template/header +7 -0
- data/examples/update.rb +31 -0
- data/ext/teradata/cli/cli.c +363 -0
- data/ext/teradata/cli/extconf.rb +20 -0
- data/lib/teradata.rb +14 -0
- data/lib/teradata/cli.rb +4 -0
- data/lib/teradata/cli/version.rb +5 -0
- data/lib/teradata/connection.rb +1125 -0
- data/lib/teradata/dbobject.rb +453 -0
- data/lib/teradata/exception.rb +15 -0
- data/lib/teradata/utils.rb +184 -0
- data/teradata-cli.gemspec +24 -0
- data/test/all +7 -0
- data/test/rubyclitestutils.rb +99 -0
- data/test/test_connection.rb +298 -0
- data/test/test_dbobject.rb +153 -0
- data/test/test_record.rb +210 -0
- metadata +115 -0
@@ -0,0 +1,453 @@
|
|
1
|
+
#
|
2
|
+
# $Id: dbobject.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/utils'
|
12
|
+
require 'teradata/connection'
|
13
|
+
require 'teradata/exception'
|
14
|
+
|
15
|
+
module Teradata
|
16
|
+
|
17
|
+
class ObjectError < Error; end
|
18
|
+
|
19
|
+
class Connection # reopen
|
20
|
+
|
21
|
+
include SQLUtils
|
22
|
+
|
23
|
+
ROOT_DATABASE_NAME = 'DBC'
|
24
|
+
|
25
|
+
def root_database
|
26
|
+
User.new(ROOT_DATABASE_NAME, self)
|
27
|
+
end
|
28
|
+
|
29
|
+
alias dbc root_database
|
30
|
+
|
31
|
+
def database(name)
|
32
|
+
kind = database_kind(name) or
|
33
|
+
raise ObjectError, "no such database: #{name.inspect}"
|
34
|
+
kind.new(name, self)
|
35
|
+
end
|
36
|
+
|
37
|
+
def database_kind(name)
|
38
|
+
recs = entries(<<-EndSQL)
|
39
|
+
SELECT dbKind
|
40
|
+
FROM dbc.databases
|
41
|
+
WHERE databaseName = #{sql_string name}
|
42
|
+
EndSQL
|
43
|
+
return nil if recs.empty?
|
44
|
+
if recs.size > 1
|
45
|
+
raise "multiple database entries exist in dbc.databases???: #{name.inspect}"
|
46
|
+
end
|
47
|
+
class_from_kind_char(recs.first[0].strip.upcase)
|
48
|
+
end
|
49
|
+
|
50
|
+
def database_exist?(name)
|
51
|
+
database_kind(name) ? true : false
|
52
|
+
end
|
53
|
+
|
54
|
+
alias database? database_exist?
|
55
|
+
|
56
|
+
def user_exist?(name)
|
57
|
+
database_kind(name) == User
|
58
|
+
end
|
59
|
+
|
60
|
+
alias user? user_exist?
|
61
|
+
|
62
|
+
def parent_databases(name)
|
63
|
+
parents = [Database.new(name, self)]
|
64
|
+
while true
|
65
|
+
db = database_owner(parents.last.name)
|
66
|
+
break unless db
|
67
|
+
parents.push db
|
68
|
+
end
|
69
|
+
parents.shift # remove myself
|
70
|
+
parents
|
71
|
+
end
|
72
|
+
|
73
|
+
# Database owner.
|
74
|
+
# Returns nil for root database (DBC).
|
75
|
+
def database_owner(name)
|
76
|
+
return nil if name.downcase == 'dbc'
|
77
|
+
owners = entries(<<-EndSQL).map {|rec| [rec[0].strip.upcase, rec[1].strip] }
|
78
|
+
SELECT owner.dbKind, self.ownerName
|
79
|
+
FROM dbc.databases self INNER JOIN dbc.databases owner
|
80
|
+
ON self.ownerName = owner.databaseName
|
81
|
+
WHERE self.databaseName = #{sql_string name}
|
82
|
+
EndSQL
|
83
|
+
if owners.empty?
|
84
|
+
raise ObjectError, "database not exist: #{name.inspect}"
|
85
|
+
end
|
86
|
+
if owners.size > 1
|
87
|
+
raise "multiple database entries exist in dbc.databases???: #{name.inspect}"
|
88
|
+
end
|
89
|
+
kind_char, owner = owners.first
|
90
|
+
return nil if owner.downcase == name.downcase
|
91
|
+
new_database(kind_char, owner)
|
92
|
+
end
|
93
|
+
|
94
|
+
def child_databases(name)
|
95
|
+
entries(<<-EndSQL).map {|rec| new_database(rec[0].strip.upcase, rec[1].strip) }
|
96
|
+
SELECT dbKind, databaseName
|
97
|
+
FROM dbc.databases
|
98
|
+
WHERE ownerName = #{sql_string name}
|
99
|
+
EndSQL
|
100
|
+
end
|
101
|
+
|
102
|
+
def class_from_kind_char(c)
|
103
|
+
c == 'U' ? User : Database
|
104
|
+
end
|
105
|
+
private :class_from_kind_char
|
106
|
+
|
107
|
+
def new_database(kind_char, name)
|
108
|
+
class_from_kind_char(kind_char).new(name, self)
|
109
|
+
end
|
110
|
+
private :new_database
|
111
|
+
|
112
|
+
Perms = Struct.new(:current, :max, :peak)
|
113
|
+
|
114
|
+
def database_own_perms(name)
|
115
|
+
perms = entries(<<-EndSQL).first
|
116
|
+
SELECT
|
117
|
+
sum(currentPerm)
|
118
|
+
, sum(maxPerm)
|
119
|
+
, sum(peakPerm)
|
120
|
+
FROM dbc.diskSpace
|
121
|
+
WHERE databaseName = #{sql_string name}
|
122
|
+
EndSQL
|
123
|
+
unless perms
|
124
|
+
raise ObjectError, "database does not exist in dbc.diskSpace: #{name.inspect}"
|
125
|
+
end
|
126
|
+
Perms.new(* perms.to_a.map {|n| n.to_i })
|
127
|
+
end
|
128
|
+
|
129
|
+
def database_total_perms(name)
|
130
|
+
recs = entries(<<-EndSQL)
|
131
|
+
SELECT
|
132
|
+
sum(ds.currentPerm)
|
133
|
+
, sum(ds.maxPerm)
|
134
|
+
, sum(ds.peakPerm)
|
135
|
+
FROM
|
136
|
+
(
|
137
|
+
(SELECT d.databaseName, d.databaseName FROM dbc.databases d)
|
138
|
+
UNION
|
139
|
+
(SELECT parent, child FROM dbc.children)
|
140
|
+
) as c (parent, child)
|
141
|
+
INNER JOIN dbc.diskSpace ds
|
142
|
+
ON c.child = ds.databaseName
|
143
|
+
WHERE
|
144
|
+
c.parent = #{sql_string name}
|
145
|
+
EndSQL
|
146
|
+
if recs.empty?
|
147
|
+
raise ObjectError, "database does not exist in dbc.diskSpace: #{@name.inspect}"
|
148
|
+
end
|
149
|
+
if recs.size > 1
|
150
|
+
raise "multiple database entry exist on dbc.diskSpace???: #{name.inspect}; size=#{recs.size}"
|
151
|
+
end
|
152
|
+
Perms.new(* recs.first.to_a.map {|n| n.to_i })
|
153
|
+
end
|
154
|
+
|
155
|
+
def tables(database)
|
156
|
+
recs = entries(<<-EndSQL)
|
157
|
+
SELECT trim(tableName)
|
158
|
+
, sum(currentPerm)
|
159
|
+
, sum(peakPerm)
|
160
|
+
FROM dbc.tableSize
|
161
|
+
WHERE databaseName = #{sql_string database}
|
162
|
+
GROUP BY tableName
|
163
|
+
EndSQL
|
164
|
+
c = ::Teradata::Table
|
165
|
+
recs.map {|rec|
|
166
|
+
name, curr, peak = *rec.to_a
|
167
|
+
c.new(database, name, curr.to_i, peak.to_i)
|
168
|
+
}
|
169
|
+
end
|
170
|
+
|
171
|
+
def views(database)
|
172
|
+
fetch_objects(database, ::Teradata::View)
|
173
|
+
end
|
174
|
+
|
175
|
+
def fetch_objects(database, obj_class)
|
176
|
+
# FIXME??: use dbc.tvm
|
177
|
+
entries("HELP DATABASE #{database}")\
|
178
|
+
.select {|rec| rec[1].strip.upcase == obj_class.type_char }\
|
179
|
+
.map {|rec| obj_class.new(database, rec[0].strip) }
|
180
|
+
end
|
181
|
+
private :fetch_objects
|
182
|
+
|
183
|
+
def objects(database)
|
184
|
+
entries("HELP DATABASE #{database}").map {|rec|
|
185
|
+
::Teradata::DBObject.create(rec[1].strip, database, rec[0].strip)
|
186
|
+
}
|
187
|
+
end
|
188
|
+
|
189
|
+
def column(obj, name)
|
190
|
+
recs = entries(<<-EndSQL)
|
191
|
+
SELECT * FROM dbc.columns
|
192
|
+
WHERE databaseName = #{sql_string obj.database}
|
193
|
+
AND tableName = #{sql_string obj.unqualified_name}
|
194
|
+
AND columnName = #{sql_string name}
|
195
|
+
EndSQL
|
196
|
+
unless recs.size == 1
|
197
|
+
raise ArgumentError, "could not specify a column: #{obj.name}.#{name}"
|
198
|
+
end
|
199
|
+
Column.for_record(recs.first)
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
class Database
|
206
|
+
|
207
|
+
def initialize(name, conn)
|
208
|
+
@name = name
|
209
|
+
@connection = conn
|
210
|
+
invalidate_cache
|
211
|
+
end
|
212
|
+
|
213
|
+
attr_reader :name
|
214
|
+
|
215
|
+
def invalidate_cache
|
216
|
+
@parents = nil
|
217
|
+
@children = nil
|
218
|
+
@tables = nil
|
219
|
+
@own_perms = nil
|
220
|
+
@total_perms = nil
|
221
|
+
end
|
222
|
+
|
223
|
+
def inspect
|
224
|
+
"\#<#{self.class} #{@name}>"
|
225
|
+
end
|
226
|
+
|
227
|
+
def user?
|
228
|
+
false
|
229
|
+
end
|
230
|
+
|
231
|
+
def owner
|
232
|
+
parents.first
|
233
|
+
end
|
234
|
+
|
235
|
+
alias parent owner
|
236
|
+
|
237
|
+
def parents
|
238
|
+
@parents ||= @connection.parent_databases(@name)
|
239
|
+
end
|
240
|
+
|
241
|
+
def children
|
242
|
+
@children ||= @connection.child_databases(@name)
|
243
|
+
end
|
244
|
+
|
245
|
+
def tables
|
246
|
+
@tables ||= @connection.tables(@name)
|
247
|
+
end
|
248
|
+
|
249
|
+
def own_current_perm
|
250
|
+
load_own_perms
|
251
|
+
@own_perms.current
|
252
|
+
end
|
253
|
+
|
254
|
+
alias current_perm own_current_perm
|
255
|
+
|
256
|
+
def own_max_perm
|
257
|
+
load_own_perms
|
258
|
+
@own_perms.max
|
259
|
+
end
|
260
|
+
|
261
|
+
alias max_perm own_max_perm
|
262
|
+
|
263
|
+
def own_peak_perm
|
264
|
+
load_own_perms
|
265
|
+
@own_perms.peak
|
266
|
+
end
|
267
|
+
|
268
|
+
alias peak_perm own_peak_perm
|
269
|
+
|
270
|
+
def load_own_perms
|
271
|
+
@own_perms ||= @connection.database_own_perms(@name)
|
272
|
+
end
|
273
|
+
private :load_own_perms
|
274
|
+
|
275
|
+
def total_current_perm
|
276
|
+
load_total_perms
|
277
|
+
@total_perms.current
|
278
|
+
end
|
279
|
+
|
280
|
+
def total_max_perm
|
281
|
+
load_total_perms
|
282
|
+
@total_perms.max
|
283
|
+
end
|
284
|
+
|
285
|
+
def total_peak_perm
|
286
|
+
load_total_perms
|
287
|
+
@total_perms.peak
|
288
|
+
end
|
289
|
+
|
290
|
+
def load_total_perms
|
291
|
+
@total_perms ||= @connection.database_total_perms(@name)
|
292
|
+
end
|
293
|
+
private :load_total_perms
|
294
|
+
|
295
|
+
end
|
296
|
+
|
297
|
+
|
298
|
+
class User < Database
|
299
|
+
|
300
|
+
def user?
|
301
|
+
true
|
302
|
+
end
|
303
|
+
|
304
|
+
end
|
305
|
+
|
306
|
+
|
307
|
+
class DBObject
|
308
|
+
|
309
|
+
def DBObject.intern(spec)
|
310
|
+
spec.kind_of?(DBObject) ? spec : parse(spec)
|
311
|
+
end
|
312
|
+
|
313
|
+
def DBObject.parse(spec)
|
314
|
+
new(* spec.split('.', 2))
|
315
|
+
end
|
316
|
+
|
317
|
+
OBJECT_TYPES = {}
|
318
|
+
|
319
|
+
class << DBObject
|
320
|
+
def declare_type(c, name)
|
321
|
+
OBJECT_TYPES[c] = self
|
322
|
+
@type_char = c
|
323
|
+
@type_name = name
|
324
|
+
end
|
325
|
+
|
326
|
+
attr_reader :type_char
|
327
|
+
attr_reader :type_name
|
328
|
+
end
|
329
|
+
|
330
|
+
def DBObject.create(type_char, *args)
|
331
|
+
cls = OBJECT_TYPES[type_char] or
|
332
|
+
raise ArgumentError, "unknown type char: #{type_char.inspect}"
|
333
|
+
cls.new(*args)
|
334
|
+
end
|
335
|
+
|
336
|
+
def initialize(x, y = nil)
|
337
|
+
if y
|
338
|
+
@database = x
|
339
|
+
@name = y
|
340
|
+
else
|
341
|
+
@database = nil
|
342
|
+
@name = x
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
attr_reader :database
|
347
|
+
|
348
|
+
def unqualified_name
|
349
|
+
@name
|
350
|
+
end
|
351
|
+
|
352
|
+
def name
|
353
|
+
@database ? "#{@database}.#{@name}" : @name
|
354
|
+
end
|
355
|
+
|
356
|
+
alias to_s name
|
357
|
+
|
358
|
+
def inspect
|
359
|
+
"\#<#{self.class} #{name}>"
|
360
|
+
end
|
361
|
+
|
362
|
+
def ==(other)
|
363
|
+
other.kind_of?(self.class) and self.name == other.name
|
364
|
+
end
|
365
|
+
|
366
|
+
def type_char
|
367
|
+
self.class.type_char
|
368
|
+
end
|
369
|
+
|
370
|
+
def type_name
|
371
|
+
self.class.type_name
|
372
|
+
end
|
373
|
+
|
374
|
+
end
|
375
|
+
|
376
|
+
|
377
|
+
class Table < DBObject
|
378
|
+
declare_type 'T', 'TABLE'
|
379
|
+
|
380
|
+
def initialize(x, y = nil, curr = nil, peak = nil)
|
381
|
+
super x, y
|
382
|
+
@current_perm = curr
|
383
|
+
@peak_perm = peak
|
384
|
+
end
|
385
|
+
|
386
|
+
attr_reader :current_perm
|
387
|
+
alias size current_perm
|
388
|
+
attr_reader :peak_perm
|
389
|
+
end
|
390
|
+
|
391
|
+
class View < DBObject
|
392
|
+
declare_type 'V', 'VIEW'
|
393
|
+
end
|
394
|
+
|
395
|
+
class Macro < DBObject
|
396
|
+
declare_type 'M', 'MACRO'
|
397
|
+
end
|
398
|
+
|
399
|
+
class Procedure < DBObject
|
400
|
+
declare_type 'P', 'PROCEDURE'
|
401
|
+
end
|
402
|
+
|
403
|
+
class JoinIndex < DBObject
|
404
|
+
declare_type 'J', 'JOIN INDEX'
|
405
|
+
end
|
406
|
+
|
407
|
+
class HashIndex < DBObject
|
408
|
+
declare_type 'N', 'HASH INDEX'
|
409
|
+
end
|
410
|
+
|
411
|
+
COLUMN_ATTRIBUTES = [
|
412
|
+
:database_name,
|
413
|
+
:table_name,
|
414
|
+
:column_name,
|
415
|
+
:column_format,
|
416
|
+
:column_title,
|
417
|
+
:sp_parameter_type,
|
418
|
+
:column_type,
|
419
|
+
:column_udt_name,
|
420
|
+
:column_length,
|
421
|
+
:default_value,
|
422
|
+
:nullable,
|
423
|
+
:comment_string,
|
424
|
+
:decimal_total_digits,
|
425
|
+
:decimal_fractional_digits,
|
426
|
+
:column_id,
|
427
|
+
:upper_case_flag,
|
428
|
+
:comprressible,
|
429
|
+
:compress_value,
|
430
|
+
:column_constraint,
|
431
|
+
:constraint_count,
|
432
|
+
:creator_name,
|
433
|
+
:create_timestamp,
|
434
|
+
:last_alter_name,
|
435
|
+
:last_alter_timestamp,
|
436
|
+
:char_type,
|
437
|
+
:id_col_type,
|
438
|
+
:access_count,
|
439
|
+
:last_access_timestamp,
|
440
|
+
:compress_value_list
|
441
|
+
]
|
442
|
+
|
443
|
+
Column = Struct.new(* COLUMN_ATTRIBUTES)
|
444
|
+
|
445
|
+
class Column # reopen
|
446
|
+
extend MetadataUtils
|
447
|
+
|
448
|
+
def Column.for_record(rec)
|
449
|
+
new(* adjust_list_size(rec.to_a, COLUMN_ATTRIBUTES.size))
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
end
|