Mercurial > sqlpython
annotate sqlpython.py @ 79:01d578f4e6e7
prevent crash when pull unresolved
author | catherine@DellZilla.myhome.westell.com |
---|---|
date | Mon, 28 Apr 2008 12:20:53 -0400 |
parents | d0bf9e40ba8d |
children | 83de0cb04f12 |
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 |
0 | 12 import pexpecter |
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: |
105 self.curs.execute(self.query) | |
9
f70cc3be6377
reporting rowcount
devlinjs@FA7CZA6N1254998.wrightpatterson.afmc.ds.af.mil
parents:
3
diff
changeset
|
106 print '\nExecuted%s\n' % ((self.curs.rowcount > 0) and ' (%d rows)' % self.curs.rowcount or '') |
0 | 107 if do_everywhere: |
108 self.fail(arg, do_everywhere = True ) | |
109 except Exception, e: | |
110 result = self.fail(arg) | |
111 if not result: | |
112 print str(e) | |
113 | |
114 def do_commit(self, arg): | |
67
d0bf9e40ba8d
eliminate double-semicolon on commit
catherine@DellZilla.myhome.westell.com
parents:
55
diff
changeset
|
115 self.default('commit %s;' % (arg), do_everywhere=True) |
0 | 116 def do_rollback(self, arg): |
67
d0bf9e40ba8d
eliminate double-semicolon on commit
catherine@DellZilla.myhome.westell.com
parents:
55
diff
changeset
|
117 self.default('rollback %s;' % (arg), do_everywhere=True) |
0 | 118 |
119 # shortcuts | |
120 do_q = do_quit | |
121 do_exit = do_quit | |
122 | |
41
33c9bc61db66
separation surgery successful?
devlinjs@FA7CZA6N1254998.wrightpatterson.afmc.ds.af.mil
parents:
40
diff
changeset
|
123 stmtEndSearchString = r'(.*)(%s)\s*(\d+)?\s*$' % terminatorSearchString |
40
1fb9f7dee7d8
tearing out cmd2
devlinjs@FA7CZA6N1254998.wrightpatterson.afmc.ds.af.mil
parents:
16
diff
changeset
|
124 statementEndPattern = re.compile(stmtEndSearchString, re.MULTILINE | re.DOTALL) |
0 | 125 |
126 def pmatrix(rows,desc,maxlen=30): | |
127 '''prints a matrix, used by sqlpython to print queries' result sets''' | |
128 names = [] | |
129 maxen = [] | |
130 toprint = [] | |
131 for d in desc: | |
132 n = d[0] | |
133 names.append(n) # list col names | |
134 maxen.append(len(n)) # col length | |
135 rcols = range(len(desc)) | |
136 rrows = range(len(rows)) | |
137 for i in rrows: # loops for all rows | |
138 rowsi = map(str, rows[i]) # current row to process | |
139 split = [] # service var is row split is needed | |
140 mustsplit = 0 # flag | |
141 for j in rcols: | |
142 if str(desc[j][1]) == "<type 'cx_Oracle.BINARY'>": # handles RAW columns | |
143 rowsi[j] = binascii.b2a_hex(rowsi[j]) | |
144 maxen[j] = max(maxen[j], len(rowsi[j])) # computes max field length | |
145 if maxen[j] <= maxlen: | |
146 split.append('') | |
147 else: # split the line is 2 because field is too long | |
148 mustsplit = 1 | |
149 maxen[j] = maxlen | |
150 split.append(rowsi[j][maxlen-1:2*maxlen-1]) | |
151 rowsi[j] = rowsi[j][0:maxlen-1] # this implem. truncates after maxlen*2 | |
152 toprint.append(rowsi) # 'toprint' is a printable copy of rows | |
153 if mustsplit != 0: | |
154 toprint.append(split) | |
155 sepcols = [] | |
156 for i in rcols: | |
157 maxcol = maxen[i] | |
158 name = names[i] | |
159 sepcols.append("-" * maxcol) # formats column names (header) | |
160 names[i] = name + (" " * (maxcol-len(name))) # formats separ line with -- | |
161 rrows2 = range(len(toprint)) | |
162 for j in rrows2: | |
163 val = toprint[j][i] | |
164 if str(desc[i][1]) == "<type 'cx_Oracle.NUMBER'>": # right align numbers | |
165 toprint[j][i] = (" " * (maxcol-len(val))) + val | |
166 else: | |
167 toprint[j][i] = val + (" " * (maxcol-len(val))) | |
168 for j in rrows2: | |
169 toprint[j] = ' '.join(toprint[j]) | |
170 names = ' '.join(names) | |
171 sepcols = ' '.join(sepcols) | |
172 toprint.insert(0, sepcols) | |
173 toprint.insert(0, names) | |
174 return '\n'.join(toprint) | |
175 |