Mercurial > sqlpython
annotate sqlpython.py @ 80:83de0cb04f12
prevent crash on lone backslash
author | catherine@localhost |
---|---|
date | Wed, 14 May 2008 17:23:52 -0400 |
parents | d0bf9e40ba8d |
children | fa8c9eb8908f |
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 do_quit(self, arg): | |
51 return 1 | |
52 | |
53 def fail(self, arg, do_everywhere=False): | |
54 if self.failover: | |
55 success, result = False, '' | |
56 for fbs in self.failoverSessions: | |
57 success, result = fbs.attempt(arg) | |
58 if success: | |
59 print result | |
60 if not do_everywhere: | |
61 return True | |
62 print result | |
63 return False | |
64 | |
65 def designated_session(self, arg, sesstype): | |
66 for fbs in self.failoverSessions: | |
67 if fbs.valid and fbs.__class__ == sesstype: | |
68 success, result = fbs.attempt(arg) | |
69 print result | |
70 return | |
71 print 'Valid %s not found' % (sesstype.__name__) | |
72 | |
73 def do_terminators(self, arg): | |
74 """; standard Oracle format | |
75 \\c CSV (with headings) | |
76 \\C CSV (no headings) | |
77 \\g list | |
78 \\G aligned list | |
79 \\h HTML table | |
80 \\i INSERT statements | |
81 \\s CSV (with headings) | |
82 \\S CSV (no headings) | |
83 \\t transposed | |
84 \\x XML""" | |
85 print self.do_terminators.__doc__ | |
86 | |
87 terminatorSearchString = '|'.join('\\' + d.split()[0] for d in do_terminators.__doc__.splitlines()) | |
88 | |
89 def do_yasql(self, arg): | |
90 '''Sends a command to a YASQL session (http://sourceforge.net/projects/yasql/)''' | |
91 self.designated_session(arg, pexpecter.YASQLSession) | |
92 do_y = do_yasql | |
93 def do_sqlplus(self, arg): | |
94 '''Sends a command to a SQL*Plus session''' | |
95 self.designated_session(arg, pexpecter.SqlPlusSession) | |
96 do_sqlp = do_sqlplus | |
97 def do_senora(self, arg): | |
98 '''Sends a command to a Senora session (http://senora.sourceforge.net/)''' | |
99 self.designated_session(arg, pexpecter.SenoraSession) | |
100 do_sen = do_senora | |
9
f70cc3be6377
reporting rowcount
devlinjs@FA7CZA6N1254998.wrightpatterson.afmc.ds.af.mil
parents:
3
diff
changeset
|
101 |
0 | 102 def default(self, arg, do_everywhere = False): |
55 | 103 self.query = self.finishStatement(arg).strip().rstrip(';') |
0 | 104 try: |
80 | 105 self.varsUsed = sqlpyPlus.findBinds(self.query, self.binds, givenBindVars={}) |
106 self.curs.execute(self.query, self.varsUsed) | |
9
f70cc3be6377
reporting rowcount
devlinjs@FA7CZA6N1254998.wrightpatterson.afmc.ds.af.mil
parents:
3
diff
changeset
|
107 print '\nExecuted%s\n' % ((self.curs.rowcount > 0) and ' (%d rows)' % self.curs.rowcount or '') |
0 | 108 if do_everywhere: |
109 self.fail(arg, do_everywhere = True ) | |
110 except Exception, e: | |
111 result = self.fail(arg) | |
112 if not result: | |
113 print str(e) | |
114 | |
115 def do_commit(self, arg): | |
67
d0bf9e40ba8d
eliminate double-semicolon on commit
catherine@DellZilla.myhome.westell.com
parents:
55
diff
changeset
|
116 self.default('commit %s;' % (arg), do_everywhere=True) |
0 | 117 def do_rollback(self, arg): |
67
d0bf9e40ba8d
eliminate double-semicolon on commit
catherine@DellZilla.myhome.westell.com
parents:
55
diff
changeset
|
118 self.default('rollback %s;' % (arg), do_everywhere=True) |
0 | 119 |
120 # shortcuts | |
121 do_q = do_quit | |
122 do_exit = do_quit | |
123 | |
41
33c9bc61db66
separation surgery successful?
devlinjs@FA7CZA6N1254998.wrightpatterson.afmc.ds.af.mil
parents:
40
diff
changeset
|
124 stmtEndSearchString = r'(.*)(%s)\s*(\d+)?\s*$' % terminatorSearchString |
40
1fb9f7dee7d8
tearing out cmd2
devlinjs@FA7CZA6N1254998.wrightpatterson.afmc.ds.af.mil
parents:
16
diff
changeset
|
125 statementEndPattern = re.compile(stmtEndSearchString, re.MULTILINE | re.DOTALL) |
0 | 126 |
127 def pmatrix(rows,desc,maxlen=30): | |
128 '''prints a matrix, used by sqlpython to print queries' result sets''' | |
129 names = [] | |
130 maxen = [] | |
131 toprint = [] | |
132 for d in desc: | |
133 n = d[0] | |
134 names.append(n) # list col names | |
135 maxen.append(len(n)) # col length | |
136 rcols = range(len(desc)) | |
137 rrows = range(len(rows)) | |
138 for i in rrows: # loops for all rows | |
139 rowsi = map(str, rows[i]) # current row to process | |
140 split = [] # service var is row split is needed | |
141 mustsplit = 0 # flag | |
142 for j in rcols: | |
143 if str(desc[j][1]) == "<type 'cx_Oracle.BINARY'>": # handles RAW columns | |
80 | 144 rowsi[j] = binascii.b2a_hex(rowsi[j]) |
0 | 145 maxen[j] = max(maxen[j], len(rowsi[j])) # computes max field length |
146 if maxen[j] <= maxlen: | |
147 split.append('') | |
148 else: # split the line is 2 because field is too long | |
149 mustsplit = 1 | |
150 maxen[j] = maxlen | |
151 split.append(rowsi[j][maxlen-1:2*maxlen-1]) | |
152 rowsi[j] = rowsi[j][0:maxlen-1] # this implem. truncates after maxlen*2 | |
153 toprint.append(rowsi) # 'toprint' is a printable copy of rows | |
154 if mustsplit != 0: | |
155 toprint.append(split) | |
156 sepcols = [] | |
157 for i in rcols: | |
158 maxcol = maxen[i] | |
159 name = names[i] | |
160 sepcols.append("-" * maxcol) # formats column names (header) | |
161 names[i] = name + (" " * (maxcol-len(name))) # formats separ line with -- | |
162 rrows2 = range(len(toprint)) | |
163 for j in rrows2: | |
164 val = toprint[j][i] | |
165 if str(desc[i][1]) == "<type 'cx_Oracle.NUMBER'>": # right align numbers | |
166 toprint[j][i] = (" " * (maxcol-len(val))) + val | |
167 else: | |
168 toprint[j][i] = val + (" " * (maxcol-len(val))) | |
169 for j in rrows2: | |
170 toprint[j] = ' '.join(toprint[j]) | |
171 names = ' '.join(names) | |
172 sepcols = ' '.join(sepcols) | |
173 toprint.insert(0, sepcols) | |
174 toprint.insert(0, names) | |
175 return '\n'.join(toprint) | |
176 |