db2c 0.0.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,13 +1,13 @@
1
- a db2 console with with history and autocomplete support
1
+ A DB2 console with history and autocomplete support, and few other goodies
2
2
  ====================================
3
3
 
4
- DB2 console mode does not support readline and autocomplete, this is a wrapper for the db2 command with support for both.
4
+ DB2 console mode does not support readline and autocomplete, this is a wrapper for the db2 command mode with support for both. It also tries to make using db2 a little bit more tolerable, adding support for psql-like commands and other shortcuts.
5
5
 
6
6
  Install
7
7
  -------
8
8
 
9
- $ apt-get install [rlwrap][0]
10
- $ gem install db2c
9
+ * apt-get install [rlwrap][0]
10
+ * gem install db2c
11
11
 
12
12
  Contributing
13
13
  ------------
@@ -23,8 +23,8 @@ Once you've made your great commits:
23
23
  Acknowledgement
24
24
  ------------
25
25
 
26
- Chris Jester-Young ([CKY][4]) found out the problem of using shell metacharacters when executing commands from Ruby.
27
- The initial script was inspired by [defunkt's repl][3], for a genenral purpose repl/wrapper, this is your friend.
26
+ * Chris Jester-Young ([CKY][4]) found out the problem of using shell metacharacters when executing commands from Ruby.
27
+ * The initial script was inspired by [defunkt's repl][3], for a genenral purpose repl/wrapper, this is your friend.
28
28
 
29
29
  Meta
30
30
  ----
data/bin/db2c CHANGED
@@ -4,19 +4,38 @@ $LOAD_PATH.unshift 'lib'
4
4
  require "db2c"
5
5
 
6
6
  run = Db2c::Run.new *ARGV
7
+ $DB2CDBG = run.debug?
7
8
 
8
9
  exec "man #{run.gdir}/man/db2c.1" if run.help?
9
- exec "rlwrap -z pipeto -i -r -s 999999 -pBLUE -f #{run.autocomplete} -H ~/.db2c_history db2c --no-rlwrap #{run.args}" if run.wrap?
10
+
11
+ puts "wrapping #{$0} #{run.args}" if run.debug? && !run.nowrap?
12
+ exec "RLWRAP_FILTERDIR=#{run.filters} rlwrap -z 'pipes less grep' -i -r -s 999999 -pBLUE -f #{run.autocomplete} -H ~/.db2c_history #{$0} --now #{run.args}" unless run.nowrap?
13
+
14
+ Db2c::Command.execute "use #{run.default_db}" if run.default_db
15
+ $/ = ";" if run.multiline?
10
16
 
11
17
  loop do
12
18
  print Db2c::Command.prompt
13
19
  begin
14
- command = Db2c::Command.new $stdin.gets
20
+ input = $stdin.gets
21
+ input = input.gsub(/;$/,'') if input
22
+ if input =~ /^(edit|vi|vim|emacs)$/
23
+ command = Db2c::Command.new Db2c::Editor.edit input
24
+ next if command.quit?
25
+ elsif input =~ /^(cat|cp|date|df|du|find|grep|irb|kill|less|ls|man|more|mv|ps|rm|sudo|tail|touch|top|wc|which|who)/
26
+ system input
27
+ next
28
+ elsif input =~ /^!/
29
+ system input[1..-1]
30
+ next
31
+ else
32
+ command = Db2c::Command.new input
33
+ end
15
34
  rescue Interrupt
16
35
  exit
17
36
  end
18
37
  exit if command.quit?
19
- system 'less ~/.db2c_history' if command.history?
38
+ system 'cat ~/.db2c_history' if command.history?
20
39
  system "man #{run.gdir}/man/db2c.1" if command.help?
21
40
  command.execute
22
41
  end
data/lib/db2c.rb CHANGED
@@ -1,7 +1,12 @@
1
1
  module Db2c
2
2
  DEFAULT_PROMPT = "db2c => "
3
- VERSION = "0.0.4"
3
+ VERSION = "1.0.0"
4
+ module CONSTANTS
5
+ DTSELECT = "select char(strip(tabschema) || '.' || strip(tabname), 128) as table from syscat.tables"
6
+ DTORDER = "order by tabschema, tabname"
7
+ end
4
8
  end
5
9
 
6
10
  require "db2c/run.rb"
7
11
  require "db2c/command.rb"
12
+ require "db2c/editor.rb"
data/lib/db2c/command.rb CHANGED
@@ -1,14 +1,14 @@
1
1
  module Db2c
2
2
  class Command
3
3
 
4
+ include CONSTANTS
4
5
  @@cdb = ''
5
- @@debug = false
6
6
 
7
7
  def initialize input
8
8
  if input
9
- puts "initializing: #{input}" if @@debug
10
- @input = input.chomp.strip
11
- parse
9
+ puts "initializing: #{input}" if $DB2CDBG
10
+ @input = input.chomp.strip.gsub(/^db2 /i,'')
11
+ parse unless @input =~ /^(select|update|delete|insert)/i
12
12
  end
13
13
  end
14
14
 
@@ -17,17 +17,46 @@ module Db2c
17
17
  end
18
18
 
19
19
  def parse
20
- @input.gsub! /^db2 /i, ''
21
- @input.gsub! /;$/, ''
22
20
  @input.gsub! /^use /, 'connect to '
23
- @input.gsub! /^\\d /, 'describe '
24
- @input.insert 0, "? sql" if @input =~ /^\-\d+$/
25
- @input.insert 0, "? " if @input =~ /^\d+$/
26
- @input.insert 0, "values " if @input =~ /^current.+$/i
27
21
 
22
+ @input.gsub! /^\\d /, 'describe '
28
23
  if @input =~ /describe [^. ]+\.[^.+ ]+/
29
24
  @input.gsub! /describe /, 'describe table '
25
+ return
26
+ end
27
+
28
+ if @input =~ /^(show|list) databases/ || @input == '\l'
29
+ @input = "list database directory"
30
+ return
31
+ end
32
+
33
+ if @input =~ /^\\lt ?(\w*)$/
34
+ @input = "list tables"
35
+ unless $1.empty?
36
+ @input += $1 == "all" ? " for all" : " for schema #{$1}"
37
+ end
38
+ return
39
+ end
40
+
41
+ if @input =~ /^\\d([a|s|t|v]) ?(\w*)$/
42
+ @input = DTSELECT
43
+ @input += " where type = '#{$1.upcase}'"
44
+ @input += " and tabschema = '#{$2.upcase}'" unless $2.empty?
45
+ @input += " #{DTORDER}"
46
+ return
30
47
  end
48
+
49
+ shortcuts
50
+ end
51
+
52
+ def shortcuts
53
+ prepend /^\-\d+$/, "? sql"
54
+ prepend /^\d+$/, "? "
55
+ prepend /^current.+$/i, "values "
56
+ end
57
+
58
+ def prepend regex, value
59
+ @input.insert 0, value if @input =~ regex
31
60
  end
32
61
 
33
62
  def quit?
@@ -47,7 +76,7 @@ module Db2c
47
76
  end
48
77
 
49
78
  def execute
50
- puts "executing: #{@input}" if @@debug
79
+ puts "executing: #{@input}" if $DB2CDBG
51
80
  system 'db2', @input if valid?
52
81
  if @input =~ /^connect to (.*)$/i
53
82
  @@cdb = $1.downcase
@@ -57,14 +86,6 @@ module Db2c
57
86
  end
58
87
  end
59
88
 
60
- def self.debug=(value)
61
- @@debug = value
62
- end
63
-
64
- def self.debug?
65
- @@debug
66
- end
67
-
68
89
  def self.prompt
69
90
  "db2c".tap do |pr|
70
91
  pr << "(#{@@cdb})" if @@cdb.length > 0
@@ -72,5 +93,9 @@ module Db2c
72
93
  end
73
94
  end
74
95
 
96
+ def self.execute command
97
+ new(command).execute
98
+ end
99
+
75
100
  end
76
101
  end
@@ -0,0 +1,33 @@
1
+ require 'fileutils'
2
+ require 'tempfile'
3
+
4
+ module Db2c
5
+ class Editor
6
+ def self.edit editor
7
+ puts "editor #{editor}" if $DB2CDBG
8
+ @file ||= Tempfile.new(["db2_tempfile", ".sql"])
9
+ mtime = File.stat(@file.path).mtime
10
+
11
+ args = []
12
+ args << command(editor)
13
+ args << @file.path
14
+ args.flatten!
15
+
16
+ @file.close
17
+
18
+ puts "editor args: #{args.inspect}" if $DB2CDBG
19
+
20
+ system(*args)
21
+
22
+ if mtime < File.stat(@file.path).mtime
23
+ return IO.read(@file.path)
24
+ end
25
+ end
26
+
27
+ def self.command editor
28
+ return ["emacs", "-nw"] if editor =~ /^emacs/
29
+ ["vi"]
30
+ end
31
+
32
+ end
33
+ end
data/lib/db2c/run.rb CHANGED
@@ -4,18 +4,17 @@ module Db2c
4
4
 
5
5
  def initialize *args
6
6
  @args = args
7
- puts "args: #{@args}" if debug?
7
+ puts "args: #{@args.inspect}" if debug?
8
8
  @gdir = File.expand_path('../../../', __FILE__)
9
- puts "cdir: #{@gdir}" if debug?
10
- Db2c::Command.debug = debug?
9
+ puts "cdir: #{@gdir.inspect}" if debug?
11
10
 
12
11
  die "version #{Db2c::VERSION}" if version?
13
12
  die "The db2 command was not found!" unless system("which db2 > /dev/null 2> /dev/null")
14
- die "This program depends on rlwrap, please install rlwrap" if wrap? && !system("which rlwrap > /dev/null 2> /dev/null")
13
+ die "This program depends on rlwrap, please install rlwrap" unless nowrap? || system("which rlwrap > /dev/null 2> /dev/null")
15
14
  end
16
15
 
17
16
  def help?
18
- !(@args & %w{-h help -help --help --man}).empty?
17
+ !(@args & %w{-h help -help --help man --man}).empty?
19
18
  end
20
19
  def version?
21
20
  !(@args & %w{-v version -version --version}).empty?
@@ -23,18 +22,33 @@ module Db2c
23
22
  def debug?
24
23
  !(@args & %w{-d debug -debug --debug}).empty?
25
24
  end
26
- def wrap?
27
- (@args & %w{--no-rlwrap --now}).empty?
25
+ def nowrap?
26
+ !(@args & %w{--no-rlwrap --now}).empty?
27
+ end
28
+ def multiline?
29
+ !(@args & %w{-t}).empty?
30
+ end
31
+
32
+ def default_db
33
+ words.first if words.length == 1 && words.first !~ /(help|man|debug|version)/
28
34
  end
29
35
 
30
36
  def autocomplete
31
37
  "#{@gdir}/lib/autocomplete"
32
38
  end
33
39
 
40
+ def filters
41
+ "#{@gdir}/rlwrap/filters"
42
+ end
43
+
34
44
  def args
35
45
  @args.join(' ')
36
46
  end
37
47
 
48
+ def words
49
+ @args.reject { |arg| arg.start_with?('-') }
50
+ end
51
+
38
52
  def die message
39
53
  puts "DB2C: #{message}"
40
54
  puts "DB2C: #{self.inspect}" if debug?
data/man/db2c.1 CHANGED
@@ -1,13 +1,13 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "DB2C" "1" "November 2011" "" ""
4
+ .TH "DB2C" "1" "February 2012" "" ""
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBdb2c\fR \- A DB2 console with with history and autocomplete support, and few other goodies
8
8
  .
9
9
  .SH "SYNOPSIS"
10
- \fBdb2c\fR \fI\fIoptions\fR\fR
10
+ \fBdb2c\fR [\fIoptions\fR] [dbname]
11
11
  .
12
12
  .SH "DESCRIPTION && EXAMPLES"
13
13
  DB2 console mode does not support readline and autocomplete, this is a wrapper for the db2 command with support for both\.
@@ -51,15 +51,15 @@ db2(testdb) => select * from xyz\.tab[double\-tab]
51
51
 
52
52
  .
53
53
  .IP "\(bu" 4
54
- \fBYou can pipe\fR:
54
+ For example, if a command outputs long lines, \fBless \-S\fR is your friend:
55
55
  .
56
56
  .IP "" 4
57
57
  .
58
58
  .nf
59
59
 
60
60
 
61
- db2(testdb) => select * from large\.table | grep \-v something
62
- db2(testdb) => select * from large\.table | less
61
+ db2(testdb) => select * from table\.with\.many\.columns | less \-S
62
+ (you can scorll horizontally with left/right arrows)
63
63
  .
64
64
  .fi
65
65
  .
@@ -67,15 +67,15 @@ db2(testdb) => select * from large\.table | less
67
67
 
68
68
  .
69
69
  .IP "\(bu" 4
70
- For example, if a command outputs long lines, \fBless \-S\fR is your friend:
70
+ \fBYou can edit last statement or use the editor to write a new multiline statement\fR:
71
71
  .
72
72
  .IP "" 4
73
73
  .
74
74
  .nf
75
75
 
76
76
 
77
- db2(testdb) => select * from table\.with\.many\.columns | less \-S
78
- (you can scorll horizontally with left/right arrows)
77
+ db2(testdb) => edit
78
+ db2(testdb) => emacs
79
79
  .
80
80
  .fi
81
81
  .
@@ -83,23 +83,78 @@ db2(testdb) => select * from table\.with\.many\.columns | less \-S
83
83
 
84
84
  .
85
85
  .IP "\(bu" 4
86
- You can use \fIsome psql\-like\fR commands
86
+ \fBAny !command will be sent to the shell as is\fR:
87
+ .
88
+ .IP "" 4
89
+ .
90
+ .nf
91
+
92
+
93
+ db2(testdb) => !clear
94
+ .
95
+ .fi
96
+ .
97
+ .IP "" 0
98
+
99
+ .
100
+ .IP "\(bu" 4
101
+ You can use \fIsome\fR common shell commands directly:
102
+ .
103
+ .IP "" 4
104
+ .
105
+ .nf
106
+
107
+
108
+ db2(testdb) => ls ~
109
+ db2(testdb) => less ~/somefile
110
+ db2(testdb) => top
111
+ db2(testdb) => irb
112
+ .
113
+ .fi
114
+ .
115
+ .IP "" 0
116
+
117
+ .
118
+ .IP "\(bu" 4
119
+ You can use \fIsome psql\-like\fR meta commands
87
120
  .
88
121
  .IP "" 4
89
122
  .
90
123
  .nf
91
124
 
92
125
 
93
- db2(testdb) => \fB\ed schema\.table\fR
94
- == describe table schema\.table
95
126
  db2(testdb) => \fB\eh\fR
96
127
  == To see this help from within the console
128
+ db2(testdb) => \fB\el\fR
129
+ == list database directory
130
+ db2(testdb) => \fB\elt [all|schema]\fR
131
+ == list tables for all or one schema using db2 list command
132
+ db2(testdb) => \fB\el[t|v|a|s] [schema]\fR
133
+ == list tables|views|aliases|summary\-tables for all or one schema using syscat\.tables
134
+ db2(testdb) => \fB\ed schema\.table\fR
135
+ == describe table schema\.table
97
136
  db2(testdb) => \fB\eq\fR
98
137
  .
99
138
  .fi
100
139
  .
101
140
  .IP "" 0
102
141
 
142
+ .
143
+ .IP "\(bu" 4
144
+ \fBYou can pipe\fR:
145
+ .
146
+ .IP "" 4
147
+ .
148
+ .nf
149
+
150
+
151
+ db2(testdb) => \edv | grep \-v SYS
152
+ db2(testdb) => select * from large\.table | less
153
+ .
154
+ .fi
155
+ .
156
+ .IP "" 0
157
+
103
158
  .
104
159
  .IP "" 0
105
160
  .
@@ -110,6 +165,10 @@ db2(testdb) => \fB\eq\fR
110
165
  Displays this help page\.
111
166
  .
112
167
  .TP
168
+ \fB\-t\fR
169
+ Commands will be executed when you enter a terminating semicolon (;)
170
+ .
171
+ .TP
113
172
  \fB\-\-debug\fR
114
173
  Displays annoying messages\.
115
174
  .
data/man/db2c.1.html CHANGED
@@ -75,7 +75,7 @@
75
75
 
76
76
  <h2 id="SYNOPSIS">SYNOPSIS</h2>
77
77
 
78
- <p><code>db2c</code> <var><a href="#OPTIONS" title="OPTIONS" data-bare-link="true">options</a></var></p>
78
+ <p><code>db2c</code> [<var>options</var>] [dbname]</p>
79
79
 
80
80
  <h2 id="DESCRIPTION-EXAMPLES">DESCRIPTION &amp;&amp; EXAMPLES</h2>
81
81
 
@@ -98,24 +98,46 @@ it remembers..
98
98
  db2(testdb) => list tables for schema xyz
99
99
  db2(testdb) => select * from xyz.tab[double-tab]
100
100
  </pre></li>
101
- <li><p><strong>You can pipe</strong>:
102
- </p><pre>
103
- db2(testdb) => select * from large.table | grep -v something
104
- db2(testdb) => select * from large.table | less
105
- </pre></li>
106
101
  <li><p>For example, if a command outputs long lines, <strong>less -S</strong> is your friend:
107
102
  </p><pre>
108
103
  db2(testdb) => select * from table.with.many.columns | less -S
109
104
  (you can scorll horizontally with left/right arrows)
110
105
  </pre></li>
111
- <li><p>You can use <em>some psql-like</em> commands
106
+ <li><p><strong>You can edit last statement or use the editor to write a new multiline statement</strong>:
107
+ </p><pre>
108
+ db2(testdb) => edit
109
+ db2(testdb) => emacs
110
+ </pre></li>
111
+ <li><p><strong>Any !command will be sent to the shell as is</strong>:
112
+ </p><pre>
113
+ db2(testdb) => !clear
114
+ </pre></li>
115
+ <li><p>You can use <em>some</em> common shell commands directly:
116
+ </p><pre>
117
+ db2(testdb) => ls ~
118
+ db2(testdb) => less ~/somefile
119
+ db2(testdb) => top
120
+ db2(testdb) => irb
121
+ </pre></li>
122
+ <li><p>You can use <em>some psql-like</em> meta commands
112
123
  </p><pre>
113
- db2(testdb) => <strong>\d schema.table</strong>
114
- == describe table schema.table
115
124
  db2(testdb) => <strong>\h</strong>
116
125
  == To see this help from within the console
126
+ db2(testdb) => <strong>\l</strong>
127
+ == list database directory
128
+ db2(testdb) => <strong>\lt [all|schema]</strong>
129
+ == list tables for all or one schema using db2 list command
130
+ db2(testdb) => <strong>\l[t|v|a|s] [schema]</strong>
131
+ == list tables|views|aliases|summary-tables for all or one schema using syscat.tables
132
+ db2(testdb) => <strong>\d schema.table</strong>
133
+ == describe table schema.table
117
134
  db2(testdb) => <strong>\q</strong>
118
135
  </pre></li>
136
+ <li><p><strong>You can pipe</strong>:
137
+ </p><pre>
138
+ db2(testdb) => \dv | grep -v SYS
139
+ db2(testdb) => select * from large.table | less
140
+ </pre></li>
119
141
  </ul>
120
142
 
121
143
 
@@ -123,6 +145,7 @@ db2(testdb) => <strong>\q</strong>
123
145
 
124
146
  <dl>
125
147
  <dt><code>-h</code>, <code>--help</code>, <code>--man</code></dt><dd><p>Displays this help page.</p></dd>
148
+ <dt class="flush"><code>-t</code></dt><dd><p>Commands will be executed when you enter a terminating semicolon (;)</p></dd>
126
149
  <dt class="flush"><code>--debug</code></dt><dd><p>Displays annoying messages.</p></dd>
127
150
  <dt><code>--no-rlrwap</code></dt><dd><p>Don't use rlwrap</p></dd>
128
151
  </dl>
@@ -134,7 +157,7 @@ db2(testdb) => <strong>\q</strong>
134
157
 
135
158
  <h2 id="AUTHOR">AUTHOR</h2>
136
159
 
137
- <p>Samer Abukhait <a href="&#x6d;&#x61;&#x69;&#x6c;&#x74;&#111;&#x3a;&#115;&#97;&#109;&#101;&#x72;&#x40;&#111;&#110;&#45;&#x73;&#x69;&#x74;&#x65;&#x4e;&#79;&#x53;&#80;&#65;&#x4d;&#x2e;&#99;&#111;&#109;" data-bare-link="true">&#x73;&#x61;&#109;&#101;&#114;&#x40;&#x6f;&#110;&#x2d;&#x73;&#105;&#x74;&#101;&#x4e;&#79;&#83;&#x50;&#x41;&#x4d;&#46;&#99;&#111;&#x6d;</a>, @s4mer</p>
160
+ <p>Samer Abukhait <a href="&#x6d;&#97;&#105;&#x6c;&#116;&#111;&#x3a;&#115;&#97;&#x6d;&#101;&#114;&#x40;&#x6f;&#110;&#x2d;&#115;&#x69;&#x74;&#x65;&#78;&#x4f;&#83;&#80;&#x41;&#x4d;&#46;&#99;&#x6f;&#x6d;" data-bare-link="true">&#x73;&#97;&#x6d;&#101;&#114;&#64;&#111;&#x6e;&#45;&#115;&#105;&#116;&#x65;&#x4e;&#79;&#x53;&#80;&#65;&#x4d;&#46;&#x63;&#x6f;&#x6d;</a>, @s4mer</p>
138
161
 
139
162
  <h2 id="SEE-ALSO">SEE ALSO</h2>
140
163
 
@@ -143,7 +166,7 @@ db2(testdb) => <strong>\q</strong>
143
166
 
144
167
  <ol class='man-decor man-foot man foot'>
145
168
  <li class='tl'></li>
146
- <li class='tc'>November 2011</li>
169
+ <li class='tc'>February 2012</li>
147
170
  <li class='tr'>db2c(1)</li>
148
171
  </ol>
149
172