Mercurial > sqlpython
annotate sqlpython.py @ 106:31de4c0b06ee v1.4.6
fixed python2.4 compat
author | catherine@localhost |
---|---|
date | Mon, 09 Jun 2008 12:35:13 -0400 |
parents | 4aa28dffe658 |
children | 38ee1ca92801 |
rev | line source |
---|---|
0 | 1 # |
103 | 2 # SqlPython V1.4.6 |
0 | 3 # Author: Luca.Canali@cern.ch, Apr 2006 |
103 | 4 # Rev 29-May-08 |
0 | 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 | |
102 | 11 import cmd2,getpass,binascii,cx_Oracle,re,os |
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 | |
102 | 28 |
29 connection_modes = {re.compile(' AS SYSDBA', re.IGNORECASE): cx_Oracle.SYSDBA, | |
30 re.compile(' AS SYSOPER', re.IGNORECASE): cx_Oracle.SYSOPER} | |
0 | 31 def do_connect(self, arg): |
32 '''Opens the DB connection''' | |
102 | 33 modeval = 0 |
34 for modere, modevalue in self.connection_modes.items(): | |
35 if modere.search(arg): | |
36 arg = modere.sub('', arg) | |
37 modeval = modevalue | |
0 | 38 try: |
102 | 39 orauser, oraserv = arg.split('@') |
40 except ValueError: | |
41 try: | |
42 oraserv = os.environ['ORACLE_SID'] | |
43 except KeyError: | |
44 print 'instance not specified and environment variable ORACLE_SID not set' | |
45 return | |
46 orauser = arg | |
47 sid = oraserv | |
48 try: | |
49 host, sid = oraserv.split('/') | |
50 try: | |
51 host, port = host.split(':') | |
52 port = int(port) | |
53 except ValueError: | |
54 port = 1521 | |
55 oraserv = cx_Oracle.makedsn(host, port, sid) | |
56 except ValueError: | |
57 pass | |
58 try: | |
59 orauser, orapass = orauser.split('/') | |
60 except ValueError: | |
61 orapass = getpass.getpass('Password: ') | |
62 if orauser.upper() == 'SYS' and not modeval: | |
63 print 'Privilege not specified for SYS, assuming SYSOPER' | |
64 modeval = cx_Oracle.SYSOPER | |
65 try: | |
66 self.orcl = cx_Oracle.connect(orauser,orapass,oraserv,modeval) | |
0 | 67 self.curs = self.orcl.cursor() |
102 | 68 self.prompt = '%s@%s> ' % (orauser, sid) |
0 | 69 self.failoverSessions = [f for f in [fbs(arg) for fbs in pexpecter.available] if f.available] |
70 except Exception, e: | |
71 print e | |
102 | 72 |
0 | 73 |
74 def emptyline(self): | |
75 pass | |
76 | |
77 def fail(self, arg, do_everywhere=False): | |
78 if self.failover: | |
79 success, result = False, '' | |
80 for fbs in self.failoverSessions: | |
81 success, result = fbs.attempt(arg) | |
82 if success: | |
83 print result | |
84 if not do_everywhere: | |
85 return True | |
86 print result | |
87 return False | |
88 | |
89 def designated_session(self, arg, sesstype): | |
90 for fbs in self.failoverSessions: | |
91 if fbs.valid and fbs.__class__ == sesstype: | |
92 success, result = fbs.attempt(arg) | |
93 print result | |
94 return | |
95 print 'Valid %s not found' % (sesstype.__name__) | |
96 | |
97 def do_terminators(self, arg): | |
98 """; standard Oracle format | |
99 \\c CSV (with headings) | |
100 \\C CSV (no headings) | |
101 \\g list | |
102 \\G aligned list | |
103 \\h HTML table | |
104 \\i INSERT statements | |
105 \\s CSV (with headings) | |
106 \\S CSV (no headings) | |
107 \\t transposed | |
108 \\x XML""" | |
109 print self.do_terminators.__doc__ | |
110 | |
111 terminatorSearchString = '|'.join('\\' + d.split()[0] for d in do_terminators.__doc__.splitlines()) | |
112 | |
113 def do_yasql(self, arg): | |
114 '''Sends a command to a YASQL session (http://sourceforge.net/projects/yasql/)''' | |
115 self.designated_session(arg, pexpecter.YASQLSession) | |
116 do_y = do_yasql | |
117 def do_sqlplus(self, arg): | |
118 '''Sends a command to a SQL*Plus session''' | |
119 self.designated_session(arg, pexpecter.SqlPlusSession) | |
120 do_sqlp = do_sqlplus | |
121 def do_senora(self, arg): | |
122 '''Sends a command to a Senora session (http://senora.sourceforge.net/)''' | |
123 self.designated_session(arg, pexpecter.SenoraSession) | |
124 do_sen = do_senora | |
9
f70cc3be6377
reporting rowcount
devlinjs@FA7CZA6N1254998.wrightpatterson.afmc.ds.af.mil
parents:
3
diff
changeset
|
125 |
0 | 126 def default(self, arg, do_everywhere = False): |
55 | 127 self.query = self.finishStatement(arg).strip().rstrip(';') |
0 | 128 try: |
80 | 129 self.varsUsed = sqlpyPlus.findBinds(self.query, self.binds, givenBindVars={}) |
130 self.curs.execute(self.query, self.varsUsed) | |
9
f70cc3be6377
reporting rowcount
devlinjs@FA7CZA6N1254998.wrightpatterson.afmc.ds.af.mil
parents:
3
diff
changeset
|
131 print '\nExecuted%s\n' % ((self.curs.rowcount > 0) and ' (%d rows)' % self.curs.rowcount or '') |
0 | 132 if do_everywhere: |
133 self.fail(arg, do_everywhere = True ) | |
134 except Exception, e: | |
135 result = self.fail(arg) | |
136 if not result: | |
137 print str(e) | |
138 | |
139 def do_commit(self, arg): | |
67
d0bf9e40ba8d
eliminate double-semicolon on commit
catherine@DellZilla.myhome.westell.com
parents:
55
diff
changeset
|
140 self.default('commit %s;' % (arg), do_everywhere=True) |
0 | 141 def do_rollback(self, arg): |
67
d0bf9e40ba8d
eliminate double-semicolon on commit
catherine@DellZilla.myhome.westell.com
parents:
55
diff
changeset
|
142 self.default('rollback %s;' % (arg), do_everywhere=True) |
0 | 143 |
144 # shortcuts | |
92 | 145 do_exit = cmd2.Cmd.do_quit |
0 | 146 |
41
33c9bc61db66
separation surgery successful?
devlinjs@FA7CZA6N1254998.wrightpatterson.afmc.ds.af.mil
parents:
40
diff
changeset
|
147 stmtEndSearchString = r'(.*)(%s)\s*(\d+)?\s*$' % terminatorSearchString |
40
1fb9f7dee7d8
tearing out cmd2
devlinjs@FA7CZA6N1254998.wrightpatterson.afmc.ds.af.mil
parents:
16
diff
changeset
|
148 statementEndPattern = re.compile(stmtEndSearchString, re.MULTILINE | re.DOTALL) |
0 | 149 |
150 def pmatrix(rows,desc,maxlen=30): | |
151 '''prints a matrix, used by sqlpython to print queries' result sets''' | |
152 names = [] | |
153 maxen = [] | |
154 toprint = [] | |
155 for d in desc: | |
156 n = d[0] | |
157 names.append(n) # list col names | |
158 maxen.append(len(n)) # col length | |
159 rcols = range(len(desc)) | |
160 rrows = range(len(rows)) | |
161 for i in rrows: # loops for all rows | |
162 rowsi = map(str, rows[i]) # current row to process | |
163 split = [] # service var is row split is needed | |
164 mustsplit = 0 # flag | |
165 for j in rcols: | |
166 if str(desc[j][1]) == "<type 'cx_Oracle.BINARY'>": # handles RAW columns | |
80 | 167 rowsi[j] = binascii.b2a_hex(rowsi[j]) |
0 | 168 maxen[j] = max(maxen[j], len(rowsi[j])) # computes max field length |
169 if maxen[j] <= maxlen: | |
170 split.append('') | |
171 else: # split the line is 2 because field is too long | |
172 mustsplit = 1 | |
173 maxen[j] = maxlen | |
174 split.append(rowsi[j][maxlen-1:2*maxlen-1]) | |
175 rowsi[j] = rowsi[j][0:maxlen-1] # this implem. truncates after maxlen*2 | |
176 toprint.append(rowsi) # 'toprint' is a printable copy of rows | |
177 if mustsplit != 0: | |
178 toprint.append(split) | |
179 sepcols = [] | |
180 for i in rcols: | |
181 maxcol = maxen[i] | |
182 name = names[i] | |
183 sepcols.append("-" * maxcol) # formats column names (header) | |
184 names[i] = name + (" " * (maxcol-len(name))) # formats separ line with -- | |
185 rrows2 = range(len(toprint)) | |
186 for j in rrows2: | |
187 val = toprint[j][i] | |
188 if str(desc[i][1]) == "<type 'cx_Oracle.NUMBER'>": # right align numbers | |
189 toprint[j][i] = (" " * (maxcol-len(val))) + val | |
190 else: | |
191 toprint[j][i] = val + (" " * (maxcol-len(val))) | |
192 for j in rrows2: | |
193 toprint[j] = ' '.join(toprint[j]) | |
194 names = ' '.join(names) | |
195 sepcols = ' '.join(sepcols) | |
196 toprint.insert(0, sepcols) | |
197 toprint.insert(0, names) | |
198 return '\n'.join(toprint) | |
199 |