1*031c2a00SAdrian Hunter#!/usr/bin/python2 2*031c2a00SAdrian Hunter# SPDX-License-Identifier: GPL-2.0 3*031c2a00SAdrian Hunter# exported-sql-viewer.py: view data from sql database 4*031c2a00SAdrian Hunter# Copyright (c) 2014-2018, Intel Corporation. 5*031c2a00SAdrian Hunter 6*031c2a00SAdrian Hunter# To use this script you will need to have exported data using either the 7*031c2a00SAdrian Hunter# export-to-sqlite.py or the export-to-postgresql.py script. Refer to those 8*031c2a00SAdrian Hunter# scripts for details. 9*031c2a00SAdrian Hunter# 10*031c2a00SAdrian Hunter# Following on from the example in the export scripts, a 11*031c2a00SAdrian Hunter# call-graph can be displayed for the pt_example database like this: 12*031c2a00SAdrian Hunter# 13*031c2a00SAdrian Hunter# python tools/perf/scripts/python/exported-sql-viewer.py pt_example 14*031c2a00SAdrian Hunter# 15*031c2a00SAdrian Hunter# Note that for PostgreSQL, this script supports connecting to remote databases 16*031c2a00SAdrian Hunter# by setting hostname, port, username, password, and dbname e.g. 17*031c2a00SAdrian Hunter# 18*031c2a00SAdrian Hunter# python tools/perf/scripts/python/exported-sql-viewer.py "hostname=myhost username=myuser password=mypassword dbname=pt_example" 19*031c2a00SAdrian Hunter# 20*031c2a00SAdrian Hunter# The result is a GUI window with a tree representing a context-sensitive 21*031c2a00SAdrian Hunter# call-graph. Expanding a couple of levels of the tree and adjusting column 22*031c2a00SAdrian Hunter# widths to suit will display something like: 23*031c2a00SAdrian Hunter# 24*031c2a00SAdrian Hunter# Call Graph: pt_example 25*031c2a00SAdrian Hunter# Call Path Object Count Time(ns) Time(%) Branch Count Branch Count(%) 26*031c2a00SAdrian Hunter# v- ls 27*031c2a00SAdrian Hunter# v- 2638:2638 28*031c2a00SAdrian Hunter# v- _start ld-2.19.so 1 10074071 100.0 211135 100.0 29*031c2a00SAdrian Hunter# |- unknown unknown 1 13198 0.1 1 0.0 30*031c2a00SAdrian Hunter# >- _dl_start ld-2.19.so 1 1400980 13.9 19637 9.3 31*031c2a00SAdrian Hunter# >- _d_linit_internal ld-2.19.so 1 448152 4.4 11094 5.3 32*031c2a00SAdrian Hunter# v-__libc_start_main@plt ls 1 8211741 81.5 180397 85.4 33*031c2a00SAdrian Hunter# >- _dl_fixup ld-2.19.so 1 7607 0.1 108 0.1 34*031c2a00SAdrian Hunter# >- __cxa_atexit libc-2.19.so 1 11737 0.1 10 0.0 35*031c2a00SAdrian Hunter# >- __libc_csu_init ls 1 10354 0.1 10 0.0 36*031c2a00SAdrian Hunter# |- _setjmp libc-2.19.so 1 0 0.0 4 0.0 37*031c2a00SAdrian Hunter# v- main ls 1 8182043 99.6 180254 99.9 38*031c2a00SAdrian Hunter# 39*031c2a00SAdrian Hunter# Points to note: 40*031c2a00SAdrian Hunter# The top level is a command name (comm) 41*031c2a00SAdrian Hunter# The next level is a thread (pid:tid) 42*031c2a00SAdrian Hunter# Subsequent levels are functions 43*031c2a00SAdrian Hunter# 'Count' is the number of calls 44*031c2a00SAdrian Hunter# 'Time' is the elapsed time until the function returns 45*031c2a00SAdrian Hunter# Percentages are relative to the level above 46*031c2a00SAdrian Hunter# 'Branch Count' is the total number of branches for that function and all 47*031c2a00SAdrian Hunter# functions that it calls 48*031c2a00SAdrian Hunter 49*031c2a00SAdrian Hunterimport sys 50*031c2a00SAdrian Hunterfrom PySide.QtCore import * 51*031c2a00SAdrian Hunterfrom PySide.QtGui import * 52*031c2a00SAdrian Hunterfrom PySide.QtSql import * 53*031c2a00SAdrian Hunterfrom decimal import * 54*031c2a00SAdrian Hunter 55*031c2a00SAdrian Hunter# Data formatting helpers 56*031c2a00SAdrian Hunter 57*031c2a00SAdrian Hunterdef dsoname(name): 58*031c2a00SAdrian Hunter if name == "[kernel.kallsyms]": 59*031c2a00SAdrian Hunter return "[kernel]" 60*031c2a00SAdrian Hunter return name 61*031c2a00SAdrian Hunter 62*031c2a00SAdrian Hunter# Percent to one decimal place 63*031c2a00SAdrian Hunter 64*031c2a00SAdrian Hunterdef PercentToOneDP(n, d): 65*031c2a00SAdrian Hunter if not d: 66*031c2a00SAdrian Hunter return "0.0" 67*031c2a00SAdrian Hunter x = (n * Decimal(100)) / d 68*031c2a00SAdrian Hunter return str(x.quantize(Decimal(".1"), rounding=ROUND_HALF_UP)) 69*031c2a00SAdrian Hunter 70*031c2a00SAdrian Hunter# Helper for queries that must not fail 71*031c2a00SAdrian Hunter 72*031c2a00SAdrian Hunterdef QueryExec(query, stmt): 73*031c2a00SAdrian Hunter ret = query.exec_(stmt) 74*031c2a00SAdrian Hunter if not ret: 75*031c2a00SAdrian Hunter raise Exception("Query failed: " + query.lastError().text()) 76*031c2a00SAdrian Hunter 77*031c2a00SAdrian Hunter# Tree data model 78*031c2a00SAdrian Hunter 79*031c2a00SAdrian Hunterclass TreeModel(QAbstractItemModel): 80*031c2a00SAdrian Hunter 81*031c2a00SAdrian Hunter def __init__(self, root, parent=None): 82*031c2a00SAdrian Hunter super(TreeModel, self).__init__(parent) 83*031c2a00SAdrian Hunter self.root = root 84*031c2a00SAdrian Hunter self.last_row_read = 0 85*031c2a00SAdrian Hunter 86*031c2a00SAdrian Hunter def Item(self, parent): 87*031c2a00SAdrian Hunter if parent.isValid(): 88*031c2a00SAdrian Hunter return parent.internalPointer() 89*031c2a00SAdrian Hunter else: 90*031c2a00SAdrian Hunter return self.root 91*031c2a00SAdrian Hunter 92*031c2a00SAdrian Hunter def rowCount(self, parent): 93*031c2a00SAdrian Hunter result = self.Item(parent).childCount() 94*031c2a00SAdrian Hunter if result < 0: 95*031c2a00SAdrian Hunter result = 0 96*031c2a00SAdrian Hunter self.dataChanged.emit(parent, parent) 97*031c2a00SAdrian Hunter return result 98*031c2a00SAdrian Hunter 99*031c2a00SAdrian Hunter def hasChildren(self, parent): 100*031c2a00SAdrian Hunter return self.Item(parent).hasChildren() 101*031c2a00SAdrian Hunter 102*031c2a00SAdrian Hunter def headerData(self, section, orientation, role): 103*031c2a00SAdrian Hunter if role == Qt.TextAlignmentRole: 104*031c2a00SAdrian Hunter return self.columnAlignment(section) 105*031c2a00SAdrian Hunter if role != Qt.DisplayRole: 106*031c2a00SAdrian Hunter return None 107*031c2a00SAdrian Hunter if orientation != Qt.Horizontal: 108*031c2a00SAdrian Hunter return None 109*031c2a00SAdrian Hunter return self.columnHeader(section) 110*031c2a00SAdrian Hunter 111*031c2a00SAdrian Hunter def parent(self, child): 112*031c2a00SAdrian Hunter child_item = child.internalPointer() 113*031c2a00SAdrian Hunter if child_item is self.root: 114*031c2a00SAdrian Hunter return QModelIndex() 115*031c2a00SAdrian Hunter parent_item = child_item.getParentItem() 116*031c2a00SAdrian Hunter return self.createIndex(parent_item.getRow(), 0, parent_item) 117*031c2a00SAdrian Hunter 118*031c2a00SAdrian Hunter def index(self, row, column, parent): 119*031c2a00SAdrian Hunter child_item = self.Item(parent).getChildItem(row) 120*031c2a00SAdrian Hunter return self.createIndex(row, column, child_item) 121*031c2a00SAdrian Hunter 122*031c2a00SAdrian Hunter def DisplayData(self, item, index): 123*031c2a00SAdrian Hunter return item.getData(index.column()) 124*031c2a00SAdrian Hunter 125*031c2a00SAdrian Hunter def columnAlignment(self, column): 126*031c2a00SAdrian Hunter return Qt.AlignLeft 127*031c2a00SAdrian Hunter 128*031c2a00SAdrian Hunter def columnFont(self, column): 129*031c2a00SAdrian Hunter return None 130*031c2a00SAdrian Hunter 131*031c2a00SAdrian Hunter def data(self, index, role): 132*031c2a00SAdrian Hunter if role == Qt.TextAlignmentRole: 133*031c2a00SAdrian Hunter return self.columnAlignment(index.column()) 134*031c2a00SAdrian Hunter if role == Qt.FontRole: 135*031c2a00SAdrian Hunter return self.columnFont(index.column()) 136*031c2a00SAdrian Hunter if role != Qt.DisplayRole: 137*031c2a00SAdrian Hunter return None 138*031c2a00SAdrian Hunter item = index.internalPointer() 139*031c2a00SAdrian Hunter return self.DisplayData(item, index) 140*031c2a00SAdrian Hunter 141*031c2a00SAdrian Hunter# Context-sensitive call graph data model item base 142*031c2a00SAdrian Hunter 143*031c2a00SAdrian Hunterclass CallGraphLevelItemBase(object): 144*031c2a00SAdrian Hunter 145*031c2a00SAdrian Hunter def __init__(self, glb, row, parent_item): 146*031c2a00SAdrian Hunter self.glb = glb 147*031c2a00SAdrian Hunter self.row = row 148*031c2a00SAdrian Hunter self.parent_item = parent_item 149*031c2a00SAdrian Hunter self.query_done = False; 150*031c2a00SAdrian Hunter self.child_count = 0 151*031c2a00SAdrian Hunter self.child_items = [] 152*031c2a00SAdrian Hunter 153*031c2a00SAdrian Hunter def getChildItem(self, row): 154*031c2a00SAdrian Hunter return self.child_items[row] 155*031c2a00SAdrian Hunter 156*031c2a00SAdrian Hunter def getParentItem(self): 157*031c2a00SAdrian Hunter return self.parent_item 158*031c2a00SAdrian Hunter 159*031c2a00SAdrian Hunter def getRow(self): 160*031c2a00SAdrian Hunter return self.row 161*031c2a00SAdrian Hunter 162*031c2a00SAdrian Hunter def childCount(self): 163*031c2a00SAdrian Hunter if not self.query_done: 164*031c2a00SAdrian Hunter self.Select() 165*031c2a00SAdrian Hunter if not self.child_count: 166*031c2a00SAdrian Hunter return -1 167*031c2a00SAdrian Hunter return self.child_count 168*031c2a00SAdrian Hunter 169*031c2a00SAdrian Hunter def hasChildren(self): 170*031c2a00SAdrian Hunter if not self.query_done: 171*031c2a00SAdrian Hunter return True 172*031c2a00SAdrian Hunter return self.child_count > 0 173*031c2a00SAdrian Hunter 174*031c2a00SAdrian Hunter def getData(self, column): 175*031c2a00SAdrian Hunter return self.data[column] 176*031c2a00SAdrian Hunter 177*031c2a00SAdrian Hunter# Context-sensitive call graph data model level 2+ item base 178*031c2a00SAdrian Hunter 179*031c2a00SAdrian Hunterclass CallGraphLevelTwoPlusItemBase(CallGraphLevelItemBase): 180*031c2a00SAdrian Hunter 181*031c2a00SAdrian Hunter def __init__(self, glb, row, comm_id, thread_id, call_path_id, time, branch_count, parent_item): 182*031c2a00SAdrian Hunter super(CallGraphLevelTwoPlusItemBase, self).__init__(glb, row, parent_item) 183*031c2a00SAdrian Hunter self.comm_id = comm_id 184*031c2a00SAdrian Hunter self.thread_id = thread_id 185*031c2a00SAdrian Hunter self.call_path_id = call_path_id 186*031c2a00SAdrian Hunter self.branch_count = branch_count 187*031c2a00SAdrian Hunter self.time = time 188*031c2a00SAdrian Hunter 189*031c2a00SAdrian Hunter def Select(self): 190*031c2a00SAdrian Hunter self.query_done = True; 191*031c2a00SAdrian Hunter query = QSqlQuery(self.glb.db) 192*031c2a00SAdrian Hunter QueryExec(query, "SELECT call_path_id, name, short_name, COUNT(calls.id), SUM(return_time - call_time), SUM(branch_count)" 193*031c2a00SAdrian Hunter " FROM calls" 194*031c2a00SAdrian Hunter " INNER JOIN call_paths ON calls.call_path_id = call_paths.id" 195*031c2a00SAdrian Hunter " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" 196*031c2a00SAdrian Hunter " INNER JOIN dsos ON symbols.dso_id = dsos.id" 197*031c2a00SAdrian Hunter " WHERE parent_call_path_id = " + str(self.call_path_id) + 198*031c2a00SAdrian Hunter " AND comm_id = " + str(self.comm_id) + 199*031c2a00SAdrian Hunter " AND thread_id = " + str(self.thread_id) + 200*031c2a00SAdrian Hunter " GROUP BY call_path_id, name, short_name" 201*031c2a00SAdrian Hunter " ORDER BY call_path_id") 202*031c2a00SAdrian Hunter while query.next(): 203*031c2a00SAdrian Hunter child_item = CallGraphLevelThreeItem(self.glb, self.child_count, self.comm_id, self.thread_id, query.value(0), query.value(1), query.value(2), query.value(3), int(query.value(4)), int(query.value(5)), self) 204*031c2a00SAdrian Hunter self.child_items.append(child_item) 205*031c2a00SAdrian Hunter self.child_count += 1 206*031c2a00SAdrian Hunter 207*031c2a00SAdrian Hunter# Context-sensitive call graph data model level three item 208*031c2a00SAdrian Hunter 209*031c2a00SAdrian Hunterclass CallGraphLevelThreeItem(CallGraphLevelTwoPlusItemBase): 210*031c2a00SAdrian Hunter 211*031c2a00SAdrian Hunter def __init__(self, glb, row, comm_id, thread_id, call_path_id, name, dso, count, time, branch_count, parent_item): 212*031c2a00SAdrian Hunter super(CallGraphLevelThreeItem, self).__init__(glb, row, comm_id, thread_id, call_path_id, time, branch_count, parent_item) 213*031c2a00SAdrian Hunter dso = dsoname(dso) 214*031c2a00SAdrian Hunter self.data = [ name, dso, str(count), str(time), PercentToOneDP(time, parent_item.time), str(branch_count), PercentToOneDP(branch_count, parent_item.branch_count) ] 215*031c2a00SAdrian Hunter self.dbid = call_path_id 216*031c2a00SAdrian Hunter 217*031c2a00SAdrian Hunter# Context-sensitive call graph data model level two item 218*031c2a00SAdrian Hunter 219*031c2a00SAdrian Hunterclass CallGraphLevelTwoItem(CallGraphLevelTwoPlusItemBase): 220*031c2a00SAdrian Hunter 221*031c2a00SAdrian Hunter def __init__(self, glb, row, comm_id, thread_id, pid, tid, parent_item): 222*031c2a00SAdrian Hunter super(CallGraphLevelTwoItem, self).__init__(glb, row, comm_id, thread_id, 1, 0, 0, parent_item) 223*031c2a00SAdrian Hunter self.data = [str(pid) + ":" + str(tid), "", "", "", "", "", ""] 224*031c2a00SAdrian Hunter self.dbid = thread_id 225*031c2a00SAdrian Hunter 226*031c2a00SAdrian Hunter def Select(self): 227*031c2a00SAdrian Hunter super(CallGraphLevelTwoItem, self).Select() 228*031c2a00SAdrian Hunter for child_item in self.child_items: 229*031c2a00SAdrian Hunter self.time += child_item.time 230*031c2a00SAdrian Hunter self.branch_count += child_item.branch_count 231*031c2a00SAdrian Hunter for child_item in self.child_items: 232*031c2a00SAdrian Hunter child_item.data[4] = PercentToOneDP(child_item.time, self.time) 233*031c2a00SAdrian Hunter child_item.data[6] = PercentToOneDP(child_item.branch_count, self.branch_count) 234*031c2a00SAdrian Hunter 235*031c2a00SAdrian Hunter# Context-sensitive call graph data model level one item 236*031c2a00SAdrian Hunter 237*031c2a00SAdrian Hunterclass CallGraphLevelOneItem(CallGraphLevelItemBase): 238*031c2a00SAdrian Hunter 239*031c2a00SAdrian Hunter def __init__(self, glb, row, comm_id, comm, parent_item): 240*031c2a00SAdrian Hunter super(CallGraphLevelOneItem, self).__init__(glb, row, parent_item) 241*031c2a00SAdrian Hunter self.data = [comm, "", "", "", "", "", ""] 242*031c2a00SAdrian Hunter self.dbid = comm_id 243*031c2a00SAdrian Hunter 244*031c2a00SAdrian Hunter def Select(self): 245*031c2a00SAdrian Hunter self.query_done = True; 246*031c2a00SAdrian Hunter query = QSqlQuery(self.glb.db) 247*031c2a00SAdrian Hunter QueryExec(query, "SELECT thread_id, pid, tid" 248*031c2a00SAdrian Hunter " FROM comm_threads" 249*031c2a00SAdrian Hunter " INNER JOIN threads ON thread_id = threads.id" 250*031c2a00SAdrian Hunter " WHERE comm_id = " + str(self.dbid)) 251*031c2a00SAdrian Hunter while query.next(): 252*031c2a00SAdrian Hunter child_item = CallGraphLevelTwoItem(self.glb, self.child_count, self.dbid, query.value(0), query.value(1), query.value(2), self) 253*031c2a00SAdrian Hunter self.child_items.append(child_item) 254*031c2a00SAdrian Hunter self.child_count += 1 255*031c2a00SAdrian Hunter 256*031c2a00SAdrian Hunter# Context-sensitive call graph data model root item 257*031c2a00SAdrian Hunter 258*031c2a00SAdrian Hunterclass CallGraphRootItem(CallGraphLevelItemBase): 259*031c2a00SAdrian Hunter 260*031c2a00SAdrian Hunter def __init__(self, glb): 261*031c2a00SAdrian Hunter super(CallGraphRootItem, self).__init__(glb, 0, None) 262*031c2a00SAdrian Hunter self.dbid = 0 263*031c2a00SAdrian Hunter self.query_done = True; 264*031c2a00SAdrian Hunter query = QSqlQuery(glb.db) 265*031c2a00SAdrian Hunter QueryExec(query, "SELECT id, comm FROM comms") 266*031c2a00SAdrian Hunter while query.next(): 267*031c2a00SAdrian Hunter if not query.value(0): 268*031c2a00SAdrian Hunter continue 269*031c2a00SAdrian Hunter child_item = CallGraphLevelOneItem(glb, self.child_count, query.value(0), query.value(1), self) 270*031c2a00SAdrian Hunter self.child_items.append(child_item) 271*031c2a00SAdrian Hunter self.child_count += 1 272*031c2a00SAdrian Hunter 273*031c2a00SAdrian Hunter# Context-sensitive call graph data model 274*031c2a00SAdrian Hunter 275*031c2a00SAdrian Hunterclass CallGraphModel(TreeModel): 276*031c2a00SAdrian Hunter 277*031c2a00SAdrian Hunter def __init__(self, glb, parent=None): 278*031c2a00SAdrian Hunter super(CallGraphModel, self).__init__(CallGraphRootItem(glb), parent) 279*031c2a00SAdrian Hunter self.glb = glb 280*031c2a00SAdrian Hunter 281*031c2a00SAdrian Hunter def columnCount(self, parent=None): 282*031c2a00SAdrian Hunter return 7 283*031c2a00SAdrian Hunter 284*031c2a00SAdrian Hunter def columnHeader(self, column): 285*031c2a00SAdrian Hunter headers = ["Call Path", "Object", "Count ", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "] 286*031c2a00SAdrian Hunter return headers[column] 287*031c2a00SAdrian Hunter 288*031c2a00SAdrian Hunter def columnAlignment(self, column): 289*031c2a00SAdrian Hunter alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ] 290*031c2a00SAdrian Hunter return alignment[column] 291*031c2a00SAdrian Hunter 292*031c2a00SAdrian Hunter# Main window 293*031c2a00SAdrian Hunter 294*031c2a00SAdrian Hunterclass MainWindow(QMainWindow): 295*031c2a00SAdrian Hunter 296*031c2a00SAdrian Hunter def __init__(self, glb, parent=None): 297*031c2a00SAdrian Hunter super(MainWindow, self).__init__(parent) 298*031c2a00SAdrian Hunter 299*031c2a00SAdrian Hunter self.glb = glb 300*031c2a00SAdrian Hunter 301*031c2a00SAdrian Hunter self.setWindowTitle("Call Graph: " + glb.dbname) 302*031c2a00SAdrian Hunter self.move(100, 100) 303*031c2a00SAdrian Hunter self.resize(800, 600) 304*031c2a00SAdrian Hunter self.setWindowIcon(self.style().standardIcon(QStyle.SP_ComputerIcon)) 305*031c2a00SAdrian Hunter self.setMinimumSize(200, 100) 306*031c2a00SAdrian Hunter 307*031c2a00SAdrian Hunter self.model = CallGraphModel(glb) 308*031c2a00SAdrian Hunter 309*031c2a00SAdrian Hunter self.view = QTreeView() 310*031c2a00SAdrian Hunter self.view.setModel(self.model) 311*031c2a00SAdrian Hunter 312*031c2a00SAdrian Hunter for c, w in ((0, 250), (1, 100), (2, 60), (3, 70), (4, 70), (5, 100)): 313*031c2a00SAdrian Hunter self.view.setColumnWidth(c, w) 314*031c2a00SAdrian Hunter 315*031c2a00SAdrian Hunter self.setCentralWidget(self.view) 316*031c2a00SAdrian Hunter 317*031c2a00SAdrian Hunter# Global data 318*031c2a00SAdrian Hunter 319*031c2a00SAdrian Hunterclass Glb(): 320*031c2a00SAdrian Hunter 321*031c2a00SAdrian Hunter def __init__(self, dbref, db, dbname): 322*031c2a00SAdrian Hunter self.dbref = dbref 323*031c2a00SAdrian Hunter self.db = db 324*031c2a00SAdrian Hunter self.dbname = dbname 325*031c2a00SAdrian Hunter self.app = None 326*031c2a00SAdrian Hunter self.mainwindow = None 327*031c2a00SAdrian Hunter 328*031c2a00SAdrian Hunter# Database reference 329*031c2a00SAdrian Hunter 330*031c2a00SAdrian Hunterclass DBRef(): 331*031c2a00SAdrian Hunter 332*031c2a00SAdrian Hunter def __init__(self, is_sqlite3, dbname): 333*031c2a00SAdrian Hunter self.is_sqlite3 = is_sqlite3 334*031c2a00SAdrian Hunter self.dbname = dbname 335*031c2a00SAdrian Hunter 336*031c2a00SAdrian Hunter def Open(self, connection_name): 337*031c2a00SAdrian Hunter dbname = self.dbname 338*031c2a00SAdrian Hunter if self.is_sqlite3: 339*031c2a00SAdrian Hunter db = QSqlDatabase.addDatabase("QSQLITE", connection_name) 340*031c2a00SAdrian Hunter else: 341*031c2a00SAdrian Hunter db = QSqlDatabase.addDatabase("QPSQL", connection_name) 342*031c2a00SAdrian Hunter opts = dbname.split() 343*031c2a00SAdrian Hunter for opt in opts: 344*031c2a00SAdrian Hunter if "=" in opt: 345*031c2a00SAdrian Hunter opt = opt.split("=") 346*031c2a00SAdrian Hunter if opt[0] == "hostname": 347*031c2a00SAdrian Hunter db.setHostName(opt[1]) 348*031c2a00SAdrian Hunter elif opt[0] == "port": 349*031c2a00SAdrian Hunter db.setPort(int(opt[1])) 350*031c2a00SAdrian Hunter elif opt[0] == "username": 351*031c2a00SAdrian Hunter db.setUserName(opt[1]) 352*031c2a00SAdrian Hunter elif opt[0] == "password": 353*031c2a00SAdrian Hunter db.setPassword(opt[1]) 354*031c2a00SAdrian Hunter elif opt[0] == "dbname": 355*031c2a00SAdrian Hunter dbname = opt[1] 356*031c2a00SAdrian Hunter else: 357*031c2a00SAdrian Hunter dbname = opt 358*031c2a00SAdrian Hunter 359*031c2a00SAdrian Hunter db.setDatabaseName(dbname) 360*031c2a00SAdrian Hunter if not db.open(): 361*031c2a00SAdrian Hunter raise Exception("Failed to open database " + dbname + " error: " + db.lastError().text()) 362*031c2a00SAdrian Hunter return db, dbname 363*031c2a00SAdrian Hunter 364*031c2a00SAdrian Hunter# Main 365*031c2a00SAdrian Hunter 366*031c2a00SAdrian Hunterdef Main(): 367*031c2a00SAdrian Hunter if (len(sys.argv) < 2): 368*031c2a00SAdrian Hunter print >> sys.stderr, "Usage is: exported-sql-viewer.py <database name>" 369*031c2a00SAdrian Hunter raise Exception("Too few arguments") 370*031c2a00SAdrian Hunter 371*031c2a00SAdrian Hunter dbname = sys.argv[1] 372*031c2a00SAdrian Hunter 373*031c2a00SAdrian Hunter is_sqlite3 = False 374*031c2a00SAdrian Hunter try: 375*031c2a00SAdrian Hunter f = open(dbname) 376*031c2a00SAdrian Hunter if f.read(15) == "SQLite format 3": 377*031c2a00SAdrian Hunter is_sqlite3 = True 378*031c2a00SAdrian Hunter f.close() 379*031c2a00SAdrian Hunter except: 380*031c2a00SAdrian Hunter pass 381*031c2a00SAdrian Hunter 382*031c2a00SAdrian Hunter dbref = DBRef(is_sqlite3, dbname) 383*031c2a00SAdrian Hunter db, dbname = dbref.Open("main") 384*031c2a00SAdrian Hunter glb = Glb(dbref, db, dbname) 385*031c2a00SAdrian Hunter app = QApplication(sys.argv) 386*031c2a00SAdrian Hunter glb.app = app 387*031c2a00SAdrian Hunter mainwindow = MainWindow(glb) 388*031c2a00SAdrian Hunter glb.mainwindow = mainwindow 389*031c2a00SAdrian Hunter mainwindow.show() 390*031c2a00SAdrian Hunter err = app.exec_() 391*031c2a00SAdrian Hunter db.close() 392*031c2a00SAdrian Hunter sys.exit(err) 393*031c2a00SAdrian Hunter 394*031c2a00SAdrian Hunterif __name__ == "__main__": 395*031c2a00SAdrian Hunter Main() 396