Merge branch 'master' of git://trac-git.assembla.com/fpdb-sql

Conflicts:
	pyfpdb/Database.py

Resolve by reverting to sqlcoder's version; it uses the nice insert in
fillDefaultData for each case now and having the DB backends separate
might be good for the foreseeable future.
This commit is contained in:
Mika Bostrom 2009-09-28 18:07:08 +03:00
commit 5260f5c384
12 changed files with 617 additions and 257 deletions

View File

@ -26,17 +26,17 @@ def twoStartCards(value1, suit1, value2, suit2):
if value1 < 2 or value2 < 2:
ret = 0
if value1 == value2: # pairs
ret = (13 * (value2-2) + (value2-1) )
ret = (13 * (value2-2) + (value2-2) )
elif suit1 == suit2:
if value1 > value2:
ret = 13 * (value1-2) + (value2-1)
ret = 13 * (value1-2) + (value2-2)
else:
ret = 13 * (value2-2) + (value1-1)
ret = 13 * (value2-2) + (value1-2)
else:
if value1 > value2:
ret = 13 * (value2-2) + (value2-1)
ret = 13 * (value2-2) + (value1-2)
else:
ret = 13 * (value1-2) + (value2-1)
ret = 13 * (value1-2) + (value2-2)
# print "twoStartCards(", value1, suit1, value2, suit2, ")=", ret
return ret
@ -46,7 +46,6 @@ def twoStartCardString(card):
into a string like AQo """
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

View File

@ -49,12 +49,15 @@ import logging, logging.config
logging.config.fileConfig(os.path.join(sys.path[0],"logging.conf"))
log = logging.getLogger('db')
class Database:
MYSQL_INNODB = 2
PGSQL = 3
SQLITE = 4
hero_hudstart_def = '1999-12-31' # default for length of Hero's stats in HUD
# 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
@ -70,19 +73,19 @@ class Database:
[ ] # 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':'Players', 'col':'name', 'drop':0} unique indexes not dropped
# {'tab':'Hands', 'col':'siteHandNo', 'drop':0} unique indexes not dropped
{'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':'tourneyTypeId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'tourneysPlayersId', 'drop':0}
, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0}
#, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} unique indexes not dropped
]
, [ # 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':'Hands', 'col':'siteHandNo', 'drop':0} unique indexes not dropped
, {'tab':'HandsActions', 'col':'handsPlayerId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'handId', 'drop':1}
, {'tab':'HandsPlayers', 'col':'playerId', 'drop':1}
@ -91,22 +94,22 @@ class Database:
, {'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':'Players', 'col':'name', 'drop':0} unique indexes not dropped
, {'tab':'Tourneys', 'col':'tourneyTypeId', 'drop':1}
, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0}
#, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} unique indexes not dropped
, {'tab':'TourneysPlayers', 'col':'playerId', 'drop':0}
, {'tab':'TourneysPlayers', 'col':'tourneyId', 'drop':0}
#, {'tab':'TourneysPlayers', 'col':'tourneyId', 'drop':0} unique indexes not dropped
, {'tab':'TourneyTypes', 'col':'siteId', 'drop':0}
]
, [ # indexes for sqlite (list index 4)
{'tab':'Players', 'col':'name', 'drop':0}
, {'tab':'Hands', 'col':'siteHandNo', 'drop':0}
, {'tab':'Hands', 'col':'gametypeId', 'drop':0}
# {'tab':'Players', 'col':'name', 'drop':0} unique indexes not dropped
# {'tab':'Hands', 'col':'siteHandNo', 'drop':0} unique indexes not dropped
{'tab':'Hands', 'col':'gametypeId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'handId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'playerId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'tourneyTypeId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'tourneysPlayersId', 'drop':0}
, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0}
#, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} unique indexes not dropped
]
]
@ -183,6 +186,7 @@ class Database:
def __init__(self, c, sql = None):
log.info("Creating Database instance, sql = %s" % sql)
self.config = c
self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql
self.fdb.do_connect(c)
self.connection = self.fdb.db
@ -368,7 +372,10 @@ class Database:
return winners
def init_hud_stat_vars(self, hud_days):
"""Initialise variables used by Hud to fetch stats."""
"""Initialise variables used by Hud to fetch stats:
self.hand_1day_ago handId of latest hand played more than a day ago
self.date_ndays_ago date n days ago
"""
self.hand_1day_ago = 1
try:
@ -381,6 +388,7 @@ class Database:
else:
if row and row[0]:
self.hand_1_day_ago = row[0]
d = timedelta(days=hud_days)
now = datetime.utcnow() - d
self.date_ndays_ago = "d%02d%02d%02d" % (now.year - 2000, now.month, now.day)
@ -403,10 +411,19 @@ class Database:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
def get_stats_from_hand(self, hand, aggregate = False, hud_style = 'A', agg_bb_mult = 100):
def get_stats_from_hand( self, hand
, hud_params = {'aggregate_tour':False, 'aggregate_ring':False, 'hud_style':'A', 'agg_bb_mult':100}
, hero_ids = {}
):
aggregate = hud_params['aggregate_tour'] if type == "tour" else hud_params['aggregate_ring']
hud_style = hud_params['hud_style']
agg_bb_mult = hud_params['agg_bb_mult']
stat_dict = {}
if hud_style == 'S':
return( self.get_stats_from_hand_session(hand) )
self.get_stats_from_hand_session(hand, stat_dict)
return stat_dict
else: # hud_style == A
@ -430,7 +447,6 @@ class Database:
# now get the stats
c.execute(self.sql.query[query], subs)
colnames = [desc[0] for desc in c.description]
stat_dict = {}
for row in c.fetchall():
t_dict = {}
for name, val in zip(colnames, row):
@ -441,7 +457,7 @@ class Database:
return stat_dict
# uses query on handsplayers instead of hudcache to get stats on just this session
def get_stats_from_hand_session(self, hand):
def get_stats_from_hand_session(self, hand, stat_dict):
query = self.sql.query['get_stats_from_hand_session']
if self.db_server == 'mysql':
@ -456,15 +472,13 @@ class Database:
#print "sess_stats: subs =", subs, "subs[0] =", subs[0]
c.execute(query, subs)
colnames = [desc[0] for desc in c.description]
n,stat_dict = 0,{}
n = 0
row = c.fetchone()
while row:
if colnames[0].lower() == 'player_id':
playerid = row[0]
else:
log.error("ERROR: query %s result does not have player_id as first column" % (query,))
break
while row:
for name, val in zip(colnames, row):
if not playerid in stat_dict:
stat_dict[playerid] = {}
@ -474,13 +488,16 @@ class Database:
elif name.lower() not in ('hand_id', 'player_id', 'seat', 'screen_name', 'seats'):
stat_dict[playerid][name.lower()] += val
n += 1
if n >= 4000: break # todo: don't think this is needed so set nice and high
if n >= 10000: break # todo: don't think this is needed so set nice and high
# for now - comment out or remove?
row = c.fetchone()
else:
log.error("ERROR: query %s result does not have player_id as first column" % (query,))
#print " %d rows fetched, len(stat_dict) = %d" % (n, len(stat_dict))
#print "session stat_dict =", stat_dict
return stat_dict
#return stat_dict
def get_player_id(self, config, site, player_name):
c = self.connection.cursor()
@ -491,6 +508,69 @@ class Database:
else:
return None
#returns the SQL ids of the names given in an array
# TODO: if someone gets industrious, they should make the parts that use the output of this function deal with a dict
# { playername: id } instead of depending on it's relation to the positions list
# then this can be reduced in complexity a bit
#def recognisePlayerIDs(cursor, names, site_id):
# result = []
# for i in xrange(len(names)):
# cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],))
# tmp=cursor.fetchall()
# if (len(tmp)==0): #new player
# cursor.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)", (names[i], site_id))
# #print "Number of players rows inserted: %d" % cursor.rowcount
# cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],))
# tmp=cursor.fetchall()
# #print "recognisePlayerIDs, names[i]:",names[i],"tmp:",tmp
# result.append(tmp[0][0])
# return result
def recognisePlayerIDs(self, names, site_id):
c = self.get_cursor()
q = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" %(site_id, " OR name=".join([self.sql.query['placeholder'] for n in names]))
c.execute(q, names) # get all playerids by the names passed in
ids = dict(c.fetchall()) # convert to dict
if len(ids) != len(names):
notfound = [n for n in names if n not in ids] # make list of names not in database
if notfound: # insert them into database
q_ins = "INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")"
q_ins = q_ins.replace('%s', self.sql.query['placeholder'])
c.executemany(q_ins, [(n,) for n in notfound])
q2 = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" % (site_id, " OR name=".join(["%s" for n in notfound]))
q2 = q2.replace('%s', self.sql.query['placeholder'])
c.execute(q2, notfound) # get their new ids
tmp = c.fetchall()
for n,id in tmp: # put them all into the same dict
ids[n] = id
# return them in the SAME ORDER that they came in in the names argument, rather than the order they came out of the DB
return [ids[n] for n in names]
#end def recognisePlayerIDs
# Here's a version that would work if it wasn't for the fact that it needs to have the output in the same order as input
# this version could also be improved upon using list comprehensions, etc
#def recognisePlayerIDs(cursor, names, site_id):
# result = []
# notfound = []
# cursor.execute("SELECT name,id FROM Players WHERE name='%s'" % "' OR name='".join(names))
# tmp = dict(cursor.fetchall())
# for n in names:
# if n not in tmp:
# notfound.append(n)
# else:
# result.append(tmp[n])
# if notfound:
# cursor.executemany("INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")", (notfound))
# cursor.execute("SELECT id FROM Players WHERE name='%s'" % "' OR name='".join(notfound))
# tmp = cursor.fetchall()
# for n in tmp:
# result.append(n[0])
#
# return result
def get_site_id(self, site):
c = self.get_cursor()
c.execute(self.sql.query['getSiteId'], (site,))
@ -855,6 +935,7 @@ class Database:
log.debug(self.sql.query['createSettingsTable'])
c = self.get_cursor()
c.execute(self.sql.query['createSettingsTable'])
log.debug(self.sql.query['createSitesTable'])
c.execute(self.sql.query['createSitesTable'])
c.execute(self.sql.query['createGametypesTable'])
@ -867,9 +948,14 @@ class Database:
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'])
# create unique indexes:
c.execute(self.sql.query['addTourneyIndex'])
c.execute(self.sql.query['addHandsIndex'])
c.execute(self.sql.query['addPlayersIndex'])
c.execute(self.sql.query['addTPlayersIndex'])
c.execute(self.sql.query['addTTypesIndex'])
self.fillDefaultData()
self.commit()
except:
@ -1011,20 +1097,48 @@ class Database:
c.execute("INSERT INTO Sites (name,currency) VALUES ('PartyPoker', 'USD')")
if self.backend == self.SQLITE:
c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);")
else:
elif self.backend == self.PGSQL:
c.execute("""insert into TourneyTypes(siteId, buyin, fee, maxSeats, knockout
,rebuyOrAddon, speed, headsUp, shootout, matrix)
values (1, 0, 0, 0, False, False, null, False, False, False);""")
elif self.backend == self.MYSQL_INNODB:
c.execute("""insert into TourneyTypes(id, siteId, buyin, fee, maxSeats, knockout
,rebuyOrAddon, speed, headsUp, shootout, matrix)
values (1, 0, 0, 0, False, False, null, False, False, False);""")
#end def fillDefaultData
def rebuild_hudcache(self):
def rebuild_hudcache(self, start=None):
"""clears hudcache and rebuilds from the individual handsplayers records"""
try:
stime = time()
# derive list of program owner's player ids
self.hero = {} # name of program owner indexed by site id
self.hero_ids = {'dummy':-53, 'dummy2':-52} # playerid of owner indexed by site id
# make sure at least two values in list
# so that tuple generation creates doesn't use
# () or (1,) style
for site in self.config.get_supported_sites():
result = self.get_site_id(site)
if result:
site_id = result[0][0]
self.hero[site_id] = self.config.supported_sites[site].screen_name
p_id = self.get_player_id(self.config, site, self.hero[site_id])
if p_id:
self.hero_ids[site_id] = int(p_id)
if start == None:
start = self.hero_hudstart_def
if self.hero_ids == {}:
where = ""
else:
where = "where hp.playerId not in " + str(tuple(self.hero_ids.values())) \
+ " or h.handStart > '" + start + "'"
rebuild_sql = self.sql.query['rebuildHudCache'].replace('<where_clause>', where)
self.get_cursor().execute(self.sql.query['clearHudCache'])
self.get_cursor().execute(self.sql.query['rebuildHudCache'])
self.get_cursor().execute(rebuild_sql)
self.commit()
print "Rebuild hudcache took %.1f seconds" % (time() - stime,)
except:
@ -1033,6 +1147,39 @@ class Database:
print err
#end def rebuild_hudcache
def get_hero_hudcache_start(self):
"""fetches earliest stylekey from hudcache for one of hero's player ids"""
try:
# derive list of program owner's player ids
self.hero = {} # name of program owner indexed by site id
self.hero_ids = {'dummy':-53, 'dummy2':-52} # playerid of owner indexed by site id
# make sure at least two values in list
# so that tuple generation creates doesn't use
# () or (1,) style
for site in self.config.get_supported_sites():
result = self.get_site_id(site)
if result:
site_id = result[0][0]
self.hero[site_id] = self.config.supported_sites[site].screen_name
p_id = self.get_player_id(self.config, site, self.hero[site_id])
if p_id:
self.hero_ids[site_id] = int(p_id)
q = self.sql.query['get_hero_hudcache_start'].replace("<playerid_list>", str(tuple(self.hero_ids.values())))
c = self.get_cursor()
c.execute(q)
tmp = c.fetchone()
if tmp == (None,):
return self.hero_hudstart_def
else:
return "20"+tmp[0][1:3] + "-" + tmp[0][3:5] + "-" + tmp[0][5:7]
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "Error rebuilding hudcache:", str(sys.exc_value)
print err
#end def get_hero_hudcache_start
def analyzeDB(self):
"""Do whatever the DB can offer to update index/table statistics"""
@ -1623,6 +1770,8 @@ class Database:
#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:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "***Error storing hand: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
raise FpdbError( "store_hands_players_holdem_omaha_tourney error: " + str(sys.exc_value) )
return result
@ -1855,27 +2004,40 @@ class Database:
#end def storeHudCache
def store_tourneys(self, tourneyTypeId, siteTourneyNo, entries, prizepool, startTime):
ret = -1
try:
# try and create tourney record, fetch id if it already exists
# avoids race condition when doing the select first
cursor = self.get_cursor()
cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s".replace('%s', self.sql.query['placeholder'])
, (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("savepoint ins_tourney")
cursor.execute("""INSERT INTO Tourneys
(tourneyTypeId, siteTourneyNo, entries, prizepool, startTime)
VALUES (%s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder'])
,(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
ret = self.get_last_insert_id(cursor)
#print "created new tourneys.id:",ret
except:
raise FpdbError( "store_tourneys error: " + str(sys.exc_value) )
#if str(sys.exc_value) contains 'sitetourneyno':
# raise FpdbError( "store_tourneys error: " + str(sys.exc_value) )
#else:
#print "error insert tourney (%s) trying select ..." % (str(sys.exc_value),)
cursor.execute("rollback to savepoint ins_tourney")
try:
cursor.execute( "SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s".replace('%s', self.sql.query['placeholder'])
, (siteTourneyNo, tourneyTypeId) )
rec = cursor.fetchone()
#print "select tourney result: ", rec
try:
len(rec)
ret = rec[0]
except:
print "Tourney id not found"
except:
print "Error selecting tourney id:", str(sys.exc_info()[1])
return tmp[0]
cursor.execute("release savepoint ins_tourney")
#print "store_tourneys returning", ret
return ret
#end def store_tourneys
def store_tourneys_players(self, tourney_id, player_ids, payin_amounts, ranks, winnings):
@ -1888,26 +2050,32 @@ class Database:
#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".replace('%s', self.sql.query['placeholder'])
,(tourney_id, player_ids[i]))
tmp=cursor.fetchone()
#print "tried SELECTing tourneys_players.id:",tmp
try:
len(tmp)
except TypeError:
cursor.execute("savepoint ins_tplayer")
cursor.execute("""INSERT INTO TourneysPlayers
(tourneyId, playerId, payinAmount, rank, winnings) VALUES (%s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']),
(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".replace('%s', self.sql.query['placeholder']),
(tourney_id, player_ids[i]))
tmp=cursor.fetchone()
#print "created new tourneys_players.id:",tmp
tmp = self.get_last_insert_id(cursor)
result.append(tmp)
#print "created new tourneys_players.id:", tmp
except:
cursor.execute("rollback to savepoint ins_tplayer")
cursor.execute("SELECT id FROM TourneysPlayers WHERE tourneyId=%s AND playerId+0=%s".replace('%s', self.sql.query['placeholder'])
,(tourney_id, player_ids[i]))
tmp = cursor.fetchone()
#print "tried SELECTing tourneys_players.id:", tmp
try:
len(tmp)
result.append(tmp[0])
except:
print "tplayer id not found for tourney,player %s,%s" % (tourney_id, player_ids[i])
pass
except:
raise FpdbError( "store_tourneys_players error: " + str(sys.exc_value) )
cursor.execute("release savepoint ins_tplayer")
#print "store_tourneys_players returning", result
return result
#end def store_tourneys_players
@ -2130,10 +2298,10 @@ class Database:
def tStoreTourneyPlayers(self, tourney, dbTourneyId):
logging.debug("Database.tStoreTourneyPlayers")
# First, get playerids for the players and specifically the one for hero :
playersIds = fpdb_simple.recognisePlayerIDs(self, tourney.players, tourney.siteId)
playersIds = self.recognisePlayerIDs(tourney.players, tourney.siteId)
# hero may be None for matrix tourneys summaries
# hero = [ tourney.hero ]
# heroId = fpdb_simple.recognisePlayerIDs(self, hero , tourney.siteId)
# heroId = self.recognisePlayerIDs(hero , tourney.siteId)
# logging.debug("hero Id = %s - playersId = %s" % (heroId , playersIds))
tourneyPlayersIds=[]

View File

@ -56,24 +56,50 @@ import Database
import Tables
import Hud
# To add to config:
aggregate_stats = {"ring": False, "tour": False} # uses agg_bb_mult
hud_style = 'A' # A=All-time
# To add to config: *** these vars now replaced by def_hud_params list
#aggregate_stats = {"ring": False, "tour": False} # uses agg_bb_mult
#hud_style = 'A' # A=All-time
# S=Session
# T=timed (last n days - set hud_days to required value)
# Future values may also include:
# H=Hands (last n hands)
hud_days = 90 # Max number of days from each player to use for hud stats
agg_bb_mult = 100 # 1 = no aggregation. When aggregating stats across levels larger blinds
#hud_days = 90 # Max number of days from each player to use for hud stats
#agg_bb_mult = 100 # 1 = no aggregation. When aggregating stats across levels larger blinds
# must be < (agg_bb_mult * smaller blinds) to be aggregated
# ie. 100 will aggregate almost everything, 2 will probably agg just the
# next higher and lower levels into the current one, try 3/10/30/100
hud_session_gap = 30 # Gap (minutes) between hands that indicates a change of session
#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)
#hud_hands = 0 # Max number of hands from each player to use for hud stats (not used)
# New list to hold all HUD params
# - Set aggregate_ring and/or aggregate_tour to True is you want to include stats from other blind levels in the HUD display
# - If aggregation is used, the value of agg_bb_mult determines how what levels are included, e.g.
# if agg_bb_mult is 100, almost all levels are included in all HUD displays
# if agg_bb_mult is 2.1, levels from half to double the current blind level are included in the HUD
# - Set hud_style to A to see stats for all-time
# Set hud_style to S to only see stats for current session (currently this shows stats for the last 24 hours)
# Set hud_style to T to only see stats for the last N days (uses value in hud_days)
# - Set hud_days to N to see stats for the last N days in the HUD (only applies if hud_style is T)
def_hud_params = { # Settings for all players apart from program owner ('hero')
'aggregate_ring' : False
, 'aggregate_tour' : True
, 'hud_style' : 'A'
, 'hud_days' : 90
, 'agg_bb_mult' : 1 # 1 means no aggregation
# , 'hud_session_gap' : 30 not currently used
# Second set of variables for hero - these settings only apply to the program owner
, 'h_aggregate_ring' : False
, 'h_aggregate_tour' : True
, 'h_hud_style' : 'A'
, 'h_hud_days' : 90
, 'h_agg_bb_mult' : 1 # 1 means no aggregation
# , 'h_hud_session_gap' : 30 not currently used
}
class HUD_main(object):
"""A main() object to own both the read_stdin thread and the gui."""
# This class mainly provides state for controlling the multiple HUDs.
@ -82,6 +108,7 @@ class HUD_main(object):
self.db_name = db_name
self.config = Configuration.Config(file=options.config, dbname=options.dbname)
self.hud_dict = {}
self.hud_params = def_hud_params
# a thread to read stdin
gobject.threads_init() # this is required
@ -104,7 +131,11 @@ class HUD_main(object):
# called by an event in the HUD, to kill this specific HUD
if table in self.hud_dict:
self.hud_dict[table].kill()
try:
# throws exception in windows sometimes (when closing using main_window menu?)
self.hud_dict[table].main_window.destroy()
except:
pass
self.vb.remove(self.hud_dict[table].tablehudlabel)
del(self.hud_dict[table])
self.main_window.resize(1,1)
@ -160,10 +191,19 @@ class HUD_main(object):
# be passed to HUDs for use in the gui thread. HUD objects should not
# need their own access to the database, but should open their own
# if it is required.
try:
self.db_connection = Database.Database(self.config)
self.db_connection.init_hud_stat_vars(hud_days)
tourny_finder = re.compile('(\d+) (\d+)')
# get hero's screen names and player ids
self.hero, self.hero_ids = {}, {}
for site in self.config.get_supported_sites():
result = self.db_connection.get_site_id(site)
if result:
site_id = result[0][0]
self.hero[site_id] = self.config.supported_sites[site].screen_name
self.hero_ids[site_id] = self.db_connection.get_player_id(self.config, site, self.hero[site_id])
while 1: # wait for a new hand number on stdin
new_hand_id = sys.stdin.readline()
new_hand_id = string.rstrip(new_hand_id)
@ -173,9 +213,7 @@ class HUD_main(object):
# get basic info about the new hand from the db
# if there is a db error, complain, skip hand, and proceed
try:
(table_name, max, poker_game, type) = self.db_connection.get_table_name(new_hand_id)
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, aggregate_stats[type]
,hud_style, agg_bb_mult)
(table_name, max, poker_game, type, site_id) = self.db_connection.get_table_name(new_hand_id)
cards = self.db_connection.get_cards(new_hand_id)
comm_cards = self.db_connection.get_common_cards(new_hand_id)
@ -203,6 +241,16 @@ class HUD_main(object):
# Update an existing HUD
if temp_key in self.hud_dict:
try:
# get stats using hud's specific params
self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days'] )
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, self.hud_dict[temp_key].hud_params, self.hero_ids)
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
if new_hand_id: # new_hand_id is none if we had an error prior to the store
sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
continue
self.hud_dict[temp_key].stat_dict = stat_dict
self.hud_dict[temp_key].cards = cards
[aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[temp_key].aux_windows]
@ -210,6 +258,16 @@ class HUD_main(object):
# Or create a new HUD
else:
try:
# get stats using default params
self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'] )
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, self.hud_params, self.hero_ids)
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
if new_hand_id: # new_hand_id is none if we had an error prior to the store
sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
continue
if type == "tour":
tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number)
else:
@ -222,6 +280,9 @@ class HUD_main(object):
else:
self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, stat_dict, cards)
self.db_connection.connection.rollback()
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
if __name__== "__main__":

