diff --git a/pyfpdb/BetfairToFpdb.py b/pyfpdb/BetfairToFpdb.py index 672e858a..1ccec5d0 100755 --- a/pyfpdb/BetfairToFpdb.py +++ b/pyfpdb/BetfairToFpdb.py @@ -34,12 +34,12 @@ class Betfair(HandHistoryConverter): re_PlayerInfo = re.compile("Seat (?P[0-9]+): (?P.*)\s\(\s(\$(?P[.0-9]+)) \)") re_Board = re.compile(ur"\[ (?P.+) \]") - def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True): + def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True, index=0): """\ in_path (default '-' = sys.stdin) out_path (default '-' = sys.stdout) follow : whether to tail -f the input""" - HandHistoryConverter.__init__(self, in_path, out_path, sitename="Betfair", follow=follow) # Call super class init. + HandHistoryConverter.__init__(self, in_path, out_path, sitename="Betfair", follow=follow, index) # Call super class init. logging.info("Initialising Betfair converter class") self.filetype = "text" self.codepage = "cp1252" diff --git a/pyfpdb/Card.py b/pyfpdb/Card.py index ab6843c5..6ab9b62d 100755 --- a/pyfpdb/Card.py +++ b/pyfpdb/Card.py @@ -24,25 +24,37 @@ def twoStartCards(value1, suit1, value2, suit2): (y+2) represents rank of second card (2=2 .. 14=Ace) If x > y then pair is suited, if x < y then unsuited""" if value1 < 2 or value2 < 2: - return(0) - if (suit1 == suit2 and value1 < value2) or (suit1 != suit2 and value2 > value1): - return(13 * (value2-2) + (value1-1)) + ret = 0 + if value1 == value2: # pairs + ret = (13 * (value2-2) + (value2-1) ) + elif suit1 == suit2: + if value1 > value2: + ret = 13 * (value1-2) + (value2-1) + else: + ret = 13 * (value2-2) + (value1-1) else: - return(13 * (value1-2) + (value2-1)) + if value1 > value2: + ret = 13 * (value2-2) + (value2-1) + else: + ret = 13 * (value1-2) + (value2-1) + +# print "twoStartCards(", value1, suit1, value2, suit2, ")=", ret + return ret def twoStartCardString(card): """ Function to convert an int representing 2 holdem hole cards (as created by twoStartCards) into a string like AQo """ - if card <= 0: - return 'xx' - else: + ret = 'xx' + if card > 0: card -= 1 s = ('2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A') - x = card/13 - y = card - 13*x - if x == y: return(s[x] + s[y]) - elif x > y: return(s[x] + s[y] + 's') - else: return(s[y] + s[x] + 'o') + x = card / 13 + y = card - 13 * x + if x == y: ret = s[x] + s[y] + elif x > y: ret = s[x] + s[y] + 's' + else: ret = s[y] + s[x] + 'o' +# print "twoStartCardString(", card ,") = " + ret + return ret def fourStartCards(value1, suit1, value2, suit2, value3, suit3, value4, suit4): """ Function to convert 4 value,suit pairs into a Omaha style starting hand, @@ -94,5 +106,23 @@ def valueSuitFromCard(card): , '2s', '3s', '4s', '5s', '6s', '7s', '8s', '9s', 'Ts', 'Js', 'Qs', 'Ks', 'As' ][card] ) +def encodeCard(cardString): + """Take a card string (Ah) and convert it to the db card code (1).""" + try: + return {'2h': 1, '3h': 2, '4h': 3, '5h': 4, '6h': 5, '7h': 6, '8h': 7, '9h': 8, 'Th': 9, 'Jh': 10, 'Qh': 11, 'Kh': 12, 'Ah': 13, + '2d': 14, '3d': 15, '4d': 16, '5d': 17, '6d': 18, '7d': 19, '8d': 20, '9d': 21, 'Td': 22, 'Jd': 23, 'Qd': 24, 'Kd': 25, 'Ad': 26, + '2c': 27, '3c': 28, '4c': 29, '5c': 30, '6c': 31, '7c': 32, '8c': 33, '9c': 34, 'Tc': 35, 'Jc': 36, 'Qc': 27, 'Kc': 38, 'Ac': 39, + '2s': 40, '3s': 41, '4s': 42, '5s': 43, '6s': 44, '7s': 45, '8s': 46, '9s': 47, 'Ts': 48, 'Js': 49, 'Qs': 50, 'Ks': 51, 'As': 52, + ' ': 0 + }[cardString] + except: + return 0 # everthing that isn't known is a unknown! +if __name__ == '__main__': + print "fpdb card encoding(same as pokersource)" + for i in xrange(1, 14): + print "card %2d = %s card %2d = %s card %2d = %s card %2d = %s" % \ + (i, valueSuitFromCard(i), i+13, valueSuitFromCard(i+13), i+26, valueSuitFromCard(i+26), i+39, valueSuitFromCard(i+39)) + print + print encodeCard('7c') \ No newline at end of file diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index 13e7cd28..e01a6b43 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -521,6 +521,8 @@ class Config: db['db-backend'] = 2 elif string.lower(self.supported_databases[name].db_server) == 'postgresql': db['db-backend'] = 3 + elif string.lower(self.supported_databases[name].db_server) == 'sqlite': + db['db-backend'] = 4 else: db['db-backend'] = None # this is big trouble return db diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 243f9aa3..8d58da50 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -27,7 +27,10 @@ Create and manage the database objects. import sys import traceback from datetime import datetime, date, time, timedelta +from time import time, strftime import string +import re +import logging # pyGTK modules @@ -39,6 +42,121 @@ import SQL import Card class Database: + + MYSQL_INNODB = 2 + PGSQL = 3 + SQLITE = 4 + + # 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':'Hands', 'col':'gametypeId', 'drop':0} # mct 22/3/09 + , {'tab':'HandsPlayers', 'col':'handId', 'drop':0} # not needed, handled by fk + , {'tab':'HandsPlayers', 'col':'playerId', 'drop':0} # not needed, handled by fk + , {'tab':'HandsPlayers', 'col':'tourneysTypeId', 'drop':0} + , {'tab':'HandsPlayers', 'col':'tourneysPlayersId', 'drop':0} + , {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} + ] + , [ # indexes for postgres (list index 3) + {'tab':'Gametypes', 'col':'siteId', 'drop':0} + , {'tab':'Hands', 'col':'gametypeId', 'drop':0} # mct 22/3/09 + , {'tab':'Hands', 'col':'siteHandNo', 'drop':0} + , {'tab':'HandsActions', 'col':'handsPlayerId', '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} + ] + , [ # indexes for sqlite (list index 4) + ] + ] + + 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':'handsPlayerId', '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':'handsPlayerId', '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 __init__(self, c, db_name = None, game = None, sql = None): # db_name and game not used any more print "\ncreating Database instance, sql =", sql self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql @@ -50,52 +168,91 @@ class Database: self.type = db_params['db-type'] self.backend = db_params['db-backend'] self.db_server = db_params['db-server'] + + if self.backend == self.PGSQL: + from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_READ_COMMITTED, ISOLATION_LEVEL_SERIALIZABLE + #ISOLATION_LEVEL_AUTOCOMMIT = 0 + #ISOLATION_LEVEL_READ_COMMITTED = 1 + #ISOLATION_LEVEL_SERIALIZABLE = 2 + # where possible avoid creating new SQL instance by using the global one passed in if sql == None: self.sql = SQL.Sql(type = self.type, db_server = db_params['db-server']) else: self.sql = sql - self.connection.rollback() - + + # config while trying out new hudcache mechanism + self.use_date_in_hudcache = True + # To add to config: + self.hud_session_gap = 30 # Gap (minutes) between hands that indicates a change of session + # (hands every 2 mins for 1 hour = one session, if followed + # by a 40 minute gap and then more hands on same table that is + # a new session) self.hud_style = 'T' # A=All-time # S=Session # T=timed (last n days) # Future values may also include: # H=Hands (last n hands) - self.hud_hands = 1000 # Max number of hands from each player to use for hud stats - self.hud_days = 90 # Max number of days from each player to use for hud stats - self.hud_session_gap = 30 # Gap (minutes) between hands that indicates a change of session - # (hands every 2 mins for 1 hour = one session, if followed - # by a 40 minute gap and then more hands on same table that is - # a new session) - cur = self.connection.cursor() + self.hud_hands = 2000 # Max number of hands from each player to use for hud stats + self.hud_days = 30 # Max number of days from each player to use for hud stats - self.hand_1day_ago = 0 - try: - cur.execute(self.sql.query['get_hand_1day_ago']) - row = cur.fetchone() + self.hud_hero_style = 'T' # Duplicate set of vars just for hero + self.hud_hero_hands = 2000 + self.hud_hero_days = 30 + + self.cursor = self.fdb.cursor + + if self.fdb.wrongDbVersion == False: + # self.hand_1day_ago used to fetch stats for current session (i.e. if hud_style = 'S') + self.hand_1day_ago = 0 + self.cursor.execute(self.sql.query['get_hand_1day_ago']) + row = self.cursor.fetchone() if row and row[0]: self.hand_1day_ago = row[0] #print "hand 1day ago =", self.hand_1day_ago + # self.date_ndays_ago used if hud_style = 'T' d = timedelta(days=self.hud_days) now = datetime.utcnow() - d self.date_ndays_ago = "d%02d%02d%02d" % (now.year-2000, now.month, now.day) - self.hand_nhands_ago = 0 # todo - #cur.execute(self.sql.query['get_table_name'], (hand_id, )) - #row = cur.fetchone() - except: # no tables created yet - pass + # self.hand_nhands_ago is used for fetching stats for last n hands (hud_style = 'H') + # This option not used yet + self.hand_nhands_ago = 0 + # should use aggregated version of query if appropriate + self.cursor.execute(self.sql.query['get_hand_nhands_ago'], (self.hud_hands,self.hud_hands)) + row = self.cursor.fetchone() + if row and row[0]: + self.hand_nhands_ago = row[0] + print "hand n hands ago =", self.hand_nhands_ago + + #self.cursor.execute(self.sql.query['get_table_name'], (hand_id, )) + #row = self.cursor.fetchone() + else: + print "Bailing on DB query, not sure it exists yet" + self.saveActions = False if self.import_options['saveActions'] == False else True + self.connection.rollback() # make sure any locks taken so far are released + #end def __init__ + + # could be used by hud to change hud style + def set_hud_style(self, style): + self.hud_style = style + def do_connect(self, c): self.fdb.do_connect(c) def commit(self): self.fdb.db.commit() + def rollback(self): + self.fdb.db.rollback() + + def get_cursor(self): + return self.connection.cursor() + def close_connection(self): self.connection.close() @@ -291,71 +448,82 @@ class Database: return row[0] else: return None + + def get_site_id(self, site): + c = self.get_cursor() + c.execute(self.sql.query['getSiteId'], (site,)) + result = c.fetchall() + return result def get_last_insert_id(self): - return self.fdb.getLastInsertId() + try: + ret = self.fdb.getLastInsertId() + except: + print "get_last_insert_id error:", str(sys.exc_value) + return ret #stores a stud/razz hand into the database - def ring_stud(self, config, settings, db, cursor, base, category, site_hand_no, gametype_id, hand_start_time + def ring_stud(self, config, settings, base, category, site_hand_no, gametype_id, hand_start_time ,names, player_ids, start_cashes, antes, card_values, card_suits, winnings, rakes ,action_types, allIns, action_amounts, actionNos, hudImportData, maxSeats, tableName ,seatNos): - fpdb_simple.fillCardArrays(len(names), base, category, card_values, card_suits) + try: + fpdb_simple.fillCardArrays(len(names), base, category, card_values, card_suits) - hands_id = fpdb_simple.storeHands(self.backend, db, cursor, site_hand_no, gametype_id - ,hand_start_time, names, tableName, maxSeats, hudImportData - ,(None, None, None, None, None), (None, None, None, None, None)) + hands_id = self.storeHands(self.backend, site_hand_no, gametype_id + ,hand_start_time, names, tableName, maxSeats, hudImportData + ,(None, None, None, None, None), (None, None, None, None, None)) - #print "before calling store_hands_players_stud, antes:", antes - hands_players_ids = fpdb_simple.store_hands_players_stud(self.backend, db, cursor, hands_id, player_ids - ,start_cashes, antes, card_values - ,card_suits, winnings, rakes, seatNos) + #print "before calling store_hands_players_stud, antes:", antes + hands_players_ids = self.store_hands_players_stud(self.backend, hands_id, player_ids + ,start_cashes, antes, card_values + ,card_suits, winnings, rakes, seatNos) - if 'updateHudCache' not in settings or settings['updateHudCache'] != 'drop': - fpdb_simple.storeHudCache(self.backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData) + if 'dropHudCache' not in settings or settings['dropHudCache'] != 'drop': + self.storeHudCache(self.backend, base, category, gametype_id, hand_start_time, player_ids, hudImportData) + except: + print "ring_stud error: " + str(sys.exc_value) # in case exception doesn't get printed + raise fpdb_simple.FpdbError("ring_stud error: " + str(sys.exc_value)) - if self.saveActions: - fpdb_simple.storeActions(cursor, hands_players_ids, action_types - ,allIns, action_amounts, actionNos) return hands_id #end def ring_stud - def ring_holdem_omaha(self, config, settings, db, cursor, base, category, site_hand_no, gametype_id + def ring_holdem_omaha(self, config, settings, base, category, site_hand_no, gametype_id ,hand_start_time, names, player_ids, start_cashes, positions, card_values ,card_suits, board_values, board_suits, winnings, rakes, action_types, allIns ,action_amounts, actionNos, hudImportData, maxSeats, tableName, seatNos): """stores a holdem/omaha hand into the database""" - t0 = time() - fpdb_simple.fillCardArrays(len(names), base, category, card_values, card_suits) - t1 = time() - fpdb_simple.fill_board_cards(board_values, board_suits) - t2 = time() + try: + t0 = time() + #print "in ring_holdem_omaha" + fpdb_simple.fillCardArrays(len(names), base, category, card_values, card_suits) + t1 = time() + fpdb_simple.fill_board_cards(board_values, board_suits) + t2 = time() - hands_id = fpdb_simple.storeHands(self.backend, db, cursor, site_hand_no, gametype_id - ,hand_start_time, names, tableName, maxSeats, - hudImportData, board_values, board_suits) - #TEMPORARY CALL! - Just until all functions are migrated - t3 = time() - hands_players_ids = fpdb_simple.store_hands_players_holdem_omaha( - self.backend, db, cursor, category, hands_id, player_ids, start_cashes - , positions, card_values, card_suits, winnings, rakes, seatNos, hudImportData) - t4 = time() - #print "ring holdem, backend=%d" % backend - if 'updateHudCache' not in settings or settings['updateHudCache'] != 'drop': - fpdb_simple.storeHudCache(self.backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData) - t5 = time() - t6 = time() - if self.saveActions: - fpdb_simple.storeActions(cursor, hands_players_ids, action_types, allIns, action_amounts, actionNos) - t7 = time() - #print "fills=(%4.3f) saves=(%4.3f,%4.3f,%4.3f,%4.3f)" % (t2-t0, t3-t2, t4-t3, t5-t4, t6-t5) + hands_id = self.storeHands(self.backend, site_hand_no, gametype_id + ,hand_start_time, names, tableName, maxSeats + ,hudImportData, board_values, board_suits) + #TEMPORARY CALL! - Just until all functions are migrated + t3 = time() + hands_players_ids = self.store_hands_players_holdem_omaha( + self.backend, category, hands_id, player_ids, start_cashes + , positions, card_values, card_suits, winnings, rakes, seatNos, hudImportData) + t4 = time() + if 'dropHudCache' not in settings or settings['dropHudCache'] != 'drop': + self.storeHudCache(self.backend, base, category, gametype_id, hand_start_time, player_ids, hudImportData) + t5 = time() + #print "fills=(%4.3f) saves=(%4.3f,%4.3f,%4.3f)" % (t2-t0, t3-t2, t4-t3, t5-t4) + except: + print "ring_holdem_omaha error: " + str(sys.exc_value) # in case exception doesn't get printed + raise fpdb_simple.FpdbError("ring_holdem_omaha error: " + str(sys.exc_value)) return hands_id #end def ring_holdem_omaha - def tourney_holdem_omaha(self, config, settings, db, cursor, base, category, siteTourneyNo, buyin, fee, knockout + def tourney_holdem_omaha(self, config, settings, base, category, siteTourneyNo, buyin, fee, knockout ,entries, prizepool, tourney_start, payin_amounts, ranks, tourneyTypeId ,siteId #end of tourney specific params ,site_hand_no, gametype_id, hand_start_time, names, player_ids @@ -364,55 +532,1201 @@ class Database: ,actionNos, hudImportData, maxSeats, tableName, seatNos): """stores a tourney holdem/omaha hand into the database""" - fpdb_simple.fillCardArrays(len(names), base, category, card_values, card_suits) - fpdb_simple.fill_board_cards(board_values, board_suits) + try: + fpdb_simple.fillCardArrays(len(names), base, category, card_values, card_suits) + fpdb_simple.fill_board_cards(board_values, board_suits) - tourney_id = fpdb_simple.store_tourneys(cursor, tourneyTypeId, siteTourneyNo, entries, prizepool, tourney_start) - tourneys_players_ids = fpdb_simple.store_tourneys_players(cursor, tourney_id, player_ids, payin_amounts, ranks, winnings) + tourney_id = self.store_tourneys(tourneyTypeId, siteTourneyNo, entries, prizepool, tourney_start) + tourneys_players_ids = self.store_tourneys_players(tourney_id, player_ids, payin_amounts, ranks, winnings) - hands_id = fpdb_simple.storeHands(self.backend, db, cursor, site_hand_no, gametype_id - ,hand_start_time, names, tableName, maxSeats) + hands_id = self.storeHands(self.backend, site_hand_no, gametype_id + ,hand_start_time, names, tableName, maxSeats + ,hudImportData, board_values, board_suits) - hands_players_ids = fpdb_simple.store_hands_players_holdem_omaha_tourney( - self.backend, db, cursor, category, hands_id, player_ids, start_cashes, positions - , card_values, card_suits, winnings, rakes, seatNos, tourneys_players_ids) + hands_players_ids = self.store_hands_players_holdem_omaha_tourney( + self.backend, category, hands_id, player_ids, start_cashes, positions + , card_values, card_suits, winnings, rakes, seatNos, tourneys_players_ids + , hudImportData) - #print "tourney holdem, backend=%d" % backend - if 'updateHudCache' not in settings or settings['updateHudCache'] != 'drop': - fpdb_simple.storeHudCache(self.backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData) + #print "tourney holdem, backend=%d" % backend + if 'dropHudCache' not in settings or settings['dropHudCache'] != 'drop': + self.storeHudCache(self.backend, base, category, gametype_id, hand_start_time, player_ids, hudImportData) + except: + print "tourney_holdem_omaha error: " + str(sys.exc_value) # in case exception doesn't get printed + raise fpdb_simple.FpdbError("tourney_holdem_omaha error: " + str(sys.exc_value)) - if self.saveActions: - fpdb_simple.storeActions(cursor, hands_players_ids, action_types, allIns, action_amounts, actionNos) return hands_id #end def tourney_holdem_omaha - def tourney_stud(self, config, settings, db, cursor, base, category, siteTourneyNo, buyin, fee, knockout, entries + def tourney_stud(self, config, settings, base, category, siteTourneyNo, buyin, fee, knockout, entries ,prizepool, tourneyStartTime, payin_amounts, ranks, tourneyTypeId, siteId ,siteHandNo, gametypeId, handStartTime, names, playerIds, startCashes, antes ,cardValues, cardSuits, winnings, rakes, actionTypes, allIns, actionAmounts ,actionNos, hudImportData, maxSeats, tableName, seatNos): #stores a tourney stud/razz hand into the database - fpdb_simple.fillCardArrays(len(names), base, category, cardValues, cardSuits) + try: + fpdb_simple.fillCardArrays(len(names), base, category, cardValues, cardSuits) - tourney_id = fpdb_simple.store_tourneys(cursor, tourneyTypeId, siteTourneyNo, entries, prizepool, tourneyStartTime) + tourney_id = self.store_tourneys(tourneyTypeId, siteTourneyNo, entries, prizepool, tourneyStartTime) - tourneys_players_ids = fpdb_simple.store_tourneys_players(cursor, tourney_id, playerIds, payin_amounts, ranks, winnings) + tourneys_players_ids = self.store_tourneys_players(tourney_id, playerIds, payin_amounts, ranks, winnings) - hands_id = fpdb_simple.storeHands(self.backend, db, cursor, siteHandNo, gametypeId, handStartTime, names, tableName, maxSeats) + hands_id = self.storeHands( self.backend, siteHandNo, gametypeId + , handStartTime, names, tableName, maxSeats + , hudImportData, board_values, board_suits ) - hands_players_ids = fpdb_simple.store_hands_players_stud_tourney(self.backend, db, cursor, hands_id - , playerIds, startCashes, antes, cardValues, cardSuits - , winnings, rakes, seatNos, tourneys_players_ids) + hands_players_ids = self.store_hands_players_stud_tourney(self.backend, hands_id + , playerIds, startCashes, antes, cardValues, cardSuits + , winnings, rakes, seatNos, tourneys_players_ids) - if 'updateHudCache' not in settings or settings['updateHudCache'] != 'drop': - fpdb_simple.storeHudCache(self.backend, cursor, base, category, gametypeId, hand_start_time, playerIds, hudImportData) + if 'dropHudCache' not in settings or settings['dropHudCache'] != 'drop': + self.storeHudCache(self.backend, base, category, gametypeId, hand_start_time, playerIds, hudImportData) + except: + print "tourney_stud error: " + str(sys.exc_value) # in case exception doesn't get printed + raise fpdb_simple.FpdbError("tourney_stud error: " + str(sys.exc_value)) - if self.saveActions: - fpdb_simple.storeActions(cursor, hands_players_ids, actionTypes, allIns, actionAmounts, actionNos) return hands_id #end def tourney_stud + def prepareBulkImport(self): + """Drop some indexes/foreign keys to prepare for bulk import. + Currently keeping the standalone indexes as needed to import quickly""" + stime = time() + c = self.get_cursor() + # sc: don't think autocommit=0 is needed, should already be in that mode + if self.backend == self.MYSQL_INNODB: + c.execute("SET foreign_key_checks=0") + c.execute("SET autocommit=0") + return + if self.backend == self.PGSQL: + self.connection.set_isolation_level(0) # allow table/index operations to work + for fk in self.foreignKeys[self.backend]: + if fk['drop'] == 1: + if self.backend == self.MYSQL_INNODB: + c.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 = c.fetchone() + print "preparebulk find fk: cons=", cons + if cons: + print "dropping mysql fk", cons[0], fk['fktab'], fk['fkcol'] + try: + c.execute("alter table " + fk['fktab'] + " drop foreign key " + cons[0]) + except: + print " drop failed: " + str(sys.exc_info()) + elif self.backend == self.PGSQL: + # DON'T FORGET TO RECREATE THEM!! + print "dropping pg fk", fk['fktab'], fk['fkcol'] + try: + # try to lock table to see if index drop will work: + # hmmm, tested by commenting out rollback in grapher. lock seems to work but + # then drop still hangs :-( does work in some tests though?? + # will leave code here for now pending further tests/enhancement ... + c.execute( "lock table %s in exclusive mode nowait" % (fk['fktab'],) ) + #print "after lock, status:", c.statusmessage + #print "alter table %s drop constraint %s_%s_fkey" % (fk['fktab'], fk['fktab'], fk['fkcol']) + try: + c.execute("alter table %s drop constraint %s_%s_fkey" % (fk['fktab'], fk['fktab'], fk['fkcol'])) + print "dropped pg fk pg fk %s_%s_fkey, continuing ..." % (fk['fktab'], fk['fkcol']) + except: + if "does not exist" not in str(sys.exc_value): + print "warning: drop pg fk %s_%s_fkey failed: %s, continuing ..." \ + % (fk['fktab'], fk['fkcol'], str(sys.exc_value).rstrip('\n') ) + except: + print "warning: constraint %s_%s_fkey not dropped: %s, continuing ..." \ + % (fk['fktab'],fk['fkcol'], str(sys.exc_value).rstrip('\n')) + else: + print "Only MySQL and Postgres supported so far" + return -1 + + for idx in self.indexes[self.backend]: + if idx['drop'] == 1: + if self.backend == self.MYSQL_INNODB: + print "dropping mysql index ", idx['tab'], idx['col'] + try: + # apparently nowait is not implemented in mysql so this just hangs if there are locks + # preventing the index drop :-( + c.execute( "alter table %s drop index %s;", (idx['tab'],idx['col']) ) + except: + print " drop index failed: " + str(sys.exc_info()) + # ALTER TABLE `fpdb`.`handsplayers` DROP INDEX `playerId`; + # using: 'HandsPlayers' drop index 'playerId' + elif self.backend == self.PGSQL: + # DON'T FORGET TO RECREATE THEM!! + print "dropping pg index ", idx['tab'], idx['col'] + try: + # try to lock table to see if index drop will work: + c.execute( "lock table %s in exclusive mode nowait" % (idx['tab'],) ) + #print "after lock, status:", c.statusmessage + try: + # table locked ok so index drop should work: + #print "drop index %s_%s_idx" % (idx['tab'],idx['col']) + c.execute( "drop index if exists %s_%s_idx" % (idx['tab'],idx['col']) ) + #print "dropped pg index ", idx['tab'], idx['col'] + except: + if "does not exist" not in str(sys.exc_value): + print "warning: drop index %s_%s_idx failed: %s, continuing ..." \ + % (idx['tab'],idx['col'], str(sys.exc_value).rstrip('\n')) + except: + print "warning: index %s_%s_idx not dropped %s, continuing ..." \ + % (idx['tab'],idx['col'], str(sys.exc_value).rstrip('\n')) + else: + print "Error: Only MySQL and Postgres supported so far" + return -1 + + if self.backend == self.PGSQL: + self.connection.set_isolation_level(1) # go back to normal isolation level + self.commit() # seems to clear up errors if there were any in postgres + ptime = time() - stime + print "prepare import took", ptime, "seconds" + #end def prepareBulkImport + + def afterBulkImport(self): + """Re-create any dropped indexes/foreign keys after bulk import""" + stime = time() + + c = self.get_cursor() + if self.backend == self.MYSQL_INNODB: + c.execute("SET foreign_key_checks=1") + c.execute("SET autocommit=1") + return + + if self.backend == self.PGSQL: + self.connection.set_isolation_level(0) # allow table/index operations to work + for fk in self.foreignKeys[self.backend]: + if fk['drop'] == 1: + if self.backend == self.MYSQL_INNODB: + c.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 = c.fetchone() + #print "afterbulk: cons=", cons + if cons: + pass + else: + print "creating fk ", fk['fktab'], fk['fkcol'], "->", fk['rtab'], fk['rcol'] + try: + c.execute("alter table " + fk['fktab'] + " add foreign key (" + + fk['fkcol'] + ") references " + fk['rtab'] + "(" + + fk['rcol'] + ")") + except: + print " create fk failed: " + str(sys.exc_info()) + elif self.backend == self.PGSQL: + print "creating fk ", fk['fktab'], fk['fkcol'], "->", fk['rtab'], fk['rcol'] + try: + c.execute("alter table " + fk['fktab'] + " add constraint " + + fk['fktab'] + '_' + fk['fkcol'] + '_fkey' + + " foreign key (" + fk['fkcol'] + + ") references " + fk['rtab'] + "(" + fk['rcol'] + ")") + except: + print " create fk failed: " + str(sys.exc_info()) + else: + print "Only MySQL and Postgres supported so far" + return -1 + + for idx in self.indexes[self.backend]: + if idx['drop'] == 1: + if self.backend == self.MYSQL_INNODB: + print "creating mysql index ", idx['tab'], idx['col'] + try: + c.execute( "alter table %s add index %s(%s)" + , (idx['tab'],idx['col'],idx['col']) ) + except: + print " create fk failed: " + str(sys.exc_info()) + elif self.backend == self.PGSQL: + # pass + # 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']) + c.execute( "create index %s_%s_idx on %s(%s)" + % (idx['tab'], idx['col'], idx['tab'], idx['col']) ) + except: + print " create index failed: " + str(sys.exc_info()) + else: + print "Only MySQL and Postgres supported so far" + return -1 + + if self.backend == self.PGSQL: + self.connection.set_isolation_level(1) # go back to normal isolation level + self.commit() # seems to clear up errors if there were any in postgres + atime = time() - stime + print "After import took", atime, "seconds" + #end def afterBulkImport + + def drop_referential_integrity(self): + """Update all tables to remove foreign keys""" + + c = self.get_cursor() + c.execute(self.sql.query['list_tables']) + result = c.fetchall() + + for i in range(len(result)): + c.execute("SHOW CREATE TABLE " + result[i][0]) + inner = c.fetchall() + + for j in range(len(inner)): + # result[i][0] - Table name + # result[i][1] - CREATE TABLE parameters + #Searching for CONSTRAINT `tablename_ibfk_1` + for m in re.finditer('(ibfk_[0-9]+)', inner[j][1]): + key = "`" + inner[j][0] + "_" + m.group() + "`" + c.execute("ALTER TABLE " + inner[j][0] + " DROP FOREIGN KEY " + key) + self.commit() + #end drop_referential_inegrity + + def recreate_tables(self): + """(Re-)creates the tables of the current DB""" + + self.drop_tables() + self.create_tables() + self.createAllIndexes() + self.commit() + print "Finished recreating tables" + #end def recreate_tables + + def create_tables(self): + #todo: should detect and fail gracefully if tables already exist. + try: + logging.debug(self.sql.query['createSettingsTable']) + c = self.get_cursor() + c.execute(self.sql.query['createSettingsTable']) + logging.debug(self.sql.query['createSitesTable']) + c.execute(self.sql.query['createSitesTable']) + c.execute(self.sql.query['createGametypesTable']) + c.execute(self.sql.query['createPlayersTable']) + c.execute(self.sql.query['createAutoratesTable']) + c.execute(self.sql.query['createHandsTable']) + c.execute(self.sql.query['createTourneyTypesTable']) + c.execute(self.sql.query['createTourneysTable']) + c.execute(self.sql.query['createTourneysPlayersTable']) + c.execute(self.sql.query['createHandsPlayersTable']) + c.execute(self.sql.query['createHandsActionsTable']) + c.execute(self.sql.query['createHudCacheTable']) + #c.execute(self.sql.query['addTourneyIndex']) + #c.execute(self.sql.query['addHandsIndex']) + #c.execute(self.sql.query['addPlayersIndex']) + self.fillDefaultData() + self.commit() + except: + print "Error creating tables: ", str(sys.exc_value) + self.rollback() + raise fpdb_simple.FpdbError( "Error creating tables " + str(sys.exc_value) ) +#end def disconnect + + def drop_tables(self): + """Drops the fpdb tables from the current db""" + + try: + c = self.get_cursor() + if(self.get_backend_name() == 'MySQL InnoDB'): + #Databases with FOREIGN KEY support need this switched of before you can drop tables + self.drop_referential_integrity() + + # Query the DB to see what tables exist + c.execute(self.sql.query['list_tables']) + for table in c: + c.execute(self.sql.query['drop_table'] + table[0]) + elif(self.get_backend_name() == 'PostgreSQL'): + self.commit()# I have no idea why this makes the query work--REB 07OCT2008 + c.execute(self.sql.query['list_tables']) + tables = c.fetchall() + for table in tables: + c.execute(self.sql.query['drop_table'] + table[0] + ' cascade') + elif(self.get_backend_name() == 'SQLite'): + c.execute(self.sql.query['list_tables']) + for table in c.fetchall(): + logging.debug(self.sql.query['drop_table'] + table[0]) + c.execute(self.sql.query['drop_table'] + table[0]) + + self.commit() + except: + print "Error dropping tables: " + str(sys.exc_value) + raise fpdb_simple.FpdbError( "Error dropping tables " + str(sys.exc_value) ) + #end def drop_tables + + def createAllIndexes(self): + """Create new indexes""" + + try: + if self.backend == self.PGSQL: + self.connection.set_isolation_level(0) # allow table/index operations to work + for idx in self.indexes[self.backend]: + if self.backend == self.MYSQL_INNODB: + print "creating mysql index ", idx['tab'], idx['col'] + try: + self.get_cursor().execute( "alter table %s add index %s(%s)" + , (idx['tab'],idx['col'],idx['col']) ) + except: + pass + elif self.backend == self.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']) + self.get_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 self.backend == self.PGSQL: + self.connection.set_isolation_level(1) # go back to normal isolation level + except: + print "Error creating indexes: " + str(sys.exc_value) + raise fpdb_simple.FpdbError( "Error creating indexes " + str(sys.exc_value) ) + #end def createAllIndexes + + def dropAllIndexes(self): + """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 self.backend == self.PGSQL: + self.connection.set_isolation_level(0) # allow table/index operations to work + for idx in self.indexes[self.backend]: + if self.backend == self.MYSQL_INNODB: + print "dropping mysql index ", idx['tab'], idx['col'] + try: + self.get_cursor().execute( "alter table %s drop index %s" + , (idx['tab'],idx['col']) ) + except: + pass + elif self.backend == self.PGSQL: + print "dropping pg index ", idx['tab'], idx['col'] + # mod to use tab_col for index name? + try: + self.get_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 self.backend == self.PGSQL: + self.connection.set_isolation_level(1) # go back to normal isolation level + #end def dropAllIndexes + + def fillDefaultData(self): + c = self.get_cursor() + c.execute("INSERT INTO Settings (version) VALUES (118);") + c.execute("INSERT INTO Sites (name,currency) VALUES ('Full Tilt Poker', 'USD')") + c.execute("INSERT INTO Sites (name,currency) VALUES ('PokerStars', 'USD')") + c.execute("INSERT INTO Sites (name,currency) VALUES ('Everleaf', 'USD')") + c.execute("INSERT INTO Sites (name,currency) VALUES ('Win2day', 'USD')") + c.execute("INSERT INTO TourneyTypes VALUES (DEFAULT, 1, 0, 0, 0, False);") + #c.execute("""INSERT INTO TourneyTypes + # (siteId,buyin,fee,knockout,rebuyOrAddon) VALUES + # (1,0,0,0,?)""",(False,) ) + #end def fillDefaultData + + def rebuild_hudcache(self): + """clears hudcache and rebuilds from the individual handsplayers records""" + + try: + stime = time() + self.connection.cursor().execute(self.sql.query['clearHudCache']) + self.connection.cursor().execute(self.sql.query['rebuildHudCache']) + self.commit() + print "Rebuild hudcache took %.1f seconds" % (time() - stime,) + except: + print "Error rebuilding hudcache:", str(sys.exc_value) + #end def rebuild_hudcache + + + def analyzeDB(self): + """Do whatever the DB can offer to update index/table statistics""" + stime = time() + if self.backend == self.MYSQL_INNODB: + try: + self.get_cursor().execute(self.sql.query['analyze']) + except: + print "Error during analyze:", str(sys.exc_value) + elif self.backend == self.PGSQL: + self.connection.set_isolation_level(0) # allow vacuum to work + try: + self.get_cursor().execute(self.sql.query['analyze']) + except: + print "Error during analyze:", str(sys.exc_value) + self.connection.set_isolation_level(1) # go back to normal isolation level + self.commit() + atime = time() - stime + print "Analyze took %.1f seconds" % (atime,) + #end def analyzeDB + + +# Start of Hand Writing routines. Idea is to provide a mixture of routines to store Hand data +# however the calling prog requires. Main aims: +# - existing static routines from fpdb_simple just modified + + def lock_for_insert(self): + """Lock tables in MySQL to try to speed inserts up""" + try: + self.get_cursor().execute(self.sql.query['lockForInsert']) + except: + print "Error during fdb.lock_for_insert:", str(sys.exc_value) + #end def lock_for_insert + + + def store_the_hand(self, h): + """Take a HandToWrite object and store it in the db""" + + # Following code writes hands to database and commits (or rolls back if there is an error) + try: + result = None + if h.isTourney: + ranks = map(lambda x: 0, h.names) # create an array of 0's equal to the length of names + payin_amounts = fpdb_simple.calcPayin(len(h.names), h.buyin, h.fee) + + if h.base == "hold": + result = self.tourney_holdem_omaha( + h.config, h.settings, h.base, h.category, h.siteTourneyNo, h.buyin + , h.fee, h.knockout, h.entries, h.prizepool, h.tourneyStartTime + , h.payin_amounts, h.ranks, h.tourneyTypeId, h.siteID, h.siteHandNo + , h.gametypeID, h.handStartTime, h.names, h.playerIDs, h.startCashes + , h.positions, h.cardValues, h.cardSuits, h.boardValues, h.boardSuits + , h.winnings, h.rakes, h.actionTypes, h.allIns, h.actionAmounts + , h.actionNos, h.hudImportData, h.maxSeats, h.tableName, h.seatNos) + elif h.base == "stud": + result = self.tourney_stud( + h.config, h.settings, h.base, h.category, h.siteTourneyNo + , h.buyin, h.fee, h.knockout, h.entries, h.prizepool, h.tourneyStartTime + , h.payin_amounts, h.ranks, h.tourneyTypeId, h.siteID, h.siteHandNo + , h.gametypeID, h.handStartTime, h.names, h.playerIDs, h.startCashes + , h.antes, h.cardValues, h.cardSuits, h.winnings, h.rakes, h.actionTypes + , h.allIns, h.actionAmounts, h.actionNos, h.hudImportData, h.maxSeats + , h.tableName, h.seatNos) + else: + raise fpself.simple.Fpself.rror("unrecognised category") + else: + if h.base == "hold": + result = self.ring_holdem_omaha( + h.config, h.settings, h.base, h.category, h.siteHandNo + , h.gametypeID, h.handStartTime, h.names, h.playerIDs + , h.startCashes, h.positions, h.cardValues, h.cardSuits + , h.boardValues, h.boardSuits, h.winnings, h.rakes + , h.actionTypes, h.allIns, h.actionAmounts, h.actionNos + , h.hudImportData, h.maxSeats, h.tableName, h.seatNos) + elif h.base == "stud": + result = self.ring_stud( + h.config, h.settings, h.base, h.category, h.siteHandNo, h.gametypeID + , h.handStartTime, h.names, h.playerIDs, h.startCashes, h.antes + , h.cardValues, h.cardSuits, h.winnings, h.rakes, h.actionTypes, h.allIns + , h.actionAmounts, h.actionNos, h.hudImportData, h.maxSeats, h.tableName + , h.seatNos) + else: + raise fpself.simple.Fpself.rror ("unrecognised category") + self.commit() + except: + print "Error storing hand: " + str(sys.exc_value) + self.rollback() + + return result + #end def store_the_hand + + def storeHands(self, backend, site_hand_no, gametype_id + ,hand_start_time, names, tableName, maxSeats, hudCache + ,board_values, board_suits): + + cards = [Card.cardFromValueSuit(v,s) for v,s in zip(board_values,board_suits)] + #stores into table hands: + try: + self.get_cursor().execute ("""INSERT INTO Hands + (siteHandNo, gametypeId, handStart, seats, tableName, importTime, maxSeats + ,boardcard1,boardcard2,boardcard3,boardcard4,boardcard5 + ,playersVpi, playersAtStreet1, playersAtStreet2 + ,playersAtStreet3, playersAtStreet4, playersAtShowdown + ,street0Raises, street1Raises, street2Raises + ,street3Raises, street4Raises, street1Pot + ,street2Pot, street3Pot, street4Pot + ,showdownPot + ) + VALUES + (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) + """ + , (site_hand_no, gametype_id, hand_start_time, len(names), tableName, datetime.today(), maxSeats + ,cards[0], cards[1], cards[2], cards[3], cards[4] + ,hudCache['playersVpi'], hudCache['playersAtStreet1'], hudCache['playersAtStreet2'] + ,hudCache['playersAtStreet3'], hudCache['playersAtStreet4'], hudCache['playersAtShowdown'] + ,hudCache['street0Raises'], hudCache['street1Raises'], hudCache['street2Raises'] + ,hudCache['street3Raises'], hudCache['street4Raises'], hudCache['street1Pot'] + ,hudCache['street2Pot'], hudCache['street3Pot'], hudCache['street4Pot'] + ,hudCache['showdownPot'] + )) + ret = self.get_last_insert_id() + except: + ret = -1 + raise fpdb_simple.FpdbError( "storeHands error: " + str(sys.exc_value) ) + + return ret + #end def storeHands + + def store_hands_players_holdem_omaha(self, backend, category, hands_id, player_ids, start_cashes + ,positions, card_values, card_suits, winnings, rakes, seatNos, hudCache): + result=[] + + # postgres (and others?) needs the booleans converted to ints before saving: + # (or we could just save them as boolean ... but then we can't sum them so easily in sql ???) + # NO - storing booleans for now so don't need this + #hudCacheInt = {} + #for k,v in hudCache.iteritems(): + # if k in ('wonWhenSeenStreet1', 'wonAtSD', 'totalProfit'): + # hudCacheInt[k] = v + # else: + # hudCacheInt[k] = map(lambda x: 1 if x else 0, v) + + try: + inserts = [] + for i in xrange(len(player_ids)): + card1 = Card.cardFromValueSuit(card_values[i][0], card_suits[i][0]) + card2 = Card.cardFromValueSuit(card_values[i][1], card_suits[i][1]) + + if (category=="holdem"): + startCards = Card.twoStartCards(card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1]) + card3 = None + card4 = None + elif (category=="omahahi" or category=="omahahilo"): + startCards = Card.fourStartCards(card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1] + ,card_values[i][2], card_suits[i][2], card_values[i][3], card_suits[i][3]) + card3 = Card.cardFromValueSuit(card_values[i][2], card_suits[i][2]) + card4 = Card.cardFromValueSuit(card_values[i][3], card_suits[i][3]) + else: + raise fpdb_simple.FpdbError("invalid category") + + inserts.append( ( + hands_id, player_ids[i], start_cashes[i], positions[i], 1, # tourneytypeid + card1, card2, card3, card4, startCards, + winnings[i], rakes[i], seatNos[i], hudCache['totalProfit'][i], + hudCache['street0VPI'][i], hudCache['street0Aggr'][i], + hudCache['street0_3BChance'][i], hudCache['street0_3BDone'][i], + hudCache['street1Seen'][i], hudCache['street2Seen'][i], hudCache['street3Seen'][i], + hudCache['street4Seen'][i], hudCache['sawShowdown'][i], + hudCache['street1Aggr'][i], hudCache['street2Aggr'][i], hudCache['street3Aggr'][i], hudCache['street4Aggr'][i], + hudCache['otherRaisedStreet1'][i], hudCache['otherRaisedStreet2'][i], + hudCache['otherRaisedStreet3'][i], hudCache['otherRaisedStreet4'][i], + hudCache['foldToOtherRaisedStreet1'][i], hudCache['foldToOtherRaisedStreet2'][i], + hudCache['foldToOtherRaisedStreet3'][i], hudCache['foldToOtherRaisedStreet4'][i], + hudCache['wonWhenSeenStreet1'][i], hudCache['wonAtSD'][i], + hudCache['stealAttemptChance'][i], hudCache['stealAttempted'][i], hudCache['foldBbToStealChance'][i], + hudCache['foldedBbToSteal'][i], hudCache['foldSbToStealChance'][i], hudCache['foldedSbToSteal'][i], + hudCache['street1CBChance'][i], hudCache['street1CBDone'][i], hudCache['street2CBChance'][i], hudCache['street2CBDone'][i], + hudCache['street3CBChance'][i], hudCache['street3CBDone'][i], hudCache['street4CBChance'][i], hudCache['street4CBDone'][i], + hudCache['foldToStreet1CBChance'][i], hudCache['foldToStreet1CBDone'][i], + hudCache['foldToStreet2CBChance'][i], hudCache['foldToStreet2CBDone'][i], + hudCache['foldToStreet3CBChance'][i], hudCache['foldToStreet3CBDone'][i], + hudCache['foldToStreet4CBChance'][i], hudCache['foldToStreet4CBDone'][i], + hudCache['street1CheckCallRaiseChance'][i], hudCache['street1CheckCallRaiseDone'][i], + hudCache['street2CheckCallRaiseChance'][i], hudCache['street2CheckCallRaiseDone'][i], + hudCache['street3CheckCallRaiseChance'][i], hudCache['street3CheckCallRaiseDone'][i], + hudCache['street4CheckCallRaiseChance'][i], hudCache['street4CheckCallRaiseDone'][i], + hudCache['street0Calls'][i], hudCache['street1Calls'][i], hudCache['street2Calls'][i], hudCache['street3Calls'][i], hudCache['street4Calls'][i], + hudCache['street0Bets'][i], hudCache['street1Bets'][i], hudCache['street2Bets'][i], hudCache['street3Bets'][i], hudCache['street4Bets'][i] + ) ) + self.get_cursor().executemany (""" + INSERT INTO HandsPlayers + (handId, playerId, startCash, position, tourneyTypeId, + card1, card2, card3, card4, startCards, winnings, rake, seatNo, totalProfit, + street0VPI, street0Aggr, street0_3BChance, street0_3BDone, + street1Seen, street2Seen, street3Seen, street4Seen, sawShowdown, + street1Aggr, street2Aggr, street3Aggr, street4Aggr, + otherRaisedStreet1, otherRaisedStreet2, otherRaisedStreet3, otherRaisedStreet4, + foldToOtherRaisedStreet1, foldToOtherRaisedStreet2, foldToOtherRaisedStreet3, foldToOtherRaisedStreet4, + wonWhenSeenStreet1, wonAtSD, + stealAttemptChance, stealAttempted, foldBbToStealChance, foldedBbToSteal, foldSbToStealChance, foldedSbToSteal, + street1CBChance, street1CBDone, street2CBChance, street2CBDone, + street3CBChance, street3CBDone, street4CBChance, street4CBDone, + foldToStreet1CBChance, foldToStreet1CBDone, foldToStreet2CBChance, foldToStreet2CBDone, + foldToStreet3CBChance, foldToStreet3CBDone, foldToStreet4CBChance, foldToStreet4CBDone, + street1CheckCallRaiseChance, street1CheckCallRaiseDone, street2CheckCallRaiseChance, street2CheckCallRaiseDone, + street3CheckCallRaiseChance, street3CheckCallRaiseDone, street4CheckCallRaiseChance, street4CheckCallRaiseDone, + street0Calls, street1Calls, street2Calls, street3Calls, street4Calls, + street0Bets, street1Bets, street2Bets, street3Bets, street4Bets + ) + VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""" + ,inserts ) + result.append( self.get_last_insert_id() ) + + #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i])) + #result.append(cursor.fetchall()[0][0]) + result.append( self.get_last_insert_id() ) + except: + raise fpdb_simple.FpdbError( "store_hands_players_holdem_omaha error: " + str(sys.exc_value) ) + + return result + #end def store_hands_players_holdem_omaha + + def store_hands_players_stud(self, backend, hands_id, player_ids, start_cashes, antes, + card_values, card_suits, winnings, rakes, seatNos): + #stores hands_players rows for stud/razz games. returns an array of the resulting IDs + + try: + result=[] + #print "before inserts in store_hands_players_stud, antes:", antes + for i in xrange(len(player_ids)): + card1 = Card.cardFromValueSuit(card_values[i][0], card_suits[i][0]) + card2 = Card.cardFromValueSuit(card_values[i][1], card_suits[i][1]) + card3 = Card.cardFromValueSuit(card_values[i][2], card_suits[i][2]) + card4 = Card.cardFromValueSuit(card_values[i][3], card_suits[i][3]) + card5 = Card.cardFromValueSuit(card_values[i][4], card_suits[i][4]) + card6 = Card.cardFromValueSuit(card_values[i][5], card_suits[i][5]) + card7 = Card.cardFromValueSuit(card_values[i][6], card_suits[i][6]) + + self.get_cursor().execute ("""INSERT INTO HandsPlayers + (handId, playerId, startCash, ante, tourneyTypeId, + card1, card2, + card3, card4, + card5, card6, + card7, winnings, rake, seatNo) + VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", + (hands_id, player_ids[i], start_cashes[i], antes[i], 1, + card1, card2, + card3, card4, + card5, card6, + card7, winnings[i], rakes[i], seatNos[i])) + #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i])) + #result.append(cursor.fetchall()[0][0]) + result.append( self.get_last_insert_id() ) + except: + raise fpdb_simple.FpdbError( "store_hands_players_stud error: " + str(sys.exc_value) ) + + return result + #end def store_hands_players_stud + + def store_hands_players_holdem_omaha_tourney(self, backend, category, hands_id, player_ids + ,start_cashes, positions, card_values, card_suits + ,winnings, rakes, seatNos, tourneys_players_ids + ,hudCache): + #stores hands_players for tourney holdem/omaha hands + + try: + result=[] + inserts = [] + for i in xrange(len(player_ids)): + card1 = Card.cardFromValueSuit(card_values[i][0], card_suits[i][0]) + card2 = Card.cardFromValueSuit(card_values[i][1], card_suits[i][1]) + + if len(card_values[0])==2: + startCards = Card.twoStartCards(card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1]) + card3 = None + card4 = None + elif len(card_values[0])==4: + startCards = Card.fourStartCards(card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1] + ,card_values[i][2], card_suits[i][2], card_values[i][3], card_suits[i][3]) + card3 = Card.cardFromValueSuit(card_values[i][2], card_suits[i][2]) + card4 = Card.cardFromValueSuit(card_values[i][3], card_suits[i][3]) + else: + raise FpdbError ("invalid card_values length:"+str(len(card_values[0]))) + + inserts.append( (hands_id, player_ids[i], start_cashes[i], positions[i], 1, # tourneytypeid + card1, card2, card3, card4, startCards, + winnings[i], rakes[i], tourneys_players_ids[i], seatNos[i], hudCache['totalProfit'][i], + hudCache['street0VPI'][i], hudCache['street0Aggr'][i], + hudCache['street0_3BChance'][i], hudCache['street0_3BDone'][i], + hudCache['street1Seen'][i], hudCache['street2Seen'][i], hudCache['street3Seen'][i], + hudCache['street4Seen'][i], hudCache['sawShowdown'][i], + hudCache['street1Aggr'][i], hudCache['street2Aggr'][i], hudCache['street3Aggr'][i], hudCache['street4Aggr'][i], + hudCache['otherRaisedStreet1'][i], hudCache['otherRaisedStreet2'][i], + hudCache['otherRaisedStreet3'][i], hudCache['otherRaisedStreet4'][i], + hudCache['foldToOtherRaisedStreet1'][i], hudCache['foldToOtherRaisedStreet2'][i], + hudCache['foldToOtherRaisedStreet3'][i], hudCache['foldToOtherRaisedStreet4'][i], + hudCache['wonWhenSeenStreet1'][i], hudCache['wonAtSD'][i], + hudCache['stealAttemptChance'][i], hudCache['stealAttempted'][i], hudCache['foldBbToStealChance'][i], + hudCache['foldedBbToSteal'][i], hudCache['foldSbToStealChance'][i], hudCache['foldedSbToSteal'][i], + hudCache['street1CBChance'][i], hudCache['street1CBDone'][i], hudCache['street2CBChance'][i], hudCache['street2CBDone'][i], + hudCache['street3CBChance'][i], hudCache['street3CBDone'][i], hudCache['street4CBChance'][i], hudCache['street4CBDone'][i], + hudCache['foldToStreet1CBChance'][i], hudCache['foldToStreet1CBDone'][i], + hudCache['foldToStreet2CBChance'][i], hudCache['foldToStreet2CBDone'][i], + hudCache['foldToStreet3CBChance'][i], hudCache['foldToStreet3CBDone'][i], + hudCache['foldToStreet4CBChance'][i], hudCache['foldToStreet4CBDone'][i], + hudCache['street1CheckCallRaiseChance'][i], hudCache['street1CheckCallRaiseDone'][i], + hudCache['street2CheckCallRaiseChance'][i], hudCache['street2CheckCallRaiseDone'][i], + hudCache['street3CheckCallRaiseChance'][i], hudCache['street3CheckCallRaiseDone'][i], + hudCache['street4CheckCallRaiseChance'][i], hudCache['street4CheckCallRaiseDone'][i], + hudCache['street0Calls'][i], hudCache['street1Calls'][i], hudCache['street2Calls'][i], + hudCache['street3Calls'][i], hudCache['street4Calls'][i], + hudCache['street0Bets'][i], hudCache['street1Bets'][i], hudCache['street2Bets'][i], + hudCache['street3Bets'][i], hudCache['street4Bets'][i] + ) ) + + self.get_cursor().executemany (""" + INSERT INTO HandsPlayers + (handId, playerId, startCash, position, tourneyTypeId, + card1, card2, card3, card4, startCards, winnings, rake, tourneysPlayersId, seatNo, totalProfit, + street0VPI, street0Aggr, street0_3BChance, street0_3BDone, + street1Seen, street2Seen, street3Seen, street4Seen, sawShowdown, + street1Aggr, street2Aggr, street3Aggr, street4Aggr, + otherRaisedStreet1, otherRaisedStreet2, otherRaisedStreet3, otherRaisedStreet4, + foldToOtherRaisedStreet1, foldToOtherRaisedStreet2, foldToOtherRaisedStreet3, foldToOtherRaisedStreet4, + wonWhenSeenStreet1, wonAtSD, + stealAttemptChance, stealAttempted, foldBbToStealChance, foldedBbToSteal, foldSbToStealChance, foldedSbToSteal, + street1CBChance, street1CBDone, street2CBChance, street2CBDone, + street3CBChance, street3CBDone, street4CBChance, street4CBDone, + foldToStreet1CBChance, foldToStreet1CBDone, foldToStreet2CBChance, foldToStreet2CBDone, + foldToStreet3CBChance, foldToStreet3CBDone, foldToStreet4CBChance, foldToStreet4CBDone, + street1CheckCallRaiseChance, street1CheckCallRaiseDone, street2CheckCallRaiseChance, street2CheckCallRaiseDone, + street3CheckCallRaiseChance, street3CheckCallRaiseDone, street4CheckCallRaiseChance, street4CheckCallRaiseDone, + street0Calls, street1Calls, street2Calls, street3Calls, street4Calls, + street0Bets, street1Bets, street2Bets, street3Bets, street4Bets + ) + VALUES + (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""" + ,inserts ) + + result.append( self.get_last_insert_id() ) + #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i])) + #result.append(cursor.fetchall()[0][0]) + except: + raise fpdb_simple.FpdbError( "store_hands_players_holdem_omaha_tourney error: " + str(sys.exc_value) ) + + return result + #end def store_hands_players_holdem_omaha_tourney + + def store_hands_players_stud_tourney(self, backend, hands_id, player_ids, start_cashes, + antes, card_values, card_suits, winnings, rakes, seatNos, tourneys_players_ids): + #stores hands_players for tourney stud/razz hands + + try: + result=[] + for i in xrange(len(player_ids)): + self.get_cursor().execute ("""INSERT INTO HandsPlayers + (handId, playerId, startCash, ante, + card1Value, card1Suit, card2Value, card2Suit, + card3Value, card3Suit, card4Value, card4Suit, + card5Value, card5Suit, card6Value, card6Suit, + card7Value, card7Suit, winnings, rake, tourneysPlayersId, seatNo) + VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, %s)""", + (hands_id, player_ids[i], start_cashes[i], antes[i], + card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1], + card_values[i][2], card_suits[i][2], card_values[i][3], card_suits[i][3], + card_values[i][4], card_suits[i][4], card_values[i][5], card_suits[i][5], + card_values[i][6], card_suits[i][6], winnings[i], rakes[i], tourneys_players_ids[i], seatNos[i])) + #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i])) + #result.append(cursor.fetchall()[0][0]) + result.append( self.get_last_insert_id() ) + except: + raise fpdb_simple.FpdbError( "store_hands_players_stud_tourney error: " + str(sys.exc_value) ) + + return result + #end def store_hands_players_stud_tourney + + def storeHudCache(self, backend, base, category, gametypeId, hand_start_time, playerIds, hudImportData): + """Update cached statistics. If update fails because no record exists, do an insert. + Can't use array updates here (not easily anyway) because we need to insert any rows + that don't get updated.""" + + # if (category=="holdem" or category=="omahahi" or category=="omahahilo"): + try: + if self.use_date_in_hudcache: + #print "key =", "d%02d%02d%02d " % (hand_start_time.year-2000, hand_start_time.month, hand_start_time.day) + styleKey = "d%02d%02d%02d" % (hand_start_time.year-2000, hand_start_time.month, hand_start_time.day) + else: + # hard-code styleKey as 'A000000' (all-time cache, no key) for now + styleKey = 'A000000' + + #print "storeHudCache, len(playerIds)=", len(playerIds), " len(vpip)=" \ + #, len(hudImportData['street0VPI']), " len(totprof)=", len(hudImportData['totalProfit']) + for player in xrange(len(playerIds)): + + # Set up a clean row + row=[] + row.append(0)#blank for id + row.append(gametypeId) + row.append(playerIds[player]) + row.append(len(playerIds))#seats + for i in xrange(len(hudImportData)+2): + row.append(0) + + if base=="hold": + row[4]=hudImportData['position'][player] + else: + row[4]=0 + row[5]=1 #tourneysGametypeId + row[6]+=1 #HDs + if hudImportData['street0VPI'][player]: row[7]+=1 + if hudImportData['street0Aggr'][player]: row[8]+=1 + if hudImportData['street0_3BChance'][player]: row[9]+=1 + if hudImportData['street0_3BDone'][player]: row[10]+=1 + if hudImportData['street1Seen'][player]: row[11]+=1 + if hudImportData['street2Seen'][player]: row[12]+=1 + if hudImportData['street3Seen'][player]: row[13]+=1 + if hudImportData['street4Seen'][player]: row[14]+=1 + if hudImportData['sawShowdown'][player]: row[15]+=1 + if hudImportData['street1Aggr'][player]: row[16]+=1 + if hudImportData['street2Aggr'][player]: row[17]+=1 + if hudImportData['street3Aggr'][player]: row[18]+=1 + if hudImportData['street4Aggr'][player]: row[19]+=1 + if hudImportData['otherRaisedStreet1'][player]: row[20]+=1 + if hudImportData['otherRaisedStreet2'][player]: row[21]+=1 + if hudImportData['otherRaisedStreet3'][player]: row[22]+=1 + if hudImportData['otherRaisedStreet4'][player]: row[23]+=1 + if hudImportData['foldToOtherRaisedStreet1'][player]: row[24]+=1 + if hudImportData['foldToOtherRaisedStreet2'][player]: row[25]+=1 + if hudImportData['foldToOtherRaisedStreet3'][player]: row[26]+=1 + if hudImportData['foldToOtherRaisedStreet4'][player]: row[27]+=1 + if hudImportData['wonWhenSeenStreet1'][player]!=0.0: row[28]+=hudImportData['wonWhenSeenStreet1'][player] + if hudImportData['wonAtSD'][player]!=0.0: row[29]+=hudImportData['wonAtSD'][player] + if hudImportData['stealAttemptChance'][player]: row[30]+=1 + if hudImportData['stealAttempted'][player]: row[31]+=1 + if hudImportData['foldBbToStealChance'][player]: row[32]+=1 + if hudImportData['foldedBbToSteal'][player]: row[33]+=1 + if hudImportData['foldSbToStealChance'][player]: row[34]+=1 + if hudImportData['foldedSbToSteal'][player]: row[35]+=1 + + if hudImportData['street1CBChance'][player]: row[36]+=1 + if hudImportData['street1CBDone'][player]: row[37]+=1 + if hudImportData['street2CBChance'][player]: row[38]+=1 + if hudImportData['street2CBDone'][player]: row[39]+=1 + if hudImportData['street3CBChance'][player]: row[40]+=1 + if hudImportData['street3CBDone'][player]: row[41]+=1 + if hudImportData['street4CBChance'][player]: row[42]+=1 + if hudImportData['street4CBDone'][player]: row[43]+=1 + + if hudImportData['foldToStreet1CBChance'][player]: row[44]+=1 + if hudImportData['foldToStreet1CBDone'][player]: row[45]+=1 + if hudImportData['foldToStreet2CBChance'][player]: row[46]+=1 + if hudImportData['foldToStreet2CBDone'][player]: row[47]+=1 + if hudImportData['foldToStreet3CBChance'][player]: row[48]+=1 + if hudImportData['foldToStreet3CBDone'][player]: row[49]+=1 + if hudImportData['foldToStreet4CBChance'][player]: row[50]+=1 + if hudImportData['foldToStreet4CBDone'][player]: row[51]+=1 + + #print "player=", player + #print "len(totalProfit)=", len(hudImportData['totalProfit']) + if hudImportData['totalProfit'][player]: + row[52]+=hudImportData['totalProfit'][player] + + if hudImportData['street1CheckCallRaiseChance'][player]: row[53]+=1 + if hudImportData['street1CheckCallRaiseDone'][player]: row[54]+=1 + if hudImportData['street2CheckCallRaiseChance'][player]: row[55]+=1 + if hudImportData['street2CheckCallRaiseDone'][player]: row[56]+=1 + if hudImportData['street3CheckCallRaiseChance'][player]: row[57]+=1 + if hudImportData['street3CheckCallRaiseDone'][player]: row[58]+=1 + if hudImportData['street4CheckCallRaiseChance'][player]: row[59]+=1 + if hudImportData['street4CheckCallRaiseDone'][player]: row[60]+=1 + + # Try to do the update first: + cursor = self.get_cursor() + num = cursor.execute("""UPDATE HudCache + SET HDs=HDs+%s, street0VPI=street0VPI+%s, street0Aggr=street0Aggr+%s, + street0_3BChance=street0_3BChance+%s, street0_3BDone=street0_3BDone+%s, + street1Seen=street1Seen+%s, street2Seen=street2Seen+%s, street3Seen=street3Seen+%s, + street4Seen=street4Seen+%s, sawShowdown=sawShowdown+%s, + street1Aggr=street1Aggr+%s, street2Aggr=street2Aggr+%s, street3Aggr=street3Aggr+%s, + street4Aggr=street4Aggr+%s, otherRaisedStreet1=otherRaisedStreet1+%s, + otherRaisedStreet2=otherRaisedStreet2+%s, otherRaisedStreet3=otherRaisedStreet3+%s, + otherRaisedStreet4=otherRaisedStreet4+%s, + foldToOtherRaisedStreet1=foldToOtherRaisedStreet1+%s, foldToOtherRaisedStreet2=foldToOtherRaisedStreet2+%s, + foldToOtherRaisedStreet3=foldToOtherRaisedStreet3+%s, foldToOtherRaisedStreet4=foldToOtherRaisedStreet4+%s, + wonWhenSeenStreet1=wonWhenSeenStreet1+%s, wonAtSD=wonAtSD+%s, stealAttemptChance=stealAttemptChance+%s, + stealAttempted=stealAttempted+%s, foldBbToStealChance=foldBbToStealChance+%s, + foldedBbToSteal=foldedBbToSteal+%s, + foldSbToStealChance=foldSbToStealChance+%s, foldedSbToSteal=foldedSbToSteal+%s, + street1CBChance=street1CBChance+%s, street1CBDone=street1CBDone+%s, street2CBChance=street2CBChance+%s, + street2CBDone=street2CBDone+%s, street3CBChance=street3CBChance+%s, + street3CBDone=street3CBDone+%s, street4CBChance=street4CBChance+%s, street4CBDone=street4CBDone+%s, + foldToStreet1CBChance=foldToStreet1CBChance+%s, foldToStreet1CBDone=foldToStreet1CBDone+%s, + foldToStreet2CBChance=foldToStreet2CBChance+%s, foldToStreet2CBDone=foldToStreet2CBDone+%s, + foldToStreet3CBChance=foldToStreet3CBChance+%s, + foldToStreet3CBDone=foldToStreet3CBDone+%s, foldToStreet4CBChance=foldToStreet4CBChance+%s, + foldToStreet4CBDone=foldToStreet4CBDone+%s, totalProfit=totalProfit+%s, + street1CheckCallRaiseChance=street1CheckCallRaiseChance+%s, + street1CheckCallRaiseDone=street1CheckCallRaiseDone+%s, street2CheckCallRaiseChance=street2CheckCallRaiseChance+%s, + street2CheckCallRaiseDone=street2CheckCallRaiseDone+%s, street3CheckCallRaiseChance=street3CheckCallRaiseChance+%s, + street3CheckCallRaiseDone=street3CheckCallRaiseDone+%s, street4CheckCallRaiseChance=street4CheckCallRaiseChance+%s, + street4CheckCallRaiseDone=street4CheckCallRaiseDone+%s + WHERE gametypeId+0=%s + AND playerId=%s + AND activeSeats=%s + AND position=%s + AND tourneyTypeId+0=%s + AND styleKey=%s + """, (row[6], row[7], row[8], row[9], row[10], + row[11], row[12], row[13], row[14], row[15], + row[16], row[17], row[18], row[19], row[20], + row[21], row[22], row[23], row[24], row[25], + row[26], row[27], row[28], row[29], row[30], + row[31], row[32], row[33], row[34], row[35], + row[36], row[37], row[38], row[39], row[40], + row[41], row[42], row[43], row[44], row[45], + row[46], row[47], row[48], row[49], row[50], + row[51], row[52], row[53], row[54], row[55], + row[56], row[57], row[58], row[59], row[60], + row[1], row[2], row[3], str(row[4]), row[5], styleKey)) + # Test statusmessage to see if update worked, do insert if not + #print "storehud2, upd num =", num + if ( (backend == self.PGSQL and cursor.statusmessage != "UPDATE 1") + or (backend == self.MYSQL_INNODB and num == 0) ): + #print "playerid before insert:",row[2]," num = ", num + cursor.execute("""INSERT INTO HudCache + (gametypeId, playerId, activeSeats, position, tourneyTypeId, styleKey, + HDs, street0VPI, street0Aggr, street0_3BChance, street0_3BDone, + street1Seen, street2Seen, street3Seen, street4Seen, sawShowdown, + street1Aggr, street2Aggr, street3Aggr, street4Aggr, otherRaisedStreet1, + otherRaisedStreet2, otherRaisedStreet3, otherRaisedStreet4, foldToOtherRaisedStreet1, foldToOtherRaisedStreet2, + foldToOtherRaisedStreet3, foldToOtherRaisedStreet4, wonWhenSeenStreet1, wonAtSD, stealAttemptChance, + stealAttempted, foldBbToStealChance, foldedBbToSteal, foldSbToStealChance, foldedSbToSteal, + street1CBChance, street1CBDone, street2CBChance, street2CBDone, street3CBChance, + street3CBDone, street4CBChance, street4CBDone, foldToStreet1CBChance, foldToStreet1CBDone, + foldToStreet2CBChance, foldToStreet2CBDone, foldToStreet3CBChance, foldToStreet3CBDone, foldToStreet4CBChance, + foldToStreet4CBDone, totalProfit, street1CheckCallRaiseChance, street1CheckCallRaiseDone, street2CheckCallRaiseChance, + street2CheckCallRaiseDone, street3CheckCallRaiseChance, street3CheckCallRaiseDone, street4CheckCallRaiseChance, street4CheckCallRaiseDone) + VALUES (%s, %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s)""" + , (row[1], row[2], row[3], row[4], row[5], styleKey, row[6], row[7], row[8], row[9], row[10] + ,row[11], row[12], row[13], row[14], row[15], row[16], row[17], row[18], row[19], row[20] + ,row[21], row[22], row[23], row[24], row[25], row[26], row[27], row[28], row[29], row[30] + ,row[31], row[32], row[33], row[34], row[35], row[36], row[37], row[38], row[39], row[40] + ,row[41], row[42], row[43], row[44], row[45], row[46], row[47], row[48], row[49], row[50] + ,row[51], row[52], row[53], row[54], row[55], row[56], row[57], row[58], row[59], row[60]) ) + #print "hopefully inserted hud data line: ", cursor.statusmessage + # message seems to be "INSERT 0 1" + else: + #print "updated(2) hud data line" + pass + # else: + # print "todo: implement storeHudCache for stud base" + + except: + raise fpdb_simple.FpdbError( "storeHudCache error: " + str(sys.exc_value) ) + + #end def storeHudCache + + def store_tourneys(self, tourneyTypeId, siteTourneyNo, entries, prizepool, startTime): + try: + cursor = self.get_cursor() + cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s", (siteTourneyNo, tourneyTypeId)) + tmp=cursor.fetchone() + #print "tried SELECTing tourneys.id, result:",tmp + + try: + len(tmp) + except TypeError:#means we have to create new one + cursor.execute("""INSERT INTO Tourneys + (tourneyTypeId, siteTourneyNo, entries, prizepool, startTime) + VALUES (%s, %s, %s, %s, %s)""", (tourneyTypeId, siteTourneyNo, entries, prizepool, startTime)) + cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s", (siteTourneyNo, tourneyTypeId)) + tmp=cursor.fetchone() + #print "created new tourneys.id:",tmp + except: + raise fpdb_simple.FpdbError( "store_tourneys error: " + str(sys.exc_value) ) + + return tmp[0] + #end def store_tourneys + + def store_tourneys_players(self, tourney_id, player_ids, payin_amounts, ranks, winnings): + try: + result=[] + cursor = self.get_cursor() + #print "in store_tourneys_players. tourney_id:",tourney_id + #print "player_ids:",player_ids + #print "payin_amounts:",payin_amounts + #print "ranks:",ranks + #print "winnings:",winnings + for i in xrange(len(player_ids)): + cursor.execute("SELECT id FROM TourneysPlayers WHERE tourneyId=%s AND playerId+0=%s", (tourney_id, player_ids[i])) + tmp=cursor.fetchone() + #print "tried SELECTing tourneys_players.id:",tmp + + try: + len(tmp) + except TypeError: + cursor.execute("""INSERT INTO TourneysPlayers + (tourneyId, playerId, payinAmount, rank, winnings) VALUES (%s, %s, %s, %s, %s)""", + (tourney_id, player_ids[i], payin_amounts[i], ranks[i], winnings[i])) + + cursor.execute("SELECT id FROM TourneysPlayers WHERE tourneyId=%s AND playerId+0=%s", + (tourney_id, player_ids[i])) + tmp=cursor.fetchone() + #print "created new tourneys_players.id:",tmp + result.append(tmp[0]) + except: + raise fpdb_simple.FpdbError( "store_tourneys_players error: " + str(sys.exc_value) ) + + return result + #end def store_tourneys_players + + +# Class used to hold all the data needed to write a hand to the db +# mainParser() in fpdb_parse_logic.py creates one of these and then passes it to + +class HandToWrite: + + def __init__(self, finished = False): # db_name and game not used any more + try: + self.finished = finished + self.config = None + self.settings = None + self.base = None + self.category = None + self.siteTourneyNo = None + self.buyin = None + self.fee = None + self.knockout = None + self.entries = None + self.prizepool = None + self.tourneyStartTime = None + self.isTourney = None + self.tourneyTypeId = None + self.siteID = None + self.siteHandNo = None + self.gametypeID = None + self.handStartTime = None + self.names = None + self.playerIDs = None + self.startCashes = None + self.positions = None + self.antes = None + self.cardValues = None + self.cardSuits = None + self.boardValues = None + self.boardSuits = None + self.winnings = None + self.rakes = None + self.actionTypes = None + self.allIns = None + self.actionAmounts = None + self.actionNos = None + self.hudImportData = None + self.maxSeats = None + self.tableName = None + self.seatNos = None + except: + print "htw.init error: " + str(sys.exc_info()) + raise + # end def __init__ + + def set_all( self, config, settings, base, category, siteTourneyNo, buyin + , fee, knockout, entries, prizepool, tourneyStartTime + , isTourney, tourneyTypeId, siteID, siteHandNo + , gametypeID, handStartTime, names, playerIDs, startCashes + , positions, antes, cardValues, cardSuits, boardValues, boardSuits + , winnings, rakes, actionTypes, allIns, actionAmounts + , actionNos, hudImportData, maxSeats, tableName, seatNos): + + try: + self.config = config + self.settings = settings + self.base = base + self.category = category + self.siteTourneyNo = siteTourneyNo + self.buyin = buyin + self.fee = fee + self.knockout = knockout + self.entries = entries + self.prizepool = prizepool + self.tourneyStartTime = tourneyStartTime + self.isTourney = isTourney + self.tourneyTypeId = tourneyTypeId + self.siteID = siteID + self.siteHandNo = siteHandNo + self.gametypeID = gametypeID + self.handStartTime = handStartTime + self.names = names + self.playerIDs = playerIDs + self.startCashes = startCashes + self.positions = positions + self.antes = antes + self.cardValues = cardValues + self.cardSuits = cardSuits + self.boardValues = boardValues + self.boardSuits = boardSuits + self.winnings = winnings + self.rakes = rakes + self.actionTypes = actionTypes + self.allIns = allIns + self.actionAmounts = actionAmounts + self.actionNos = actionNos + self.hudImportData = hudImportData + self.maxSeats = maxSeats + self.tableName = tableName + self.seatNos = seatNos + except: + print "htw.set_all error: " + str(sys.exc_info()) + raise + # end def set_hand + + def set_ring_holdem_omaha( self, config, settings, base, category, siteHandNo + , gametypeID, handStartTime, names, playerIDs + , startCashes, positions, cardValues, cardSuits + , boardValues, boardSuits, winnings, rakes + , actionTypes, allIns, actionAmounts, actionNos + , hudImportData, maxSeats, tableName, seatNos ): + self.config = config + self.settings = settings + self.base = base + self.category = category + self.siteHandNo = siteHandNo + self.gametypeID = gametypeID + self.handStartTime = handStartTime + self.names = names + self.playerIDs = playerIDs + self.startCashes = startCashes + self.positions = positions + self.cardValues = cardValues + self.cardSuits = cardSuits + self.boardValues = boardValues + self.boardSuits = boardSuits + self.winnings = winnings + self.rakes = rakes + self.actionTypes = actionTypes + self.allIns = allIns + self.actionAmounts = actionAmounts + self.actionNos = actionNos + self.hudImportData = hudImportData + self.maxSeats = maxSeats + self.tableName = tableName + self.seatNos = seatNos + # end def set_ring_holdem_omaha + + def send_ring_holdem_omaha(self, db): + result = db.ring_holdem_omaha( + self.config, self.settings, self.base, self.category, self.siteHandNo + , self.gametypeID, self.handStartTime, self.names, self.playerIDs + , self.startCashes, self.positions, self.cardValues, self.cardSuits + , self.boardValues, self.boardSuits, self.winnings, self.rakes + , self.actionTypes, self.allIns, self.actionAmounts, self.actionNos + , self.hudImportData, self.maxSeats, self.tableName, self.seatNos) + # end def send_ring_holdem_omaha + + def get_finished(self): + return( self.finished ) + # end def get_finished + + def get_siteHandNo(self): + return( self.siteHandNo ) + # end def get_siteHandNo + + if __name__=="__main__": c = Configuration.Config() diff --git a/pyfpdb/EverleafToFpdb.py b/pyfpdb/EverleafToFpdb.py index ee4942f1..a7685f90 100755 --- a/pyfpdb/EverleafToFpdb.py +++ b/pyfpdb/EverleafToFpdb.py @@ -37,7 +37,7 @@ class Everleaf(HandHistoryConverter): re_Board = re.compile(ur"\[ (?P.+) \]") - def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True, debugging=False): + def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True, debugging=False, index=0): """\ in_path (default '-' = sys.stdin) out_path (default '-' = sys.stdout) @@ -45,7 +45,7 @@ follow : whether to tail -f the input autostart: whether to run the thread (or you can call start() yourself) debugging: if False, pass on partially supported game types. If true, have a go and error...""" print "DEBUG: XXXXXXXXXXXXXXX" - HandHistoryConverter.__init__(self, in_path, out_path, sitename="Everleaf", follow=follow) + HandHistoryConverter.__init__(self, in_path, out_path, sitename="Everleaf", follow=follow, index=index) logging.info("Initialising Everleaf converter class") self.filetype = "text" self.codepage = "cp1252" @@ -237,11 +237,14 @@ or None if we fail to get the info """ # Also works with Omaha hands. cards = m.group('CARDS') cards = [card.strip() for card in cards.split(',')] - hand.addHoleCards(cards, m.group('PNAME')) +# hand.addHoleCards(cards, m.group('PNAME')) + hand.addHoleCards('PREFLOP', hand.hero, closed=cards, shown=False, mucked=False, dealt=True) + else: #Not involved in hand hand.involved = False + def readStudPlayerCards(self, hand, street): # lol. see Plymouth.txt logging.warning("Everleaf readStudPlayerCards is only a stub.") @@ -292,7 +295,8 @@ or None if we fail to get the info """ cards = cards.split(', ') player = m.group('PNAME') logging.debug("readShownCards %s cards=%s" % (player, cards)) - hand.addShownCards(cards=None, player=m.group('PNAME'), holeandboard=cards) +# hand.addShownCards(cards=None, player=m.group('PNAME'), holeandboard=cards) + hand.addShownCards(cards=cards, player=m.group('PNAME')) diff --git a/pyfpdb/FpdbSQLQueries.py b/pyfpdb/FpdbSQLQueries.py index db2d7231..b47f45eb 100644 --- a/pyfpdb/FpdbSQLQueries.py +++ b/pyfpdb/FpdbSQLQueries.py @@ -30,1489 +30,19 @@ class FpdbSQLQueries: self.query = {} self.dbname = db - ################################ - # List tables - ################################ - if(self.dbname == 'MySQL InnoDB'): - self.query['list_tables'] = """SHOW TABLES""" - elif(self.dbname == 'PostgreSQL'): - self.query['list_tables'] = """SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'""" + + if(self.dbname == 'MySQL InnoDB' or self.dbname == 'PostgreSQL'): + self.query['set tx level'] = """SET SESSION TRANSACTION + ISOLATION LEVEL READ COMMITTED""" elif(self.dbname == 'SQLite'): - self.query['list_tables'] = """ """ + self.query['set tx level'] = """ """ - ################################################################## - # Drop Tables - MySQL, PostgreSQL and SQLite all share same syntax - ################################################################## - - if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'): - self.query['drop_table'] = """DROP TABLE IF EXISTS """ - - - ################################ - # Create Tables - ################################ - - ################################ - # Create Settings - ################################ - if(self.dbname == 'MySQL InnoDB'): - self.query['createSettingsTable'] = """CREATE TABLE Settings ( - version SMALLINT NOT NULL) - ENGINE=INNODB""" - elif(self.dbname == 'PostgreSQL'): - self.query['createSettingsTable'] = """CREATE TABLE Settings (version SMALLINT)""" - - elif(self.dbname == 'SQLite'): - #Probably doesn't work. - self.query['createSettingsTable'] = """ """ - - - ################################ - # Create Sites - ################################ - - if(self.dbname == 'MySQL InnoDB'): - self.query['createSitesTable'] = """CREATE TABLE Sites ( - id SMALLINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), - name varchar(32) NOT NULL, - currency char(3) NOT NULL) - ENGINE=INNODB""" - elif(self.dbname == 'PostgreSQL'): - self.query['createSitesTable'] = """CREATE TABLE Sites ( - id SERIAL, PRIMARY KEY (id), - name varchar(32), - currency char(3))""" - elif(self.dbname == 'SQLite'): - self.query['createSitesTable'] = """ """ - - - ################################ - # Create Gametypes - ################################ - - if(self.dbname == 'MySQL InnoDB'): - self.query['createGametypesTable'] = """CREATE TABLE Gametypes ( - id SMALLINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), - siteId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (siteId) REFERENCES Sites(id), - type char(4) NOT NULL, - base char(4) NOT NULL, - category varchar(9) NOT NULL, - limitType char(2) NOT NULL, - hiLo char(1) NOT NULL, - smallBlind int, - bigBlind int, - smallBet int NOT NULL, - bigBet int NOT NULL) - ENGINE=INNODB""" - elif(self.dbname == 'PostgreSQL'): - self.query['createGametypesTable'] = """CREATE TABLE Gametypes ( - id SERIAL, PRIMARY KEY (id), - siteId INTEGER, FOREIGN KEY (siteId) REFERENCES Sites(id), - type char(4), - base char(4), - category varchar(9), - limitType char(2), - hiLo char(1), - smallBlind int, - bigBlind int, - smallBet int, - bigBet int)""" - elif(self.dbname == 'SQLite'): - self.query['createGametypesTable'] = """ """ - - - ################################ - # Create Players - ################################ - - if(self.dbname == 'MySQL InnoDB'): - self.query['createPlayersTable'] = """CREATE TABLE Players ( - id INT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), - name VARCHAR(32) CHARACTER SET utf8 NOT NULL, - siteId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (siteId) REFERENCES Sites(id), - comment text, - commentTs DATETIME) - ENGINE=INNODB""" - elif(self.dbname == 'PostgreSQL'): - self.query['createPlayersTable'] = """CREATE TABLE Players ( - id SERIAL, PRIMARY KEY (id), - name VARCHAR(32), - siteId INTEGER, FOREIGN KEY (siteId) REFERENCES Sites(id), - comment text, - commentTs timestamp without time zone)""" - elif(self.dbname == 'SQLite'): - self.query['createPlayersTable'] = """ """ - - - ################################ - # Create Autorates - ################################ - - if(self.dbname == 'MySQL InnoDB'): - self.query['createAutoratesTable'] = """CREATE TABLE Autorates ( - id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), - playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id), - gametypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id), - description varchar(50) NOT NULL, - shortDesc char(8) NOT NULL, - ratingTime DATETIME NOT NULL, - handCount int NOT NULL) - ENGINE=INNODB""" - elif(self.dbname == 'PostgreSQL'): - self.query['createAutoratesTable'] = """CREATE TABLE Autorates ( - id BIGSERIAL, PRIMARY KEY (id), - playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id), - gametypeId INT, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id), - description varchar(50), - shortDesc char(8), - ratingTime timestamp without time zone, - handCount int)""" - elif(self.dbname == 'SQLite'): - self.query['createAutoratesTable'] = """ """ - - - ################################ - # Create Hands - ################################ - - if(self.dbname == 'MySQL InnoDB'): - self.query['createHandsTable'] = """CREATE TABLE Hands ( - id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), - tableName VARCHAR(20) NOT NULL, - siteHandNo BIGINT NOT NULL, - gametypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id), - handStart DATETIME NOT NULL, - importTime DATETIME NOT NULL, - seats TINYINT NOT NULL, - maxSeats TINYINT NOT NULL, - boardcard1 smallint, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */ - boardcard2 smallint, - boardcard3 smallint, - boardcard4 smallint, - boardcard5 smallint, - texture smallint, - playersVpi SMALLINT NOT NULL, /* num of players vpi */ - playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4 */ - playersAtStreet2 SMALLINT NOT NULL, - playersAtStreet3 SMALLINT NOT NULL, - playersAtStreet4 SMALLINT NOT NULL, - playersAtShowdown SMALLINT NOT NULL, - street0Raises TINYINT NOT NULL, /* num small bets paid to see flop/street4, including blind */ - street1Raises TINYINT NOT NULL, /* num small bets paid to see turn/street5 */ - street2Raises TINYINT NOT NULL, /* num big bets paid to see river/street6 */ - street3Raises TINYINT NOT NULL, /* num big bets paid to see sd/street7 */ - street4Raises TINYINT NOT NULL, /* num big bets paid to see showdown */ - street1Pot INT, /* pot size at flop/street4 */ - street2Pot INT, /* pot size at turn/street5 */ - street3Pot INT, /* pot size at river/street6 */ - street4Pot INT, /* pot size at sd/street7 */ - showdownPot INT, /* pot size at sd/street7 */ - comment TEXT, - commentTs DATETIME) - ENGINE=INNODB""" - elif(self.dbname == 'PostgreSQL'): - self.query['createHandsTable'] = """CREATE TABLE Hands ( - id BIGSERIAL, PRIMARY KEY (id), - tableName VARCHAR(20) NOT NULL, - siteHandNo BIGINT NOT NULL, - gametypeId INT NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id), - handStart timestamp without time zone NOT NULL, - importTime timestamp without time zone NOT NULL, - seats SMALLINT NOT NULL, - maxSeats SMALLINT NOT NULL, - boardcard1 smallint, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */ - boardcard2 smallint, - boardcard3 smallint, - boardcard4 smallint, - boardcard5 smallint, - texture smallint, - playersVpi SMALLINT NOT NULL, /* num of players vpi */ - playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4 */ - playersAtStreet2 SMALLINT NOT NULL, - playersAtStreet3 SMALLINT NOT NULL, - playersAtStreet4 SMALLINT NOT NULL, - playersAtShowdown SMALLINT NOT NULL, - street0Raises SMALLINT NOT NULL, /* num small bets paid to see flop/street4, including blind */ - street1Raises SMALLINT NOT NULL, /* num small bets paid to see turn/street5 */ - street2Raises SMALLINT NOT NULL, /* num big bets paid to see river/street6 */ - street3Raises SMALLINT NOT NULL, /* num big bets paid to see sd/street7 */ - street4Raises SMALLINT NOT NULL, /* num big bets paid to see showdown */ - street1Pot INT, /* pot size at flop/street4 */ - street2Pot INT, /* pot size at turn/street5 */ - street3Pot INT, /* pot size at river/street6 */ - street4Pot INT, /* pot size at sd/street7 */ - showdownPot INT, /* pot size at sd/street7 */ - comment TEXT, - commentTs timestamp without time zone)""" - elif(self.dbname == 'SQLite'): - self.query['createHandsTable'] = """ """ - - - ################################ - # Create TourneyTypes - ################################ - - if(self.dbname == 'MySQL InnoDB'): - self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes ( - id SMALLINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), - siteId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (siteId) REFERENCES Sites(id), - buyin INT NOT NULL, - fee INT NOT NULL, - knockout INT NOT NULL, - rebuyOrAddon BOOLEAN NOT NULL) - ENGINE=INNODB""" - elif(self.dbname == 'PostgreSQL'): - self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes ( - id SERIAL, PRIMARY KEY (id), - siteId INT, FOREIGN KEY (siteId) REFERENCES Sites(id), - buyin INT, - fee INT, - knockout INT, - rebuyOrAddon BOOLEAN)""" - elif(self.dbname == 'SQLite'): - self.query['createTourneyTypesTable'] = """ """ - - - ################################ - # Create Tourneys - ################################ - - if(self.dbname == 'MySQL InnoDB'): - self.query['createTourneysTable'] = """CREATE TABLE Tourneys ( - id INT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), - tourneyTypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), - siteTourneyNo BIGINT NOT NULL, - entries INT NOT NULL, - prizepool INT NOT NULL, - startTime DATETIME NOT NULL, - comment TEXT, - commentTs DATETIME) - ENGINE=INNODB""" - elif(self.dbname == 'PostgreSQL'): - self.query['createTourneysTable'] = """CREATE TABLE Tourneys ( - id SERIAL, PRIMARY KEY (id), - tourneyTypeId INT, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), - siteTourneyNo BIGINT, - entries INT, - prizepool INT, - startTime timestamp without time zone, - comment TEXT, - commentTs timestamp without time zone)""" - elif(self.dbname == 'SQLite'): - self.query['createTourneysTable'] = """ """ - - ################################ - # Create HandsPlayers - ################################ - - if(self.dbname == 'MySQL InnoDB'): - self.query['createHandsPlayersTable'] = """CREATE TABLE HandsPlayers ( - id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), - handId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (handId) REFERENCES Hands(id), - playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id), - startCash INT NOT NULL, - position CHAR(1), - seatNo SMALLINT NOT NULL, - - card1 smallint NOT NULL, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */ - card2 smallint NOT NULL, - card3 smallint, - card4 smallint, - card5 smallint, - card6 smallint, - card7 smallint, - startCards smallint, - - ante INT, - winnings int NOT NULL, - rake int NOT NULL, - totalProfit INT NOT NULL, - comment text, - commentTs DATETIME, - tourneysPlayersId BIGINT UNSIGNED, - tourneyTypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), - - wonWhenSeenStreet1 FLOAT NOT NULL, - wonWhenSeenStreet2 FLOAT, - wonWhenSeenStreet3 FLOAT, - wonWhenSeenStreet4 FLOAT, - wonAtSD FLOAT NOT NULL, - - street0VPI BOOLEAN NOT NULL, - street0Aggr BOOLEAN NOT NULL, - street0_3BChance BOOLEAN NOT NULL, - street0_3BDone BOOLEAN NOT NULL, - street0_4BChance BOOLEAN, - street0_4BDone BOOLEAN, - other3BStreet0 BOOLEAN, - other4BStreet0 BOOLEAN, - - street1Seen BOOLEAN NOT NULL, - street2Seen BOOLEAN NOT NULL, - street3Seen BOOLEAN NOT NULL, - street4Seen BOOLEAN NOT NULL, - sawShowdown BOOLEAN NOT NULL, - - street1Aggr BOOLEAN NOT NULL, - street2Aggr BOOLEAN NOT NULL, - street3Aggr BOOLEAN NOT NULL, - street4Aggr BOOLEAN NOT NULL, - - otherRaisedStreet0 BOOLEAN, - otherRaisedStreet1 BOOLEAN NOT NULL, - otherRaisedStreet2 BOOLEAN NOT NULL, - otherRaisedStreet3 BOOLEAN NOT NULL, - otherRaisedStreet4 BOOLEAN NOT NULL, - foldToOtherRaisedStreet0 BOOLEAN, - foldToOtherRaisedStreet1 BOOLEAN NOT NULL, - foldToOtherRaisedStreet2 BOOLEAN NOT NULL, - foldToOtherRaisedStreet3 BOOLEAN NOT NULL, - foldToOtherRaisedStreet4 BOOLEAN NOT NULL, - - stealAttemptChance BOOLEAN NOT NULL, - stealAttempted BOOLEAN NOT NULL, - foldBbToStealChance BOOLEAN NOT NULL, - foldedBbToSteal BOOLEAN NOT NULL, - foldSbToStealChance BOOLEAN NOT NULL, - foldedSbToSteal BOOLEAN NOT NULL, - - street1CBChance BOOLEAN NOT NULL, - street1CBDone BOOLEAN NOT NULL, - street2CBChance BOOLEAN NOT NULL, - street2CBDone BOOLEAN NOT NULL, - street3CBChance BOOLEAN NOT NULL, - street3CBDone BOOLEAN NOT NULL, - street4CBChance BOOLEAN NOT NULL, - street4CBDone BOOLEAN NOT NULL, - - foldToStreet1CBChance BOOLEAN NOT NULL, - foldToStreet1CBDone BOOLEAN NOT NULL, - foldToStreet2CBChance BOOLEAN NOT NULL, - foldToStreet2CBDone BOOLEAN NOT NULL, - foldToStreet3CBChance BOOLEAN NOT NULL, - foldToStreet3CBDone BOOLEAN NOT NULL, - foldToStreet4CBChance BOOLEAN NOT NULL, - foldToStreet4CBDone BOOLEAN NOT NULL, - - street1CheckCallRaiseChance BOOLEAN NOT NULL, - street1CheckCallRaiseDone BOOLEAN NOT NULL, - street2CheckCallRaiseChance BOOLEAN NOT NULL, - street2CheckCallRaiseDone BOOLEAN NOT NULL, - street3CheckCallRaiseChance BOOLEAN NOT NULL, - street3CheckCallRaiseDone BOOLEAN NOT NULL, - street4CheckCallRaiseChance BOOLEAN NOT NULL, - street4CheckCallRaiseDone BOOLEAN NOT NULL, - - street0Calls TINYINT, - street1Calls TINYINT, - street2Calls TINYINT, - street3Calls TINYINT, - street4Calls TINYINT, - street0Bets TINYINT, - street1Bets TINYINT, - street2Bets TINYINT, - street3Bets TINYINT, - street4Bets TINYINT, - street0Raises TINYINT, - street1Raises TINYINT, - street2Raises TINYINT, - street3Raises TINYINT, - street4Raises TINYINT, - - actionString VARCHAR(15), - - FOREIGN KEY (tourneysPlayersId) REFERENCES TourneysPlayers(id)) - ENGINE=INNODB""" - elif(self.dbname == 'PostgreSQL'): - self.query['createHandsPlayersTable'] = """CREATE TABLE HandsPlayers ( - id BIGSERIAL, PRIMARY KEY (id), - handId BIGINT NOT NULL, FOREIGN KEY (handId) REFERENCES Hands(id), - playerId INT NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id), - startCash INT NOT NULL, - position CHAR(1), - seatNo SMALLINT NOT NULL, - - card1 smallint NOT NULL, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */ - card2 smallint NOT NULL, - card3 smallint, - card4 smallint, - card5 smallint, - card6 smallint, - card7 smallint, - startCards smallint, - - ante INT, - winnings int NOT NULL, - rake int NOT NULL, - totalProfit INT NOT NULL, - comment text, - commentTs timestamp without time zone, - tourneysPlayersId BIGINT, - tourneyTypeId INT NOT NULL, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), - - wonWhenSeenStreet1 FLOAT NOT NULL, - wonWhenSeenStreet2 FLOAT, - wonWhenSeenStreet3 FLOAT, - wonWhenSeenStreet4 FLOAT, - wonAtSD FLOAT NOT NULL, - - street0VPI BOOLEAN NOT NULL, - street0Aggr BOOLEAN NOT NULL, - street0_3BChance BOOLEAN NOT NULL, - street0_3BDone BOOLEAN NOT NULL, - street0_4BChance BOOLEAN, - street0_4BDone BOOLEAN, - other3BStreet0 BOOLEAN, - other4BStreet0 BOOLEAN, - - street1Seen BOOLEAN NOT NULL, - street2Seen BOOLEAN NOT NULL, - street3Seen BOOLEAN NOT NULL, - street4Seen BOOLEAN NOT NULL, - sawShowdown BOOLEAN NOT NULL, - - street1Aggr BOOLEAN NOT NULL, - street2Aggr BOOLEAN NOT NULL, - street3Aggr BOOLEAN NOT NULL, - street4Aggr BOOLEAN NOT NULL, - - otherRaisedStreet0 BOOLEAN, - otherRaisedStreet1 BOOLEAN NOT NULL, - otherRaisedStreet2 BOOLEAN NOT NULL, - otherRaisedStreet3 BOOLEAN NOT NULL, - otherRaisedStreet4 BOOLEAN NOT NULL, - foldToOtherRaisedStreet0 BOOLEAN, - foldToOtherRaisedStreet1 BOOLEAN NOT NULL, - foldToOtherRaisedStreet2 BOOLEAN NOT NULL, - foldToOtherRaisedStreet3 BOOLEAN NOT NULL, - foldToOtherRaisedStreet4 BOOLEAN NOT NULL, - - stealAttemptChance BOOLEAN NOT NULL, - stealAttempted BOOLEAN NOT NULL, - foldBbToStealChance BOOLEAN NOT NULL, - foldedBbToSteal BOOLEAN NOT NULL, - foldSbToStealChance BOOLEAN NOT NULL, - foldedSbToSteal BOOLEAN NOT NULL, - - street1CBChance BOOLEAN NOT NULL, - street1CBDone BOOLEAN NOT NULL, - street2CBChance BOOLEAN NOT NULL, - street2CBDone BOOLEAN NOT NULL, - street3CBChance BOOLEAN NOT NULL, - street3CBDone BOOLEAN NOT NULL, - street4CBChance BOOLEAN NOT NULL, - street4CBDone BOOLEAN NOT NULL, - - foldToStreet1CBChance BOOLEAN NOT NULL, - foldToStreet1CBDone BOOLEAN NOT NULL, - foldToStreet2CBChance BOOLEAN NOT NULL, - foldToStreet2CBDone BOOLEAN NOT NULL, - foldToStreet3CBChance BOOLEAN NOT NULL, - foldToStreet3CBDone BOOLEAN NOT NULL, - foldToStreet4CBChance BOOLEAN NOT NULL, - foldToStreet4CBDone BOOLEAN NOT NULL, - - street1CheckCallRaiseChance BOOLEAN NOT NULL, - street1CheckCallRaiseDone BOOLEAN NOT NULL, - street2CheckCallRaiseChance BOOLEAN NOT NULL, - street2CheckCallRaiseDone BOOLEAN NOT NULL, - street3CheckCallRaiseChance BOOLEAN NOT NULL, - street3CheckCallRaiseDone BOOLEAN NOT NULL, - street4CheckCallRaiseChance BOOLEAN NOT NULL, - street4CheckCallRaiseDone BOOLEAN NOT NULL, - - street0Calls SMALLINT, - street1Calls SMALLINT, - street2Calls SMALLINT, - street3Calls SMALLINT, - street4Calls SMALLINT, - street0Bets SMALLINT, - street1Bets SMALLINT, - street2Bets SMALLINT, - street3Bets SMALLINT, - street4Bets SMALLINT, - street0Raises SMALLINT, - street1Raises SMALLINT, - street2Raises SMALLINT, - street3Raises SMALLINT, - street4Raises SMALLINT, - - actionString VARCHAR(15), - - FOREIGN KEY (tourneysPlayersId) REFERENCES TourneysPlayers(id))""" - elif(self.dbname == 'SQLite'): - self.query['createHandsPlayersTable'] = """ """ - - - ################################ - # Create TourneysPlayers - ################################ - - if(self.dbname == 'MySQL InnoDB'): - self.query['createTourneysPlayersTable'] = """CREATE TABLE TourneysPlayers ( - id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), - tourneyId INT UNSIGNED NOT NULL, FOREIGN KEY (tourneyId) REFERENCES Tourneys(id), - playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id), - payinAmount INT NOT NULL, - rank INT NOT NULL, - winnings INT NOT NULL, - comment TEXT, - commentTs DATETIME) - ENGINE=INNODB""" - elif(self.dbname == 'PostgreSQL'): - self.query['createTourneysPlayersTable'] = """CREATE TABLE TourneysPlayers ( - id BIGSERIAL, PRIMARY KEY (id), - tourneyId INT, FOREIGN KEY (tourneyId) REFERENCES Tourneys(id), - playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id), - payinAmount INT, - rank INT, - winnings INT, - comment TEXT, - commentTs timestamp without time zone)""" - elif(self.dbname == 'SQLite'): - self.query['createTourneysPlayersTable'] = """ """ - - - ################################ - # Create HandsActions - ################################ - - if(self.dbname == 'MySQL InnoDB'): - self.query['createHandsActionsTable'] = """CREATE TABLE HandsActions ( - id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), - handsPlayerId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (handsPlayerId) REFERENCES HandsPlayers(id), - street SMALLINT NOT NULL, - actionNo SMALLINT NOT NULL, - action CHAR(5) NOT NULL, - allIn BOOLEAN NOT NULL, - amount INT NOT NULL, - comment TEXT, - commentTs DATETIME) - ENGINE=INNODB""" - elif(self.dbname == 'PostgreSQL'): - self.query['createHandsActionsTable'] = """CREATE TABLE HandsActions ( - id BIGSERIAL, PRIMARY KEY (id), - handsPlayerId BIGINT, FOREIGN KEY (handsPlayerId) REFERENCES HandsPlayers(id), - street SMALLINT, - actionNo SMALLINT, - action CHAR(5), - allIn BOOLEAN, - amount INT, - comment TEXT, - commentTs timestamp without time zone)""" - elif(self.dbname == 'SQLite'): - self.query['createHandsActionsTable'] = """ """ - - - ################################ - # Create HudCache - ################################ - - if(self.dbname == 'MySQL InnoDB'): - self.query['createHudCacheTable'] = """CREATE TABLE HudCache ( - id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), - gametypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id), - playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id), - activeSeats SMALLINT NOT NULL, - position CHAR(1), - tourneyTypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), - styleKey CHAR(7) NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */ - HDs INT NOT NULL, - - wonWhenSeenStreet1 FLOAT NOT NULL, - wonWhenSeenStreet2 FLOAT, - wonWhenSeenStreet3 FLOAT, - wonWhenSeenStreet4 FLOAT, - wonAtSD FLOAT NOT NULL, - - street0VPI INT NOT NULL, - street0Aggr INT NOT NULL, - street0_3BChance INT NOT NULL, - street0_3BDone INT NOT NULL, - street0_4BChance INT, - street0_4BDone INT, - other3BStreet0 INT, - other4BStreet0 INT, - - street1Seen INT NOT NULL, - street2Seen INT NOT NULL, - street3Seen INT NOT NULL, - street4Seen INT NOT NULL, - sawShowdown INT NOT NULL, - - street1Aggr INT NOT NULL, - street2Aggr INT NOT NULL, - street3Aggr INT NOT NULL, - street4Aggr INT NOT NULL, - - otherRaisedStreet0 INT, - otherRaisedStreet1 INT NOT NULL, - otherRaisedStreet2 INT NOT NULL, - otherRaisedStreet3 INT NOT NULL, - otherRaisedStreet4 INT NOT NULL, - foldToOtherRaisedStreet0 INT, - foldToOtherRaisedStreet1 INT NOT NULL, - foldToOtherRaisedStreet2 INT NOT NULL, - foldToOtherRaisedStreet3 INT NOT NULL, - foldToOtherRaisedStreet4 INT NOT NULL, - - stealAttemptChance INT NOT NULL, - stealAttempted INT NOT NULL, - foldBbToStealChance INT NOT NULL, - foldedBbToSteal INT NOT NULL, - foldSbToStealChance INT NOT NULL, - foldedSbToSteal INT NOT NULL, - - street1CBChance INT NOT NULL, - street1CBDone INT NOT NULL, - street2CBChance INT NOT NULL, - street2CBDone INT NOT NULL, - street3CBChance INT NOT NULL, - street3CBDone INT NOT NULL, - street4CBChance INT NOT NULL, - street4CBDone INT NOT NULL, - - foldToStreet1CBChance INT NOT NULL, - foldToStreet1CBDone INT NOT NULL, - foldToStreet2CBChance INT NOT NULL, - foldToStreet2CBDone INT NOT NULL, - foldToStreet3CBChance INT NOT NULL, - foldToStreet3CBDone INT NOT NULL, - foldToStreet4CBChance INT NOT NULL, - foldToStreet4CBDone INT NOT NULL, - - totalProfit INT NOT NULL, - - street1CheckCallRaiseChance INT NOT NULL, - street1CheckCallRaiseDone INT NOT NULL, - street2CheckCallRaiseChance INT NOT NULL, - street2CheckCallRaiseDone INT NOT NULL, - street3CheckCallRaiseChance INT NOT NULL, - street3CheckCallRaiseDone INT NOT NULL, - street4CheckCallRaiseChance INT NOT NULL, - street4CheckCallRaiseDone INT NOT NULL, - - street0Calls INT, - street1Calls INT, - street2Calls INT, - street3Calls INT, - street4Calls INT, - street0Bets INT, - street1Bets INT, - street2Bets INT, - street3Bets INT, - street4Bets INT, - street0Raises INT, - street1Raises INT, - street2Raises INT, - street3Raises INT, - street4Raises INT) - - ENGINE=INNODB""" - elif(self.dbname == 'PostgreSQL'): - self.query['createHudCacheTable'] = """CREATE TABLE HudCache ( - id BIGSERIAL, PRIMARY KEY (id), - gametypeId INT, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id), - playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id), - activeSeats SMALLINT, - position CHAR(1), - tourneyTypeId INT, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), - styleKey CHAR(7) NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */ - HDs INT, - - wonWhenSeenStreet1 FLOAT NOT NULL, - wonWhenSeenStreet2 FLOAT, - wonWhenSeenStreet3 FLOAT, - wonWhenSeenStreet4 FLOAT, - wonAtSD FLOAT NOT NULL, - - street0VPI INT NOT NULL, - street0Aggr INT, - street0_3BChance INT NOT NULL, - street0_3BDone INT NOT NULL, - street0_4BChance INT, - street0_4BDone INT, - other3BStreet0 INT, - other4BStreet0 INT, - - street1Seen INT, - street2Seen INT, - street3Seen INT, - street4Seen INT, - sawShowdown INT, - street1Aggr INT, - street2Aggr INT, - street3Aggr INT, - street4Aggr INT, - - otherRaisedStreet0 INT, - otherRaisedStreet1 INT, - otherRaisedStreet2 INT, - otherRaisedStreet3 INT, - otherRaisedStreet4 INT, - foldToOtherRaisedStreet0 INT, - foldToOtherRaisedStreet1 INT, - foldToOtherRaisedStreet2 INT, - foldToOtherRaisedStreet3 INT, - foldToOtherRaisedStreet4 INT, - - stealAttemptChance INT, - stealAttempted INT, - foldBbToStealChance INT, - foldedBbToSteal INT, - foldSbToStealChance INT, - foldedSbToSteal INT, - - street1CBChance INT, - street1CBDone INT, - street2CBChance INT, - street2CBDone INT, - street3CBChance INT, - street3CBDone INT, - street4CBChance INT, - street4CBDone INT, - - foldToStreet1CBChance INT, - foldToStreet1CBDone INT, - foldToStreet2CBChance INT, - foldToStreet2CBDone INT, - foldToStreet3CBChance INT, - foldToStreet3CBDone INT, - foldToStreet4CBChance INT, - foldToStreet4CBDone INT, - - totalProfit INT, - - street1CheckCallRaiseChance INT, - street1CheckCallRaiseDone INT, - street2CheckCallRaiseChance INT, - street2CheckCallRaiseDone INT, - street3CheckCallRaiseChance INT, - street3CheckCallRaiseDone INT, - street4CheckCallRaiseChance INT, - street4CheckCallRaiseDone INT, - - street0Calls INT, - street1Calls INT, - street2Calls INT, - street3Calls INT, - street4Calls INT, - street0Bets INT, - street1Bets INT, - street2Bets INT, - street3Bets INT, - street4Bets INT, - street0Raises INT, - street1Raises INT, - street2Raises INT, - street3Raises INT, - street4Raises INT) - """ - elif(self.dbname == 'SQLite'): - self.query['createHudCacheTable'] = """ """ - - if(self.dbname == 'MySQL InnoDB'): - self.query['addTourneyIndex'] = """ALTER TABLE Tourneys ADD INDEX siteTourneyNo(siteTourneyNo)""" - elif(self.dbname == 'PostgreSQL'): - self.query['addTourneyIndex'] = """CREATE INDEX siteTourneyNo ON Tourneys (siteTourneyNo)""" - elif(self.dbname == 'SQLite'): - self.query['addHandsIndex'] = """ """ - - if(self.dbname == 'MySQL InnoDB'): - self.query['addHandsIndex'] = """ALTER TABLE Hands ADD INDEX siteHandNo(siteHandNo)""" - elif(self.dbname == 'PostgreSQL'): - self.query['addHandsIndex'] = """CREATE INDEX siteHandNo ON Hands (siteHandNo)""" - elif(self.dbname == 'SQLite'): - self.query['addHandsIndex'] = """ """ - - if(self.dbname == 'MySQL InnoDB'): - self.query['addPlayersIndex'] = """ALTER TABLE Players ADD INDEX name(name)""" - elif(self.dbname == 'PostgreSQL'): - self.query['addPlayersIndex'] = """CREATE INDEX name ON Players (name)""" - elif(self.dbname == 'SQLite'): - self.query['addPlayersIndex'] = """ """ - - ################################ - # Queries used in GuiGraphViewer - ################################ - - - if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL'): - self.query['getPlayerId'] = """SELECT id from Players where name = %s""" - elif(self.dbname == 'SQLite'): - self.query['getPlayerId'] = """SELECT id from Players where name = %s""" if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL'): self.query['getSiteId'] = """SELECT id from Sites where name = %s""" elif(self.dbname == 'SQLite'): self.query['getSiteId'] = """SELECT id from Sites where name = %s""" - if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'): - self.query['getRingProfitAllHandsPlayerIdSite'] = """ - SELECT hp.handId, hp.totalProfit, hp.totalProfit, hp.totalProfit - FROM HandsPlayers hp - INNER JOIN Players pl ON hp.playerId = pl.id - INNER JOIN Hands h ON h.id = hp.handId - INNER JOIN Gametypes g ON h.gametypeId = g.id - where pl.id in - AND pl.siteId in - AND h.handStart > '' - AND h.handStart < '' - AND g.bigBlind in - AND hp.tourneysPlayersId IS NULL - GROUP BY h.handStart, hp.handId, hp.totalProfit - ORDER BY h.handStart""" - - if self.dbname in ['MySQL InnoDB']: - self.query['playerDetailedStats'] = """ - select AS hgametypeid - ,gt.base - ,gt.category - ,upper(gt.limitType) AS limittype - ,s.name - ,min(gt.bigBlind) AS minbigblind - ,max(gt.bigBlind) AS maxbigblind - /*, AS gtid*/ - , AS plposition - ,count(1) AS n - ,100.0*sum(cast(hp.street0VPI as integer))/count(1) AS vpip - ,100.0*sum(cast(hp.street0Aggr as integer))/count(1) AS pfr - ,case when sum(cast(hp.street0_3Bchance as integer)) = 0 then -999 - else 100.0*sum(cast(hp.street0_3Bdone as integer))/sum(cast(hp.street0_3Bchance as integer)) - end AS pf3 - ,case when sum(cast(hp.stealattemptchance as integer)) = 0 then -999 - else 100.0*sum(cast(hp.stealattempted as integer))/sum(cast(hp.stealattemptchance as integer)) - end AS steals - ,100.0*sum(cast(hp.street1Seen as integer))/count(1) AS saw_f - ,100.0*sum(cast(hp.sawShowdown as integer))/count(1) AS sawsd - ,case when sum(cast(hp.street1Seen as integer)) = 0 then -999 - else 100.0*sum(cast(hp.sawShowdown as integer))/sum(cast(hp.street1Seen as integer)) - end AS wtsdwsf - ,case when sum(cast(hp.sawShowdown as integer)) = 0 then -999 - else 100.0*sum(cast(hp.wonAtSD as integer))/sum(cast(hp.sawShowdown as integer)) - end AS wmsd - ,case when sum(cast(hp.street1Seen as integer)) = 0 then -999 - else 100.0*sum(cast(hp.street1Aggr as integer))/sum(cast(hp.street1Seen as integer)) - end AS flafq - ,case when sum(cast(hp.street2Seen as integer)) = 0 then -999 - else 100.0*sum(cast(hp.street2Aggr as integer))/sum(cast(hp.street2Seen as integer)) - end AS tuafq - ,case when sum(cast(hp.street3Seen as integer)) = 0 then -999 - else 100.0*sum(cast(hp.street3Aggr as integer))/sum(cast(hp.street3Seen as integer)) - end AS rvafq - ,case when sum(cast(hp.street1Seen as integer))+sum(cast(hp.street2Seen as integer))+sum(cast(hp.street3Seen as integer)) = 0 then -999 - else 100.0*(sum(cast(hp.street1Aggr as integer))+sum(cast(hp.street2Aggr as integer))+sum(cast(hp.street3Aggr as integer))) - /(sum(cast(hp.street1Seen as integer))+sum(cast(hp.street2Seen as integer))+sum(cast(hp.street3Seen as integer))) - end AS pofafq - ,sum(hp.totalProfit)/100.0 AS net - ,sum(hp.rake)/100.0 AS rake - ,100.0*avg(hp.totalProfit/(gt.bigBlind+0.0)) AS bbper100 - ,avg(hp.totalProfit)/100.0 AS profitperhand - ,100.0*avg((hp.totalProfit+hp.rake)/(gt.bigBlind+0.0)) AS bb100xr - ,avg((hp.totalProfit+hp.rake)/100.0) AS profhndxr - ,avg(h.seats+0.0) AS avgseats - ,variance(hp.totalProfit/100.0) AS variance - from HandsPlayers hp - inner join Hands h on (h.id = hp.handId) - inner join Gametypes gt on (gt.Id = h.gameTypeId) - inner join Sites s on (s.Id = gt.siteId) - where hp.playerId in - and hp.tourneysPlayersId IS NULL - and h.seats - - - and date_format(h.handStart, '%Y-%m-%d') - group by hgameTypeId - ,hp.playerId - ,gt.base - ,gt.category - - ,plposition - ,upper(gt.limitType) - ,s.name - order by hp.playerId - ,gt.base - ,gt.category - - ,case when 'B' then 'B' - when 'S' then 'S' - else concat('Z', ) - end - - ,maxbigblind desc - ,upper(gt.limitType) - ,s.name - """ - elif self.dbname in ['PostgreSQL']: - self.query['playerDetailedStats'] = """ - select AS hgametypeid - ,gt.base - ,gt.category - ,upper(gt.limitType) AS limittype - ,s.name - ,min(gt.bigBlind) AS minbigblind - ,max(gt.bigBlind) AS maxbigblind - /*, AS gtid*/ - , AS plposition - ,count(1) AS n - ,100.0*sum(cast(hp.street0VPI as integer))/count(1) AS vpip - ,100.0*sum(cast(hp.street0Aggr as integer))/count(1) AS pfr - ,case when sum(cast(hp.street0_3Bchance as integer)) = 0 then -999 - else 100.0*sum(cast(hp.street0_3Bdone as integer))/sum(cast(hp.street0_3Bchance as integer)) - end AS pf3 - ,case when sum(cast(hp.stealattemptchance as integer)) = 0 then -999 - else 100.0*sum(cast(hp.stealattempted as integer))/sum(cast(hp.stealattemptchance as integer)) - end AS steals - ,100.0*sum(cast(hp.street1Seen as integer))/count(1) AS saw_f - ,100.0*sum(cast(hp.sawShowdown as integer))/count(1) AS sawsd - ,case when sum(cast(hp.street1Seen as integer)) = 0 then -999 - else 100.0*sum(cast(hp.sawShowdown as integer))/sum(cast(hp.street1Seen as integer)) - end AS wtsdwsf - ,case when sum(cast(hp.sawShowdown as integer)) = 0 then -999 - else 100.0*sum(cast(hp.wonAtSD as integer))/sum(cast(hp.sawShowdown as integer)) - end AS wmsd - ,case when sum(cast(hp.street1Seen as integer)) = 0 then -999 - else 100.0*sum(cast(hp.street1Aggr as integer))/sum(cast(hp.street1Seen as integer)) - end AS flafq - ,case when sum(cast(hp.street2Seen as integer)) = 0 then -999 - else 100.0*sum(cast(hp.street2Aggr as integer))/sum(cast(hp.street2Seen as integer)) - end AS tuafq - ,case when sum(cast(hp.street3Seen as integer)) = 0 then -999 - else 100.0*sum(cast(hp.street3Aggr as integer))/sum(cast(hp.street3Seen as integer)) - end AS rvafq - ,case when sum(cast(hp.street1Seen as integer))+sum(cast(hp.street2Seen as integer))+sum(cast(hp.street3Seen as integer)) = 0 then -999 - else 100.0*(sum(cast(hp.street1Aggr as integer))+sum(cast(hp.street2Aggr as integer))+sum(cast(hp.street3Aggr as integer))) - /(sum(cast(hp.street1Seen as integer))+sum(cast(hp.street2Seen as integer))+sum(cast(hp.street3Seen as integer))) - end AS pofafq - ,sum(hp.totalProfit)/100.0 AS net - ,sum(hp.rake)/100.0 AS rake - ,100.0*avg(hp.totalProfit/(gt.bigBlind+0.0)) AS bbper100 - ,avg(hp.totalProfit)/100.0 AS profitperhand - ,100.0*avg((hp.totalProfit+hp.rake)/(gt.bigBlind+0.0)) AS bb100xr - ,avg((hp.totalProfit+hp.rake)/100.0) AS profhndxr - ,avg(h.seats+0.0) AS avgseats - ,variance(hp.totalProfit/100.0) AS variance - from HandsPlayers hp - inner join Hands h on (h.id = hp.handId) - inner join Gametypes gt on (gt.Id = h.gameTypeId) - inner join Sites s on (s.Id = gt.siteId) - where hp.playerId in - and hp.tourneysPlayersId IS NULL - and h.seats - - - and to_char(h.handStart, 'YYYY-MM-DD') - group by hgameTypeId - ,hp.playerId - ,gt.base - ,gt.category - - ,plposition - ,upper(gt.limitType) - ,s.name - order by hp.playerId - ,gt.base - ,gt.category - - ,case when 'B' then 'B' - when 'S' then 'S' - else 'Z'|| - end - - ,maxbigblind desc - ,upper(gt.limitType) - ,s.name - """ - elif(self.dbname == 'SQLite'): - self.query['playerDetailedStats'] = """ """ - - if(self.dbname == 'MySQL InnoDB'): - self.query['playerStats'] = """ - SELECT - concat(upper(stats.limitType), ' ' - ,concat(upper(substring(stats.category,1,1)),substring(stats.category,2) ), ' ' - ,stats.name, ' ' - ,cast(stats.bigBlindDesc as char) - ) AS Game - ,stats.n - ,stats.vpip - ,stats.pfr - ,stats.pf3 - ,stats.steals - ,stats.saw_f - ,stats.sawsd - ,stats.wtsdwsf - ,stats.wmsd - ,stats.FlAFq - ,stats.TuAFq - ,stats.RvAFq - ,stats.PoFAFq - ,stats.Net - ,stats.BBper100 - ,stats.Profitperhand - ,case when hprof2.variance = -999 then '-' - else format(hprof2.variance, 2) - end AS Variance - ,stats.AvgSeats - FROM - (select /* stats from hudcache */ - gt.base - ,gt.category - ,upper(gt.limitType) as limitType - ,s.name - , AS bigBlindDesc - , AS gtId - ,sum(HDs) AS n - ,format(100.0*sum(street0VPI)/sum(HDs),1) AS vpip - ,format(100.0*sum(street0Aggr)/sum(HDs),1) AS pfr - ,case when sum(street0_3Bchance) = 0 then '0' - else format(100.0*sum(street0_3Bdone)/sum(street0_3Bchance),1) - end AS pf3 - ,case when sum(stealattemptchance) = 0 then '-' - else format(100.0*sum(stealattempted)/sum(stealattemptchance),1) - end AS steals - ,format(100.0*sum(street1Seen)/sum(HDs),1) AS saw_f - ,format(100.0*sum(sawShowdown)/sum(HDs),1) AS sawsd - ,case when sum(street1Seen) = 0 then '-' - else format(100.0*sum(sawShowdown)/sum(street1Seen),1) - end AS wtsdwsf - ,case when sum(sawShowdown) = 0 then '-' - else format(100.0*sum(wonAtSD)/sum(sawShowdown),1) - end AS wmsd - ,case when sum(street1Seen) = 0 then '-' - else format(100.0*sum(street1Aggr)/sum(street1Seen),1) - end AS FlAFq - ,case when sum(street2Seen) = 0 then '-' - else format(100.0*sum(street2Aggr)/sum(street2Seen),1) - end AS TuAFq - ,case when sum(street3Seen) = 0 then '-' - else format(100.0*sum(street3Aggr)/sum(street3Seen),1) - end AS RvAFq - ,case when sum(street1Seen)+sum(street2Seen)+sum(street3Seen) = 0 then '-' - else format(100.0*(sum(street1Aggr)+sum(street2Aggr)+sum(street3Aggr)) - /(sum(street1Seen)+sum(street2Seen)+sum(street3Seen)),1) - end AS PoFAFq - ,format(sum(totalProfit)/100.0,2) AS Net - ,format((sum(totalProfit/(gt.bigBlind+0.0))) / (sum(HDs)/100.0),2) - AS BBper100 - ,format( (sum(totalProfit)/100.0) / sum(HDs), 4) AS Profitperhand - ,format( sum(activeSeats*HDs)/(sum(HDs)+0.0), 2) AS AvgSeats - from Gametypes gt - inner join Sites s on s.Id = gt.siteId - inner join HudCache hc on hc.gameTypeId = gt.Id - where hc.playerId in - and - and hc.activeSeats - and concat( '20', substring(hc.styleKey,2,2), '-', substring(hc.styleKey,4,2), '-' - , substring(hc.styleKey,6,2) ) - group by gt.base - ,gt.category - ,upper(gt.limitType) - ,s.name - - ,gtId - ) stats - inner join - ( select # profit from handsplayers/handsactions - hprof.gtId, sum(hprof.profit) sum_profit, - avg(hprof.profit/100.0) profitperhand, - case when hprof.gtId = -1 then -999 - else variance(hprof.profit/100.0) - end as variance - from - (select hp.handId, as gtId, hp.totalProfit as profit - from HandsPlayers hp - inner join Hands h ON h.id = hp.handId - where hp.playerId in - and hp.tourneysPlayersId IS NULL - and date_format(h.handStart, '%Y-%m-%d') - group by hp.handId, gtId, hp.totalProfit - ) hprof - group by hprof.gtId - ) hprof2 - on hprof2.gtId = stats.gtId - order by stats.category, stats.limittype, stats.bigBlindDesc desc """ - elif(self.dbname == 'PostgreSQL'): - self.query['playerStats'] = """ - SELECT upper(stats.limitType) || ' ' - || initcap(stats.category) || ' ' - || stats.name || ' ' - || stats.bigBlindDesc AS Game - ,stats.n - ,stats.vpip - ,stats.pfr - ,stats.pf3 - ,stats.steals - ,stats.saw_f - ,stats.sawsd - ,stats.wtsdwsf - ,stats.wmsd - ,stats.FlAFq - ,stats.TuAFq - ,stats.RvAFq - ,stats.PoFAFq - ,stats.Net - ,stats.BBper100 - ,stats.Profitperhand - ,case when hprof2.variance = -999 then '-' - else to_char(hprof2.variance, '0D00') - end AS Variance - ,AvgSeats - FROM - (select gt.base - ,gt.category - ,upper(gt.limitType) AS limitType - ,s.name - , AS bigBlindDesc - , AS gtId - ,sum(HDs) as n - ,to_char(100.0*sum(street0VPI)/sum(HDs),'990D0') AS vpip - ,to_char(100.0*sum(street0Aggr)/sum(HDs),'90D0') AS pfr - ,case when sum(street0_3Bchance) = 0 then '0' - else to_char(100.0*sum(street0_3Bdone)/sum(street0_3Bchance),'90D0') - end AS pf3 - ,case when sum(stealattemptchance) = 0 then '-' - else to_char(100.0*sum(stealattempted)/sum(stealattemptchance),'90D0') - end AS steals - ,to_char(100.0*sum(street1Seen)/sum(HDs),'90D0') AS saw_f - ,to_char(100.0*sum(sawShowdown)/sum(HDs),'90D0') AS sawsd - ,case when sum(street1Seen) = 0 then '-' - else to_char(100.0*sum(sawShowdown)/sum(street1Seen),'90D0') - end AS wtsdwsf - ,case when sum(sawShowdown) = 0 then '-' - else to_char(100.0*sum(wonAtSD)/sum(sawShowdown),'90D0') - end AS wmsd - ,case when sum(street1Seen) = 0 then '-' - else to_char(100.0*sum(street1Aggr)/sum(street1Seen),'90D0') - end AS FlAFq - ,case when sum(street2Seen) = 0 then '-' - else to_char(100.0*sum(street2Aggr)/sum(street2Seen),'90D0') - end AS TuAFq - ,case when sum(street3Seen) = 0 then '-' - else to_char(100.0*sum(street3Aggr)/sum(street3Seen),'90D0') - end AS RvAFq - ,case when sum(street1Seen)+sum(street2Seen)+sum(street3Seen) = 0 then '-' - else to_char(100.0*(sum(street1Aggr)+sum(street2Aggr)+sum(street3Aggr)) - /(sum(street1Seen)+sum(street2Seen)+sum(street3Seen)),'90D0') - end AS PoFAFq - ,round(sum(totalProfit)/100.0,2) AS Net - ,to_char((sum(totalProfit/(gt.bigBlind+0.0))) / (sum(HDs)/100.0), '990D00') - AS BBper100 - ,to_char(sum(totalProfit/100.0) / (sum(HDs)+0.0), '990D0000') AS Profitperhand - ,to_char(sum(activeSeats*HDs)/(sum(HDs)+0.0),'90D00') AS AvgSeats - from Gametypes gt - inner join Sites s on s.Id = gt.siteId - inner join HudCache hc on hc.gameTypeId = gt.Id - where hc.playerId in - and - and hc.activeSeats - and '20' || SUBSTR(hc.styleKey,2,2) || '-' || SUBSTR(hc.styleKey,4,2) || '-' - || SUBSTR(hc.styleKey,6,2) - group by gt.base - ,gt.category - ,upper(gt.limitType) - ,s.name - - ,gtId - ) stats - inner join - ( select - hprof.gtId, sum(hprof.profit) AS sum_profit, - avg(hprof.profit/100.0) AS profitperhand, - case when hprof.gtId = -1 then -999 - else variance(hprof.profit/100.0) - end as variance - from - (select hp.handId, as gtId, hp.totalProfit as profit - from HandsPlayers hp - inner join Hands h ON (h.id = hp.handId) - where hp.playerId in - and hp.tourneysPlayersId IS NULL - and to_char(h.handStart, 'YYYY-MM-DD') - group by hp.handId, gtId, hp.totalProfit - ) hprof - group by hprof.gtId - ) hprof2 - on hprof2.gtId = stats.gtId - order by stats.base, stats.limittype, stats.bigBlindDesc desc """ - elif(self.dbname == 'SQLite'): - self.query['playerStats'] = """ """ - - if(self.dbname == 'MySQL InnoDB'): - self.query['playerStatsByPosition'] = """ - SELECT - concat(upper(stats.limitType), ' ' - ,concat(upper(substring(stats.category,1,1)),substring(stats.category,2) ), ' ' - ,stats.name, ' ' - ,cast(stats.bigBlindDesc as char) - ) AS Game - ,case when stats.PlPosition = -2 then 'BB' - when stats.PlPosition = -1 then 'SB' - when stats.PlPosition = 0 then 'Btn' - when stats.PlPosition = 1 then 'CO' - when stats.PlPosition = 2 then 'MP' - when stats.PlPosition = 5 then 'EP' - else '??' - end AS PlPosition - ,stats.n - ,stats.vpip - ,stats.pfr - ,stats.pf3 - ,stats.steals - ,stats.saw_f - ,stats.sawsd - ,stats.wtsdwsf - ,stats.wmsd - ,stats.FlAFq - ,stats.TuAFq - ,stats.RvAFq - ,stats.PoFAFq - ,stats.Net - ,stats.BBper100 - ,stats.Profitperhand - ,case when hprof2.variance = -999 then '-' - else format(hprof2.variance, 2) - end AS Variance - ,stats.AvgSeats - FROM - (select /* stats from hudcache */ - gt.base - ,gt.category - ,upper(gt.limitType) AS limitType - ,s.name - , AS bigBlindDesc - , AS gtId - ,case when hc.position = 'B' then -2 - when hc.position = 'S' then -1 - when hc.position = 'D' then 0 - when hc.position = 'C' then 1 - when hc.position = 'M' then 2 - when hc.position = 'E' then 5 - else 9 - end as PlPosition - ,sum(HDs) AS n - ,format(100.0*sum(street0VPI)/sum(HDs),1) AS vpip - ,format(100.0*sum(street0Aggr)/sum(HDs),1) AS pfr - ,case when sum(street0_3Bchance) = 0 then '0' - else format(100.0*sum(street0_3Bdone)/sum(street0_3Bchance),1) - end AS pf3 - ,case when sum(stealattemptchance) = 0 then '-' - else format(100.0*sum(stealattempted)/sum(stealattemptchance),1) - end AS steals - ,format(100.0*sum(street1Seen)/sum(HDs),1) AS saw_f - ,format(100.0*sum(sawShowdown)/sum(HDs),1) AS sawsd - ,case when sum(street1Seen) = 0 then '-' - else format(100.0*sum(sawShowdown)/sum(street1Seen),1) - end AS wtsdwsf - ,case when sum(sawShowdown) = 0 then '-' - else format(100.0*sum(wonAtSD)/sum(sawShowdown),1) - end AS wmsd - ,case when sum(street1Seen) = 0 then '-' - else format(100.0*sum(street1Aggr)/sum(street1Seen),1) - end AS FlAFq - ,case when sum(street2Seen) = 0 then '-' - else format(100.0*sum(street2Aggr)/sum(street2Seen),1) - end AS TuAFq - ,case when sum(street3Seen) = 0 then '-' - else format(100.0*sum(street3Aggr)/sum(street3Seen),1) - end AS RvAFq - ,case when sum(street1Seen)+sum(street2Seen)+sum(street3Seen) = 0 then '-' - else format(100.0*(sum(street1Aggr)+sum(street2Aggr)+sum(street3Aggr)) - /(sum(street1Seen)+sum(street2Seen)+sum(street3Seen)),1) - end AS PoFAFq - ,format(sum(totalProfit)/100.0,2) AS Net - ,format((sum(totalProfit/(gt.bigBlind+0.0))) / (sum(HDs)/100.0),2) - AS BBper100 - ,format( (sum(totalProfit)/100.0) / sum(HDs), 4) AS Profitperhand - ,format( sum(activeSeats*HDs)/(sum(HDs)+0.0), 2) AS AvgSeats - from Gametypes gt - inner join Sites s on s.Id = gt.siteId - inner join HudCache hc on hc.gameTypeId = gt.Id - where hc.playerId in - and - and hc.activeSeats - and concat( '20', substring(hc.styleKey,2,2), '-', substring(hc.styleKey,4,2), '-' - , substring(hc.styleKey,6,2) ) - group by gt.base - ,gt.category - ,upper(gt.limitType) - ,s.name - - ,gtId - - ,PlPosition - ) stats - inner join - ( select # profit from handsplayers/handsactions - hprof.gtId, - case when hprof.position = 'B' then -2 - when hprof.position = 'S' then -1 - when hprof.position in ('3','4') then 2 - when hprof.position in ('6','7') then 5 - else hprof.position - end as PlPosition, - sum(hprof.profit) as sum_profit, - avg(hprof.profit/100.0) as profitperhand, - case when hprof.gtId = -1 then -999 - else variance(hprof.profit/100.0) - end as variance - from - (select hp.handId, as gtId, hp.position - , hp.totalProfit as profit - from HandsPlayers hp - inner join Hands h ON (h.id = hp.handId) - where hp.playerId in - and hp.tourneysPlayersId IS NULL - and date_format(h.handStart, '%Y-%m-%d') - group by hp.handId, gtId, hp.position, hp.totalProfit - ) hprof - group by hprof.gtId, PlPosition - ) hprof2 - on ( hprof2.gtId = stats.gtId - and hprof2.PlPosition = stats.PlPosition) - order by stats.category, stats.limitType, stats.bigBlindDesc desc - , cast(stats.PlPosition as signed) - """ - elif(self.dbname == 'PostgreSQL'): - self.query['playerStatsByPosition'] = """ - select /* stats from hudcache */ - upper(stats.limitType) || ' ' - || upper(substr(stats.category,1,1)) || substr(stats.category,2) || ' ' - || stats.name || ' ' - || stats.bigBlindDesc AS Game - ,case when stats.PlPosition = -2 then 'BB' - when stats.PlPosition = -1 then 'SB' - when stats.PlPosition = 0 then 'Btn' - when stats.PlPosition = 1 then 'CO' - when stats.PlPosition = 2 then 'MP' - when stats.PlPosition = 5 then 'EP' - else '??' - end AS PlPosition - ,stats.n - ,stats.vpip - ,stats.pfr - ,stats.pf3 - ,stats.steals - ,stats.saw_f - ,stats.sawsd - ,stats.wtsdwsf - ,stats.wmsd - ,stats.FlAFq - ,stats.TuAFq - ,stats.RvAFq - ,stats.PoFAFq - ,stats.Net - ,stats.BBper100 - ,stats.Profitperhand - ,case when hprof2.variance = -999 then '-' - else to_char(hprof2.variance, '0D00') - end AS Variance - ,stats.AvgSeats - FROM - (select /* stats from hudcache */ - gt.base - ,gt.category - ,upper(gt.limitType) AS limitType - ,s.name - , AS bigBlindDesc - , AS gtId - ,case when hc.position = 'B' then -2 - when hc.position = 'S' then -1 - when hc.position = 'D' then 0 - when hc.position = 'C' then 1 - when hc.position = 'M' then 2 - when hc.position = 'E' then 5 - else 9 - end AS PlPosition - ,sum(HDs) AS n - ,to_char(round(100.0*sum(street0VPI)/sum(HDs)),'990D0') AS vpip - ,to_char(round(100.0*sum(street0Aggr)/sum(HDs)),'90D0') AS pfr - ,case when sum(street0_3Bchance) = 0 then '0' - else to_char(100.0*sum(street0_3Bdone)/sum(street0_3Bchance),'90D0') - end AS pf3 - ,case when sum(stealattemptchance) = 0 then '-' - else to_char(100.0*sum(stealattempted)/sum(stealattemptchance),'90D0') - end AS steals - ,to_char(round(100.0*sum(street1Seen)/sum(HDs)),'90D0') AS saw_f - ,to_char(round(100.0*sum(sawShowdown)/sum(HDs)),'90D0') AS sawsd - ,case when sum(street1Seen) = 0 then '-' - else to_char(round(100.0*sum(sawShowdown)/sum(street1Seen)),'90D0') - end AS wtsdwsf - ,case when sum(sawShowdown) = 0 then '-' - else to_char(round(100.0*sum(wonAtSD)/sum(sawShowdown)),'90D0') - end AS wmsd - ,case when sum(street1Seen) = 0 then '-' - else to_char(round(100.0*sum(street1Aggr)/sum(street1Seen)),'90D0') - end AS FlAFq - ,case when sum(street2Seen) = 0 then '-' - else to_char(round(100.0*sum(street2Aggr)/sum(street2Seen)),'90D0') - end AS TuAFq - ,case when sum(street3Seen) = 0 then '-' - else to_char(round(100.0*sum(street3Aggr)/sum(street3Seen)),'90D0') - end AS RvAFq - ,case when sum(street1Seen)+sum(street2Seen)+sum(street3Seen) = 0 then '-' - else to_char(round(100.0*(sum(street1Aggr)+sum(street2Aggr)+sum(street3Aggr)) - /(sum(street1Seen)+sum(street2Seen)+sum(street3Seen))),'90D0') - end AS PoFAFq - ,to_char(sum(totalProfit)/100.0,'9G999G990D00') AS Net - ,case when sum(HDs) = 0 then '0' - else to_char(sum(totalProfit/(gt.bigBlind+0.0)) / (sum(HDs)/100.0), '990D00') - end AS BBper100 - ,case when sum(HDs) = 0 then '0' - else to_char( (sum(totalProfit)/100.0) / sum(HDs), '90D0000') - end AS Profitperhand - ,to_char(sum(activeSeats*HDs)/(sum(HDs)+0.0),'90D00') AS AvgSeats - from Gametypes gt - inner join Sites s on (s.Id = gt.siteId) - inner join HudCache hc on (hc.gameTypeId = gt.Id) - where hc.playerId in - and - and hc.activeSeats - and '20' || SUBSTR(hc.styleKey,2,2) || '-' || SUBSTR(hc.styleKey,4,2) || '-' - || SUBSTR(hc.styleKey,6,2) - group by gt.base - ,gt.category - ,upper(gt.limitType) - ,s.name - - ,gtId - - ,PlPosition - ) stats - inner join - ( select /* profit from handsplayers/handsactions */ - hprof.gtId, - case when hprof.position = 'B' then -2 - when hprof.position = 'S' then -1 - when hprof.position in ('3','4') then 2 - when hprof.position in ('6','7') then 5 - else cast(hprof.position as smallint) - end as PlPosition, - sum(hprof.profit) as sum_profit, - avg(hprof.profit/100.0) as profitperhand, - case when hprof.gtId = -1 then -999 - else variance(hprof.profit/100.0) - end as variance - from - (select hp.handId, as gtId, hp.position - , hp.totalProfit as profit - from HandsPlayers hp - inner join Hands h ON (h.id = hp.handId) - where hp.playerId in - and hp.tourneysPlayersId IS NULL - and to_char(h.handStart, 'YYYY-MM-DD') - group by hp.handId, gameTypeId, hp.position, hp.totalProfit - ) hprof - group by hprof.gtId, PlPosition - ) hprof2 - on ( hprof2.gtId = stats.gtId - and hprof2.PlPosition = stats.PlPosition) - order by stats.category, stats.limitType, stats.bigBlindDesc desc - , cast(stats.PlPosition as smallint) - """ - elif(self.dbname == 'SQLite'): - self.query['playerStatsByPosition'] = """ """ - if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'): self.query['getGames'] = """SELECT DISTINCT category from Gametypes""" @@ -1520,311 +50,6 @@ class FpdbSQLQueries: self.query['getLimits'] = """SELECT DISTINCT bigBlind from Gametypes ORDER by bigBlind DESC""" - #################################### - # Queries to rebuild/modify hudcache - #################################### - - if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'): - self.query['clearHudCache'] = """DELETE FROM HudCache""" - - if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'): - self.query['rebuildHudCache'] = """ - INSERT INTO HudCache - (gametypeId - ,playerId - ,activeSeats - ,position - ,tourneyTypeId - ,styleKey - ,HDs - ,wonWhenSeenStreet1 - ,wonAtSD - ,street0VPI - ,street0Aggr - ,street0_3BChance - ,street0_3BDone - ,street1Seen - ,street2Seen - ,street3Seen - ,street4Seen - ,sawShowdown - ,street1Aggr - ,street2Aggr - ,street3Aggr - ,street4Aggr - ,otherRaisedStreet1 - ,otherRaisedStreet2 - ,otherRaisedStreet3 - ,otherRaisedStreet4 - ,foldToOtherRaisedStreet1 - ,foldToOtherRaisedStreet2 - ,foldToOtherRaisedStreet3 - ,foldToOtherRaisedStreet4 - ,stealAttemptChance - ,stealAttempted - ,foldBbToStealChance - ,foldedBbToSteal - ,foldSbToStealChance - ,foldedSbToSteal - ,street1CBChance - ,street1CBDone - ,street2CBChance - ,street2CBDone - ,street3CBChance - ,street3CBDone - ,street4CBChance - ,street4CBDone - ,foldToStreet1CBChance - ,foldToStreet1CBDone - ,foldToStreet2CBChance - ,foldToStreet2CBDone - ,foldToStreet3CBChance - ,foldToStreet3CBDone - ,foldToStreet4CBChance - ,foldToStreet4CBDone - ,totalProfit - ,street1CheckCallRaiseChance - ,street1CheckCallRaiseDone - ,street2CheckCallRaiseChance - ,street2CheckCallRaiseDone - ,street3CheckCallRaiseChance - ,street3CheckCallRaiseDone - ,street4CheckCallRaiseChance - ,street4CheckCallRaiseDone - ) - SELECT h.gametypeId - ,hp.playerId - ,h.seats - ,case when hp.position = 'B' then 'B' - when hp.position = 'S' then 'S' - when hp.position = '0' then 'D' - when hp.position = '1' then 'C' - when hp.position = '2' then 'M' - when hp.position = '3' then 'M' - when hp.position = '4' then 'M' - when hp.position = '5' then 'E' - when hp.position = '6' then 'E' - when hp.position = '7' then 'E' - when hp.position = '8' then 'E' - when hp.position = '9' then 'E' - else 'E' - end AS hc_position - ,hp.tourneyTypeId - ,date_format(h.handStart, 'd%y%m%d') - ,count(1) - ,sum(wonWhenSeenStreet1) - ,sum(wonAtSD) - ,sum(CAST(street0VPI as integer)) - ,sum(CAST(street0Aggr as integer)) - ,sum(CAST(street0_3BChance as integer)) - ,sum(CAST(street0_3BDone as integer)) - ,sum(CAST(street1Seen as integer)) - ,sum(CAST(street2Seen as integer)) - ,sum(CAST(street3Seen as integer)) - ,sum(CAST(street4Seen as integer)) - ,sum(CAST(sawShowdown as integer)) - ,sum(CAST(street1Aggr as integer)) - ,sum(CAST(street2Aggr as integer)) - ,sum(CAST(street3Aggr as integer)) - ,sum(CAST(street4Aggr as integer)) - ,sum(CAST(otherRaisedStreet1 as integer)) - ,sum(CAST(otherRaisedStreet2 as integer)) - ,sum(CAST(otherRaisedStreet3 as integer)) - ,sum(CAST(otherRaisedStreet4 as integer)) - ,sum(CAST(foldToOtherRaisedStreet1 as integer)) - ,sum(CAST(foldToOtherRaisedStreet2 as integer)) - ,sum(CAST(foldToOtherRaisedStreet3 as integer)) - ,sum(CAST(foldToOtherRaisedStreet4 as integer)) - ,sum(CAST(stealAttemptChance as integer)) - ,sum(CAST(stealAttempted as integer)) - ,sum(CAST(foldBbToStealChance as integer)) - ,sum(CAST(foldedBbToSteal as integer)) - ,sum(CAST(foldSbToStealChance as integer)) - ,sum(CAST(foldedSbToSteal as integer)) - ,sum(CAST(street1CBChance as integer)) - ,sum(CAST(street1CBDone as integer)) - ,sum(CAST(street2CBChance as integer)) - ,sum(CAST(street2CBDone as integer)) - ,sum(CAST(street3CBChance as integer)) - ,sum(CAST(street3CBDone as integer)) - ,sum(CAST(street4CBChance as integer)) - ,sum(CAST(street4CBDone as integer)) - ,sum(CAST(foldToStreet1CBChance as integer)) - ,sum(CAST(foldToStreet1CBDone as integer)) - ,sum(CAST(foldToStreet2CBChance as integer)) - ,sum(CAST(foldToStreet2CBDone as integer)) - ,sum(CAST(foldToStreet3CBChance as integer)) - ,sum(CAST(foldToStreet3CBDone as integer)) - ,sum(CAST(foldToStreet4CBChance as integer)) - ,sum(CAST(foldToStreet4CBDone as integer)) - ,sum(CAST(totalProfit as integer)) - ,sum(CAST(street1CheckCallRaiseChance as integer)) - ,sum(CAST(street1CheckCallRaiseDone as integer)) - ,sum(CAST(street2CheckCallRaiseChance as integer)) - ,sum(CAST(street2CheckCallRaiseDone as integer)) - ,sum(CAST(street3CheckCallRaiseChance as integer)) - ,sum(CAST(street3CheckCallRaiseDone as integer)) - ,sum(CAST(street4CheckCallRaiseChance as integer)) - ,sum(CAST(street4CheckCallRaiseDone as integer)) - FROM HandsPlayers hp - INNER JOIN Hands h ON (h.id = hp.handId) - GROUP BY h.gametypeId - ,hp.playerId - ,h.seats - ,hc_position - ,hp.tourneyTypeId - ,date_format(h.handStart, 'd%y%m%d') -""" - elif (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'): - self.query['rebuildHudCache'] = """ - INSERT INTO HudCache - (gametypeId - ,playerId - ,activeSeats - ,position - ,tourneyTypeId - ,styleKey - ,HDs - ,wonWhenSeenStreet1 - ,wonAtSD - ,street0VPI - ,street0Aggr - ,street0_3BChance - ,street0_3BDone - ,street1Seen - ,street2Seen - ,street3Seen - ,street4Seen - ,sawShowdown - ,street1Aggr - ,street2Aggr - ,street3Aggr - ,street4Aggr - ,otherRaisedStreet1 - ,otherRaisedStreet2 - ,otherRaisedStreet3 - ,otherRaisedStreet4 - ,foldToOtherRaisedStreet1 - ,foldToOtherRaisedStreet2 - ,foldToOtherRaisedStreet3 - ,foldToOtherRaisedStreet4 - ,stealAttemptChance - ,stealAttempted - ,foldBbToStealChance - ,foldedBbToSteal - ,foldSbToStealChance - ,foldedSbToSteal - ,street1CBChance - ,street1CBDone - ,street2CBChance - ,street2CBDone - ,street3CBChance - ,street3CBDone - ,street4CBChance - ,street4CBDone - ,foldToStreet1CBChance - ,foldToStreet1CBDone - ,foldToStreet2CBChance - ,foldToStreet2CBDone - ,foldToStreet3CBChance - ,foldToStreet3CBDone - ,foldToStreet4CBChance - ,foldToStreet4CBDone - ,totalProfit - ,street1CheckCallRaiseChance - ,street1CheckCallRaiseDone - ,street2CheckCallRaiseChance - ,street2CheckCallRaiseDone - ,street3CheckCallRaiseChance - ,street3CheckCallRaiseDone - ,street4CheckCallRaiseChance - ,street4CheckCallRaiseDone - ) - SELECT h.gametypeId - ,hp.playerId - ,h.seats - ,case when hp.position = 'B' then 'B' - when hp.position = 'S' then 'S' - when hp.position = '0' then 'D' - when hp.position = '1' then 'C' - when hp.position = '2' then 'M' - when hp.position = '3' then 'M' - when hp.position = '4' then 'M' - when hp.position = '5' then 'E' - when hp.position = '6' then 'E' - when hp.position = '7' then 'E' - when hp.position = '8' then 'E' - when hp.position = '9' then 'E' - else 'E' - end AS hc_position - ,hp.tourneyTypeId - ,'d' || to_char(h.handStart, 'YYMMDD') - ,count(1) - ,sum(wonWhenSeenStreet1) - ,sum(wonAtSD) - ,sum(CAST(street0VPI as integer)) - ,sum(CAST(street0Aggr as integer)) - ,sum(CAST(street0_3BChance as integer)) - ,sum(CAST(street0_3BDone as integer)) - ,sum(CAST(street1Seen as integer)) - ,sum(CAST(street2Seen as integer)) - ,sum(CAST(street3Seen as integer)) - ,sum(CAST(street4Seen as integer)) - ,sum(CAST(sawShowdown as integer)) - ,sum(CAST(street1Aggr as integer)) - ,sum(CAST(street2Aggr as integer)) - ,sum(CAST(street3Aggr as integer)) - ,sum(CAST(street4Aggr as integer)) - ,sum(CAST(otherRaisedStreet1 as integer)) - ,sum(CAST(otherRaisedStreet2 as integer)) - ,sum(CAST(otherRaisedStreet3 as integer)) - ,sum(CAST(otherRaisedStreet4 as integer)) - ,sum(CAST(foldToOtherRaisedStreet1 as integer)) - ,sum(CAST(foldToOtherRaisedStreet2 as integer)) - ,sum(CAST(foldToOtherRaisedStreet3 as integer)) - ,sum(CAST(foldToOtherRaisedStreet4 as integer)) - ,sum(CAST(stealAttemptChance as integer)) - ,sum(CAST(stealAttempted as integer)) - ,sum(CAST(foldBbToStealChance as integer)) - ,sum(CAST(foldedBbToSteal as integer)) - ,sum(CAST(foldSbToStealChance as integer)) - ,sum(CAST(foldedSbToSteal as integer)) - ,sum(CAST(street1CBChance as integer)) - ,sum(CAST(street1CBDone as integer)) - ,sum(CAST(street2CBChance as integer)) - ,sum(CAST(street2CBDone as integer)) - ,sum(CAST(street3CBChance as integer)) - ,sum(CAST(street3CBDone as integer)) - ,sum(CAST(street4CBChance as integer)) - ,sum(CAST(street4CBDone as integer)) - ,sum(CAST(foldToStreet1CBChance as integer)) - ,sum(CAST(foldToStreet1CBDone as integer)) - ,sum(CAST(foldToStreet2CBChance as integer)) - ,sum(CAST(foldToStreet2CBDone as integer)) - ,sum(CAST(foldToStreet3CBChance as integer)) - ,sum(CAST(foldToStreet3CBDone as integer)) - ,sum(CAST(foldToStreet4CBChance as integer)) - ,sum(CAST(foldToStreet4CBDone as integer)) - ,sum(CAST(totalProfit as integer)) - ,sum(CAST(street1CheckCallRaiseChance as integer)) - ,sum(CAST(street1CheckCallRaiseDone as integer)) - ,sum(CAST(street2CheckCallRaiseChance as integer)) - ,sum(CAST(street2CheckCallRaiseDone as integer)) - ,sum(CAST(street3CheckCallRaiseChance as integer)) - ,sum(CAST(street3CheckCallRaiseDone as integer)) - ,sum(CAST(street4CheckCallRaiseChance as integer)) - ,sum(CAST(street4CheckCallRaiseDone as integer)) - FROM HandsPlayers hp - INNER JOIN Hands h ON (h.id = hp.handId) - GROUP BY h.gametypeId - ,hp.playerId - ,h.seats - ,hc_position - ,hp.tourneyTypeId - ,to_char(h.handStart, 'YYMMDD') -""" - - if __name__== "__main__": from optparse import OptionParser diff --git a/pyfpdb/FulltiltToFpdb.py b/pyfpdb/FulltiltToFpdb.py index f7b834a6..4fb0e8b3 100755 --- a/pyfpdb/FulltiltToFpdb.py +++ b/pyfpdb/FulltiltToFpdb.py @@ -23,25 +23,49 @@ import logging from HandHistoryConverter import * # Fulltilt HH Format converter +# TODO: cat tourno and table to make table name for tournaments class Fulltilt(HandHistoryConverter): # Static regexes - re_GameInfo = re.compile('- (?P\$|)?(?P[.0-9]+)/\$?(?P[.0-9]+) (Ante \$(?P[.0-9]+) )?- (?P(No Limit|Pot Limit|Limit))? (?P(Hold\'em|Omaha Hi|Razz))') + re_GameInfo = re.compile('''(?:(?P.+)\s\((?P\d+)\),\s)? + .+ + -\s(?P\$|)? + (?P[.0-9]+)/ + \$?(?P[.0-9]+)\s + (Ante\s\$?(?P[.0-9]+)\s)?-\s + (?P(No\sLimit|Pot\sLimit|Limit))?\s + (?P(Hold\'em|Omaha\sHi|Omaha\sH/L|7\sCard\sStud|Stud\sH/L|Razz|Stud\sHi)) + ''', re.VERBOSE) re_SplitHands = re.compile(r"\n\n+") re_TailSplitHands = re.compile(r"(\n\n+)") - re_HandInfo = re.compile('.*#(?P[0-9]+): Table (?P[- a-zA-Z]+) (\((?P.+)\) )?- \$?(?P[.0-9]+)/\$?(?P[.0-9]+) (Ante \$(?P[.0-9]+) )?- (?P[a-zA-Z\' ]+) - (?P.*)') + re_HandInfo = re.compile('''.*\#(?P[0-9]+):\s + (?:(?P.+)\s\((?P\d+)\),\s)? + Table\s + (?PPlay\sChip\s|PC)? + (?P
[-\s\da-zA-Z]+)\s + (\((?P.+)\)\s)?-\s + \$?(?P[.0-9]+)/\$?(?P[.0-9]+)\s(Ante\s\$?(?P[.0-9]+)\s)?-\s + (?P[a-zA-Z\/\'\s]+)\s-\s + (?P.*) + ''', re.VERBOSE) re_Button = re.compile('^The button is in seat #(?P
[ a-zA-Z]+) - \$?(?P[.0-9]+)/\$?(?P[.0-9]+) - (?P.*) - (?P
[0-9]+):(?P[0-9]+) ET - (?P[0-9]+)/(?P[0-9]+)/(?P[0-9]+)Table (?P
[ a-zA-Z]+)\nSeat (?P
[- a-zA-Z]+)\'(?P.+?$)?", re.MULTILINE) + re_Button = re.compile('\n\n\n + re_PlayerInfo = re.compile('^', re.MULTILINE) + re_Card = re.compile('^', re.MULTILINE) + re_BoardLast = re.compile('^', re.MULTILINE) + + def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True, index=0): + HandHistoryConverter.__init__(self, in_path, out_path, sitename="Win2day", follow=follow, index=index) + logging.info("Initialising Win2day converter class") + self.filetype = "text" + self.codepage = "cp1252" + self.sideID = 4 + if autostart: + self.start() + + + def compilePlayerRegexs(self, hand): + players = set([player[1] for player in hand.players]) + if not players <= self.compiledPlayers: # x <= y means 'x is subset of y' + # we need to recompile the player regexs. + self.compiledPlayers = players + player_re = "(?P" + "|".join(map(re.escape, players)) + ")" + logging.debug("player_re: " + player_re) + # + + self.re_PostSB = re.compile(r'^' % player_re, re.MULTILINE) + self.re_PostBB = re.compile(r'^' % player_re, re.MULTILINE) + self.re_Antes = re.compile(r"^%s: posts the ante \$?(?P[.0-9]+)" % player_re, re.MULTILINE) + self.re_BringIn = re.compile(r"^%s: brings[- ]in( low|) for \$?(?P[.0-9]+)" % player_re, re.MULTILINE) + self.re_PostBoth = re.compile(r'^' % player_re, re.MULTILINE) + + #r'\n\n' + self.re_HeroCards = re.compile(r'\n(?P\n)' % player_re, re.MULTILINE) + + #'^' + self.re_Action = re.compile(r'^' % player_re, re.MULTILINE) + + self.re_ShowdownAction = re.compile(r'\n(?P\n)' % player_re, re.MULTILINE) + # + # + self.re_CollectPot = re.compile(r'' % player_re, re.MULTILINE) + self.re_sitsOut = re.compile("^%s sits out" % player_re, re.MULTILINE) + self.re_ShownCards = re.compile("^Seat (?P[0-9]+): %s \(.*\) showed \[(?P.*)\].*" % player_re, re.MULTILINE) + + + def readSupportedGames(self): + return [["ring", "hold", "nl"], + ["ring", "hold", "pl"], + ["ring", "hold", "fl"], + ["ring", "stud", "fl"], + ["ring", "draw", "fl"], + ["ring", "omaha", "pl"] + ] + + def determineGameType(self, handText): + info = {'type':'ring'} + + m = self.re_GameInfo.search(handText) + if not m: + print "determineGameType:", handText + return None + + mg = m.groupdict() + + # translations from captured groups to our info strings + #limits = { 'NL':'nl', 'PL':'pl', 'Limit':'fl' } + limits = { 'NL':'nl', 'PL':'pl'} + games = { # base, category + "GAME_THM" : ('hold','holdem'), + # 'Omaha' : ('hold','omahahi'), + #'Omaha Hi/Lo' : ('hold','omahahilo'), + # 'Razz' : ('stud','razz'), + #'7 Card Stud' : ('stud','studhi'), + # 'Badugi' : ('draw','badugi') + } + if 'LIMIT' in mg: + info['limitType'] = limits[mg['LIMIT']] + if 'GAME' in mg: + (info['base'], info['category']) = games[mg['GAME']] + if 'SB' in mg: + info['sb'] = mg['SB'] + if 'BB' in mg: + info['bb'] = mg['BB'] + if 'CURRENCY' in mg: + info['currency'] = mg['CURRENCY'] + # NB: SB, BB must be interpreted as blinds or bets depending on limit type. + + return info + + + def readHandInfo(self, hand): + info = {} + m = self.re_HandInfo.search(hand.handText,re.DOTALL) + if m: + info.update(m.groupdict()) + # TODO: Be less lazy and parse maxseats from the HandInfo regex + if m.group('TABLEATTRIBUTES'): + m2 = re.search("\s*(\d+)-max", m.group('TABLEATTRIBUTES')) + hand.maxseats = int(m2.group(1)) + m = self.re_GameInfo.search(hand.handText) + if m: info.update(m.groupdict()) + m = self.re_Button.search(hand.handText) + if m: info.update(m.groupdict()) + # TODO : I rather like the idea of just having this dict as hand.info + logging.debug("readHandInfo: %s" % info) + for key in info: + if key == 'DATETIME': + # Win2day uses UTC timestamp + hand.starttime = datetime.datetime.fromtimestamp(int(info[key])) + if key == 'HID': + hand.handid = info[key] + if key == 'TABLE': + hand.tablename = info[key] + if key == 'BUTTON': + hand.buttonpos = info[key] + + def readButton(self, hand): + m = self.re_Button.search(hand.handText) + if m: + for player in hand.players: + if player[1] == m.group('BUTTON'): + hand.buttonpos = player[0] + break + else: + logging.info('readButton: not found') + + def readPlayerStacks(self, hand): + logging.debug("readPlayerStacks") + m = self.re_PlayerInfo.finditer(hand.handText) + players = [] + for a in m: + hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH')) + + def markStreets(self, hand): + # PREFLOP = ** Dealing down cards ** + # This re fails if, say, river is missing; then we don't get the ** that starts the river. + if hand.gametype['base'] in ("hold"): + #m = re.search(r"\*\*\* HOLE CARDS \*\*\*(?P.+(?=\*\*\* FLOP \*\*\*)|.+)" + # r"(\*\*\* FLOP \*\*\*(?P \[\S\S \S\S \S\S\].+(?=\*\*\* TURN \*\*\*)|.+))?" + # r"(\*\*\* TURN \*\*\* \[\S\S \S\S \S\S] (?P\[\S\S\].+(?=\*\*\* RIVER \*\*\*)|.+))?" + # r"(\*\*\* RIVER \*\*\* \[\S\S \S\S \S\S \S\S] (?P\[\S\S\].+))?", hand.handText,re.DOTALL) + + m = re.search('(?P.+(?=.+(?=.+(?=.+(?= 38): + retCard += 's' + elif(card > 25): + retCard += 'h' + elif(card > 12): + retCard += 'c' + else: + retCard += 'd' + + return(retCard) + + def readDrawCards(self, hand, street): + logging.debug("readDrawCards") + m = self.re_HeroCards.finditer(hand.streets[street]) + if m == None: + hand.involved = False + else: + for player in m: + hand.hero = player.group('PNAME') # Only really need to do this once + newcards = player.group('NEWCARDS') + oldcards = player.group('OLDCARDS') + if newcards == None: + newcards = set() + else: + newcards = set(newcards.split(' ')) + if oldcards == None: + oldcards = set() + else: + oldcards = set(oldcards.split(' ')) + hand.addDrawHoleCards(newcards, oldcards, player.group('PNAME'), street) + + + def readStudPlayerCards(self, hand, street): + # See comments of reference implementation in FullTiltToFpdb.py + logging.debug("readStudPlayerCards") + m = self.re_HeroCards.finditer(hand.streets[street]) + for player in m: + #~ logging.debug(player.groupdict()) + (pname, oldcards, newcards) = (player.group('PNAME'), player.group('OLDCARDS'), player.group('NEWCARDS')) + if oldcards: + oldcards = [c.strip() for c in oldcards.split(' ')] + if newcards: + newcards = [c.strip() for c in newcards.split(' ')] + if street=='ANTES': + return + elif street=='THIRD': + # we'll have observed hero holecards in CARDS and thirdstreet open cards in 'NEWCARDS' + # hero: [xx][o] + # others: [o] + hand.addPlayerCards(player = player.group('PNAME'), street = street, closed = oldcards, open = newcards) + elif street in ('FOURTH', 'FIFTH', 'SIXTH'): + # 4th: + # hero: [xxo] [o] + # others: [o] [o] + # 5th: + # hero: [xxoo] [o] + # others: [oo] [o] + # 6th: + # hero: [xxooo] [o] + # others: [ooo] [o] + hand.addPlayerCards(player = player.group('PNAME'), street = street, open = newcards) + # we may additionally want to check the earlier streets tally with what we have but lets trust it for now. + elif street=='SEVENTH' and newcards: + # hero: [xxoooo] [x] + # others: not reported. + hand.addPlayerCards(player = player.group('PNAME'), street = street, closed = newcards) + + def readAction(self, hand, street): + m = self.re_Action.finditer(hand.streets[street]) + for action in m: + if action.group('ATYPE') == 'ACTION_RAISE': + hand.addRaiseBy( street, action.group('PNAME'), action.group('BET') ) + elif action.group('ATYPE') == 'ACTION_CALL': + hand.addCall( street, action.group('PNAME'), action.group('BET') ) + elif action.group('ATYPE') == 'ACTION_ALLIN': + hand.addRaiseBy( street, action.group('PNAME'), action.group('BET') ) + elif action.group('ATYPE') == 'ACTION_BET': + hand.addBet( street, action.group('PNAME'), action.group('BET') ) + elif action.group('ATYPE') == 'ACTION_FOLD': + hand.addFold( street, action.group('PNAME')) + elif action.group('ATYPE') == 'ACTION_CHECK': + hand.addCheck( street, action.group('PNAME')) + elif action.group('ATYPE') == 'ACTION_DISCARD': + hand.addDiscard(street, action.group('PNAME'), action.group('NODISCARDED'), action.group('DISCARDED')) + elif action.group('ATYPE') == 'ACTION_STAND': + hand.addStandsPat( street, action.group('PNAME')) + else: + print "DEBUG: unimplemented readAction: '%s' '%s'" %(action.group('PNAME'),action.group('ATYPE'),) + + + def readShowdownActions(self, hand): + for shows in self.re_ShowdownAction.finditer(hand.handText): + showdownCards = set([]) + for card in self.re_Card.finditer(shows.group('CARDS')): + #print "DEBUG:", card, card.group('CARD'), self.convertWin2dayCards(card.group('CARD')) + showdownCards.add(self.convertWin2dayCards(card.group('CARD'))) + + hand.addShownCards(showdownCards, shows.group('PNAME')) + + def readCollectPot(self,hand): + for m in self.re_CollectPot.finditer(hand.handText): + potcoll = Decimal(m.group('POT')) + if potcoll > 0: + hand.addCollectPot(player=m.group('PNAME'),pot=potcoll) + + def readShownCards(self,hand): + for m in self.re_ShownCards.finditer(hand.handText): + if m.group('CARDS') is not None: + cards = m.group('CARDS') + cards = set(cards.split(' ')) + hand.addShownCards(cards=cards, player=m.group('PNAME')) + +if __name__ == "__main__": + parser = OptionParser() + parser.add_option("-i", "--input", dest="ipath", help="parse input hand history", default="-") + parser.add_option("-o", "--output", dest="opath", help="output translation to", default="-") + parser.add_option("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False) + parser.add_option("-q", "--quiet", + action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO) + parser.add_option("-v", "--verbose", + action="store_const", const=logging.INFO, dest="verbosity") + parser.add_option("--vv", + action="store_const", const=logging.DEBUG, dest="verbosity") + + (options, args) = parser.parse_args() + + LOG_FILENAME = './logging.out' + logging.basicConfig(filename=LOG_FILENAME,level=options.verbosity) + + e = Win2day(in_path = options.ipath, out_path = options.opath, follow = options.follow) diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index cdb89894..b3162239 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -17,9 +17,9 @@ import os import sys +import threading import Options import string - cl_options = string.join(sys.argv[1:]) (options, sys.argv) = Options.fpdb_options() @@ -28,10 +28,14 @@ if not options.errorsToConsole: errorFile = open('fpdb-error-log.txt', 'w', 0) sys.stderr = errorFile +import logging + import pygtk pygtk.require('2.0') import gtk +import interlocks + import fpdb_simple import GuiBulkImport @@ -115,11 +119,13 @@ class fpdb: def dia_create_del_database(self, widget, data=None): print "todo: implement dia_create_del_database" self.obtain_global_lock() + self.release_global_lock() #end def dia_create_del_database def dia_create_del_user(self, widget, data=None): print "todo: implement dia_create_del_user" self.obtain_global_lock() + self.release_global_lock() #end def dia_create_del_user def dia_database_stats(self, widget, data=None): @@ -128,7 +134,7 @@ class fpdb: #end def dia_database_stats def dia_database_sessions(self, widget, data=None): - new_sessions_thread=GuiSessionViewer.GuiSessionViewer(self.config, self.querydict) + new_sessions_thread=GuiSessionViewer.GuiSessionViewer(self.config, self.sql) self.threads.append(new_sessions_thread) sessions_tab=new_sessions_thread.get_vbox() self.add_and_display_tab(sessions_tab, "Sessions") @@ -136,16 +142,19 @@ class fpdb: def dia_delete_db_parts(self, widget, data=None): print "todo: implement dia_delete_db_parts" self.obtain_global_lock() + self.release_global_lock() #end def dia_delete_db_parts def dia_edit_profile(self, widget=None, data=None, create_default=False, path=None): print "todo: implement dia_edit_profile" self.obtain_global_lock() + self.release_global_lock() #end def dia_edit_profile def dia_export_db(self, widget, data=None): print "todo: implement dia_export_db" self.obtain_global_lock() + self.release_global_lock() #end def dia_export_db def dia_get_db_root_credentials(self): @@ -171,6 +180,7 @@ class fpdb: def dia_import_db(self, widget, data=None): print "todo: implement dia_import_db" self.obtain_global_lock() + self.release_global_lock() #end def dia_import_db def dia_licensing(self, widget, data=None): @@ -179,7 +189,7 @@ class fpdb: def dia_load_profile(self, widget, data=None): """Dialogue to select a file to load a profile from""" - if self.obtain_global_lock() == 0: # returns 0 if successful + if self.obtain_global_lock(): # returns true if successful #try: # chooser = gtk.FileChooserDialog(title="Please select a profile file to load", # action=gtk.FILE_CHOOSER_ACTION_OPEN, @@ -194,15 +204,18 @@ class fpdb: # print 'User cancelled loading profile' #except: # pass - self.load_profile() + try: + self.load_profile() + except: + pass self.release_global_lock() #end def dia_load_profile def dia_recreate_tables(self, widget, data=None): """Dialogue that asks user to confirm that he wants to delete and recreate the tables""" - if self.obtain_global_lock() in (0,2): # returns 0 if successful, 2 if Hands table does not exist + if self.obtain_global_lock(): # returns true if successful - lock_released = False + #lock_released = False try: dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm deleting and recreating tables") @@ -213,27 +226,46 @@ class fpdb: response = dia_confirm.run() dia_confirm.destroy() if response == gtk.RESPONSE_YES: - if self.db.fdb.backend == self.fdb_lock.fdb.MYSQL_INNODB: + #if self.db.fdb.backend == self.fdb_lock.fdb.MYSQL_INNODB: # mysql requires locks on all tables or none - easier to release this lock # than lock all the other tables # ToDo: lock all other tables so that lock doesn't have to be released - self.release_global_lock() - lock_released = True - self.db.fdb.recreate_tables() - else: + # self.release_global_lock() + # lock_released = True + self.db.recreate_tables() + #else: # for other dbs use same connection as holds global lock - self.fdb_lock.fdb.recreate_tables() + # self.fdb_lock.fdb.recreate_tables() elif response == gtk.RESPONSE_NO: print 'User cancelled recreating tables' except: pass - if not lock_released: - self.release_global_lock() + #if not lock_released: + self.release_global_lock() #end def dia_recreate_tables + + def dia_recreate_hudcache(self, widget, data=None): + if self.obtain_global_lock(): + try: + dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm recreating HUD cache") + diastring = "Please confirm that you want to re-create the HUD cache." + dia_confirm.format_secondary_text(diastring) + + response = dia_confirm.run() + dia_confirm.destroy() + if response == gtk.RESPONSE_YES: + self.db.rebuild_hudcache() + elif response == gtk.REPSONSE_NO: + print 'User cancelled rebuilding hud cache' + except: + pass + self.release_global_lock() + def dia_regression_test(self, widget, data=None): print "todo: implement dia_regression_test" self.obtain_global_lock() + self.release_global_lock() #end def dia_regression_test def dia_save_profile(self, widget, data=None): @@ -292,6 +324,7 @@ class fpdb: + @@ -330,6 +363,7 @@ class fpdb: ('createdb', None, 'Create or Delete _Database (todo)', None, 'Create or Delete Database', self.dia_create_del_database), ('createuser', None, 'Create or Delete _User (todo)', None, 'Create or Delete User', self.dia_create_del_user), ('createtabs', None, 'Create or Recreate _Tables', None, 'Create or Recreate Tables ', self.dia_recreate_tables), + ('rebuildhudcache', None, 'Rebuild HUD Cache', None, 'Rebuild HUD Cache', self.dia_recreate_hudcache), ('stats', None, '_Statistics (todo)', None, 'View Database Statistics', self.dia_database_stats), ('sessions', None, 'Sessions', None, 'View Sessions', self.dia_database_sessions), ('help', None, '_Help'), @@ -352,6 +386,7 @@ class fpdb: """Loads profile from the provided path name.""" self.config = Configuration.Config(file=options.config, dbname=options.dbname) self.settings = {} + self.settings['global_lock'] = self.lock if (os.sep=="/"): self.settings['os']="linuxmac" else: @@ -395,7 +430,6 @@ class fpdb: self.status_bar.set_text("Status: Connected to %s database named %s on host %s" % (self.db.get_backend_name(),self.db.fdb.database, self.db.fdb.host)) # Database connected to successfully, load queries to pass on to other classes - self.querydict = FpdbSQLQueries.FpdbSQLQueries(self.db.get_backend_name()) self.db.connection.rollback() #end def load_profile @@ -404,10 +438,15 @@ class fpdb: #end def not_implemented def obtain_global_lock(self): - print "\nTaking global lock ..." - self.fdb_lock = Database.Database(self.config, sql = self.sql) - self.fdb_lock.do_connect(self.config) - return self.fdb_lock.fdb.get_global_lock() + ret = self.lock.acquire(False) # will return false if lock is already held + if ret: + print "\nGlobal lock taken ..." + else: + print "\nFailed to get global lock." + return ret + # need to release it later: + # self.lock.release() + #end def obtain_global_lock def quit(self, widget, data=None): @@ -418,8 +457,7 @@ class fpdb: #end def quit_cliecked def release_global_lock(self): - self.fdb_lock.fdb.db.rollback() - self.fdb_lock.fdb.disconnect() + self.lock.release() print "Global lock released.\n" #end def release_global_lock @@ -438,20 +476,20 @@ class fpdb: def tab_bulk_import(self, widget, data=None): """opens a tab for bulk importing""" #print "start of tab_bulk_import" - new_import_thread=GuiBulkImport.GuiBulkImport(self.settings, self.config) + new_import_thread = GuiBulkImport.GuiBulkImport(self.settings, self.config, self.sql) self.threads.append(new_import_thread) bulk_tab=new_import_thread.get_vbox() self.add_and_display_tab(bulk_tab, "Bulk Import") #end def tab_bulk_import def tab_player_stats(self, widget, data=None): - new_ps_thread=GuiPlayerStats.GuiPlayerStats(self.config, self.querydict, self.window) + new_ps_thread=GuiPlayerStats.GuiPlayerStats(self.config, self.sql, self.window) self.threads.append(new_ps_thread) ps_tab=new_ps_thread.get_vbox() self.add_and_display_tab(ps_tab, "Player Stats") def tab_positional_stats(self, widget, data=None): - new_ps_thread=GuiPositionalStats.GuiPositionalStats(self.config, self.querydict) + new_ps_thread = GuiPositionalStats.GuiPositionalStats(self.config, self.sql) self.threads.append(new_ps_thread) ps_tab=new_ps_thread.get_vbox() self.add_and_display_tab(ps_tab, "Positional Stats") @@ -478,7 +516,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") def tabGraphViewer(self, widget, data=None): """opens a graph viewer tab""" #print "start of tabGraphViewer" - new_gv_thread = GuiGraphViewer.GuiGraphViewer(self.querydict, self.config) + new_gv_thread = GuiGraphViewer.GuiGraphViewer(self.sql, self.config) self.threads.append(new_gv_thread) gv_tab=new_gv_thread.get_vbox() self.add_and_display_tab(gv_tab, "Graphs") @@ -486,6 +524,8 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") def __init__(self): self.threads = [] + # no more than 1 process can this lock at a time: + self.lock = interlocks.InterProcessLock(name="fpdb_global_lock") self.db = None self.status_bar = None diff --git a/pyfpdb/fpdb_db.py b/pyfpdb/fpdb_db.py index 2ec96580..a92625fd 100644 --- a/pyfpdb/fpdb_db.py +++ b/pyfpdb/fpdb_db.py @@ -18,124 +18,21 @@ import os import re import sys +import logging from time import time, strftime import fpdb_simple import FpdbSQLQueries class fpdb_db: + MYSQL_INNODB = 2 + PGSQL = 3 + SQLITE = 4 def __init__(self): """Simple constructor, doesnt really do anything""" self.db = None self.cursor = None self.sql = {} - self.MYSQL_INNODB = 2 - self.PGSQL = 3 - self.SQLITE = 4 - - # 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 - - self.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':0} # mct 22/3/09 - , {'tab':'Hands', 'col':'siteHandNo', 'drop':0} - , {'tab':'HandsActions', 'col':'handsPlayerId', '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} - ] - ] - - self.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':'handsPlayerId', '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':'handsPlayerId', '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 #end def __init__ def do_connect(self, config=None): @@ -146,12 +43,12 @@ class fpdb_db: self.settings = {} self.settings['os'] = "linuxmac" if os.name != "nt" else "windows" - self.settings.update(config.get_db_parameters()) - self.connect(self.settings['db-backend'], - self.settings['db-host'], - self.settings['db-databaseName'], - self.settings['db-user'], - self.settings['db-password']) + db = config.get_db_parameters() + self.connect(backend=db['db-backend'], + host=db['db-host'], + database=db['db-databaseName'], + user=db['db-user'], + password=db['db-password']) #end def do_connect def connect(self, backend=None, host=None, database=None, @@ -164,13 +61,13 @@ class fpdb_db: self.user=user self.password=password self.database=database - if backend==self.MYSQL_INNODB: + if backend==fpdb_db.MYSQL_INNODB: import MySQLdb try: self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True) except: raise fpdb_simple.FpdbError("MySQL connection failed") - elif backend==self.PGSQL: + elif backend==fpdb_db.PGSQL: import psycopg2 import psycopg2.extensions psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) @@ -182,9 +79,7 @@ class fpdb_db: # sqlcoder: This database only connect failed in my windows setup?? # Modifed it to try the 4 parameter style if the first connect fails - does this work everywhere? connected = False - if self.host == None or self.host == '' \ - or self.host == "localhost" \ - or self.host == "127.0.0.1": + if self.host == "localhost" or self.host == "127.0.0.1": try: self.db = psycopg2.connect(database = database) connected = True @@ -203,13 +98,19 @@ class fpdb_db: msg = "PostgreSQL connection to database (%s) user (%s) failed." % (database, user) print msg raise fpdb_simple.FpdbError(msg) + elif backend==fpdb_db.SQLITE: + logging.info("Connecting to SQLite:%(database)s" % {'database':database}) + import sqlite3 + self.db = sqlite3.connect(database,detect_types=sqlite3.PARSE_DECLTYPES) + sqlite3.register_converter("bool", lambda x: bool(int(x))) + sqlite3.register_adapter(bool, lambda x: "1" if x else "0") + else: raise fpdb_simple.FpdbError("unrecognised database backend:"+backend) self.cursor=self.db.cursor() - self.cursor.execute('SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED') - self.db.commit() # Set up query dictionary as early in the connection process as we can. self.sql = FpdbSQLQueries.FpdbSQLQueries(self.get_backend_name()) + self.cursor.execute(self.sql.query['set tx level']) self.wrongDbVersion=False try: self.cursor.execute("SELECT * FROM Settings") @@ -237,71 +138,6 @@ class fpdb_db: #print "started fpdb_db.reconnect" self.disconnect(due_to_error) self.connect(self.backend, self.host, self.database, self.user, self.password) - - def create_tables(self): - #todo: should detect and fail gracefully if tables already exist. - self.cursor.execute(self.sql.query['createSettingsTable']) - self.cursor.execute(self.sql.query['createSitesTable']) - self.cursor.execute(self.sql.query['createGametypesTable']) - self.cursor.execute(self.sql.query['createPlayersTable']) - self.cursor.execute(self.sql.query['createAutoratesTable']) - self.cursor.execute(self.sql.query['createHandsTable']) - self.cursor.execute(self.sql.query['createTourneyTypesTable']) - self.cursor.execute(self.sql.query['createTourneysTable']) - self.cursor.execute(self.sql.query['createTourneysPlayersTable']) - self.cursor.execute(self.sql.query['createHandsPlayersTable']) - self.cursor.execute(self.sql.query['createHandsActionsTable']) - self.cursor.execute(self.sql.query['createHudCacheTable']) - #self.cursor.execute(self.sql.query['addTourneyIndex']) - #self.cursor.execute(self.sql.query['addHandsIndex']) - #self.cursor.execute(self.sql.query['addPlayersIndex']) - self.fillDefaultData() - self.db.commit() -#end def disconnect - - def drop_tables(self): - """Drops the fpdb tables from the current db""" - - if(self.get_backend_name() == 'MySQL InnoDB'): - #Databases with FOREIGN KEY support need this switched of before you can drop tables - self.drop_referential_integrity() - - # Query the DB to see what tables exist - self.cursor.execute(self.sql.query['list_tables']) - for table in self.cursor: - self.cursor.execute(self.sql.query['drop_table'] + table[0]) - elif(self.get_backend_name() == 'PostgreSQL'): - self.db.commit()# I have no idea why this makes the query work--REB 07OCT2008 - self.cursor.execute(self.sql.query['list_tables']) - tables = self.cursor.fetchall() - for table in tables: - self.cursor.execute(self.sql.query['drop_table'] + table[0] + ' cascade') - elif(self.get_backend_name() == 'SQLite'): - #todo: sqlite version here - print "Empty function here" - - self.db.commit() - #end def drop_tables - - def drop_referential_integrity(self): - """Update all tables to remove foreign keys""" - - self.cursor.execute(self.sql.query['list_tables']) - result = self.cursor.fetchall() - - for i in range(len(result)): - self.cursor.execute("SHOW CREATE TABLE " + result[i][0]) - inner = self.cursor.fetchall() - - for j in range(len(inner)): - # result[i][0] - Table name - # result[i][1] - CREATE TABLE parameters - #Searching for CONSTRAINT `tablename_ibfk_1` - for m in re.finditer('(ibfk_[0-9]+)', inner[j][1]): - key = "`" + inner[j][0] + "_" + m.group() + "`" - self.cursor.execute("ALTER TABLE " + inner[j][0] + " DROP FOREIGN KEY " + key) - self.db.commit() - #end drop_referential_inegrity def get_backend_name(self): """Returns the name of the currently used backend""" @@ -309,6 +145,8 @@ class fpdb_db: return "MySQL InnoDB" elif self.backend==3: return "PostgreSQL" + elif self.backend==4: + return "SQLite" else: raise fpdb_simple.FpdbError("invalid backend") #end def get_backend_name @@ -316,343 +154,108 @@ class fpdb_db: def get_db_info(self): return (self.host, self.database, self.user, self.password) #end def get_db_info - - def fillDefaultData(self): - self.cursor.execute("INSERT INTO Settings VALUES (118);") - self.cursor.execute("INSERT INTO Sites VALUES (DEFAULT, 'Full Tilt Poker', 'USD');") - self.cursor.execute("INSERT INTO Sites VALUES (DEFAULT, 'PokerStars', 'USD');") - self.cursor.execute("INSERT INTO Sites VALUES (DEFAULT, 'Everleaf', 'USD');") - self.cursor.execute("INSERT INTO TourneyTypes VALUES (DEFAULT, 1, 0, 0, 0, False);") - #end def fillDefaultData - - def recreate_tables(self): - """(Re-)creates the tables of the current DB""" - - self.drop_tables() - self.create_tables() - self.createAllIndexes() - self.db.commit() - print "Finished recreating tables" - #end def recreate_tables - - def prepareBulkImport(self): - """Drop some indexes/foreign keys to prepare for bulk import. - Currently keeping the standalone indexes as needed to import quickly""" - stime = time() - if self.backend == self.PGSQL: - self.db.set_isolation_level(0) # allow table/index operations to work - for fk in self.foreignKeys[self.backend]: - if fk['drop'] == 1: - if self.backend == self.MYSQL_INNODB: - self.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 = self.cursor.fetchone() - #print "preparebulk: cons=", cons - if cons: - print "dropping mysql fk", cons[0], fk['fktab'], fk['fkcol'] - try: - self.cursor.execute("alter table " + fk['fktab'] + " drop foreign key " + cons[0]) - except: - pass - elif self.backend == self.PGSQL: - # DON'T FORGET TO RECREATE THEM!! - print "dropping pg fk", fk['fktab'], fk['fkcol'] - try: - # try to lock table to see if index drop will work: - # hmmm, tested by commenting out rollback in grapher. lock seems to work but - # then drop still hangs :-( does work in some tests though?? - # will leave code here for now pending further tests/enhancement ... - self.cursor.execute( "lock table %s in exclusive mode nowait" % (fk['fktab'],) ) - #print "after lock, status:", self.cursor.statusmessage - #print "alter table %s drop constraint %s_%s_fkey" % (fk['fktab'], fk['fktab'], fk['fkcol']) - try: - self.cursor.execute("alter table %s drop constraint %s_%s_fkey" % (fk['fktab'], fk['fktab'], fk['fkcol'])) - print "dropped pg fk pg fk %s_%s_fkey, continuing ..." % (fk['fktab'], fk['fkcol']) - except: - if "does not exist" not in str(sys.exc_value): - print "warning: drop pg fk %s_%s_fkey failed: %s, continuing ..." \ - % (fk['fktab'], fk['fkcol'], str(sys.exc_value).rstrip('\n') ) - except: - print "warning: constraint %s_%s_fkey not dropped: %s, continuing ..." \ - % (fk['fktab'],fk['fkcol'], str(sys.exc_value).rstrip('\n')) - else: - print "Only MySQL and Postgres supported so far" - return -1 - - for idx in self.indexes[self.backend]: - if idx['drop'] == 1: - if self.backend == self.MYSQL_INNODB: - print "dropping mysql index ", idx['tab'], idx['col'] - try: - # apparently nowait is not implemented in mysql so this just hands if there are locks - # preventing the index drop :-( - self.cursor.execute( "alter table %s drop index %s", (idx['tab'],idx['col']) ) - except: - pass - elif self.backend == self.PGSQL: - # DON'T FORGET TO RECREATE THEM!! - print "dropping pg index ", idx['tab'], idx['col'] - try: - # try to lock table to see if index drop will work: - self.cursor.execute( "lock table %s in exclusive mode nowait" % (idx['tab'],) ) - #print "after lock, status:", self.cursor.statusmessage - try: - # table locked ok so index drop should work: - #print "drop index %s_%s_idx" % (idx['tab'],idx['col']) - self.cursor.execute( "drop index if exists %s_%s_idx" % (idx['tab'],idx['col']) ) - #print "dropped pg index ", idx['tab'], idx['col'] - except: - if "does not exist" not in str(sys.exc_value): - print "warning: drop index %s_%s_idx failed: %s, continuing ..." \ - % (idx['tab'],idx['col'], str(sys.exc_value).rstrip('\n')) - except: - print "warning: index %s_%s_idx not dropped %s, continuing ..." \ - % (idx['tab'],idx['col'], str(sys.exc_value).rstrip('\n')) - else: - print "Error: Only MySQL and Postgres supported so far" - return -1 - - if self.backend == self.PGSQL: - self.db.set_isolation_level(1) # go back to normal isolation level - self.db.commit() # seems to clear up errors if there were any in postgres - ptime = time() - stime - print "prepare import took", ptime, "seconds" - #end def prepareBulkImport - - def afterBulkImport(self): - """Re-create any dropped indexes/foreign keys after bulk import""" - stime = time() - if self.backend == self.PGSQL: - self.db.set_isolation_level(0) # allow table/index operations to work - for fk in self.foreignKeys[self.backend]: - if fk['drop'] == 1: - if self.backend == self.MYSQL_INNODB: - self.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 = self.cursor.fetchone() - print "afterbulk: cons=", cons - if cons: - pass - else: - print "creating fk ", fk['fktab'], fk['fkcol'], "->", fk['rtab'], fk['rcol'] - try: - self.cursor.execute("alter table " + fk['fktab'] + " add foreign key (" - + fk['fkcol'] + ") references " + fk['rtab'] + "(" - + fk['rcol'] + ")") - except: - pass - elif self.backend == self.PGSQL: - print "creating fk ", fk['fktab'], fk['fkcol'], "->", fk['rtab'], fk['rcol'] - try: - self.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 self.indexes[self.backend]: - if idx['drop'] == 1: - if self.backend == self.MYSQL_INNODB: - print "creating mysql index ", idx['tab'], idx['col'] - try: - self.cursor.execute( "alter table %s add index %s(%s)" - , (idx['tab'],idx['col'],idx['col']) ) - except: - pass - elif self.backend == self.PGSQL: - # pass - # 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']) - self.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 self.backend == self.PGSQL: - self.db.set_isolation_level(1) # go back to normal isolation level - self.db.commit() # seems to clear up errors if there were any in postgres - atime = time() - stime - print "after import took", atime, "seconds" - #end def afterBulkImport - - def createAllIndexes(self): - """Create new indexes""" - if self.backend == self.PGSQL: - self.db.set_isolation_level(0) # allow table/index operations to work - for idx in self.indexes[self.backend]: - if self.backend == self.MYSQL_INNODB: - print "creating mysql index ", idx['tab'], idx['col'] - try: - self.cursor.execute( "alter table %s add index %s(%s)" - , (idx['tab'],idx['col'],idx['col']) ) - except: - pass - elif self.backend == self.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']) - self.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 self.backend == self.PGSQL: - self.db.set_isolation_level(1) # go back to normal isolation level - #end def createAllIndexes - - def dropAllIndexes(self): - """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 self.backend == self.PGSQL: - self.db.set_isolation_level(0) # allow table/index operations to work - for idx in self.indexes[self.backend]: - if self.backend == self.MYSQL_INNODB: - print "dropping mysql index ", idx['tab'], idx['col'] - try: - self.cursor.execute( "alter table %s drop index %s" - , (idx['tab'],idx['col']) ) - except: - pass - elif self.backend == self.PGSQL: - print "dropping pg index ", idx['tab'], idx['col'] - # mod to use tab_col for index name? - try: - self.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 self.backend == self.PGSQL: - self.db.set_isolation_level(1) # go back to normal isolation level - #end def dropAllIndexes - - def analyzeDB(self): - """Do whatever the DB can offer to update index/table statistics""" - stime = time() - if self.backend == self.PGSQL: - self.db.set_isolation_level(0) # allow vacuum to work - try: - self.cursor.execute("vacuum analyze") - except: - print "Error during vacuum" - self.db.set_isolation_level(1) # go back to normal isolation level - self.db.commit() - atime = time() - stime - print "analyze took", atime, "seconds" - #end def analyzeDB - - # Currently uses an exclusive lock on the Players table as a global lock - # ( Changed because Hands is used in Database.init() ) - # Return values are Unix style, 0 for success, positive integers for errors - # 1 = generic error - # 2 = players table does not exist (error message is suppressed) - def get_global_lock(self): - if self.backend == self.MYSQL_INNODB: - try: - self.cursor.execute( "lock tables Players write" ) - except: - # Table 'fpdb.players' doesn't exist - if str(sys.exc_value).find(".Players' doesn't exist") >= 0: - return(2) - print "Error! failed to obtain global lock. Close all programs accessing " \ - + "database (including fpdb) and try again (%s)." \ - % ( str(sys.exc_value).rstrip('\n'), ) - return(1) - elif self.backend == self.PGSQL: - try: - self.db.commit() - self.cursor.execute( "lock table Players in exclusive mode nowait" ) - #print "... after lock table, status =", self.cursor.statusmessage - except: - # relation "players" does not exist - if str(sys.exc_value).find('does not exist') >= 0: - return(2) - print "Error! failed to obtain global lock. Close all programs accessing " \ - + "database (including fpdb) and try again (%s)." \ - % ( str(sys.exc_value).rstrip('\n'), ) - return(1) - return(0) def getLastInsertId(self): - if self.backend == self.MYSQL_INNODB: - ret = self.db.insert_id() - if ret < 1 or ret > 999999999: - print "getLastInsertId(): problem fetching insert_id? ret=", ret - ret = -1 - elif self.backend == self.PGSQL: - # some options: - # currval(hands_id_seq) - use name of implicit seq here - # lastval() - still needs sequences set up? - # insert ... returning is useful syntax (but postgres specific?) - # see rules (fancy trigger type things) - self.cursor.execute ("SELECT lastval()") - row = self.cursor.fetchone() - if not row: - print "getLastInsertId(%s): problem fetching lastval? row=" % seq, row + try: + if self.backend == self.MYSQL_INNODB: + ret = self.db.insert_id() + if ret < 1 or ret > 999999999: + print "getLastInsertId(): problem fetching insert_id? ret=", ret + ret = -1 + elif self.backend == self.PGSQL: + # some options: + # currval(hands_id_seq) - use name of implicit seq here + # lastval() - still needs sequences set up? + # insert ... returning is useful syntax (but postgres specific?) + # see rules (fancy trigger type things) + c = self.db.cursor() + ret = c.execute ("SELECT lastval()") + row = c.fetchone() + if not row: + print "getLastInsertId(%s): problem fetching lastval? row=" % seq, row + ret = -1 + else: + ret = row[0] + elif self.backend == fpdb_db.SQLITE: + # don't know how to do this in sqlite + print "getLastInsertId(): not coded for sqlite yet" ret = -1 else: - ret = row[0] - elif self.backend == self.SQLITE: - # don't know how to do this in sqlite - print "getLastInsertId(): not coded for sqlite yet" - ret = -1 - else: - print "getLastInsertId(): unknown backend ", self.backend + print "getLastInsertId(): unknown backend ", self.backend + ret = -1 + except: ret = -1 + print "getLastInsertId error:", str(sys.exc_value), " ret =", ret + raise fpdb_simple.FpdbError( "getLastInsertId error: " + str(sys.exc_value) ) + return ret def storeHand(self, p): #stores into table hands: - self.cursor.execute ("""INSERT INTO Hands - (siteHandNo, gametypeId, handStart, seats, tableName, importTime, maxSeats - ,boardcard1, boardcard2, boardcard3, boardcard4, boardcard5 - ,playersVpi, playersAtStreet1, playersAtStreet2 - ,playersAtStreet3, playersAtStreet4, playersAtShowdown - ,street0Raises, street1Raises, street2Raises - ,street3Raises, street4Raises, street1Pot - ,street2Pot, street3Pot, street4Pot - ,showdownPot + self.cursor.execute ("""INSERT INTO Hands ( + tablename, + sitehandno, + gametypeid, + handstart, + importtime, + seats, + maxseats, + boardcard1, + boardcard2, + boardcard3, + boardcard4, + boardcard5, +-- texture, + playersVpi, + playersAtStreet1, + playersAtStreet2, + playersAtStreet3, + playersAtStreet4, + playersAtShowdown, + street0Raises, + street1Raises, + street2Raises, + street3Raises, + street4Raises, +-- street1Pot, +-- street2Pot, +-- street3Pot, +-- street4Pot, +-- showdownPot ) VALUES - (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""" - ,(p['siteHandNo'], gametype_id, p['handStart'], len(names), p['tableName'], datetime.datetime.today(), p['maxSeats'] - ,p['boardcard1'], ['boardcard2'], p['boardcard3'], ['boardcard4'], ['boardcard5'] - ,hudCache['playersVpi'], hudCache['playersAtStreet1'], hudCache['playersAtStreet2'] - ,hudCache['playersAtStreet3'], hudCache['playersAtStreet4'], hudCache['playersAtShowdown'] - ,hudCache['street0Raises'], hudCache['street1Raises'], hudCache['street2Raises'] - ,hudCache['street3Raises'], hudCache['street4Raises'], hudCache['street1Pot'] - ,hudCache['street2Pot'], hudCache['street3Pot'], hudCache['street4Pot'] - ,hudCache['showdownPot'] - ) - ) + (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, %s, %s)""", + ( + p['tablename'], + p['sitehandno'], + p['gametypeid'], + p['handStart'], + datetime.datetime.today(), + len(p['names']), + p['maxSeats'], + p['boardcard1'], + p['boardcard2'], + p['boardcard3'], + p['boardcard4'], + p['boardcard5'], + hudCache['playersVpi'], + hudCache['playersAtStreet1'], + hudCache['playersAtStreet2'], + hudCache['playersAtStreet3'], + hudCache['playersAtStreet4'], + hudCache['playersAtShowdown'], + hudCache['street0Raises'], + hudCache['street1Raises'], + hudCache['street2Raises'], + hudCache['street3Raises'], + hudCache['street4Raises'], + hudCache['street1Pot'], + hudCache['street2Pot'], + hudCache['street3Pot'], + hudCache['street4Pot'], + hudCache['showdownPot'] + ) + ) #return getLastInsertId(backend, conn, cursor) #end class fpdb_db diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 2468fecf..ed87731b 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -22,6 +22,7 @@ import os # todo: remove this once import_dir is in fpdb_import import sys from time import time, strftime +import logging import traceback import math import datetime @@ -53,14 +54,14 @@ except: class Importer: - def __init__(self, caller, settings, config): + def __init__(self, caller, settings, config, sql = None): """Constructor""" self.settings = settings self.caller = caller self.config = config + self.sql = sql + self.database = None # database will be the main db interface eventually - self.fdb = None # fdb may disappear or just hold the simple db connection - self.cursor = None self.filelist = {} self.dirlist = {} self.siteIds = {} @@ -77,10 +78,10 @@ class Importer: self.settings.setdefault("minPrint", 30) self.settings.setdefault("handCount", 0) - self.database = Database.Database(self.config) # includes .connection and .sql variables - self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql - self.fdb.do_connect(self.config) - self.fdb.db.rollback() + self.database = Database.Database(self.config, sql = self.sql) # includes .connection and .sql variables + + self.NEWIMPORT = False + self.allow_hudcache_rebuild = False #Set functions def setCallHud(self, value): @@ -119,8 +120,7 @@ class Importer: self.filelist[filename] = [site] + [filter] if site not in self.siteIds: # Get id from Sites table in DB - self.fdb.cursor.execute(self.fdb.sql.query['getSiteId'], (site,)) - result = self.fdb.cursor.fetchall() + result = self.database.get_site_id(site) if len(result) == 1: self.siteIds[site] = result[0][0] else: @@ -165,13 +165,19 @@ class Importer: def runImport(self): """"Run full import on self.filelist.""" + start = datetime.datetime.now() - print "started at", start, "--", len(self.filelist), "files to import.", self.settings['dropIndexes'] + print "Started at", start, "--", len(self.filelist), "files to import.", self.settings['dropIndexes'] if self.settings['dropIndexes'] == 'auto': - self.settings['dropIndexes'] = self.calculate_auto2(10.0, 500.0) + self.settings['dropIndexes'] = self.calculate_auto2(12.0, 500.0) + if self.allow_hudcache_rebuild: + self.settings['dropHudCache'] = self.calculate_auto2(25.0, 500.0) # returns "drop"/"don't drop" + if self.settings['dropIndexes'] == 'drop': - self.fdb.prepareBulkImport() - #self.settings['updateHudCache'] = self.calculate_auto2(10.0, 500.0) + self.database.prepareBulkImport() + else: + print "No need to drop indexes." + #print "dropInd =", self.settings['dropIndexes'], " dropHudCache =", self.settings['dropHudCache'] totstored = 0 totdups = 0 totpartial = 0 @@ -186,8 +192,14 @@ class Importer: toterrors += errors tottime += ttime if self.settings['dropIndexes'] == 'drop': - self.fdb.afterBulkImport() - self.fdb.analyzeDB() + self.database.afterBulkImport() + else: + print "No need to rebuild indexes." + if self.allow_hudcache_rebuild and self.settings['dropHudCache'] == 'drop': + self.database.rebuild_hudcache() + else: + print "No need to rebuild hudcache." + self.database.analyzeDB() return (totstored, totdups, totpartial, toterrors, tottime) # else: import threaded @@ -196,7 +208,7 @@ class Importer: if len(self.filelist) == 1: return "don't drop" if 'handsInDB' not in self.settings: try: - tmpcursor = self.fdb.db.cursor() + tmpcursor = self.database.get_cursor() tmpcursor.execute("Select count(1) from Hands;") self.settings['handsInDB'] = tmpcursor.fetchone()[0] except: @@ -219,7 +231,7 @@ class Importer: # get number of hands in db if 'handsInDB' not in self.settings: try: - tmpcursor = self.fdb.db.cursor() + tmpcursor = self.database.get_cursor() tmpcursor.execute("Select count(1) from Hands;") self.settings['handsInDB'] = tmpcursor.fetchone()[0] except: @@ -234,11 +246,12 @@ class Importer: # if hands_in_db is zero or very low, we want to drop indexes, otherwise compare # import size with db size somehow: - #print "auto2: handsindb =", self.settings['handsInDB'], "total_size =", total_size, "size_per_hand =", \ - # size_per_hand, "inc =", increment + ret = "don't drop" if self.settings['handsInDB'] < scale * (total_size/size_per_hand) + increment: - return "drop" - return "don't drop" + ret = "drop" + #print "auto2: handsindb =", self.settings['handsInDB'], "total_size =", total_size, "size_per_hand =", \ + # size_per_hand, "inc =", increment, "return:", ret + return ret #Run import on updated files, then store latest update time. def runUpdated(self): @@ -282,12 +295,13 @@ class Importer: self.addToDirList = {} self.removeFromFileList = {} - self.fdb.db.rollback() + self.database.rollback() #rulog.writelines(" finished\n") #rulog.close() # This is now an internal function that should not be called directly. def import_file_dict(self, file, site, filter): + #print "import_file_dict" if os.path.isdir(file): self.addToDirList[file] = [site] + [filter] return @@ -309,9 +323,17 @@ class Importer: mod = __import__(filter) obj = getattr(mod, filter_name, None) if callable(obj): - conv = obj(in_path = file, out_path = out_path) - if(conv.getStatus()): + conv = obj(in_path = file, out_path = out_path, index = 0) # Index into file 0 until changeover + if(conv.getStatus() and self.NEWIMPORT == False): (stored, duplicates, partial, errors, ttime) = self.import_fpdb_file(out_path, site) + elif (conv.getStatus() and self.NEWIMPORT == True): + #This code doesn't do anything yet + handlist = hhc.getProcessedHands() + self.pos_in_file[file] = hhc.getLastCharacterRead() + + for hand in handlist: + hand.prepInsert() + hand.insert() else: # conversion didn't work # TODO: appropriate response? @@ -325,6 +347,7 @@ class Importer: def import_fpdb_file(self, file, site): + #print "import_fpdb_file" starttime = time() last_read_hand = 0 loc = 0 @@ -354,6 +377,8 @@ class Importer: self.pos_in_file[file] = inputFile.tell() inputFile.close() + #self.database.lock_for_insert() # should be ok when using one thread + try: # sometimes we seem to be getting an empty self.lines, in which case, we just want to return. firstline = self.lines[0] except: @@ -395,10 +420,10 @@ class Importer: self.hand=hand try: - handsId = fpdb_parse_logic.mainParser( self.settings, self.fdb + handsId = fpdb_parse_logic.mainParser( self.settings , self.siteIds[site], category, hand , self.config, self.database ) - self.fdb.db.commit() + self.database.commit() stored += 1 if self.callHud: @@ -408,23 +433,23 @@ class Importer: self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep) except fpdb_simple.DuplicateError: duplicates += 1 - self.fdb.db.rollback() + self.database.rollback() except (ValueError), fe: errors += 1 self.printEmailErrorMessage(errors, file, hand) if (self.settings['failOnError']): - self.fdb.db.commit() #dont remove this, in case hand processing was cancelled. + self.database.commit() #dont remove this, in case hand processing was cancelled. raise else: - self.fdb.db.rollback() + self.database.rollback() except (fpdb_simple.FpdbError), fe: errors += 1 self.printEmailErrorMessage(errors, file, hand) - self.fdb.db.rollback() + self.database.rollback() if self.settings['failOnError']: - self.fdb.db.commit() #dont remove this, in case hand processing was cancelled. + self.database.commit() #dont remove this, in case hand processing was cancelled. raise if self.settings['minPrint']: @@ -451,7 +476,7 @@ class Importer: print "failed to read a single hand from file:", inputFile handsId=0 #todo: this will cause return of an unstored hand number if the last hand was error - self.fdb.db.commit() + self.database.commit() self.handsId=handsId return (stored, duplicates, partial, errors, ttime) diff --git a/pyfpdb/fpdb_parse_logic.py b/pyfpdb/fpdb_parse_logic.py index bb361f63..fd2d6796 100644 --- a/pyfpdb/fpdb_parse_logic.py +++ b/pyfpdb/fpdb_parse_logic.py @@ -15,19 +15,25 @@ #In the "official" distribution you can find the license in #agpl-3.0.txt in the docs folder of the package. -#methods that are specific to holdem but not trivial +#parses an in-memory fpdb hand history and calls db routine to store it + +import sys import fpdb_simple import Database +from time import time, strftime + #parses a holdem hand -def mainParser(settings, fdb, siteID, category, hand, config, db = None): +def mainParser(settings, siteID, category, hand, config, db = None): + #print "mainparser" + # fdb is not used now - to be removed ... + + t0 = time() + #print "mainparser" backend = settings['db-backend'] if db == None: - #This is redundant - hopefully fdb will be a Database object in an iteration soon db = Database.Database(c = config, sql = None) - else: - db = db category = fpdb_simple.recogniseCategory(hand[0]) base = "hold" if category == "holdem" or category == "omahahi" or category == "omahahilo" else "stud" @@ -50,9 +56,8 @@ def mainParser(settings, fdb, siteID, category, hand, config, db = None): if line[-2:] == "$0": continue smallBlindLine = i break - #print "small blind line:",smallBlindLine - gametypeID = fpdb_simple.recogniseGametypeID(backend, fdb.db, fdb.cursor, hand[0], hand[smallBlindLine], siteID, category, isTourney) + gametypeID = fpdb_simple.recogniseGametypeID(backend, db, db.get_cursor(), hand[0], hand[smallBlindLine], siteID, category, isTourney) if isTourney: siteTourneyNo = fpdb_simple.parseTourneyNo(hand[0]) buyin = fpdb_simple.parseBuyin(hand[0]) @@ -63,9 +68,20 @@ def mainParser(settings, fdb, siteID, category, hand, config, db = None): tourneyStartTime= handStartTime #todo: read tourney start time rebuyOrAddon = fpdb_simple.isRebuyOrAddon(hand[0]) - tourneyTypeId = fpdb_simple.recogniseTourneyTypeId(fdb.cursor, siteID, buyin, fee, knockout, rebuyOrAddon) + tourneyTypeId = fpdb_simple.recogniseTourneyTypeId(db.get_cursor(), siteID, buyin, fee, knockout, rebuyOrAddon) + else: + siteTourneyNo = -1 + buyin = -1 + fee = -1 + entries = -1 + prizepool = -1 + knockout = 0 + tourneyStartTime= None + rebuyOrAddon = -1 - fpdb_simple.isAlreadyInDB(fdb.cursor, gametypeID, siteHandNo) + tourneyTypeId = 1 + + fpdb_simple.isAlreadyInDB(db.get_cursor(), gametypeID, siteHandNo) hand = fpdb_simple.filterCrap(hand, isTourney) @@ -79,7 +95,7 @@ def mainParser(settings, fdb, siteID, category, hand, config, db = None): seatLines.append(line) names = fpdb_simple.parseNames(seatLines) - playerIDs = fpdb_simple.recognisePlayerIDs(fdb.cursor, names, siteID) + playerIDs = fpdb_simple.recognisePlayerIDs(db.get_cursor(), names, siteID) # inserts players as needed tmp = fpdb_simple.parseCashesAndSeatNos(seatLines) startCashes = tmp['startCashes'] seatNos = tmp['seatNos'] @@ -126,8 +142,9 @@ def mainParser(settings, fdb, siteID, category, hand, config, db = None): fpdb_simple.convertBlindBet(actionTypes, actionAmounts) fpdb_simple.checkPositions(positions) - fdb.cursor.execute("SELECT limitType FROM Gametypes WHERE id=%s",(gametypeID, )) - limit_type = fdb.cursor.fetchone()[0] + c = db.get_cursor() + c.execute("SELECT limitType FROM Gametypes WHERE id=%s",(gametypeID, )) + limit_type = c.fetchone()[0] fpdb_simple.convert3B4B(category, limit_type, actionTypes, actionAmounts) totalWinnings = sum(winnings) @@ -143,49 +160,27 @@ def mainParser(settings, fdb, siteID, category, hand, config, db = None): , allIns, actionTypeByNo, winnings, totalWinnings, None , actionTypes, actionAmounts, antes) - if isTourney: - ranks = map(lambda x: 0, names) # create an array of 0's equal to the length of names - payin_amounts = fpdb_simple.calcPayin(len(names), buyin, fee) - - if base == "hold": - result = db.tourney_holdem_omaha( - config, settings, fdb.db, fdb.cursor, base, category, siteTourneyNo, buyin - , fee, knockout, entries, prizepool, tourneyStartTime - , payin_amounts, ranks, tourneyTypeId, siteID, siteHandNo - , gametypeID, handStartTime, names, playerIDs, startCashes - , positions, cardValues, cardSuits, boardValues, boardSuits - , winnings, rakes, actionTypes, allIns, actionAmounts - , actionNos, hudImportData, maxSeats, tableName, seatNos) - elif base == "stud": - result = db.tourney_stud( - config, settings, fdb.db, fdb.cursor, base, category, siteTourneyNo - , buyin, fee, knockout, entries, prizepool, tourneyStartTime - , payin_amounts, ranks, tourneyTypeId, siteID, siteHandNo - , gametypeID, handStartTime, names, playerIDs, startCashes - , antes, cardValues, cardSuits, winnings, rakes, actionTypes - , allIns, actionAmounts, actionNos, hudImportData, maxSeats - , tableName, seatNos) - else: - raise fpdb_simple.FpdbError("unrecognised category") - else: - if base == "hold": - result = db.ring_holdem_omaha( - config, settings, fdb.db, fdb.cursor, base, category, siteHandNo - , gametypeID, handStartTime, names, playerIDs - , startCashes, positions, cardValues, cardSuits - , boardValues, boardSuits, winnings, rakes - , actionTypes, allIns, actionAmounts, actionNos - , hudImportData, maxSeats, tableName, seatNos) - elif base == "stud": - result = db.ring_stud( - config, settings, fdb.db, fdb.cursor, base, category, siteHandNo, gametypeID - , handStartTime, names, playerIDs, startCashes, antes - , cardValues, cardSuits, winnings, rakes, actionTypes, allIns - , actionAmounts, actionNos, hudImportData, maxSeats, tableName - , seatNos) - else: - raise fpdb_simple.FpdbError ("unrecognised category") - fdb.db.commit() + #print "parse: hand data prepared" # only reads up to here apart from inserting new players + try: + db.commit() # need to commit new players as different db connection used + # for other writes. maybe this will change maybe not ... + except: + print "parse: error during commit: " + str(sys.exc_value) + + + # save data structures in a HandToWrite instance and then insert into database: + htw = Database.HandToWrite() + htw.set_all( config, settings, base, category, siteTourneyNo, buyin + , fee, knockout, entries, prizepool, tourneyStartTime + , isTourney, tourneyTypeId, siteID, siteHandNo + , gametypeID, handStartTime, names, playerIDs, startCashes + , positions, antes, cardValues, cardSuits, boardValues, boardSuits + , winnings, rakes, actionTypes, allIns, actionAmounts + , actionNos, hudImportData, maxSeats, tableName, seatNos) + result = db.store_the_hand(htw) + + t9 = time() + #print "parse and save=(%4.3f)" % (t9-t0) return result #end def mainParser diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index 3e862254..6584dd19 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -37,9 +37,6 @@ MYSQL_INNODB = 2 PGSQL = 3 SQLITE = 4 -# config while trying out new hudcache mechanism -use_date_in_hudcache = True - class DuplicateError(Exception): def __init__(self, value): self.value = value @@ -986,7 +983,7 @@ def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, c #AND limitType=%s AND smallBlind=%s AND bigBlind=%s", (site_id, type, category, limit_type, small_bet, big_bet)) #result=(db.insert_id(),) - result=(getLastInsertId(backend,db,cursor),) + result=(db.get_last_insert_id(),) return result[0] #end def recogniseGametypeID @@ -1122,282 +1119,6 @@ def splitRake(winnings, rakes, totalRake): rakes[i]=totalRake*winPortion #end def splitRake -def storeActions(cursor, handsPlayersIds, actionTypes, allIns, actionAmounts, actionNos): -#stores into table hands_actions - #print "start of storeActions, actionNos:",actionNos - #print " action_amounts:",action_amounts - inserts = [] - for i in xrange(len(actionTypes)): #iterate through streets - for j in xrange(len(actionTypes[i])): #iterate through names - for k in xrange(len(actionTypes[i][j])): #iterate through individual actions of that player on that street - # Add inserts into a list and let - inserts = inserts + [(handsPlayersIds[j], i, actionNos[i][j][k], actionTypes[i][j][k], allIns[i][j][k], actionAmounts[i][j][k])] - - cursor.executemany("INSERT INTO HandsActions (handsPlayerId, street, actionNo, action, allIn, amount) VALUES (%s, %s, %s, %s, %s, %s)", inserts) -#end def storeActions - -def storeHands(backend, conn, cursor, site_hand_no, gametype_id - ,hand_start_time, names, tableName, maxSeats, hudCache, - board_values, board_suits): - cards = [Card.cardFromValueSuit(v,s) for v,s in zip(board_values,board_suits)] -#stores into table hands: - cursor.execute ("""INSERT INTO Hands - (siteHandNo, gametypeId, handStart, seats, tableName, importTime, maxSeats - ,boardcard1,boardcard2,boardcard3,boardcard4,boardcard5 - ,playersVpi, playersAtStreet1, playersAtStreet2 - ,playersAtStreet3, playersAtStreet4, playersAtShowdown - ,street0Raises, street1Raises, street2Raises - ,street3Raises, street4Raises, street1Pot - ,street2Pot, street3Pot, street4Pot - ,showdownPot - ) - VALUES - (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) - """ - , (site_hand_no, gametype_id, hand_start_time, len(names), tableName, datetime.datetime.today(), maxSeats - ,cards[0], cards[1], cards[2], cards[3], cards[4] - ,hudCache['playersVpi'], hudCache['playersAtStreet1'], hudCache['playersAtStreet2'] - ,hudCache['playersAtStreet3'], hudCache['playersAtStreet4'], hudCache['playersAtShowdown'] - ,hudCache['street0Raises'], hudCache['street1Raises'], hudCache['street2Raises'] - ,hudCache['street3Raises'], hudCache['street4Raises'], hudCache['street1Pot'] - ,hudCache['street2Pot'], hudCache['street3Pot'], hudCache['street4Pot'] - ,hudCache['showdownPot'] - )) - return getLastInsertId(backend, conn, cursor) -#end def storeHands - -def store_hands_players_holdem_omaha(backend, conn, cursor, category, hands_id, player_ids, start_cashes - ,positions, card_values, card_suits, winnings, rakes, seatNos, hudCache): - result=[] - - # postgres (and others?) needs the booleans converted to ints before saving: - # (or we could just save them as boolean ... but then we can't sum them so easily in sql ???) - # NO - storing booleans for now so don't need this - #hudCacheInt = {} - #for k,v in hudCache.iteritems(): - # if k in ('wonWhenSeenStreet1', 'wonAtSD', 'totalProfit'): - # hudCacheInt[k] = v - # else: - # hudCacheInt[k] = map(lambda x: 1 if x else 0, v) - - if (category=="holdem"): - for i in xrange(len(player_ids)): - startCards = Card.twoStartCards(card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1]) - card1 = Card.cardFromValueSuit(card_values[i][0], card_suits[i][0]) - card2 = Card.cardFromValueSuit(card_values[i][1], card_suits[i][1]) - cursor.execute (""" -INSERT INTO HandsPlayers -(handId, playerId, startCash, position, tourneyTypeId, - card1, card2, startCards, winnings, rake, seatNo, totalProfit, - street0VPI, street0Aggr, street0_3BChance, street0_3BDone, - street1Seen, street2Seen, street3Seen, street4Seen, sawShowdown, - street1Aggr, street2Aggr, street3Aggr, street4Aggr, - otherRaisedStreet1, otherRaisedStreet2, otherRaisedStreet3, otherRaisedStreet4, - foldToOtherRaisedStreet1, foldToOtherRaisedStreet2, foldToOtherRaisedStreet3, foldToOtherRaisedStreet4, - wonWhenSeenStreet1, wonAtSD, - stealAttemptChance, stealAttempted, foldBbToStealChance, foldedBbToSteal, foldSbToStealChance, foldedSbToSteal, - street1CBChance, street1CBDone, street2CBChance, street2CBDone, - street3CBChance, street3CBDone, street4CBChance, street4CBDone, - foldToStreet1CBChance, foldToStreet1CBDone, foldToStreet2CBChance, foldToStreet2CBDone, - foldToStreet3CBChance, foldToStreet3CBDone, foldToStreet4CBChance, foldToStreet4CBDone, - street1CheckCallRaiseChance, street1CheckCallRaiseDone, street2CheckCallRaiseChance, street2CheckCallRaiseDone, - street3CheckCallRaiseChance, street3CheckCallRaiseDone, street4CheckCallRaiseChance, street4CheckCallRaiseDone, - street0Calls, street1Calls, street2Calls, street3Calls, street4Calls, - street0Bets, street1Bets, street2Bets, street3Bets, street4Bets -) -VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, %s, %s, %s)""", - (hands_id, player_ids[i], start_cashes[i], positions[i], 1, # tourneytypeid - card1, card2, startCards, - winnings[i], rakes[i], seatNos[i], hudCache['totalProfit'][i], - hudCache['street0VPI'][i], hudCache['street0Aggr'][i], - hudCache['street0_3BChance'][i], hudCache['street0_3BDone'][i], - hudCache['street1Seen'][i], hudCache['street2Seen'][i], hudCache['street3Seen'][i], - hudCache['street4Seen'][i], hudCache['sawShowdown'][i], - hudCache['street1Aggr'][i], hudCache['street2Aggr'][i], hudCache['street3Aggr'][i], hudCache['street4Aggr'][i], - hudCache['otherRaisedStreet1'][i], hudCache['otherRaisedStreet2'][i], - hudCache['otherRaisedStreet3'][i], hudCache['otherRaisedStreet4'][i], - hudCache['foldToOtherRaisedStreet1'][i], hudCache['foldToOtherRaisedStreet2'][i], - hudCache['foldToOtherRaisedStreet3'][i], hudCache['foldToOtherRaisedStreet4'][i], - hudCache['wonWhenSeenStreet1'][i], hudCache['wonAtSD'][i], - hudCache['stealAttemptChance'][i], hudCache['stealAttempted'][i], hudCache['foldBbToStealChance'][i], - hudCache['foldedBbToSteal'][i], hudCache['foldSbToStealChance'][i], hudCache['foldedSbToSteal'][i], - hudCache['street1CBChance'][i], hudCache['street1CBDone'][i], hudCache['street2CBChance'][i], hudCache['street2CBDone'][i], - hudCache['street3CBChance'][i], hudCache['street3CBDone'][i], hudCache['street4CBChance'][i], hudCache['street4CBDone'][i], - hudCache['foldToStreet1CBChance'][i], hudCache['foldToStreet1CBDone'][i], - hudCache['foldToStreet2CBChance'][i], hudCache['foldToStreet2CBDone'][i], - hudCache['foldToStreet3CBChance'][i], hudCache['foldToStreet3CBDone'][i], - hudCache['foldToStreet4CBChance'][i], hudCache['foldToStreet4CBDone'][i], - hudCache['street1CheckCallRaiseChance'][i], hudCache['street1CheckCallRaiseDone'][i], - hudCache['street2CheckCallRaiseChance'][i], hudCache['street2CheckCallRaiseDone'][i], - hudCache['street3CheckCallRaiseChance'][i], hudCache['street3CheckCallRaiseDone'][i], - hudCache['street4CheckCallRaiseChance'][i], hudCache['street4CheckCallRaiseDone'][i], - hudCache['street0Calls'][i], hudCache['street1Calls'][i], hudCache['street2Calls'][i], hudCache['street3Calls'][i], hudCache['street4Calls'][i], - hudCache['street0Bets'][i], hudCache['street1Bets'][i], hudCache['street2Bets'][i], hudCache['street3Bets'][i], hudCache['street4Bets'][i] - ) ) - #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId=%s", (hands_id, player_ids[i])) - #result.append(cursor.fetchall()[0][0]) - result.append( getLastInsertId(backend, conn, cursor) ) - elif (category=="omahahi" or category=="omahahilo"): - for i in xrange(len(player_ids)): - startCards = Card.fourStartCards(card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1], card_values[i][2], card_suits[i][2], card_values[i][3], card_suits[i][3]) - card1 = Card.cardFromValueSuit(card_values[i][0], card_suits[i][0]) - card2 = Card.cardFromValueSuit(card_values[i][1], card_suits[i][1]) - card3 = Card.cardFromValueSuit(card_values[i][2], card_suits[i][2]) - card4 = Card.cardFromValueSuit(card_values[i][3], card_suits[i][3]) - cursor.execute ("""INSERT INTO HandsPlayers -(handId, playerId, startCash, position, tourneyTypeId, - card1, card2, card3, card4, winnings, rake, seatNo, totalProfit, - street0VPI, street0Aggr, street0_3BChance, street0_3BDone, - street1Seen, street2Seen, street3Seen, street4Seen, sawShowdown, - street1Aggr, street2Aggr, street3Aggr, street4Aggr, - otherRaisedStreet1, otherRaisedStreet2, otherRaisedStreet3, otherRaisedStreet4, - foldToOtherRaisedStreet1, foldToOtherRaisedStreet2, foldToOtherRaisedStreet3, foldToOtherRaisedStreet4, - wonWhenSeenStreet1, wonAtSD, - stealAttemptChance, stealAttempted, foldBbToStealChance, foldedBbToSteal, foldSbToStealChance, foldedSbToSteal, - street1CBChance, street1CBDone, street2CBChance, street2CBDone, - street3CBChance, street3CBDone, street4CBChance, street4CBDone, - foldToStreet1CBChance, foldToStreet1CBDone, foldToStreet2CBChance, foldToStreet2CBDone, - foldToStreet3CBChance, foldToStreet3CBDone, foldToStreet4CBChance, foldToStreet4CBDone, - street1CheckCallRaiseChance, street1CheckCallRaiseDone, street2CheckCallRaiseChance, street2CheckCallRaiseDone, - street3CheckCallRaiseChance, street3CheckCallRaiseDone, street4CheckCallRaiseChance, street4CheckCallRaiseDone, - street0Calls, street1Calls, street2Calls, street3Calls, street4Calls, - street0Bets, street1Bets, street2Bets, street3Bets, street4Bets -) -VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, %s, %s, %s)""", - (hands_id, player_ids[i], start_cashes[i], positions[i], 1, # tourneytypeid - card1, card2, card3, card4, - winnings[i], rakes[i], seatNos[i], hudCache['totalProfit'][i], - hudCache['street0VPI'][i], hudCache['street0Aggr'][i], - hudCache['street0_3BChance'][i], hudCache['street0_3BDone'][i], - hudCache['street1Seen'][i], hudCache['street2Seen'][i], hudCache['street3Seen'][i], - hudCache['street4Seen'][i], hudCache['sawShowdown'][i], - hudCache['street1Aggr'][i], hudCache['street2Aggr'][i], hudCache['street3Aggr'][i], hudCache['street4Aggr'][i], - hudCache['otherRaisedStreet1'][i], hudCache['otherRaisedStreet2'][i], - hudCache['otherRaisedStreet3'][i], hudCache['otherRaisedStreet4'][i], - hudCache['foldToOtherRaisedStreet1'][i], hudCache['foldToOtherRaisedStreet2'][i], - hudCache['foldToOtherRaisedStreet3'][i], hudCache['foldToOtherRaisedStreet4'][i], - hudCache['wonWhenSeenStreet1'][i], hudCache['wonAtSD'][i], - hudCache['stealAttemptChance'][i], hudCache['stealAttempted'][i], hudCache['foldBbToStealChance'][i], - hudCache['foldedBbToSteal'][i], hudCache['foldSbToStealChance'][i], hudCache['foldedSbToSteal'][i], - hudCache['street1CBChance'][i], hudCache['street1CBDone'][i], hudCache['street2CBChance'][i], hudCache['street2CBDone'][i], - hudCache['street3CBChance'][i], hudCache['street3CBDone'][i], hudCache['street4CBChance'][i], hudCache['street4CBDone'][i], - hudCache['foldToStreet1CBChance'][i], hudCache['foldToStreet1CBDone'][i], - hudCache['foldToStreet2CBChance'][i], hudCache['foldToStreet2CBDone'][i], - hudCache['foldToStreet3CBChance'][i], hudCache['foldToStreet3CBDone'][i], - hudCache['foldToStreet4CBChance'][i], hudCache['foldToStreet4CBDone'][i], - hudCache['street1CheckCallRaiseChance'][i], hudCache['street1CheckCallRaiseDone'][i], - hudCache['street2CheckCallRaiseChance'][i], hudCache['street2CheckCallRaiseDone'][i], - hudCache['street3CheckCallRaiseChance'][i], hudCache['street3CheckCallRaiseDone'][i], - hudCache['street4CheckCallRaiseChance'][i], hudCache['street4CheckCallRaiseDone'][i], - hudCache['street0Calls'][i], hudCache['street1Calls'][i], hudCache['street2Calls'][i], hudCache['street3Calls'][i], hudCache['street4Calls'][i], - hudCache['street0Bets'][i], hudCache['street1Bets'][i], hudCache['street2Bets'][i], hudCache['street3Bets'][i], hudCache['street4Bets'][i] - ) ) - #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i])) - #result.append(cursor.fetchall()[0][0]) - result.append( getLastInsertId(backend, conn, cursor) ) - else: - raise FpdbError("invalid category") - return result -#end def store_hands_players_holdem_omaha - -def store_hands_players_stud(backend, conn, cursor, hands_id, player_ids, start_cashes, antes, - card_values, card_suits, winnings, rakes, seatNos): -#stores hands_players rows for stud/razz games. returns an array of the resulting IDs - result=[] - #print "before inserts in store_hands_players_stud, antes:", antes - for i in xrange(len(player_ids)): - card1 = Card.cardFromValueSuit(card_values[i][0], card_suits[i][0]) - card2 = Card.cardFromValueSuit(card_values[i][1], card_suits[i][1]) - card3 = Card.cardFromValueSuit(card_values[i][2], card_suits[i][2]) - card4 = Card.cardFromValueSuit(card_values[i][3], card_suits[i][3]) - card5 = Card.cardFromValueSuit(card_values[i][4], card_suits[i][4]) - card6 = Card.cardFromValueSuit(card_values[i][5], card_suits[i][5]) - card7 = Card.cardFromValueSuit(card_values[i][6], card_suits[i][6]) - - cursor.execute ("""INSERT INTO HandsPlayers -(handId, playerId, startCash, ante, tourneyTypeId, -card1, card2, -card3, card4, -card5, card6, -card7, winnings, rake, seatNo) -VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", - (hands_id, player_ids[i], start_cashes[i], antes[i], 1, - card1, card2, - card3, card4, - card5, card6, - card7, winnings[i], rakes[i], seatNos[i])) - #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i])) - #result.append(cursor.fetchall()[0][0]) - result.append( getLastInsertId(backend, conn, cursor) ) - return result -#end def store_hands_players_stud - -def store_hands_players_holdem_omaha_tourney(backend, conn, cursor, category, hands_id, player_ids - ,start_cashes, positions, card_values, card_suits - , winnings, rakes, seatNos, tourneys_players_ids): - #stores hands_players for tourney holdem/omaha hands - result=[] - for i in xrange(len(player_ids)): - if len(card_values[0])==2: - cursor.execute ("""INSERT INTO HandsPlayers -(handId, playerId, startCash, position, -card1Value, card1Suit, card2Value, card2Suit, -winnings, rake, tourneysPlayersId, seatNo) -VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", - (hands_id, player_ids[i], start_cashes[i], positions[i], - card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1], - winnings[i], rakes[i], tourneys_players_ids[i], seatNos[i])) - elif len(card_values[0])==4: - cursor.execute ("""INSERT INTO HandsPlayers -(handId, playerId, startCash, position, -card1Value, card1Suit, card2Value, card2Suit, -card3Value, card3Suit, card4Value, card4Suit, -winnings, rake, tourneysPlayersId, seatNo) -VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", - (hands_id, player_ids[i], start_cashes[i], positions[i], - card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1], - card_values[i][2], card_suits[i][2], card_values[i][3], card_suits[i][3], - winnings[i], rakes[i], tourneys_players_ids[i], seatNos[i])) - else: - raise FpdbError ("invalid card_values length:"+str(len(card_values[0]))) - #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i])) - #result.append(cursor.fetchall()[0][0]) - result.append( getLastInsertId(backend, conn, cursor) ) - - return result -#end def store_hands_players_holdem_omaha_tourney - -def store_hands_players_stud_tourney(backend, conn, cursor, hands_id, player_ids, start_cashes, - antes, card_values, card_suits, winnings, rakes, seatNos, tourneys_players_ids): -#stores hands_players for tourney stud/razz hands - result=[] - for i in xrange(len(player_ids)): - cursor.execute ("""INSERT INTO HandsPlayers -(handId, playerId, startCash, ante, -card1Value, card1Suit, card2Value, card2Suit, -card3Value, card3Suit, card4Value, card4Suit, -card5Value, card5Suit, card6Value, card6Suit, -card7Value, card7Suit, winnings, rake, tourneysPlayersId, seatNo) -VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, -%s, %s, %s, %s, %s, %s)""", - (hands_id, player_ids[i], start_cashes[i], antes[i], - card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1], - card_values[i][2], card_suits[i][2], card_values[i][3], card_suits[i][3], - card_values[i][4], card_suits[i][4], card_values[i][5], card_suits[i][5], - card_values[i][6], card_suits[i][6], winnings[i], rakes[i], tourneys_players_ids[i], seatNos[i])) - #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i])) - #result.append(cursor.fetchall()[0][0]) - result.append( getLastInsertId(backend, conn, cursor) ) - return result -#end def store_hands_players_stud_tourney - def generateHudCacheData(player_ids, base, category, action_types, allIns, actionTypeByNo ,winnings, totalWinnings, positions, actionTypes, actionAmounts, antes): """calculates data for the HUD during import. IMPORTANT: if you change this method make @@ -2105,230 +1826,3 @@ def generateFoldToCB(street, playerIDs, didStreetCB, streetCBDone, foldToStreetC if action[1]=="fold": foldToStreetCBDone[player]=True #end def generateFoldToCB - -def storeHudCache(backend, cursor, base, category, gametypeId, hand_start_time, playerIds, hudImportData): - """Modified version aiming for more speed ...""" -# if (category=="holdem" or category=="omahahi" or category=="omahahilo"): - if use_date_in_hudcache: - #print "key =", "d%02d%02d%02d " % (hand_start_time.year-2000, hand_start_time.month, hand_start_time.day) - styleKey = "d%02d%02d%02d" % (hand_start_time.year-2000, hand_start_time.month, hand_start_time.day) - else: - # hard-code styleKey as 'A000000' (all-time cache, no key) for now - styleKey = 'A000000' - - #print "storeHudCache2, len(playerIds)=", len(playerIds), " len(vpip)=" \ - #, len(hudImportData['street0VPI']), " len(totprof)=", len(hudImportData['totalProfit']) - for player in xrange(len(playerIds)): - - # Set up a clean row - row=[] - row.append(0)#blank for id - row.append(gametypeId) - row.append(playerIds[player]) - row.append(len(playerIds))#seats - for i in xrange(len(hudImportData)+2): - row.append(0) - - if base=="hold": - row[4]=hudImportData['position'][player] - else: - row[4]=0 - row[5]=1 #tourneysGametypeId - row[6]+=1 #HDs - if hudImportData['street0VPI'][player]: row[7]+=1 - if hudImportData['street0Aggr'][player]: row[8]+=1 - if hudImportData['street0_3BChance'][player]: row[9]+=1 - if hudImportData['street0_3BDone'][player]: row[10]+=1 - if hudImportData['street1Seen'][player]: row[11]+=1 - if hudImportData['street2Seen'][player]: row[12]+=1 - if hudImportData['street3Seen'][player]: row[13]+=1 - if hudImportData['street4Seen'][player]: row[14]+=1 - if hudImportData['sawShowdown'][player]: row[15]+=1 - if hudImportData['street1Aggr'][player]: row[16]+=1 - if hudImportData['street2Aggr'][player]: row[17]+=1 - if hudImportData['street3Aggr'][player]: row[18]+=1 - if hudImportData['street4Aggr'][player]: row[19]+=1 - if hudImportData['otherRaisedStreet1'][player]: row[20]+=1 - if hudImportData['otherRaisedStreet2'][player]: row[21]+=1 - if hudImportData['otherRaisedStreet3'][player]: row[22]+=1 - if hudImportData['otherRaisedStreet4'][player]: row[23]+=1 - if hudImportData['foldToOtherRaisedStreet1'][player]: row[24]+=1 - if hudImportData['foldToOtherRaisedStreet2'][player]: row[25]+=1 - if hudImportData['foldToOtherRaisedStreet3'][player]: row[26]+=1 - if hudImportData['foldToOtherRaisedStreet4'][player]: row[27]+=1 - if hudImportData['wonWhenSeenStreet1'][player]!=0.0: row[28]+=hudImportData['wonWhenSeenStreet1'][player] - if hudImportData['wonAtSD'][player]!=0.0: row[29]+=hudImportData['wonAtSD'][player] - if hudImportData['stealAttemptChance'][player]: row[30]+=1 - if hudImportData['stealAttempted'][player]: row[31]+=1 - if hudImportData['foldBbToStealChance'][player]: row[32]+=1 - if hudImportData['foldedBbToSteal'][player]: row[33]+=1 - if hudImportData['foldSbToStealChance'][player]: row[34]+=1 - if hudImportData['foldedSbToSteal'][player]: row[35]+=1 - - if hudImportData['street1CBChance'][player]: row[36]+=1 - if hudImportData['street1CBDone'][player]: row[37]+=1 - if hudImportData['street2CBChance'][player]: row[38]+=1 - if hudImportData['street2CBDone'][player]: row[39]+=1 - if hudImportData['street3CBChance'][player]: row[40]+=1 - if hudImportData['street3CBDone'][player]: row[41]+=1 - if hudImportData['street4CBChance'][player]: row[42]+=1 - if hudImportData['street4CBDone'][player]: row[43]+=1 - - if hudImportData['foldToStreet1CBChance'][player]: row[44]+=1 - if hudImportData['foldToStreet1CBDone'][player]: row[45]+=1 - if hudImportData['foldToStreet2CBChance'][player]: row[46]+=1 - if hudImportData['foldToStreet2CBDone'][player]: row[47]+=1 - if hudImportData['foldToStreet3CBChance'][player]: row[48]+=1 - if hudImportData['foldToStreet3CBDone'][player]: row[49]+=1 - if hudImportData['foldToStreet4CBChance'][player]: row[50]+=1 - if hudImportData['foldToStreet4CBDone'][player]: row[51]+=1 - - #print "player=", player - #print "len(totalProfit)=", len(hudImportData['totalProfit']) - if hudImportData['totalProfit'][player]: - row[52]+=hudImportData['totalProfit'][player] - - if hudImportData['street1CheckCallRaiseChance'][player]: row[53]+=1 - if hudImportData['street1CheckCallRaiseDone'][player]: row[54]+=1 - if hudImportData['street2CheckCallRaiseChance'][player]: row[55]+=1 - if hudImportData['street2CheckCallRaiseDone'][player]: row[56]+=1 - if hudImportData['street3CheckCallRaiseChance'][player]: row[57]+=1 - if hudImportData['street3CheckCallRaiseDone'][player]: row[58]+=1 - if hudImportData['street4CheckCallRaiseChance'][player]: row[59]+=1 - if hudImportData['street4CheckCallRaiseDone'][player]: row[60]+=1 - - # Try to do the update first: - num = cursor.execute("""UPDATE HudCache -SET HDs=HDs+%s, street0VPI=street0VPI+%s, street0Aggr=street0Aggr+%s, - street0_3BChance=street0_3BChance+%s, street0_3BDone=street0_3BDone+%s, - street1Seen=street1Seen+%s, street2Seen=street2Seen+%s, street3Seen=street3Seen+%s, - street4Seen=street4Seen+%s, sawShowdown=sawShowdown+%s, - street1Aggr=street1Aggr+%s, street2Aggr=street2Aggr+%s, street3Aggr=street3Aggr+%s, - street4Aggr=street4Aggr+%s, otherRaisedStreet1=otherRaisedStreet1+%s, - otherRaisedStreet2=otherRaisedStreet2+%s, otherRaisedStreet3=otherRaisedStreet3+%s, - otherRaisedStreet4=otherRaisedStreet4+%s, - foldToOtherRaisedStreet1=foldToOtherRaisedStreet1+%s, foldToOtherRaisedStreet2=foldToOtherRaisedStreet2+%s, - foldToOtherRaisedStreet3=foldToOtherRaisedStreet3+%s, foldToOtherRaisedStreet4=foldToOtherRaisedStreet4+%s, - wonWhenSeenStreet1=wonWhenSeenStreet1+%s, wonAtSD=wonAtSD+%s, stealAttemptChance=stealAttemptChance+%s, - stealAttempted=stealAttempted+%s, foldBbToStealChance=foldBbToStealChance+%s, - foldedBbToSteal=foldedBbToSteal+%s, - foldSbToStealChance=foldSbToStealChance+%s, foldedSbToSteal=foldedSbToSteal+%s, - street1CBChance=street1CBChance+%s, street1CBDone=street1CBDone+%s, street2CBChance=street2CBChance+%s, - street2CBDone=street2CBDone+%s, street3CBChance=street3CBChance+%s, - street3CBDone=street3CBDone+%s, street4CBChance=street4CBChance+%s, street4CBDone=street4CBDone+%s, - foldToStreet1CBChance=foldToStreet1CBChance+%s, foldToStreet1CBDone=foldToStreet1CBDone+%s, - foldToStreet2CBChance=foldToStreet2CBChance+%s, foldToStreet2CBDone=foldToStreet2CBDone+%s, - foldToStreet3CBChance=foldToStreet3CBChance+%s, - foldToStreet3CBDone=foldToStreet3CBDone+%s, foldToStreet4CBChance=foldToStreet4CBChance+%s, - foldToStreet4CBDone=foldToStreet4CBDone+%s, totalProfit=totalProfit+%s, - street1CheckCallRaiseChance=street1CheckCallRaiseChance+%s, - street1CheckCallRaiseDone=street1CheckCallRaiseDone+%s, street2CheckCallRaiseChance=street2CheckCallRaiseChance+%s, - street2CheckCallRaiseDone=street2CheckCallRaiseDone+%s, street3CheckCallRaiseChance=street3CheckCallRaiseChance+%s, - street3CheckCallRaiseDone=street3CheckCallRaiseDone+%s, street4CheckCallRaiseChance=street4CheckCallRaiseChance+%s, - street4CheckCallRaiseDone=street4CheckCallRaiseDone+%s -WHERE gametypeId+0=%s -AND playerId=%s -AND activeSeats=%s -AND position=%s -AND tourneyTypeId+0=%s -AND styleKey=%s - """, (row[6], row[7], row[8], row[9], row[10], - row[11], row[12], row[13], row[14], row[15], - row[16], row[17], row[18], row[19], row[20], - row[21], row[22], row[23], row[24], row[25], - row[26], row[27], row[28], row[29], row[30], - row[31], row[32], row[33], row[34], row[35], - row[36], row[37], row[38], row[39], row[40], - row[41], row[42], row[43], row[44], row[45], - row[46], row[47], row[48], row[49], row[50], - row[51], row[52], row[53], row[54], row[55], - row[56], row[57], row[58], row[59], row[60], - row[1], row[2], row[3], str(row[4]), row[5], styleKey)) - # Test statusmessage to see if update worked, do insert if not - #print "storehud2, upd num =", num - if ( (backend == PGSQL and cursor.statusmessage != "UPDATE 1") - or (backend == MYSQL_INNODB and num == 0) ): - #print "playerid before insert:",row[2]," num = ", num - cursor.execute("""INSERT INTO HudCache -(gametypeId, playerId, activeSeats, position, tourneyTypeId, styleKey, -HDs, street0VPI, street0Aggr, street0_3BChance, street0_3BDone, -street1Seen, street2Seen, street3Seen, street4Seen, sawShowdown, -street1Aggr, street2Aggr, street3Aggr, street4Aggr, otherRaisedStreet1, -otherRaisedStreet2, otherRaisedStreet3, otherRaisedStreet4, foldToOtherRaisedStreet1, foldToOtherRaisedStreet2, -foldToOtherRaisedStreet3, foldToOtherRaisedStreet4, wonWhenSeenStreet1, wonAtSD, stealAttemptChance, -stealAttempted, foldBbToStealChance, foldedBbToSteal, foldSbToStealChance, foldedSbToSteal, -street1CBChance, street1CBDone, street2CBChance, street2CBDone, street3CBChance, -street3CBDone, street4CBChance, street4CBDone, foldToStreet1CBChance, foldToStreet1CBDone, -foldToStreet2CBChance, foldToStreet2CBDone, foldToStreet3CBChance, foldToStreet3CBDone, foldToStreet4CBChance, -foldToStreet4CBDone, totalProfit, street1CheckCallRaiseChance, street1CheckCallRaiseDone, street2CheckCallRaiseChance, -street2CheckCallRaiseDone, street3CheckCallRaiseChance, street3CheckCallRaiseDone, street4CheckCallRaiseChance, street4CheckCallRaiseDone) -VALUES (%s, %s, %s, %s, %s, %s, -%s, %s, %s, %s, %s, -%s, %s, %s, %s, %s, -%s, %s, %s, %s, %s, -%s, %s, %s, %s, %s, -%s, %s, %s, %s, %s, -%s, %s, %s, %s, %s, -%s, %s, %s, %s, %s, -%s, %s, %s, %s, %s, -%s, %s, %s, %s, %s, -%s, %s, %s, %s, %s, -%s, %s, %s, %s, %s)""" - , (row[1], row[2], row[3], row[4], row[5], styleKey, row[6], row[7], row[8], row[9], row[10] - ,row[11], row[12], row[13], row[14], row[15], row[16], row[17], row[18], row[19], row[20] - ,row[21], row[22], row[23], row[24], row[25], row[26], row[27], row[28], row[29], row[30] - ,row[31], row[32], row[33], row[34], row[35], row[36], row[37], row[38], row[39], row[40] - ,row[41], row[42], row[43], row[44], row[45], row[46], row[47], row[48], row[49], row[50] - ,row[51], row[52], row[53], row[54], row[55], row[56], row[57], row[58], row[59], row[60]) ) - #print "hopefully inserted hud data line: ", cursor.statusmessage - # message seems to be "INSERT 0 1" - else: - #print "updated(2) hud data line" - pass -# else: -# print "todo: implement storeHudCache for stud base" -#end def storeHudCache2 - -def store_tourneys(cursor, tourneyTypeId, siteTourneyNo, entries, prizepool, startTime): - cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s", (siteTourneyNo, tourneyTypeId)) - tmp=cursor.fetchone() - #print "tried SELECTing tourneys.id, result:",tmp - - try: - len(tmp) - except TypeError:#means we have to create new one - cursor.execute("""INSERT INTO Tourneys -(tourneyTypeId, siteTourneyNo, entries, prizepool, startTime) -VALUES (%s, %s, %s, %s, %s)""", (tourneyTypeId, siteTourneyNo, entries, prizepool, startTime)) - cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s", (siteTourneyNo, tourneyTypeId)) - tmp=cursor.fetchone() - #print "created new tourneys.id:",tmp - return tmp[0] -#end def store_tourneys - -def store_tourneys_players(cursor, tourney_id, player_ids, payin_amounts, ranks, winnings): - result=[] - #print "in store_tourneys_players. tourney_id:",tourney_id - #print "player_ids:",player_ids - #print "payin_amounts:",payin_amounts - #print "ranks:",ranks - #print "winnings:",winnings - for i in xrange(len(player_ids)): - cursor.execute("SELECT id FROM TourneysPlayers WHERE tourneyId=%s AND playerId+0=%s", (tourney_id, player_ids[i])) - tmp=cursor.fetchone() - #print "tried SELECTing tourneys_players.id:",tmp - - try: - len(tmp) - except TypeError: - cursor.execute("""INSERT INTO TourneysPlayers -(tourneyId, playerId, payinAmount, rank, winnings) VALUES (%s, %s, %s, %s, %s)""", - (tourney_id, player_ids[i], payin_amounts[i], ranks[i], winnings[i])) - - cursor.execute("SELECT id FROM TourneysPlayers WHERE tourneyId=%s AND playerId+0=%s", - (tourney_id, player_ids[i])) - tmp=cursor.fetchone() - #print "created new tourneys_players.id:",tmp - result.append(tmp[0]) - return result -#end def store_tourneys_players diff --git a/pyfpdb/interlocks.py b/pyfpdb/interlocks.py new file mode 100755 index 00000000..96edaa3e --- /dev/null +++ b/pyfpdb/interlocks.py @@ -0,0 +1,271 @@ + +# Code from http://ender.snowburst.org:4747/~jjohns/interlocks.py +# Thanks JJ! + +import sys +import os, os.path +import subprocess +import time +import signal +import base64 + +InterProcessLock = None + +""" +Just use me like a thread lock. acquire() / release() / locked() + +Differences compared to thread locks: +1. By default, acquire()'s wait parameter is false. +2. When acquire fails, SingleInstanceError is thrown instead of simply returning false. +3. acquire() can take a 3rd parameter retry_time, which, if wait is True, tells the locking + mechanism how long to sleep between retrying the lock. Has no effect for unix/InterProcessLockFcntl. + +Differences in fpdb version to JJ's original: +1. Changed acquire() to return false like other locks +2. Made acquire fail if same process already has the lock +""" + +class SingleInstanceError(RuntimeError): + "Thrown when you try to acquire an InterProcessLock and another version of the process is already running." + +class InterProcessLockBase: + def __init__(self, name=None ): + self._has_lock = False + if not name: + name = sys.argv[0] + self.name = name + + def getHashedName(self): + return base64.b64encode(self.name).replace('=','') + + def acquire_impl(self, wait): abstract + + def acquire(self, wait=False, retry_time=1): + if self._has_lock: # make sure 2nd acquire in same process fails + return False + while not self._has_lock: + try: + self.acquire_impl(wait) + self._has_lock = True + #print 'i have the lock' + except SingleInstanceError: + if not wait: + # raise # change back to normal acquire functionality, sorry JJ! + return False + time.sleep(retry_time) + return True + + def release(self): + self.release_impl() + self._has_lock = False + + def locked(self): + if self._has_lock: + return True + try: + self.acquire() + self.release() + return False + except SingleInstanceError: + return True + +LOCK_FILE_DIRECTORY = '/tmp' + +class InterProcessLockFcntl(InterProcessLockBase): + def __init__(self, name=None): + InterProcessLockBase.__init__(self, name) + self.lockfd = 0 + self.lock_file_name = os.path.join(LOCK_FILE_DIRECTORY, self.getHashedName() + '.lck') + assert(os.path.isdir(LOCK_FILE_DIRECTORY)) + + # This is the suggested way to get a safe file name, but I like having a descriptively named lock file. + def getHashedName(self): + import re + bad_filename_character_re = re.compile(r'/\?<>\\\:;\*\|\'\"\^=\.\[\]') + return bad_filename_character_re.sub('_',self.name) + + def acquire_impl(self, wait): + self.lockfd = open(self.lock_file_name, 'w') + fcntrl_options = fcntl.LOCK_EX + if not wait: + fcntrl_options |= fcntl.LOCK_NB + try: + fcntl.flock(self.lockfd, fcntrl_options) + except IOError: + self.lockfd.close() + self.lockfd = 0 + raise SingleInstanceError('Could not acquire exclusive lock on '+self.lock_file_name) + + def release_impl(self): + fcntl.lockf(self.lockfd, fcntl.LOCK_UN) + self.lockfd.close() + self.lockfd = 0 + try: + os.unlink(self.lock_file_name) + except IOError: + # We don't care about the existence of the file too much here. It's the flock() we care about, + # And that should just go away magically. + pass + +class InterProcessLockWin32(InterProcessLockBase): + def __init__(self, name=None): + InterProcessLockBase.__init__(self, name) + self.mutex = None + + def acquire_impl(self,wait): + self.mutex = win32event.CreateMutex(None, 0, self.getHashedName()) + if win32api.GetLastError() == winerror.ERROR_ALREADY_EXISTS: + self.mutex.Close() + self.mutex = None + raise SingleInstanceError('Could not acquire exclusive lock on ' + self.name) + + def release_impl(self): + self.mutex.Close() + +class InterProcessLockSocket(InterProcessLockBase): + def __init__(self, name=None): + InterProcessLockBase.__init__(self, name) + self.socket = None + self.portno = 65530 - abs(self.getHashedName().__hash__()) % 32749 + + def acquire_impl(self, wait): + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + self.socket.bind(('127.0.0.1', self.portno)) + except socket.error: + self.socket.close() + self.socket = None + raise SingleInstanceError('Could not acquire exclusive lock on ' + self.name) + + def release_impl(self): + self.socket.close() + self.socket = None + +# Set InterProcessLock to the correct type given the sysem parameters available +try: + import fcntl + InterProcessLock = InterProcessLockFcntl +except ImportError: + try: + import win32event + import win32api + import winerror + InterProcessLock = InterProcessLockWin32 + except ImportError: + import socket + InterProcessLock = InterProcessLockSocket + +def test_construct(): + """ + # Making the name of the test unique so it can be executed my multiple users on the same machine. + >>> test_name = 'InterProcessLockTest' +str(os.getpid()) + str(time.time()) + + >>> lock1 = InterProcessLock(name=test_name) + >>> lock1.acquire() + + >>> lock2 = InterProcessLock(name=test_name) + >>> lock3 = InterProcessLock(name=test_name) + + # Since lock1 is locked, other attempts to acquire it fail. + >>> lock2.acquire() + Traceback (most recent call last): + ... + SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck + + >>> lock3.acquire() + Traceback (most recent call last): + ... + SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck + + # Release the lock and let lock2 have it. + >>> lock1.release() + >>> lock2.acquire() + + >>> lock3.acquire() + Traceback (most recent call last): + ... + SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck + + # Release it and give it back to lock1 + >>> lock2.release() + >>> lock1.acquire() + + >>> lock2.acquire() + Traceback (most recent call last): + ... + SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck + + # Test lock status + >>> lock2.locked() + True + >>> lock3.locked() + True + >>> lock1.locked() + True + + >>> lock1.release() + + >>> lock2.locked() + False + >>> lock3.locked() + False + >>> lock1.locked() + False + + >>> if os.name == 'posix': + ... def os_independent_kill(pid): + ... import signal + ... os.kill(pid, signal.SIGKILL) + ... else: + ... assert(os.name == 'nt') + ... def os_independent_kill(pid): + ... ''' http://www.python.org/doc/faq/windows/#how-do-i-emulate-os-kill-in-windows ''' + ... import win32api + ... import win32con + ... import pywintypes + ... handle = win32api.OpenProcess(win32con.PROCESS_TERMINATE , pywintypes.FALSE, pid) + ... return (0 != win32api.TerminateProcess(handle, 0)) + + # Test to acquire the lock in another process. + >>> def execute(cmd): + ... cmd = 'import time;' + cmd + 'time.sleep(10);' + ... process = subprocess.Popen([sys.executable, '-c', cmd]) + ... pid = process.pid + ... time.sleep(2) # quick hack, but we test synchronization in the end + ... return pid + + >>> pid = execute('import interlocks;a=interlocks.InterProcessLock(name=\\''+test_name+ '\\');a.acquire();') + + >>> lock1.acquire() + Traceback (most recent call last): + ... + SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck + + >>> os_independent_kill(pid) + + >>> time.sleep(1) + + >>> lock1.acquire() + >>> lock1.release() + + # Testing wait + + >>> pid = execute('import interlocks;a=interlocks.InterProcessLock(name=\\''+test_name+ '\\');a.acquire();') + + >>> lock1.acquire() + Traceback (most recent call last): + ... + SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck + + >>> os_independent_kill(pid) + + >>> lock1.acquire(True) + >>> lock1.release() + + """ + + pass + +if __name__=='__main__': + import doctest + doctest.testmod(optionflags=doctest.IGNORE_EXCEPTION_DETAIL)