Mercurial > sqlpython
annotate sqlpython.py @ 92:fa8c9eb8908f
accepting command-line args
author | catherine@cordelia |
---|---|
date | Sun, 25 May 2008 01:35:08 -0400 |
parents | 83de0cb04f12 |
children | c5f601abc993 |
rev | line source |
---|---|
0 | 1 # |
2 # SqlPython V1.3 | |
3 # Author: Luca.Canali@cern.ch, Apr 2006 | |
4 # Rev 18-Oct-07 | |
5 # | |
6 # A python module to reproduce Oracle's command line 'sqlplus-like' within python | |
7 # Intended to allow easy customizations and extentions | |
8 # Best used with the companion modules sqlpyPlus and mysqlpy | |
9 # See also http://twiki.cern.ch/twiki/bin/view/PSSGroup/SqlPython | |
10 | |
16
2776755a3a7e
beginning separation of cmd2
devlinjs@FA7CZA6N1254998.wrightpatterson.afmc.ds.af.mil
parents:
9
diff
changeset
|
11 import cmd2,getpass,binascii,cx_Oracle,re |
80 | 12 import pexpecter, sqlpyPlus |
0 | 13 |
14 # complication! separate sessions -> | |
15 # separate transactions !!!!! | |
16 # also: timeouts, other session failures | |
40
1fb9f7dee7d8
tearing out cmd2
devlinjs@FA7CZA6N1254998.wrightpatterson.afmc.ds.af.mil
parents:
16
diff
changeset
|
17 |
16
2776755a3a7e
beginning separation of cmd2
devlinjs@FA7CZA6N1254998.wrightpatterson.afmc.ds.af.mil
parents:
9
diff
changeset
|
18 class sqlpython(cmd2.Cmd): |
0 | 19 '''A python module to reproduce Oracle's command line with focus on customization and extention''' |
20 | |
21 def __init__(self): | |
16
2776755a3a7e
beginning separation of cmd2
devlinjs@FA7CZA6N1254998.wrightpatterson.afmc.ds.af.mil
parents:
9
diff
changeset
|
22 cmd2.Cmd.__init__(self) |
0 | 23 self.prompt = 'SQL.No_Connection> ' |
24 self.maxfetch = 1000 | |
25 self.failoverSessions = [] | |
26 self.terminator = ';' | |
27 self.timeout = 30 | |
28 | |
29 def do_connect(self, arg): | |
30 '''Opens the DB connection''' | |
31 try: | |
32 if arg.find('/') == -1: | |
33 orapass = getpass.getpass('Password: ') | |
34 orauser = arg.split('@')[0] | |
35 oraserv = arg.split('@')[1] | |
36 self.orcl = cx_Oracle.connect(orauser,orapass,oraserv) | |
37 arg = '%s/%s@%s' % (orauser, orapass, oraserv) | |
38 else: | |
39 self.orcl = cx_Oracle.connect(arg) | |
40 self.curs = self.orcl.cursor() | |
41 self.prompt = 'SQL.'+self.orcl.tnsentry+'> ' | |
42 self.failoverSessions = [f for f in [fbs(arg) for fbs in pexpecter.available] if f.available] | |
43 | |
44 except Exception, e: | |
45 print e | |
46 | |
47 def emptyline(self): | |
48 pass | |
49 | |
50 def fail(self, arg, do_everywhere=False): | |
51 if self.failover: | |
52 success, result = False, '' | |
53 for fbs in self.failoverSessions: | |
54 success, result = fbs.attempt(arg) | |
55 if success: | |
56 print result | |
57 if not do_everywhere: | |
58 return True | |
59 print result | |
60 return False | |
61 | |
62 def designated_session(self, arg, sesstype): | |
63 for fbs in self.failoverSessions: | |
64 if fbs.valid and fbs.__class__ == sesstype: | |
65 success, result = fbs.attempt(arg) | |
66 print result | |
67 return | |
68 print 'Valid %s not found' % (sesstype.__name__) | |
69 | |
70 def do_terminators(self, arg): | |
71 """; standard Oracle format | |
72 \\c CSV (with headings) | |
73 \\C CSV (no headings) | |
74 \\g list | |
75 \\G aligned list | |
76 \\h HTML table | |
77 \\i INSERT statements | |
78 \\s CSV (with headings) | |
79 \\S CSV (no headings) | |
80 \\t transposed | |
81 \\x XML""" | |
82 print self.do_terminators.__doc__ | |
83 | |
84 terminatorSearchString = '|'.join('\\' + d.split()[0] for d in do_terminators.__doc__.splitlines()) | |
85 | |
86 def do_yasql(self, arg): | |
87 '''Sends a command to a YASQL session (http://sourceforge.net/projects/yasql/)''' | |
88 self.designated_session(arg, pexpecter.YASQLSession) | |
89 do_y = do_yasql | |
90 def do_sqlplus(self, arg): | |
91 '''Sends a command to a SQL*Plus session''' | |
92 self.designated_session(arg, pexpecter.SqlPlusSession) | |
93 do_sqlp = do_sqlplus | |
94 def do_senora(self, arg): | |
95 '''Sends a command to a Senora session (http://senora.sourceforge.net/)''' | |
96 self.designated_session(arg, pexpecter.SenoraSession) | |
97 do_sen = do_senora | |
9
f70cc3be6377
reporting rowcount
devlinjs@FA7CZA6N1254998.wrightpatterson.afmc.ds.af.mil
parents:
3
diff
changeset
|
98 |
0 | 99 def default(self, arg, do_everywhere = False): |
55 | 100 self.query = self.finishStatement(arg).strip().rstrip(';') |
0 | 101 try: |
80 | 102 self.varsUsed = sqlpyPlus.findBinds(self.query, self.binds, givenBindVars={}) |
103 self.curs.execute(self.query, self.varsUsed) | |
9
f70cc3be6377
reporting rowcount
devlinjs@FA7CZA6N1254998.wrightpatterson.afmc.ds.af.mil
parents:
3
diff
changeset
|
104 print '\nExecuted%s\n' % ((self.curs.rowcount > 0) and ' (%d rows)' % self.curs.rowcount or '') |
0 | 105 if do_everywhere: |
106 self.fail(arg, do_everywhere = True ) | |
107 except Exception, e: | |
108 result = self.fail(arg) | |
109 if not result: | |
110 print str(e) | |
111 | |
112 def do_commit(self, arg): | |
67
d0bf9e40ba8d
eliminate double-semicolon on commit
catherine@DellZilla.myhome.westell.com
parents:
55
diff
changeset
|
113 self.default('commit %s;' % (arg), do_everywhere=True) |
0 | 114 def do_rollback(self, arg): |
67
d0bf9e40ba8d
eliminate double-semicolon on commit
catherine@DellZilla.myhome.westell.com
parents:
55
diff
changeset
|
115 self.default('rollback %s;' % (arg), do_everywhere=True) |
0 | 116 |
117 # shortcuts | |
92 | 118 do_exit = cmd2.Cmd.do_quit |
0 | 119 |
41
33c9bc61db66
separation surgery successful?
devlinjs@FA7CZA6N1254998.wrightpatterson.afmc.ds.af.mil
parents:
40
diff
changeset
|
120 stmtEndSearchString = r'(.*)(%s)\s*(\d+)?\s*$' % terminatorSearchString |
40
1fb9f7dee7d8
tearing out cmd2
devlinjs@FA7CZA6N1254998.wrightpatterson.afmc.ds.af.mil
parents:
16
diff
changeset
|
121 statementEndPattern = re.compile(stmtEndSearchString, re.MULTILINE | re.DOTALL) |
0 | 122 |
123 def pmatrix(rows,desc,maxlen=30): | |
124 '''prints a matrix, used by sqlpython to print queries' result sets''' | |
125 names = [] | |
126 maxen = [] | |
127 toprint = [] | |
128 for d in desc: | |
129 n = d[0] | |
130 names.append(n) # list col names | |
131 maxen.append(len(n)) # col length | |
132 rcols = range(len(desc)) | |
133 rrows = range(len(rows)) | |
134 for i in rrows: # loops for all rows | |
135 rowsi = map(str, rows[i]) # current row to process | |
136 split = [] # service var is row split is needed | |
137 mustsplit = 0 # flag | |
138 for j in rcols: | |
139 if str(desc[j][1]) == "<type 'cx_Oracle.BINARY'>": # handles RAW columns | |
80 | 140 rowsi[j] = binascii.b2a_hex(rowsi[j]) |
0 | 141 maxen[j] = max(maxen[j], len(rowsi[j])) # computes max field length |
142 if maxen[j] <= maxlen: | |
143 split.append('') | |
144 else: # split the line is 2 because field is too long | |
145 mustsplit = 1 | |
146 maxen[j] = maxlen | |
147 split.append(rowsi[j][maxlen-1:2*maxlen-1]) | |
148 rowsi[j] = rowsi[j][0:maxlen-1] # this implem. truncates after maxlen*2 | |
149 toprint.append(rowsi) # 'toprint' is a printable copy of rows | |
150 if mustsplit != 0: | |
151 toprint.append(split) | |
152 sepcols = [] | |
153 for i in rcols: | |
154 maxcol = maxen[i] | |
155 name = names[i] | |
156 sepcols.append("-" * maxcol) # formats column names (header) | |
157 names[i] = name + (" " * (maxcol-len(name))) # formats separ line with -- | |
158 rrows2 = range(len(toprint)) | |
159 for j in rrows2: | |
160 val = toprint[j][i] | |
161 if str(desc[i][1]) == "<type 'cx_Oracle.NUMBER'>": # right align numbers | |
162 toprint[j][i] = (" " * (maxcol-len(val))) + val | |
163 else: | |
164 toprint[j][i] = val + (" " * (maxcol-len(val))) | |
165 for j in rrows2: | |
166 toprint[j] = ' '.join(toprint[j]) | |
167 names = ' '.join(names) | |
168 sepcols = ' '.join(sepcols) | |
169 toprint.insert(0, sepcols) | |
170 toprint.insert(0, names) | |
171 return '\n'.join(toprint) | |
172 |