View File

@ -673,7 +673,14 @@ class HoldemOmahaHand(Hand):
if shown: self.shown.add(player)
if mucked: self.mucked.add(player)
else:
if len(cards) in (2, 4): # avoid adding board by mistake (Everleaf problem)
self.addHoleCards('PREFLOP', player, open=[], closed=cards, shown=shown, mucked=mucked, dealt=dealt)
elif len(cards) == 5: # cards holds a winning hand, not hole cards
# filter( lambda x: x not in b, a ) # calcs a - b where a and b are lists
# so diff is set to the winning hand minus the board cards, if we're lucky that leaves the hole cards
diff = filter( lambda x: x not in self.board['FLOP']+self.board['TURN']+self.board['RIVER'], cards )
if len(diff) == 2 and self.gametype['category'] in ('holdem'):
self.addHoleCards('PREFLOP', player, open=[], closed=diff, shown=shown, mucked=mucked, dealt=dealt)
def getStreetTotals(self):
# street1Pot INT, /* pot size at flop/street4 */

View File

@ -73,6 +73,7 @@ class Hud:
self.stacked = True
self.site = table.site
self.mw_created = False
self.hud_params = parent.hud_params
self.stat_windows = {}
self.popup_windows = {}
@ -144,6 +145,47 @@ class Hud:
menu.append(repositem)
repositem.connect("activate", self.reposition_windows)
aggitem = gtk.MenuItem('Show Stats')
menu.append(aggitem)
aggMenu = gtk.Menu()
aggitem.set_submenu(aggMenu)
# set agg_bb_mult to 1 to stop aggregation
item = gtk.MenuItem('For This Blind Level')
item.ms = 1
aggMenu.append(item)
item.connect("activate", self.set_aggregation)
setattr(self, 'showStatsMenuItem1', item)
#
item = gtk.MenuItem('For Multiple Blind Levels:')
aggMenu.append(item)
setattr(self, 'showStatsMenuItem2', item)
#
item = gtk.MenuItem(' 0.5 to 2.0 x Current Blinds')
item.ms = 2.01
aggMenu.append(item)
item.connect("activate", self.set_aggregation)
setattr(self, 'showStatsMenuItem3', item)
#
item = gtk.MenuItem(' 0.33 to 3.0 x Current Blinds')
item.ms = 3.01
aggMenu.append(item)
item.connect("activate", self.set_aggregation)
setattr(self, 'showStatsMenuItem4', item)
#
item = gtk.MenuItem(' 0.1 to 10 x Current Blinds')
item.ms = 10.01
aggMenu.append(item)
item.connect("activate", self.set_aggregation)
setattr(self, 'showStatsMenuItem5', item)
#
item = gtk.MenuItem(' All Levels')
item.ms = 10000
aggMenu.append(item)
item.connect("activate", self.set_aggregation)
setattr(self, 'showStatsMenuItem6', item)
eventbox.connect_object("button-press-event", self.on_button_press, menu)
debugitem = gtk.MenuItem('Debug StatWindows')
menu.append(debugitem)
debugitem.connect("activate", self.debug_stat_windows)
@ -176,9 +218,18 @@ class Hud:
self.create(*self.creation_attrs)
self.update(self.hand, self.config)
except Exception, e:
print "Expcetion:",str(e)
print "Exception:",str(e)
pass
def set_aggregation(self, widget):
# try setting these to true all the time, and set the multiplier to 1 to turn agg off:
self.hud_params['aggregate_ring'] = True
self.hud_params['aggregate_tour'] = True
if self.hud_params['agg_bb_mult'] != widget.ms:
print 'set_aggregation', widget.ms
self.hud_params['agg_bb_mult'] = widget.ms
def update_table_position(self):
if os.name == 'nt':
if not win32gui.IsWindow(self.table.number):
@ -218,7 +269,11 @@ class Hud:
# heap dead, burnt bodies, blood 'n guts, veins between my teeth
for s in self.stat_windows.itervalues():
s.kill_popups()
try:
# throws "invalid window handle" in WinXP (sometimes?)
s.window.destroy()
except:
pass
self.stat_windows = {}
# also kill any aux windows
for aux in self.aux_windows:

View File

@ -331,7 +331,8 @@ class Sql:
speed varchar(10),
headsUp BOOLEAN NOT NULL DEFAULT False,
shootout BOOLEAN NOT NULL DEFAULT False,
matrix BOOLEAN NOT NULL DEFAULT False
matrix BOOLEAN NOT NULL DEFAULT False,
sng BOOLEAN NOT NULL DEFAULT False
)
ENGINE=INNODB"""
elif db_server == 'postgresql':
@ -346,7 +347,8 @@ class Sql:
speed varchar(10),
headsUp BOOLEAN NOT NULL DEFAULT False,
shootout BOOLEAN NOT NULL DEFAULT False,
matrix BOOLEAN NOT NULL DEFAULT False
matrix BOOLEAN NOT NULL DEFAULT False,
sng BOOLEAN NOT NULL DEFAULT False
)"""
elif db_server == 'sqlite':
self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes (
@ -360,7 +362,8 @@ class Sql:
speed TEXT,
headsUp BOOLEAN NOT NULL DEFAULT 0,
shootout BOOLEAN NOT NULL DEFAULT 0,
matrix BOOLEAN NOT NULL DEFAULT 0
matrix BOOLEAN NOT NULL DEFAULT 0,
sng BOOLEAN NOT NULL DEFAULT 0
)"""
################################
@ -820,7 +823,21 @@ class Sql:
comment TEXT,
commentTs timestamp without time zone)"""
elif db_server == 'sqlite':
self.query['createTourneysPlayersTable'] = """ """
self.query['createTourneysPlayersTable'] = """CREATE TABLE TourneysPlayers (
id INT PRIMARY KEY,
tourneyId INT,
playerId INT,
payinAmount INT,
rank INT,
winnings INT,
nbRebuys INT DEFAULT 0,
nbAddons INT DEFAULT 0,
nbKO INT DEFAULT 0,
comment TEXT,
commentTs timestamp without time zone,
FOREIGN KEY (tourneyId) REFERENCES Tourneys(id),
FOREIGN KEY (playerId) REFERENCES Players(id)
)"""
################################
@ -851,7 +868,18 @@ class Sql:
comment TEXT,
commentTs timestamp without time zone)"""
elif db_server == 'sqlite':
self.query['createHandsActionsTable'] = """ """
self.query['createHandsActionsTable'] = """CREATE TABLE HandsActions (
id INT PRIMARY KEY,
handsPlayerId BIGINT,
street SMALLINT,
actionNo SMALLINT,
action CHAR(5),
allIn INT,
amount INT,
comment TEXT,
commentTs timestamp without time zone,
FOREIGN KEY (handsPlayerId) REFERENCES HandsPlayers(id)
)"""
################################
@ -1160,26 +1188,42 @@ class Sql:
if db_server == 'mysql':
self.query['addTourneyIndex'] = """ALTER TABLE Tourneys ADD INDEX siteTourneyNo(siteTourneyNo)"""
self.query['addTourneyIndex'] = """ALTER TABLE Tourneys ADD UNIQUE INDEX siteTourneyNo(siteTourneyNo, tourneyTypeId)"""
elif db_server == 'postgresql':
self.query['addTourneyIndex'] = """CREATE INDEX siteTourneyNo ON Tourneys (siteTourneyNo)"""
self.query['addTourneyIndex'] = """CREATE UNIQUE INDEX siteTourneyNo ON Tourneys (siteTourneyNo, tourneyTypeId)"""
elif db_server == 'sqlite':
self.query['addHandsIndex'] = """ """
self.query['addTourneyIndex'] = """CREATE UNIQUE INDEX siteTourneyNo ON Tourneys (siteTourneyNo, tourneyTypeId)"""
if db_server == 'mysql':
self.query['addHandsIndex'] = """ALTER TABLE Hands ADD INDEX siteHandNo(siteHandNo)"""
self.query['addHandsIndex'] = """ALTER TABLE Hands ADD UNIQUE INDEX siteHandNo(siteHandNo, gameTypeId)"""
elif db_server == 'postgresql':
self.query['addHandsIndex'] = """CREATE INDEX siteHandNo ON Hands (siteHandNo)"""
self.query['addHandsIndex'] = """CREATE UNIQUE INDEX siteHandNo ON Hands (siteHandNo, gameTypeId)"""
elif db_server == 'sqlite':
self.query['addHandsIndex'] = """ """
self.query['addHandsIndex'] = """CREATE UNIQUE INDEX siteHandNo ON Hands (siteHandNo, gameTypeId)"""
if db_server == 'mysql':
self.query['addPlayersIndex'] = """ALTER TABLE Players ADD INDEX name(name)"""
self.query['addPlayersIndex'] = """ALTER TABLE Players ADD UNIQUE INDEX name(name, siteId)"""
elif db_server == 'postgresql':
self.query['addPlayersIndex'] = """CREATE INDEX name ON Players (name)"""
self.query['addPlayersIndex'] = """CREATE UNIQUE INDEX name ON Players (name, siteId)"""
elif db_server == 'sqlite':
self.query['addPlayersIndex'] = """ """
self.query['addPlayersIndex'] = """CREATE UNIQUE INDEX name ON Players (name, siteId)"""
if db_server == 'mysql':
self.query['addTPlayersIndex'] = """ALTER TABLE TourneysPlayers ADD UNIQUE INDEX tourneyId(tourneyId, playerId)"""
elif db_server == 'postgresql':
self.query['addTPlayersIndex'] = """CREATE UNIQUE INDEX tourneyId ON TourneysPlayers (tourneyId, playerId)"""
elif db_server == 'sqlite':
self.query['addTPlayersIndex'] = """CREATE UNIQUE INDEX tourneyId ON TourneysPlayers (tourneyId, playerId)"""
if db_server == 'mysql':
self.query['addTTypesIndex'] = """ALTER TABLE TourneyTypes ADD UNIQUE INDEX tourneytypes_all(buyin, fee
, maxSeats, knockout, rebuyOrAddon, speed, headsUp, shootout, matrix, sng)"""
elif db_server == 'postgresql':
self.query['addTTypesIndex'] = """CREATE UNIQUE INDEX tourneyTypes_all ON TourneyTypes (buyin, fee
, maxSeats, knockout, rebuyOrAddon, speed, headsUp, shootout, matrix, sng)"""
elif db_server == 'sqlite':
self.query['addTTypesIndex'] = """CREATE UNIQUE INDEX tourneyTypes_all ON TourneyTypes (buyin, fee
, maxSeats, knockout, rebuyOrAddon, speed, headsUp, shootout, matrix, sng)"""
self.query['get_last_hand'] = "select max(id) from Hands"
@ -1188,7 +1232,7 @@ class Sql:
from Players, Sites
where Players.name = %s
and Sites.name = %s
and Players.SiteId = Sites.id
and Players.siteId = Sites.id
"""
self.query['getSiteId'] = """SELECT id from Sites where name = %s"""
@ -1537,10 +1581,11 @@ class Sql:
"""
self.query['get_table_name'] = """
select tableName, maxSeats, category, type
from Hands,Gametypes
where Hands.id = %s
and Gametypes.id = Hands.gametypeId
select h.tableName, h.maxSeats, gt.category, gt.type, gt.siteId
from Hands h
,Gametypes gt
where h.id = %s
and gt.id = h.gametypeId
"""
self.query['get_actual_seat'] = """
@ -2466,6 +2511,7 @@ class Sql:
,sum(street4CheckCallRaiseDone)
FROM HandsPlayers hp
INNER JOIN Hands h ON (h.id = hp.handId)
<where_clause>
GROUP BY h.gametypeId
,hp.playerId
,h.seats
@ -2614,6 +2660,7 @@ class Sql:
,sum(CAST(street4CheckCallRaiseDone as integer))
FROM HandsPlayers hp
INNER JOIN Hands h ON (h.id = hp.handId)
<where_clause>
GROUP BY h.gametypeId
,hp.playerId
,h.seats
@ -2762,6 +2809,7 @@ class Sql:
,sum(CAST(street4CheckCallRaiseDone as integer))
FROM HandsPlayers hp
INNER JOIN Hands h ON (h.id = hp.handId)
<where_clause>
GROUP BY h.gametypeId
,hp.playerId
,h.seats
@ -2770,9 +2818,14 @@ class Sql:
,'d' || substr(strftime('%Y%m%d', h.handStart),3,7)
"""
self.query['get_hero_hudcache_start'] = """select min(hc.styleKey)
from HudCache hc
where hc.playerId in <playerid_list>
and hc.styleKey like 'd%'"""
if db_server == 'mysql':
self.query['analyze'] = """
analyze table Autorates, GameTypes, Hands, HandsPlayers, Hudcache, Players
analyze table Autorates, GameTypes, Hands, HandsPlayers, HudCache, Players
, Settings, Sites, Tourneys, TourneysPlayers, TourneyTypes
"""
else: # assume postgres

View File

@ -248,7 +248,7 @@ class ttracker_main(object):
# get basic info about the new hand from the db
# if there is a db error, complain, skip hand, and proceed
try:
(table_name, max, poker_game, type) = self.db_connection.get_table_name(new_hand_id)
(table_name, max, poker_game, type, site_id) = self.db_connection.get_table_name(new_hand_id)
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, aggregate_stats[type]
,hud_style, agg_bb_mult)

View File

@ -257,18 +257,66 @@ class fpdb:
def dia_recreate_hudcache(self, widget, data=None):
if self.obtain_global_lock():
dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm recreating HUD cache")
self.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)
self.dia_confirm.format_secondary_text(diastring)
response = dia_confirm.run()
dia_confirm.destroy()
hb = gtk.HBox(True, 1)
self.start_date = gtk.Entry(max=12)
self.start_date.set_text( self.db.get_hero_hudcache_start() )
lbl = gtk.Label(" Hero's cache starts: ")
btn = gtk.Button()
btn.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON))
btn.connect('clicked', self.__calendar_dialog, self.start_date)
hb.pack_start(lbl, expand=True, padding=3)
hb.pack_start(self.start_date, expand=True, padding=2)
hb.pack_start(btn, expand=False, padding=3)
self.dia_confirm.vbox.add(hb)
hb.show_all()
response = self.dia_confirm.run()
self.dia_confirm.destroy()
if response == gtk.RESPONSE_YES:
self.db.rebuild_hudcache()
elif response == gtk.REPSONSE_NO:
self.db.rebuild_hudcache( self.start_date.get_text() )
elif response == gtk.RESPONSE_NO:
print 'User cancelled rebuilding hud cache'
self.release_global_lock()
def __calendar_dialog(self, widget, entry):
self.dia_confirm.set_modal(False)
d = gtk.Window(gtk.WINDOW_TOPLEVEL)
d.set_title('Pick a date')
vb = gtk.VBox()
cal = gtk.Calendar()
vb.pack_start(cal, expand=False, padding=0)
btn = gtk.Button('Done')
btn.connect('clicked', self.__get_date, cal, entry, d)
vb.pack_start(btn, expand=False, padding=4)
d.add(vb)
d.set_position(gtk.WIN_POS_MOUSE)
d.show_all()
def __get_dates(self):
t1 = self.start_date.get_text()
if t1 == '':
t1 = '1970-01-01'
return (t1)
def __get_date(self, widget, calendar, entry, win):
# year and day are correct, month is 0..11
(year, month, day) = calendar.get_date()
month += 1
ds = '%04d-%02d-%02d' % (year, month, day)
entry.set_text(ds)
win.destroy()
self.dia_confirm.set_modal(True)
def dia_regression_test(self, widget, data=None):
self.warning_box("Unimplemented: Regression Test")
self.obtain_global_lock()

View File

@ -38,6 +38,8 @@ class fpdb_db:
MYSQL_INNODB = 2
PGSQL = 3
SQLITE = 4
sqlite_db_dir = ".." + os.sep + "database"
def __init__(self):
"""Simple constructor, doesnt really do anything"""
self.db = None
@ -119,7 +121,12 @@ class fpdb_db:
sqlite3 = pool.manage(sqlite3, pool_size=1)
else:
logging.warning("SQLite won't work well without 'sqlalchemy' installed.")
self.db = sqlite3.connect(database,detect_types=sqlite3.PARSE_DECLTYPES)
if not os.path.isdir(self.sqlite_db_dir):
print "Creating directory: '%s'" % (self.sqlite_db_dir)
os.mkdir(self.sqlite_db_dir)
self.db = sqlite3.connect( self.sqlite_db_dir + os.sep + 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:

View File

@ -547,7 +547,7 @@ class Importer:
if self.callHud:
#print "call to HUD here. handsId:",handsId
#pipe the Hands.id out to the HUD
#print "sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud
print "sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud
self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep)
except Exceptions.DuplicateError:
duplicates += 1

View File

@ -118,7 +118,7 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non
seatLines.append(line)
names = fpdb_simple.parseNames(seatLines)
playerIDs = fpdb_simple.recognisePlayerIDs(db, names, siteID) # inserts players as needed
playerIDs = db.recognisePlayerIDs(names, siteID) # inserts players as needed
tmp = fpdb_simple.parseCashesAndSeatNos(seatLines)
startCashes = tmp['startCashes']
seatNos = tmp['seatNos']

View File

@ -913,92 +913,54 @@ def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, c
#end def recogniseGametypeID
def recogniseTourneyTypeId(db, siteId, tourneySiteId, buyin, fee, knockout, rebuyOrAddon):
ret = -1
cursor = db.get_cursor()
# First we try to find the tourney itself (by its tourneySiteId) in case it has already been inserted before (by a summary file for instance)
# The reason is that some tourneys may not be identified correctly in the HH toplines (especially Buy-In and Fee which are used to search/create the TourneyTypeId)
#TODO: When the summary file will be dumped to BD, if the tourney is already in, Buy-In/Fee may need an update (e.g. creation of a new type and link to the Tourney)
cursor.execute (db.sql.query['getTourneyTypeIdByTourneyNo'].replace('%s', db.sql.query['placeholder']), (tourneySiteId, siteId))
result=cursor.fetchone()
result = cursor.fetchone()
try:
len(result)
ret = result[0]
except:
cursor.execute ("SELECT id FROM TourneyTypes WHERE siteId=%s AND buyin=%s AND fee=%s AND knockout=%s AND rebuyOrAddon=%s", (siteId, buyin, fee, knockout, rebuyOrAddon))
result=cursor.fetchone()
#print "tried SELECTing gametypes.id, result:",result
cursor.execute( """SELECT id FROM TourneyTypes
WHERE siteId=%s AND buyin=%s AND fee=%s
AND knockout=%s AND rebuyOrAddon=%s"""
, (siteId, buyin, fee, knockout, rebuyOrAddon) )
result = cursor.fetchone()
#print "tried selecting tourneytypes.id, result:", result
try:
len(result)
ret = result[0]
except TypeError:#this means we need to create a new entry
cursor.execute("""INSERT INTO TourneyTypes (siteId, buyin, fee, knockout, rebuyOrAddon) VALUES (%s, %s, %s, %s, %s)""", (siteId, buyin, fee, knockout, rebuyOrAddon))
cursor.execute("SELECT id FROM TourneyTypes WHERE siteId=%s AND buyin=%s AND fee=%s AND knockout=%s AND rebuyOrAddon=%s", (siteId, buyin, fee, knockout, rebuyOrAddon))
result=cursor.fetchone()
#print "insert new tourneytype record ..."
try:
cursor.execute( """INSERT INTO TourneyTypes (siteId, buyin, fee, knockout, rebuyOrAddon)
VALUES (%s, %s, %s, %s, %s)"""
, (siteId, buyin, fee, knockout, rebuyOrAddon) )
ret = db.get_last_insert_id(cursor)
except:
#print "maybe tourneytype was created since select, try selecting again ..."
cursor.execute( """SELECT id FROM TourneyTypes
WHERE siteId=%s AND buyin=%s AND fee=%s
AND knockout=%s AND rebuyOrAddon=%s"""
, (siteId, buyin, fee, knockout, rebuyOrAddon) )
result = cursor.fetchone()
try:
len(result)
ret = result[0]
except:
print "Failed to find or insert TourneyTypes record"
ret = -1 # failed to find or insert record
#print "tried selecting tourneytypes.id again, result:", result
return result[0]
#print "recogniseTourneyTypeId: returning", ret
return ret
#end def recogniseTourneyTypeId
#returns the SQL ids of the names given in an array
# TODO: if someone gets industrious, they should make the parts that use the output of this function deal with a dict
# { playername: id } instead of depending on it's relation to the positions list
# then this can be reduced in complexity a bit
#def recognisePlayerIDs(cursor, names, site_id):
# result = []
# for i in xrange(len(names)):
# cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],))
# tmp=cursor.fetchall()
# if (len(tmp)==0): #new player
# cursor.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)", (names[i], site_id))
# #print "Number of players rows inserted: %d" % cursor.rowcount
# cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],))
# tmp=cursor.fetchall()
# #print "recognisePlayerIDs, names[i]:",names[i],"tmp:",tmp
# result.append(tmp[0][0])
# return result
def recognisePlayerIDs(db, names, site_id):
c = db.get_cursor()
q = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" %(site_id, " OR name=".join([db.sql.query['placeholder'] for n in names]))
c.execute(q, names) # get all playerids by the names passed in
ids = dict(c.fetchall()) # convert to dict
if len(ids) != len(names):
notfound = [n for n in names if n not in ids] # make list of names not in database
if notfound: # insert them into database
q_ins = "INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")"
q_ins = q_ins.replace('%s', db.sql.query['placeholder'])
c.executemany(q_ins, [(n,) for n in notfound])
q2 = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" % (site_id, " OR name=".join(["%s" for n in notfound]))
q2 = q2.replace('%s', db.sql.query['placeholder'])
c.execute(q2, notfound) # get their new ids
tmp = c.fetchall()
for n,id in tmp: # put them all into the same dict
ids[n] = id
# return them in the SAME ORDER that they came in in the names argument, rather than the order they came out of the DB
return [ids[n] for n in names]
#end def recognisePlayerIDs
# Here's a version that would work if it wasn't for the fact that it needs to have the output in the same order as input
# this version could also be improved upon using list comprehensions, etc
#def recognisePlayerIDs(cursor, names, site_id):
# result = []
# notfound = []
# cursor.execute("SELECT name,id FROM Players WHERE name='%s'" % "' OR name='".join(names))
# tmp = dict(cursor.fetchall())
# for n in names:
# if n not in tmp:
# notfound.append(n)
# else:
# result.append(tmp[n])
# if notfound:
# cursor.executemany("INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")", (notfound))
# cursor.execute("SELECT id FROM Players WHERE name='%s'" % "' OR name='".join(notfound))
# tmp = cursor.fetchall()
# for n in tmp:
# result.append(n[0])
#
# return result
#recognises the name in the given line and returns its array position in the given array
def recognisePlayerNo(line, names, atype):