diff --git a/pyfpdb/GuiAutoImport.py b/pyfpdb/GuiAutoImport.py index 820642e4..ceb3da0d 100644 --- a/pyfpdb/GuiAutoImport.py +++ b/pyfpdb/GuiAutoImport.py @@ -154,8 +154,11 @@ class GuiAutoImport (threading.Thread): else: # toggled off self.doAutoImportBool = False # do_import will return this and stop the gobject callback timer print "Stopping autoimport" - print >>self.pipe_to_hud.stdin, "\n" - #self.pipe_to_hud.communicate('\n') # waits for process to terminate + if self.pipe_to_hud.poll() is not None: + print "HUD already terminated" + else: + #print >>self.pipe_to_hud.stdin, "\n" + self.pipe_to_hud.communicate('\n') # waits for process to terminate self.pipe_to_hud = None self.startButton.set_label(u'Start Autoimport') diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index 12417a23..9bf630b6 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -52,6 +52,7 @@ import Hud # global dict for keeping the huds hud_dict = {} +eb = 0 # our former event-box db_connection = 0; config = 0; @@ -61,11 +62,18 @@ def destroy(*args): # call back for terminating the main eventloop def create_HUD(new_hand_id, table, db_name, table_name, max, poker_game, db_connection, config, stat_dict): global hud_dict + global eb def idle_func(): global hud_dict + global eb gtk.gdk.threads_enter() try: + newlabel = gtk.Label(table_name) + eb.add(newlabel) + newlabel.show() + hud_dict[table_name] = Hud.Hud(table, max, poker_game, config, db_connection) + hud_dict[table_name].tablehudlabel = newlabel hud_dict[table_name].create(new_hand_id, config) for m in hud_dict[table_name].aux_windows: m.update_data(new_hand_id, db_connection) @@ -92,6 +100,7 @@ def update_HUD(new_hand_id, table_name, config, stat_dict): def read_stdin(): # This is the thread function global hud_dict + global eb db_connection = Database.Database(config, db_name, 'temp') tourny_finder = re.compile('(\d+) (\d+)') @@ -105,6 +114,7 @@ def read_stdin(): # This is the thread function # delete hud_dict entries for any HUD destroyed since last iteration for h in hud_dict.keys(): if hud_dict[h].deleted: + eb.remove(hud_dict[h].tablehudlabel) del(hud_dict[h]) # get basic info about the new hand from the db @@ -162,10 +172,11 @@ if __name__== "__main__": main_window = gtk.Window() main_window.connect("destroy", destroy) - eb = gtk.EventBox() + eb = gtk.VBox() label = gtk.Label('Closing this window will exit from the HUD.') eb.add(label) main_window.add(eb) + main_window.set_title("HUD Main Window") main_window.show_all() diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index 09f52065..24ccbe3f 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -576,5 +576,7 @@ class Pot(object): elif len(self.pots) == 3: return "Total pot $%.2f Main pot $%.2f. Side pot-1 $%2.2f. Side pot-2 $%.2f." % (self.total, self.pots[0], self.pots[1], self.pots[2]) else: - return "too many pots.. fix me.", self.pots + return "maybe no pot.. or too many pots.. no small blind and walk in bb?." + # I don't know stars format for a walk in the bb when sb doesn't post. + # The thing to do here is raise a Hand error like fpdb import does and file it into errors.txt diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index c6ee4fe0..2dfb51fd 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -68,28 +68,31 @@ class Hud: else: print "Setting font to ", font + " " + font_size self.font = pango.FontDescription(font + " " + font_size) + + # do we need to add some sort of condition here for dealing with a request for a font that doesn't exist? # Set up a main window for this this instance of the HUD self.main_window = gtk.Window() -# self.window.set_decorated(0) self.main_window.set_gravity(gtk.gdk.GRAVITY_STATIC) self.main_window.set_title(table.name + " FPDBHUD") self.main_window.connect("destroy", self.kill_hud) self.main_window.set_decorated(False) self.main_window.set_opacity(self.colors["hudopacity"]) - #self.main_window.set_transient_for(parent.get_toplevel()) self.ebox = gtk.EventBox() -# self.label = gtk.Label("Right click to close HUD for %s\nor Save Stat Positions." % (table.name)) self.label = gtk.Label("FPDB Menu (Right Click)\nLeft-drag to move") - self.label.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudbgcolor'])) - self.label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudfgcolor'])) + self.backgroundcolor = gtk.gdk.color_parse(self.colors['hudbgcolor']) + self.foregroundcolor = gtk.gdk.color_parse(self.colors['hudfgcolor']) + + self.label.modify_bg(gtk.STATE_NORMAL, self.backgroundcolor) + self.label.modify_fg(gtk.STATE_NORMAL, self.foregroundcolor) self.main_window.add(self.ebox) self.ebox.add(self.label) - self.ebox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudbgcolor'])) - self.ebox.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudfgcolor'])) + + self.ebox.modify_bg(gtk.STATE_NORMAL, self.backgroundcolor) + self.ebox.modify_fg(gtk.STATE_NORMAL, self.foregroundcolor) self.main_window.move(self.table.x, self.table.y) @@ -118,24 +121,21 @@ class Hud: self.ebox.connect_object("button-press-event", self.on_button_press, self.menu) self.main_window.show_all() -# set_keep_above(1) for windows + if os.name == 'nt': self.topify_window(self.main_window) else: self.main_window.parentgdkhandle = gtk.gdk.window_foreign_new(self.table.number) # gets a gdk handle for poker client self.main_window.gdkhandle = gtk.gdk.window_foreign_new(self.main_window.window.xid) # gets a gdk handle for the hud table window self.main_window.gdkhandle.set_transient_for(self.main_window.parentgdkhandle) # - - self.main_window.set_destroy_with_parent(True) - + def update_table_position(self): -# self.main_window.parentgdkhandle = gtk.gdk.window_foreign_new(self.table.number) -# if self.main_window.parentgdkhandle == None: if os.name == 'nt': if not win32gui.IsWindow(self.table.number): self.kill_hud() return False - + # anyone know how to do this in unix, or better yet, trap the X11 error that is triggered when executing the get_origin() for a closed window? + (x, y) = self.main_window.parentgdkhandle.get_origin() if self.table.x != x or self.table.y != y: self.table.x = x @@ -146,8 +146,7 @@ class Hud: for i in range(1, self.max + 1): (x, y) = loc[adj[i]] if self.stat_windows.has_key(i): - self.stat_windows[i].relocate(x, y) - + self.stat_windows[i].relocate(x, y) return True def on_button_press(self, widget, event): @@ -176,7 +175,6 @@ class Hud: def save_layout(self, *args): new_layout = [(0, 0)] * self.max -# todo: have the hud track the poker table's window position regularly, don't forget to update table.x and table.y. for sw in self.stat_windows: loc = self.stat_windows[sw].window.get_position() new_loc = (loc[0] - self.table.x, loc[1] - self.table.y) @@ -267,8 +265,9 @@ class Hud: self.stat_windows[stat_dict[s]['seat']].label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(this_stat.hudcolor)) self.stat_windows[stat_dict[s]['seat']].label[r][c].set_text(statstring) - if statstring != "xxx": + if statstring != "xxx": # is there a way to tell if this particular stat window is visible already, or no? self.stat_windows[stat_dict[s]['seat']].window.show_all() + self.reposition_windows() tip = stat_dict[s]['screen_name'] + "\n" + number[5] + "\n" + \ number[3] + ", " + number[4] Stats.do_tip(self.stat_windows[stat_dict[s]['seat']].e_box[r][c], tip) @@ -291,29 +290,13 @@ class Hud: for w in tl_windows: if w[1] == unique_name: - #win32gui.ShowWindow(w[0], win32con.SW_HIDE) self.main_window.parentgdkhandle = gtk.gdk.window_foreign_new(long(self.table.number)) self.main_window.gdkhandle = gtk.gdk.window_foreign_new(w[0]) self.main_window.gdkhandle.set_transient_for(self.main_window.parentgdkhandle) - #win32gui.ShowWindow(w[0], win32con.SW_SHOW) style = win32gui.GetWindowLong(self.table.number, win32con.GWL_EXSTYLE) - #style |= win32con.WS_EX_TOOLWINDOW - #style &= ~win32con.WS_EX_APPWINDOW style |= win32con.WS_CLIPCHILDREN win32gui.SetWindowLong(self.table.number, win32con.GWL_EXSTYLE, style) - - - #win32gui.SetWindowPos(w[0], win32con.HWND_TOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE|win32con.SWP_NOSIZE) - -# notify_id = (w[0], -# 0, -# win32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP, -# win32con.WM_USER+20, -# 0, -# '') -# win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, notify_id) -# window.set_title(real_name) class Stat_Window: @@ -335,7 +318,6 @@ class Stat_Window: if event.button == 2: # middle button event self.window.hide() -# print "middle button clicked" pass if event.button == 1: # left button event @@ -349,7 +331,6 @@ class Stat_Window: # Callback from the timeout in the single-click finding part of the # button press call back. This needs to be modified to get all the # arguments from the call. -# print "left button clicked" self.sb_click = 0 Popup_window(widget, self) return False @@ -404,19 +385,18 @@ class Stat_Window: for c in range(self.game.cols): self.e_box[r].append( gtk.EventBox() ) - self.e_box[r][c].modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(parent.colors['hudbgcolor'])) - self.e_box[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(parent.colors['hudfgcolor'])) + self.e_box[r][c].modify_bg(gtk.STATE_NORMAL, parent.backgroundcolor) + self.e_box[r][c].modify_fg(gtk.STATE_NORMAL, parent.foregroundcolor) Stats.do_tip(self.e_box[r][c], 'farts') self.grid.attach(self.e_box[r][c], c, c+1, r, r+1, xpadding = 0, ypadding = 0) self.label[r].append( gtk.Label('xxx') ) - self.label[r][c].modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(parent.colors['hudbgcolor'])) - self.label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(parent.colors['hudfgcolor'])) + self.label[r][c].modify_bg(gtk.STATE_NORMAL, parent.backgroundcolor) + self.label[r][c].modify_fg(gtk.STATE_NORMAL, parent.foregroundcolor) self.e_box[r][c].add(self.label[r][c]) self.e_box[r][c].connect("button_press_event", self.button_press_cb) -# font = pango.FontDescription(self.font) self.label[r][c].modify_font(font) self.window.set_opacity(parent.colors['hudopacity']) @@ -436,7 +416,6 @@ class Popup_window: self.window = gtk.Window() self.window.set_decorated(0) self.window.set_gravity(gtk.gdk.GRAVITY_STATIC) -# self.window.set_keep_above(1) self.window.set_title("popup") self.window.set_property("skip-taskbar-hint", True) self.window.set_transient_for(parent.get_toplevel()) @@ -451,15 +430,13 @@ class Popup_window: self.window.add(self.ebox) self.ebox.add(self.lab) - self.ebox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(stat_window.parent.colors['hudbgcolor'])) - self.ebox.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(stat_window.parent.colors['hudfgcolor'])) - self.window.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(stat_window.parent.colors['hudbgcolor'])) - self.window.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(stat_window.parent.colors['hudfgcolor'])) - self.lab.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(stat_window.parent.colors['hudbgcolor'])) - self.lab.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(stat_window.parent.colors['hudfgcolor'])) + self.ebox.modify_bg(gtk.STATE_NORMAL, stat_window.parent.backgroundcolor) + self.ebox.modify_fg(gtk.STATE_NORMAL, stat_window.parent.foregroundcolor) + self.window.modify_bg(gtk.STATE_NORMAL, stat_window.parent.backgroundcolor) + self.window.modify_fg(gtk.STATE_NORMAL, stat_window.parent.foregroundcolor) + self.lab.modify_bg(gtk.STATE_NORMAL, stat_window.parent.backgroundcolor) + self.lab.modify_fg(gtk.STATE_NORMAL, stat_window.parent.foregroundcolor) -# self.window.realize() - # figure out the row, col address of the click that activated the popup row = 0 col = 0 @@ -502,8 +479,8 @@ class Popup_window: self.window.set_transient_for(stat_window.window) -# set_keep_above(1) for windows - if os.name == 'nt': self.topify_window(self.window) + if os.name == 'nt': + self.topify_window(self.window) def button_press_cb(self, widget, event, *args): # This handles all callbacks from button presses on the event boxes in @@ -521,11 +498,9 @@ class Popup_window: if event.button == 2: # middle button event pass -# print "middle button clicked" if event.button == 3: # right button event pass -# print "right button clicked" def single_click(self, widget): # Callback from the timeout in the single-click finding part of the @@ -564,22 +539,8 @@ class Popup_window: for w in tl_windows: if w[1] == unique_name: -# win32gui.ShowWindow(w[0], win32con.SW_HIDE) -# style = win32gui.GetWindowLong(w[0], win32con.GWL_EXSTYLE) -# style |= win32con.WS_EX_TOOLWINDOW -# style &= ~win32con.WS_EX_APPWINDOW -# win32gui.SetWindowLong(w[0], win32con.GWL_EXSTYLE, style) -# win32gui.ShowWindow(w[0], win32con.SW_SHOW) win32gui.SetWindowPos(w[0], win32con.HWND_TOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE|win32con.SWP_NOSIZE) -# notify_id = (w[0], -# 0, -# win32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP, -# win32con.WM_USER+20, -# 0, -# '') -# win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, notify_id) -# window.set_title(real_name) if __name__== "__main__": diff --git a/pyfpdb/Stats.py b/pyfpdb/Stats.py index 80b3c7f1..3f55c7fc 100644 --- a/pyfpdb/Stats.py +++ b/pyfpdb/Stats.py @@ -281,13 +281,7 @@ def steal(stat_dict, player): '% steal attempted' ) except: - return (stat, - '%3.1f' % (0) + '%', - 'st=%3.1f' % (0) + '%', - 'steal=%3.1f' % (0) + '%', - '(%d/%d)' % (0, 0), - '% steal attempted' - ) + return (stat, 'NA', 'st=NA', 'steal=NA', '(0/0)', '% steal attempted') def f_SB_steal(stat_dict, player): """ Folded SB to steal.""" @@ -306,7 +300,7 @@ def f_SB_steal(stat_dict, player): 'NA', 'fSB=NA', 'fSB_s=NA', - '0/0', + '(0/0)', '% folded SB to steal') def f_BB_steal(stat_dict, player): @@ -326,7 +320,7 @@ def f_BB_steal(stat_dict, player): 'NA', 'fBB=NA', 'fBB_s=NA', - '0/0', + '(0/0)', '% folded BB to steal') def three_B_0(stat_dict, player): diff --git a/pyfpdb/Tables.py b/pyfpdb/Tables.py index 54079425..6d88d079 100755 --- a/pyfpdb/Tables.py +++ b/pyfpdb/Tables.py @@ -152,7 +152,7 @@ def discover_posix_by_name(c, tablename): info = decode_xwininfo(c, listing) if not info['name'] == tablename: continue return info - return False + return None def discover_posix_tournament(c, t_number, s_number): """Finds the X window for a client, given tournament and table nos.""" @@ -160,7 +160,7 @@ def discover_posix_tournament(c, t_number, s_number): for listing in os.popen('xwininfo -root -tree').readlines(): if re.search(search_string, listing): return decode_xwininfo(c, listing) - return False + return None def decode_xwininfo(c, info_string): """Gets window parameters from xwinifo string--XWindows.""" @@ -231,7 +231,7 @@ def discover_nt_by_name(c, tablename): if titles[hwnd].find("HUD:") > -1: continue if titles[hwnd].find("Chat:") > -1: continue return decode_windows(c, titles[hwnd], hwnd) - return False + return None def discover_nt_tournament(c, tour_number, tab_number): """Finds the Windows window handle for the given tournament/table.""" @@ -242,7 +242,7 @@ def discover_nt_tournament(c, tour_number, tab_number): for hwnd in titles.keys(): if re.search(search_string, titles[hwnd]): return decode_windows(c, titles[hwnd], hwnd) - return False + return None def get_nt_exe(hwnd): """Finds the name of the executable that the given window handle belongs to.""" diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 2d35a97a..a793e3ad 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -282,14 +282,12 @@ class Importer: self.fdb.db.commit() self.handsId=handsId return handsId -#end def import_file_dict def parseTourneyHistory(self): print "Tourney history parser stub" #Find tournament boundaries. #print self.foabs - def printEmailErrorMessage(self, errors, filename, line): traceback.print_exc(file=sys.stderr) print "Error No.",errors,", please send the hand causing this to steffen@sycamoretest.info so I can fix it." diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index e1e0f737..a94e53f5 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -329,6 +329,307 @@ def analyzeDB(fdb): #end def analyzeDB +# Data Structures for index and foreign key creation +# drop_code is an int with possible values: 0 - don't drop for bulk import +# 1 - drop during bulk import +# db differences: +# - note that mysql automatically creates indexes on constrained columns when +# foreign keys are created, while postgres does not. Hence the much longer list +# of indexes is required for postgres. +# all primary keys are left on all the time +# +# table column drop_code + +indexes = [ + [ ] # no db with index 0 + , [ ] # no db with index 1 + , [ # indexes for mysql (list index 2) + {'tab':'Players', 'col':'name', 'drop':0} + , {'tab':'Hands', 'col':'siteHandNo', 'drop':0} + , {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} + ] + , [ # indexes for postgres (list index 3) + {'tab':'Boardcards', 'col':'handId', 'drop':0} + , {'tab':'Gametypes', 'col':'siteId', 'drop':0} + , {'tab':'Hands', 'col':'gametypeId', 'drop':1} + , {'tab':'Hands', 'col':'siteHandNo', 'drop':0} + , {'tab':'HandsActions', 'col':'handplayerId', 'drop':0} + , {'tab':'HandsPlayers', 'col':'handId', 'drop':1} + , {'tab':'HandsPlayers', 'col':'playerId', 'drop':1} + , {'tab':'HandsPlayers', 'col':'tourneysPlayersId', 'drop':0} + , {'tab':'HudCache', 'col':'gametypeId', 'drop':1} + , {'tab':'HudCache', 'col':'playerId', 'drop':0} + , {'tab':'HudCache', 'col':'tourneyTypeId', 'drop':0} + , {'tab':'Players', 'col':'siteId', 'drop':1} + , {'tab':'Players', 'col':'name', 'drop':0} + , {'tab':'Tourneys', 'col':'tourneyTypeId', 'drop':1} + , {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} + , {'tab':'TourneysPlayers', 'col':'playerId', 'drop':0} + , {'tab':'TourneysPlayers', 'col':'tourneyId', 'drop':0} + , {'tab':'TourneyTypes', 'col':'siteId', 'drop':0} + ] + ] + +foreignKeys = [ + [ ] # no db with index 0 + , [ ] # no db with index 1 + , [ # foreign keys for mysql + {'fktab':'Hands', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1} + , {'fktab':'HandsPlayers', 'fkcol':'handId', 'rtab':'Hands', 'rcol':'id', 'drop':1} + , {'fktab':'HandsPlayers', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':1} + , {'fktab':'HandsActions', 'fkcol':'handPlayerId', 'rtab':'HandsPlayers', 'rcol':'id', 'drop':1} + , {'fktab':'HudCache', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1} + , {'fktab':'HudCache', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':0} + , {'fktab':'HudCache', 'fkcol':'tourneyTypeId', 'rtab':'TourneyTypes', 'rcol':'id', 'drop':1} + ] + , [ # foreign keys for postgres + {'fktab':'Hands', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1} + , {'fktab':'HandsPlayers', 'fkcol':'handId', 'rtab':'Hands', 'rcol':'id', 'drop':1} + , {'fktab':'HandsPlayers', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':1} + , {'fktab':'HandsActions', 'fkcol':'handPlayerId', 'rtab':'HandsPlayers', 'rcol':'id', 'drop':1} + , {'fktab':'HudCache', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1} + , {'fktab':'HudCache', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':0} + , {'fktab':'HudCache', 'fkcol':'tourneyTypeId', 'rtab':'TourneyTypes', 'rcol':'id', 'drop':1} + ] + ] + + +# MySQL Notes: +# "FOREIGN KEY (handId) REFERENCES Hands(id)" - requires index on Hands.id +# - creates index handId on .handId +# alter table t drop foreign key fk +# alter table t add foreign key (fkcol) references tab(rcol) +# alter table t add constraint c foreign key (fkcol) references tab(rcol) +# (fkcol is used for foreigh key name) + +# mysql to list indexes: +# SELECT table_name, index_name, non_unique, column_name +# FROM INFORMATION_SCHEMA.STATISTICS +# WHERE table_name = 'tbl_name' +# AND table_schema = 'db_name' +# ORDER BY table_name, index_name, seq_in_index +# +# ALTER TABLE Tourneys ADD INDEX siteTourneyNo(siteTourneyNo) +# ALTER TABLE tab DROP INDEX idx + +# mysql to list fks: +# SELECT constraint_name, table_name, column_name, referenced_table_name, referenced_column_name +# FROM information_schema.KEY_COLUMN_USAGE +# WHERE REFERENCED_TABLE_SCHEMA = (your schema name here) +# AND REFERENCED_TABLE_NAME is not null +# ORDER BY TABLE_NAME, COLUMN_NAME; + +# this may indicate missing object +# _mysql_exceptions.OperationalError: (1025, "Error on rename of '.\\fpdb\\hands' to '.\\fpdb\\#sql2-7f0-1b' (errno: 152)") + + +# PG notes: + +# To add a foreign key constraint to a table: +# ALTER TABLE tab ADD CONSTRAINT c FOREIGN KEY (col) REFERENCES t2(col2) MATCH FULL; +# ALTER TABLE tab DROP CONSTRAINT zipchk +# +# Note: index names must be unique across a schema +# CREATE INDEX idx ON tab(col) +# DROP INDEX idx + +def prepareBulkImport(fdb): + """Drop some indexes/foreign keys to prepare for bulk import. + Currently keeping the standalone indexes as needed to import quickly""" + # fdb is a fpdb_db object including backend, db, cursor, sql variables + if fdb.backend == PGSQL: + fdb.db.set_isolation_level(0) # allow table/index operations to work + for fk in foreignKeys[fdb.backend]: + if fk['drop'] == 1: + if fdb.backend == MYSQL_INNODB: + fdb.cursor.execute("SELECT constraint_name " + + "FROM information_schema.KEY_COLUMN_USAGE " + + #"WHERE REFERENCED_TABLE_SCHEMA = 'fpdb' + "WHERE 1=1 " + + "AND table_name = %s AND column_name = %s " + + "AND referenced_table_name = %s " + + "AND referenced_column_name = %s ", + (fk['fktab'], fk['fkcol'], fk['rtab'], fk['rcol']) ) + cons = fdb.cursor.fetchone() + print "preparebulk: cons=", cons + if cons: + print "dropping mysql fk", cons[0], fk['fktab'], fk['fkcol'] + try: + fdb.cursor.execute("alter table " + fk['fktab'] + " drop foreign key " + cons[0]) + except: + pass + elif fdb.backend == PGSQL: + print "dropping pg fk", fk['fktab'], fk['fkcol'] + try: + fdb.cursor.execute("alter table " + fk['fktab'] + " drop constraint " + + fk['fktab'] + '_' + fk['fkcol'] + '_fkey') + except: + pass + else: + print "Only MySQL and Postgres supported so far" + return -1 + + for idx in indexes[fdb.backend]: + if idx['drop'] == 1: + if fdb.backend == MYSQL_INNODB: + print "dropping mysql index ", idx['tab'], idx['col'] + try: + fdb.cursor.execute( "alter table %s drop index %s", (idx['tab'],idx['col']) ) + except: + pass + elif fdb.backend == PGSQL: + print "dropping pg index ", idx['tab'], idx['col'] + # mod to use tab_col for index name? + try: + fdb.cursor.execute( "drop index %s_%s_idx" % (idx['tab'],idx['col']) ) + except: + pass + else: + print "Only MySQL and Postgres supported so far" + return -1 + + if fdb.backend == PGSQL: + fdb.db.set_isolation_level(1) # go back to normal isolation level + fdb.db.commit() # seems to clear up errors if there were any in postgres +#end def prepareBulkImport + +def afterBulkImport(fdb): + """Re-create any dropped indexes/foreign keys after bulk import""" + # fdb is a fpdb_db object including backend, db, cursor, sql variables + if fdb.backend == PGSQL: + fdb.db.set_isolation_level(0) # allow table/index operations to work + for fk in foreignKeys[fdb.backend]: + if fk['drop'] == 1: + if fdb.backend == MYSQL_INNODB: + fdb.cursor.execute("SELECT constraint_name " + + "FROM information_schema.KEY_COLUMN_USAGE " + + #"WHERE REFERENCED_TABLE_SCHEMA = 'fpdb' + "WHERE 1=1 " + + "AND table_name = %s AND column_name = %s " + + "AND referenced_table_name = %s " + + "AND referenced_column_name = %s ", + (fk['fktab'], fk['fkcol'], fk['rtab'], fk['rcol']) ) + cons = fdb.cursor.fetchone() + print "afterbulk: cons=", cons + if cons: + pass + else: + print "creating fk ", fk['fktab'], fk['fkcol'], "->", fk['rtab'], fk['rcol'] + try: + fdb.cursor.execute("alter table " + fk['fktab'] + " add foreign key (" + + fk['fkcol'] + ") references " + fk['rtab'] + "(" + + fk['rcol'] + ")") + except: + pass + elif fdb.backend == PGSQL: + print "creating fk ", fk['fktab'], fk['fkcol'], "->", fk['rtab'], fk['rcol'] + try: + fdb.cursor.execute("alter table " + fk['fktab'] + " add constraint " + + fk['fktab'] + '_' + fk['fkcol'] + '_fkey' + + " foreign key (" + fk['fkcol'] + + ") references " + fk['rtab'] + "(" + fk['rcol'] + ")") + except: + pass + else: + print "Only MySQL and Postgres supported so far" + return -1 + + for idx in indexes[fdb.backend]: + if idx['drop'] == 1: + if fdb.backend == MYSQL_INNODB: + print "creating mysql index ", idx['tab'], idx['col'] + try: + fdb.cursor.execute( "alter table %s add index %s(%s)" + , (idx['tab'],idx['col'],idx['col']) ) + except: + pass + elif fdb.backend == PGSQL: + # mod to use tab_col for index name? + print "creating pg index ", idx['tab'], idx['col'] + try: + print "create index %s_%s_idx on %s(%s)" % (idx['tab'], idx['col'], idx['tab'], idx['col']) + fdb.cursor.execute( "create index %s_%s_idx on %s(%s)" + % (idx['tab'], idx['col'], idx['tab'], idx['col']) ) + except: + print " ERROR! :-(" + pass + else: + print "Only MySQL and Postgres supported so far" + return -1 + + if fdb.backend == PGSQL: + fdb.db.set_isolation_level(1) # go back to normal isolation level + fdb.db.commit() # seems to clear up errors if there were any in postgres +#end def afterBulkImport + +def createAllIndexes(fdb): + """Create new indexes""" + if fdb.backend == PGSQL: + fdb.db.set_isolation_level(0) # allow table/index operations to work + for idx in indexes[fdb.backend]: + if fdb.backend == MYSQL_INNODB: + print "creating mysql index ", idx['tab'], idx['col'] + try: + fdb.cursor.execute( "alter table %s add index %s(%s)" + , (idx['tab'],idx['col'],idx['col']) ) + except: + pass + elif fdb.backend == PGSQL: + # mod to use tab_col for index name? + print "creating pg index ", idx['tab'], idx['col'] + try: + print "create index %s_%s_idx on %s(%s)" % (idx['tab'], idx['col'], idx['tab'], idx['col']) + fdb.cursor.execute( "create index %s_%s_idx on %s(%s)" + % (idx['tab'], idx['col'], idx['tab'], idx['col']) ) + except: + print " ERROR! :-(" + pass + else: + print "Only MySQL and Postgres supported so far" + return -1 + if fdb.backend == PGSQL: + fdb.db.set_isolation_level(1) # go back to normal isolation level +#end def createAllIndexes + +def dropAllIndexes(fdb): + """Drop all standalone indexes (i.e. not including primary keys or foreign keys) + using list of indexes in indexes data structure""" + # maybe upgrade to use data dictionary?? (but take care to exclude PK and FK) + if fdb.backend == PGSQL: + fdb.db.set_isolation_level(0) # allow table/index operations to work + for idx in indexes[fdb.backend]: + if fdb.backend == MYSQL_INNODB: + print "dropping mysql index ", idx['tab'], idx['col'] + try: + fdb.cursor.execute( "alter table %s drop index %s" + , (idx['tab'],idx['col']) ) + except: + pass + elif fdb.backend == PGSQL: + print "dropping pg index ", idx['tab'], idx['col'] + # mod to use tab_col for index name? + try: + fdb.cursor.execute( "drop index %s_%s_idx" + % (idx['tab'],idx['col']) ) + except: + pass + else: + print "Only MySQL and Postgres supported so far" + return -1 + if fdb.backend == PGSQL: + fdb.db.set_isolation_level(1) # go back to normal isolation level +#end def dropAllIndexes + +def analyzeDB(fdb): + """Do whatever the DB can offer to update index/table statistics""" + if fdb.backend == PGSQL: + fdb.db.set_isolation_level(0) # allow vacuum to work + try: + fdb.cursor.execute("vacuum analyze") + except: + print "Error during vacuum" + fdb.db.set_isolation_level(1) # go back to normal isolation level +#end def analyzeDB class DuplicateError(Exception): def __init__(self, value): @@ -341,7 +642,7 @@ class FpdbError(Exception): self.value = value def __str__(self): return repr(self.value) - + # gets value for last auto-increment key generated # returns -1 if a problem occurs def getLastInsertId(backend, conn, cursor): @@ -382,18 +683,19 @@ def calcPayin(count, buyin, fee): #end def calcPayin def checkPositions(positions): - """verifies that these positions are valid""" - for i in range (len(positions)): - pos=positions[i] - try:#todo: use type recognition instead of error - if (len(pos)!=1): - raise FpdbError("invalid position found in checkPositions. i: "+str(i)+" position: "+pos) #dont need to str() here - except TypeError:#->not string->is int->fine - pass - - ### RHH modified to allow for "position 9" here (pos==9 is when you're a dead hand before the BB - if (pos!="B" and pos!="S" and pos!=0 and pos!=1 and pos!=2 and pos!=3 and pos!=4 and pos!=5 and pos!=6 and pos!=7 and pos != 8 and pos!=9): - raise FpdbError("invalid position found in checkPositions. i: "+str(i)+" position: "+str(pos)) + """verifies that these positions are valid""" + for i in range (len(positions)): + pos=positions[i] + try:#todo: use type recognition instead of error + if (len(pos)!=1): + raise FpdbError("invalid position found in checkPositions. i: "+str(i)+" position: "+pos) #dont need to str() here + except TypeError:#->not string->is int->fine + pass + + ### RHH modified to allow for "position 9" here (pos==9 is when you're a dead hand before the BB + ### eric - position 8 could be valid - if only one blind is posted, but there's still 10 people, ie a sitout is present, and the small is dead... + if not (pos == "B" or pos == "S" or (pos >= 0 and pos <= 9)): + raise FpdbError("invalid position found in checkPositions. i: "+str(i)+" position: "+str(pos)) #end def fpdb_simple.checkPositions #classifies each line for further processing in later code. Manipulates the passed arrays. @@ -1207,67 +1509,83 @@ def parseNames(lines): #returns an array with the positions of the respective players def parsePositions (hand, names): - #prep array - positions=[] - for i in range(len(names)): - positions.append(-1) - - #find blinds - sb,bb=-1,-1 - for i in range (len(hand)): - if (sb==-1 and hand[i].find("small blind")!=-1 and hand[i].find("dead small blind")==-1): - sb=hand[i] - #print "sb:",sb - if (bb==-1 and hand[i].find("big blind")!=-1 and hand[i].find("dead big blind")==-1): - bb=hand[i] - #print "bb:",bb - - #identify blinds - #print "parsePositions before recognising sb/bb. names:",names - sbExists=True - if (sb!=-1): - sb=recognisePlayerNo(sb, names, "bet") - else: - sbExists=False - if (bb!=-1): - bb=recognisePlayerNo(bb, names, "bet") - - #write blinds into array - if (sbExists): - positions[sb]="S" - positions[bb]="B" - - #fill up rest of array - if (sbExists): - arraypos=sb-1 - else: - arraypos=bb-1 - distFromBtn=0 - while (arraypos>=0 and arraypos != bb): - #print "parsePositions first while, arraypos:",arraypos,"positions:",positions - positions[arraypos]=distFromBtn - arraypos-=1 - distFromBtn+=1 - - ### RHH - Changed to set the null seats before BB to "9" - i=bb-1 - while positions[i] < 0: - positions[i]=9 - i-=1 - - arraypos=len(names)-1 - if (bb!=0 or (bb==0 and sbExists==False)): - while (arraypos>bb): - positions[arraypos]=distFromBtn - arraypos-=1 - distFromBtn+=1 - - for i in range (len(names)): - if positions[i]==-1: - print "parsePositions names:",names - print "result:",positions - raise FpdbError ("failed to read positions") - return positions + #prep array + positions=[] + for i in range(len(names)): + positions.append(-1) + + #find blinds + sb,bb=-1,-1 + for i in range (len(hand)): + if (sb==-1 and hand[i].find("small blind")!=-1 and hand[i].find("dead small blind")==-1): + sb=hand[i] + #print "sb:",sb + if (bb==-1 and hand[i].find("big blind")!=-1 and hand[i].find("dead big blind")==-1): + bb=hand[i] + #print "bb:",bb + + #identify blinds + #print "parsePositions before recognising sb/bb. names:",names + sbExists=True + if (sb!=-1): + sb=recognisePlayerNo(sb, names, "bet") + else: + sbExists=False + if (bb!=-1): + bb=recognisePlayerNo(bb, names, "bet") + +# print "sb = ", sb, "bb = ", bb + if bb == sb: + sbExists = False + sb = -1 + + #write blinds into array + if (sbExists): + positions[sb]="S" + positions[bb]="B" + + + #fill up rest of array + if (sbExists): + arraypos=sb-1 + else: + arraypos=bb-1 + distFromBtn=0 + while (arraypos>=0 and arraypos != bb): + #print "parsePositions first while, arraypos:",arraypos,"positions:",positions + positions[arraypos]=distFromBtn + arraypos-=1 + distFromBtn+=1 + + # eric - this takes into account dead seats between blinds + if sbExists: + i = bb - 1 + while positions[i] < 0 and i != sb: + positions[i] = 9 + i -= 1 + ### RHH - Changed to set the null seats before BB to "9" + if sbExists: + i = sb-1 + else: + i = bb-1 + while positions[i] < 0: + positions[i]=9 + i-=1 + + arraypos=len(names)-1 + if (bb!=0 or (bb==0 and sbExists==False) or (bb == 1 and sb != arraypos) ): + while (arraypos>bb and arraypos > sb): + positions[arraypos]=distFromBtn + arraypos-=1 + distFromBtn+=1 + + for i in range (len(names)): + if positions[i]==-1: + print "parsePositions names:",names + print "result:",positions + raise FpdbError ("failed to read positions") +# print str(positions), "\n" + return positions #end def parsePositions #simply parses the rake amount and returns it as an int @@ -2048,7 +2366,7 @@ sure to also change the following storage method and table_viewer.prepare_data i hudDataPositions.append('C') elif pos>=2 and pos<=4: hudDataPositions.append('M') - elif pos>=5 and pos<=7: + elif pos>=5 and pos<=8: hudDataPositions.append('E') ### RHH Added this elif to handle being a dead hand before the BB (pos==9) elif pos==9: