Merge branch 'master' of git://git.assembla.com/fpdb-sql
Conflicts: pyfpdb/Configuration.py pyfpdb/Database.py
This commit is contained in:
commit
1ec6a36ece
|
@ -56,8 +56,7 @@ def get_exec_path():
|
||||||
if hasattr(sys, "frozen"): # compiled by py2exe
|
if hasattr(sys, "frozen"): # compiled by py2exe
|
||||||
return os.path.dirname(sys.executable)
|
return os.path.dirname(sys.executable)
|
||||||
else:
|
else:
|
||||||
pathname = os.path.dirname(sys.argv[0])
|
return sys.path[0]
|
||||||
return os.path.abspath(pathname)
|
|
||||||
|
|
||||||
def get_config(file_name, fallback = True):
|
def get_config(file_name, fallback = True):
|
||||||
"""Looks in exec dir and in self.default_config_path for a config file."""
|
"""Looks in exec dir and in self.default_config_path for a config file."""
|
||||||
|
@ -82,7 +81,10 @@ def get_config(file_name, fallback = True):
|
||||||
log.error("No %s found, using %s.example.\n" % (file_name, file_name) )
|
log.error("No %s found, using %s.example.\n" % (file_name, file_name) )
|
||||||
except:
|
except:
|
||||||
print "No %s found, cannot fall back. Exiting.\n" % file_name
|
print "No %s found, cannot fall back. Exiting.\n" % file_name
|
||||||
log.critical("No %s found, cannot fall back. Exiting.\n" % file_name)
|
sys.exit()
|
||||||
|
else:
|
||||||
|
print "No %s found, cannot fall back. Exiting.\n" % file_name
|
||||||
|
sys.stderr.write("No %s found, cannot fall back. Exiting.\n" % file_name)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
return file_name
|
return file_name
|
||||||
|
|
||||||
|
@ -429,7 +431,7 @@ class Config:
|
||||||
log.error("Specified configuration file %s not found. Using defaults." % (file))
|
log.error("Specified configuration file %s not found. Using defaults." % (file))
|
||||||
file = None
|
file = None
|
||||||
|
|
||||||
if file is None: file = get_config("HUD_config.xml")
|
if file is None: file = get_config("HUD_config.xml", True)
|
||||||
|
|
||||||
# Parse even if there was no real config file found and we are using the example
|
# Parse even if there was no real config file found and we are using the example
|
||||||
# If using the example, we'll edit it later
|
# If using the example, we'll edit it later
|
||||||
|
@ -446,6 +448,8 @@ class Config:
|
||||||
|
|
||||||
self.doc = doc
|
self.doc = doc
|
||||||
self.file = file
|
self.file = file
|
||||||
|
self.dir = os.path.dirname(self.file)
|
||||||
|
self.dir_databases = os.path.join(self.dir, 'database')
|
||||||
self.supported_sites = {}
|
self.supported_sites = {}
|
||||||
self.supported_games = {}
|
self.supported_games = {}
|
||||||
self.supported_databases = {} # databaseName --> Database instance
|
self.supported_databases = {} # databaseName --> Database instance
|
||||||
|
|
|
@ -39,11 +39,30 @@ import string
|
||||||
import re
|
import re
|
||||||
import Queue
|
import Queue
|
||||||
import codecs
|
import codecs
|
||||||
|
import logging
|
||||||
|
import math
|
||||||
|
|
||||||
|
|
||||||
# pyGTK modules
|
# pyGTK modules
|
||||||
|
|
||||||
|
|
||||||
|
# Other library modules
|
||||||
|
try:
|
||||||
|
import sqlalchemy.pool as pool
|
||||||
|
use_pool = True
|
||||||
|
except ImportError:
|
||||||
|
logging.info("Not using sqlalchemy connection pool.")
|
||||||
|
use_pool = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
from numpy import var
|
||||||
|
use_numpy = True
|
||||||
|
except ImportError:
|
||||||
|
logging.info("Not using numpy to define variance in sqlite.")
|
||||||
|
use_numpy = False
|
||||||
|
|
||||||
|
|
||||||
# FreePokerTools modules
|
# FreePokerTools modules
|
||||||
import fpdb_db
|
|
||||||
import Configuration
|
import Configuration
|
||||||
import SQL
|
import SQL
|
||||||
import Card
|
import Card
|
||||||
|
@ -55,6 +74,27 @@ log = Configuration.get_logger("logging.conf", config = "db")
|
||||||
log.debug("db logger initialized.")
|
log.debug("db logger initialized.")
|
||||||
encoder = codecs.lookup('utf-8')
|
encoder = codecs.lookup('utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
DB_VERSION = 119
|
||||||
|
|
||||||
|
|
||||||
|
# Variance created as sqlite has a bunch of undefined aggregate functions.
|
||||||
|
|
||||||
|
class VARIANCE:
|
||||||
|
def __init__(self):
|
||||||
|
self.store = []
|
||||||
|
|
||||||
|
def step(self, value):
|
||||||
|
self.store.append(value)
|
||||||
|
|
||||||
|
def finalize(self):
|
||||||
|
return float(var(self.store))
|
||||||
|
|
||||||
|
class sqlitemath:
|
||||||
|
def mod(self, a, b):
|
||||||
|
return a%b
|
||||||
|
|
||||||
|
|
||||||
class Database:
|
class Database:
|
||||||
|
|
||||||
MYSQL_INNODB = 2
|
MYSQL_INNODB = 2
|
||||||
|
@ -191,7 +231,22 @@ class Database:
|
||||||
log.info("Creating Database instance, sql = %s" % sql)
|
log.info("Creating Database instance, sql = %s" % sql)
|
||||||
self.config = c
|
self.config = c
|
||||||
self.__connected = False
|
self.__connected = False
|
||||||
self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql
|
self.settings = {}
|
||||||
|
self.settings['os'] = "linuxmac" if os.name != "nt" else "windows"
|
||||||
|
db_params = c.get_db_parameters()
|
||||||
|
self.import_options = c.get_import_parameters()
|
||||||
|
self.backend = db_params['db-backend']
|
||||||
|
self.db_server = db_params['db-server']
|
||||||
|
self.database = db_params['db-databaseName']
|
||||||
|
self.host = db_params['db-host']
|
||||||
|
|
||||||
|
# where possible avoid creating new SQL instance by using the global one passed in
|
||||||
|
if sql is None:
|
||||||
|
self.sql = SQL.Sql(db_server = self.db_server)
|
||||||
|
else:
|
||||||
|
self.sql = sql
|
||||||
|
|
||||||
|
# connect to db
|
||||||
self.do_connect(c)
|
self.do_connect(c)
|
||||||
print "connection =", self.connection
|
print "connection =", self.connection
|
||||||
if self.backend == self.PGSQL:
|
if self.backend == self.PGSQL:
|
||||||
|
@ -200,12 +255,6 @@ class Database:
|
||||||
#ISOLATION_LEVEL_READ_COMMITTED = 1
|
#ISOLATION_LEVEL_READ_COMMITTED = 1
|
||||||
#ISOLATION_LEVEL_SERIALIZABLE = 2
|
#ISOLATION_LEVEL_SERIALIZABLE = 2
|
||||||
|
|
||||||
# where possible avoid creating new SQL instance by using the global one passed in
|
|
||||||
if sql is None:
|
|
||||||
self.sql = SQL.Sql(db_server = self.db_server)
|
|
||||||
else:
|
|
||||||
self.sql = sql
|
|
||||||
|
|
||||||
if self.backend == self.SQLITE and self.database == ':memory:' and self.wrongDbVersion:
|
if self.backend == self.SQLITE and self.database == ':memory:' and self.wrongDbVersion:
|
||||||
log.info("sqlite/:memory: - creating")
|
log.info("sqlite/:memory: - creating")
|
||||||
self.recreate_tables()
|
self.recreate_tables()
|
||||||
|
@ -228,8 +277,6 @@ class Database:
|
||||||
self.h_date_ndays_ago = 'd000000' # date N days ago ('d' + YYMMDD) for hero
|
self.h_date_ndays_ago = 'd000000' # date N days ago ('d' + YYMMDD) for hero
|
||||||
self.date_nhands_ago = {} # dates N hands ago per player - not used yet
|
self.date_nhands_ago = {} # dates N hands ago per player - not used yet
|
||||||
|
|
||||||
self.cursor = self.fdb.cursor
|
|
||||||
|
|
||||||
self.saveActions = False if self.import_options['saveActions'] == False else True
|
self.saveActions = False if self.import_options['saveActions'] == False else True
|
||||||
|
|
||||||
self.connection.rollback() # make sure any locks taken so far are released
|
self.connection.rollback() # make sure any locks taken so far are released
|
||||||
|
@ -240,14 +287,20 @@ class Database:
|
||||||
self.hud_style = style
|
self.hud_style = style
|
||||||
|
|
||||||
def do_connect(self, c):
|
def do_connect(self, c):
|
||||||
|
if c is None:
|
||||||
|
raise FpdbError('Configuration not defined')
|
||||||
|
|
||||||
|
db = c.get_db_parameters()
|
||||||
try:
|
try:
|
||||||
self.fdb.do_connect(c)
|
self.connect(backend=db['db-backend'],
|
||||||
|
host=db['db-host'],
|
||||||
|
database=db['db-databaseName'],
|
||||||
|
user=db['db-user'],
|
||||||
|
password=db['db-password'])
|
||||||
except:
|
except:
|
||||||
# error during connect
|
# error during connect
|
||||||
self.__connected = False
|
self.__connected = False
|
||||||
raise
|
raise
|
||||||
self.connection = self.fdb.db
|
|
||||||
self.wrongDbVersion = self.fdb.wrongDbVersion
|
|
||||||
|
|
||||||
db_params = c.get_db_parameters()
|
db_params = c.get_db_parameters()
|
||||||
self.import_options = c.get_import_parameters()
|
self.import_options = c.get_import_parameters()
|
||||||
|
@ -257,11 +310,137 @@ class Database:
|
||||||
self.host = db_params['db-host']
|
self.host = db_params['db-host']
|
||||||
self.__connected = True
|
self.__connected = True
|
||||||
|
|
||||||
|
def connect(self, backend=None, host=None, database=None,
|
||||||
|
user=None, password=None):
|
||||||
|
"""Connects a database with the given parameters"""
|
||||||
|
if backend is None:
|
||||||
|
raise FpdbError('Database backend not defined')
|
||||||
|
self.backend = backend
|
||||||
|
self.host = host
|
||||||
|
self.user = user
|
||||||
|
self.password = password
|
||||||
|
self.database = database
|
||||||
|
self.connection = None
|
||||||
|
self.cursor = None
|
||||||
|
|
||||||
|
if backend == Database.MYSQL_INNODB:
|
||||||
|
import MySQLdb
|
||||||
|
if use_pool:
|
||||||
|
MySQLdb = pool.manage(MySQLdb, pool_size=5)
|
||||||
|
try:
|
||||||
|
self.connection = MySQLdb.connect(host=host, user=user, passwd=password, db=database, use_unicode=True)
|
||||||
|
#TODO: Add port option
|
||||||
|
except MySQLdb.Error, ex:
|
||||||
|
if ex.args[0] == 1045:
|
||||||
|
raise FpdbMySQLAccessDenied(ex.args[0], ex.args[1])
|
||||||
|
elif ex.args[0] == 2002 or ex.args[0] == 2003: # 2002 is no unix socket, 2003 is no tcp socket
|
||||||
|
raise FpdbMySQLNoDatabase(ex.args[0], ex.args[1])
|
||||||
|
else:
|
||||||
|
print "*** WARNING UNKNOWN MYSQL ERROR", ex
|
||||||
|
elif backend == Database.PGSQL:
|
||||||
|
import psycopg2
|
||||||
|
import psycopg2.extensions
|
||||||
|
if use_pool:
|
||||||
|
psycopg2 = pool.manage(psycopg2, pool_size=5)
|
||||||
|
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
|
||||||
|
# If DB connection is made over TCP, then the variables
|
||||||
|
# host, user and password are required
|
||||||
|
# For local domain-socket connections, only DB name is
|
||||||
|
# needed, and everything else is in fact undefined and/or
|
||||||
|
# flat out wrong
|
||||||
|
# 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 == "localhost" or self.host == "127.0.0.1":
|
||||||
|
try:
|
||||||
|
self.connection = psycopg2.connect(database = database)
|
||||||
|
connected = True
|
||||||
|
except:
|
||||||
|
# direct connection failed so try user/pass/... version
|
||||||
|
pass
|
||||||
|
if not connected:
|
||||||
|
try:
|
||||||
|
self.connection = psycopg2.connect(host = host,
|
||||||
|
user = user,
|
||||||
|
password = password,
|
||||||
|
database = database)
|
||||||
|
except Exception, ex:
|
||||||
|
if 'Connection refused' in ex.args[0]:
|
||||||
|
# meaning eg. db not running
|
||||||
|
raise FpdbPostgresqlNoDatabase(errmsg = ex.args[0])
|
||||||
|
elif 'password authentication' in ex.args[0]:
|
||||||
|
raise FpdbPostgresqlAccessDenied(errmsg = ex.args[0])
|
||||||
|
else:
|
||||||
|
msg = ex.args[0]
|
||||||
|
print msg
|
||||||
|
raise FpdbError(msg)
|
||||||
|
elif backend == Database.SQLITE:
|
||||||
|
logging.info("Connecting to SQLite: %(database)s" % {'database':database})
|
||||||
|
import sqlite3
|
||||||
|
if use_pool:
|
||||||
|
sqlite3 = pool.manage(sqlite3, pool_size=1)
|
||||||
|
else:
|
||||||
|
logging.warning("SQLite won't work well without 'sqlalchemy' installed.")
|
||||||
|
|
||||||
|
if database != ":memory:":
|
||||||
|
if not os.path.isdir(self.config.dir_databases):
|
||||||
|
print "Creating directory: '%s'" % (self.config.dir_databases)
|
||||||
|
logging.info("Creating directory: '%s'" % (self.config.dir_databases))
|
||||||
|
os.mkdir(self.config.dir_databases)
|
||||||
|
database = os.path.join(self.config.dir_databases, database)
|
||||||
|
logging.info(" sqlite db: " + database)
|
||||||
|
self.connection = 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")
|
||||||
|
self.connection.create_function("floor", 1, math.floor)
|
||||||
|
tmp = sqlitemath()
|
||||||
|
self.connection.create_function("mod", 2, tmp.mod)
|
||||||
|
if use_numpy:
|
||||||
|
self.connection.create_aggregate("variance", 1, VARIANCE)
|
||||||
|
else:
|
||||||
|
logging.warning("Some database functions will not work without NumPy support")
|
||||||
|
else:
|
||||||
|
raise FpdbError("unrecognised database backend:"+backend)
|
||||||
|
|
||||||
|
self.cursor = self.connection.cursor()
|
||||||
|
self.cursor.execute(self.sql.query['set tx level'])
|
||||||
|
self.check_version(database=database, create=True)
|
||||||
|
|
||||||
|
|
||||||
|
def check_version(self, database, create):
|
||||||
|
self.wrongDbVersion = False
|
||||||
|
try:
|
||||||
|
self.cursor.execute("SELECT * FROM Settings")
|
||||||
|
settings = self.cursor.fetchone()
|
||||||
|
if settings[0] != DB_VERSION:
|
||||||
|
logging.error("outdated or too new database version (%s) - please recreate tables"
|
||||||
|
% (settings[0]))
|
||||||
|
self.wrongDbVersion = True
|
||||||
|
except:# _mysql_exceptions.ProgrammingError:
|
||||||
|
if database != ":memory:":
|
||||||
|
if create:
|
||||||
|
print "Failed to read settings table - recreating tables"
|
||||||
|
log.info("failed to read settings table - recreating tables")
|
||||||
|
self.recreate_tables()
|
||||||
|
self.check_version(database=database, create=False)
|
||||||
|
if not self.wrongDbVersion:
|
||||||
|
msg = "Edit your screen_name and hand history path in the supported_sites "\
|
||||||
|
+"section of the \nPreferences window (Main menu) before trying to import hands"
|
||||||
|
print "\n%s" % msg
|
||||||
|
log.warning(msg)
|
||||||
|
else:
|
||||||
|
print "Failed to read settings table - please recreate tables"
|
||||||
|
log.info("failed to read settings table - please recreate tables")
|
||||||
|
self.wrongDbVersion = True
|
||||||
|
else:
|
||||||
|
self.wrongDbVersion = True
|
||||||
|
#end def connect
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
self.fdb.db.commit()
|
self.connection.commit()
|
||||||
|
|
||||||
def rollback(self):
|
def rollback(self):
|
||||||
self.fdb.db.rollback()
|
self.connection.rollback()
|
||||||
|
|
||||||
def connected(self):
|
def connected(self):
|
||||||
return self.__connected
|
return self.__connected
|
||||||
|
@ -274,11 +453,18 @@ class Database:
|
||||||
|
|
||||||
def disconnect(self, due_to_error=False):
|
def disconnect(self, due_to_error=False):
|
||||||
"""Disconnects the DB (rolls back if param is true, otherwise commits"""
|
"""Disconnects the DB (rolls back if param is true, otherwise commits"""
|
||||||
self.fdb.disconnect(due_to_error)
|
if due_to_error:
|
||||||
|
self.connection.rollback()
|
||||||
|
else:
|
||||||
|
self.connection.commit()
|
||||||
|
self.cursor.close()
|
||||||
|
self.connection.close()
|
||||||
|
|
||||||
def reconnect(self, due_to_error=False):
|
def reconnect(self, due_to_error=False):
|
||||||
"""Reconnects the DB"""
|
"""Reconnects the DB"""
|
||||||
self.fdb.reconnect(due_to_error=False)
|
#print "started reconnect"
|
||||||
|
self.disconnect(due_to_error)
|
||||||
|
self.connect(self.backend, self.host, self.database, self.user, self.password)
|
||||||
|
|
||||||
def get_backend_name(self):
|
def get_backend_name(self):
|
||||||
"""Returns the name of the currently used backend"""
|
"""Returns the name of the currently used backend"""
|
||||||
|
@ -291,6 +477,9 @@ class Database:
|
||||||
else:
|
else:
|
||||||
raise FpdbError("invalid backend")
|
raise FpdbError("invalid backend")
|
||||||
|
|
||||||
|
def get_db_info(self):
|
||||||
|
return (self.host, self.database, self.user, self.password)
|
||||||
|
|
||||||
def get_table_name(self, hand_id):
|
def get_table_name(self, hand_id):
|
||||||
c = self.connection.cursor()
|
c = self.connection.cursor()
|
||||||
c.execute(self.sql.query['get_table_name'], (hand_id, ))
|
c.execute(self.sql.query['get_table_name'], (hand_id, ))
|
||||||
|
@ -846,6 +1035,7 @@ class Database:
|
||||||
self.create_tables()
|
self.create_tables()
|
||||||
self.createAllIndexes()
|
self.createAllIndexes()
|
||||||
self.commit()
|
self.commit()
|
||||||
|
print "Finished recreating tables"
|
||||||
log.info("Finished recreating tables")
|
log.info("Finished recreating tables")
|
||||||
#end def recreate_tables
|
#end def recreate_tables
|
||||||
|
|
||||||
|
@ -1111,7 +1301,7 @@ class Database:
|
||||||
|
|
||||||
def fillDefaultData(self):
|
def fillDefaultData(self):
|
||||||
c = self.get_cursor()
|
c = self.get_cursor()
|
||||||
c.execute("INSERT INTO Settings (version) VALUES (118);")
|
c.execute("INSERT INTO Settings (version) VALUES (%s);" % (DB_VERSION))
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('Full Tilt Poker', 'USD')")
|
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 ('PokerStars', 'USD')")
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('Everleaf', 'USD')")
|
c.execute("INSERT INTO Sites (name,currency) VALUES ('Everleaf', 'USD')")
|
||||||
|
@ -1267,7 +1457,7 @@ class Database:
|
||||||
try:
|
try:
|
||||||
self.get_cursor().execute(self.sql.query['lockForInsert'])
|
self.get_cursor().execute(self.sql.query['lockForInsert'])
|
||||||
except:
|
except:
|
||||||
print "Error during fdb.lock_for_insert:", str(sys.exc_value)
|
print "Error during lock_for_insert:", str(sys.exc_value)
|
||||||
#end def lock_for_insert
|
#end def lock_for_insert
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
|
@ -1286,6 +1476,7 @@ class Database:
|
||||||
p['tableName'],
|
p['tableName'],
|
||||||
p['gameTypeId'],
|
p['gameTypeId'],
|
||||||
p['siteHandNo'],
|
p['siteHandNo'],
|
||||||
|
0, # tourneyId: 0 means not a tourney hand
|
||||||
p['handStart'],
|
p['handStart'],
|
||||||
datetime.today(), #importtime
|
datetime.today(), #importtime
|
||||||
p['seats'],
|
p['seats'],
|
||||||
|
|
|
@ -27,8 +27,8 @@ import gobject
|
||||||
#import pokereval
|
#import pokereval
|
||||||
|
|
||||||
import Configuration
|
import Configuration
|
||||||
import fpdb_db
|
import Database
|
||||||
import FpdbSQLQueries
|
import SQL
|
||||||
import Charset
|
import Charset
|
||||||
|
|
||||||
class Filters(threading.Thread):
|
class Filters(threading.Thread):
|
||||||
|
@ -790,10 +790,10 @@ def main(argv=None):
|
||||||
config = Configuration.Config()
|
config = Configuration.Config()
|
||||||
db = None
|
db = None
|
||||||
|
|
||||||
db = fpdb_db.fpdb_db()
|
db = Database.Database()
|
||||||
db.do_connect(config)
|
db.do_connect(config)
|
||||||
|
|
||||||
qdict = FpdbSQLQueries.FpdbSQLQueries(db.get_backend_name())
|
qdict = SQL.SQL(db.get_backend_name())
|
||||||
|
|
||||||
i = Filters(db, config, qdict)
|
i = Filters(db, config, qdict)
|
||||||
main_window = gtk.Window()
|
main_window = gtk.Window()
|
||||||
|
|
|
@ -300,7 +300,6 @@ if __name__== "__main__":
|
||||||
(options, argv) = parser.parse_args()
|
(options, argv) = parser.parse_args()
|
||||||
|
|
||||||
config = Configuration.Config()
|
config = Configuration.Config()
|
||||||
# db = fpdb_db.fpdb_db()
|
|
||||||
|
|
||||||
settings = {}
|
settings = {}
|
||||||
settings['minPrint'] = options.minPrint
|
settings['minPrint'] = options.minPrint
|
||||||
|
|
|
@ -27,7 +27,6 @@ from time import time, strftime
|
||||||
import Card
|
import Card
|
||||||
import fpdb_import
|
import fpdb_import
|
||||||
import Database
|
import Database
|
||||||
import fpdb_db
|
|
||||||
import Filters
|
import Filters
|
||||||
import Charset
|
import Charset
|
||||||
|
|
||||||
|
|
|
@ -588,8 +588,8 @@ Left-Drag to Move"
|
||||||
</hhcs>
|
</hhcs>
|
||||||
|
|
||||||
<supported_databases>
|
<supported_databases>
|
||||||
<database db_name="fpdb" db_server="mysql" db_ip="localhost" db_user="fpdb" db_pass="YOUR MYSQL PASSWORD"></database>
|
<!-- <database db_name="fpdb" db_server="mysql" db_ip="localhost" db_user="fpdb" db_pass="YOUR MYSQL PASSWORD"></database> -->
|
||||||
<!-- <database db_ip="localhost" db_name="fpdb" db_pass="fpdb" db_server="sqlite" db_user="fpdb"/> -->
|
<database db_ip="localhost" db_server="sqlite" db_name="fpdb.db3" db_user="fpdb" db_pass="fpdb"/>
|
||||||
</supported_databases>
|
</supported_databases>
|
||||||
|
|
||||||
</FreePokerToolsConfig>
|
</FreePokerToolsConfig>
|
||||||
|
|
|
@ -205,7 +205,7 @@ dealt whether they were seen in a 'dealt to' line
|
||||||
def insert(self, db):
|
def insert(self, db):
|
||||||
""" Function to insert Hand into database
|
""" Function to insert Hand into database
|
||||||
Should not commit, and do minimal selects. Callers may want to cache commits
|
Should not commit, and do minimal selects. Callers may want to cache commits
|
||||||
db: a connected fpdb_db object"""
|
db: a connected Database object"""
|
||||||
|
|
||||||
|
|
||||||
self.stats.getStats(self)
|
self.stats.getStats(self)
|
||||||
|
|
|
@ -58,6 +58,27 @@ class Sql:
|
||||||
self.query['drop_table'] = """DROP TABLE IF EXISTS """
|
self.query['drop_table'] = """DROP TABLE IF EXISTS """
|
||||||
|
|
||||||
|
|
||||||
|
##################################################################
|
||||||
|
# Set transaction isolation level
|
||||||
|
##################################################################
|
||||||
|
|
||||||
|
if db_server == 'mysql' or db_server == 'postgresql':
|
||||||
|
self.query['set tx level'] = """SET SESSION TRANSACTION
|
||||||
|
ISOLATION LEVEL READ COMMITTED"""
|
||||||
|
elif db_server == 'sqlite':
|
||||||
|
self.query['set tx level'] = """ """
|
||||||
|
|
||||||
|
|
||||||
|
################################
|
||||||
|
# Select basic info
|
||||||
|
################################
|
||||||
|
|
||||||
|
self.query['getSiteId'] = """SELECT id from Sites where name = %s"""
|
||||||
|
|
||||||
|
self.query['getGames'] = """SELECT DISTINCT category from Gametypes"""
|
||||||
|
|
||||||
|
self.query['getLimits'] = """SELECT DISTINCT bigBlind from Gametypes ORDER by bigBlind DESC"""
|
||||||
|
|
||||||
################################
|
################################
|
||||||
# Create Settings
|
# Create Settings
|
||||||
################################
|
################################
|
||||||
|
@ -214,6 +235,7 @@ class Sql:
|
||||||
id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
|
id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
|
||||||
tableName VARCHAR(22) NOT NULL,
|
tableName VARCHAR(22) NOT NULL,
|
||||||
siteHandNo BIGINT NOT NULL,
|
siteHandNo BIGINT NOT NULL,
|
||||||
|
tourneyId INT UNSIGNED NOT NULL,
|
||||||
gametypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
|
gametypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
|
||||||
handStart DATETIME NOT NULL,
|
handStart DATETIME NOT NULL,
|
||||||
importTime DATETIME NOT NULL,
|
importTime DATETIME NOT NULL,
|
||||||
|
@ -249,6 +271,7 @@ class Sql:
|
||||||
id BIGSERIAL, PRIMARY KEY (id),
|
id BIGSERIAL, PRIMARY KEY (id),
|
||||||
tableName VARCHAR(22) NOT NULL,
|
tableName VARCHAR(22) NOT NULL,
|
||||||
siteHandNo BIGINT NOT NULL,
|
siteHandNo BIGINT NOT NULL,
|
||||||
|
tourneyId INT NOT NULL,
|
||||||
gametypeId INT NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
|
gametypeId INT NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
|
||||||
handStart timestamp without time zone NOT NULL,
|
handStart timestamp without time zone NOT NULL,
|
||||||
importTime timestamp without time zone NOT NULL,
|
importTime timestamp without time zone NOT NULL,
|
||||||
|
@ -283,6 +306,7 @@ class Sql:
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
tableName TEXT(22) NOT NULL,
|
tableName TEXT(22) NOT NULL,
|
||||||
siteHandNo INT NOT NULL,
|
siteHandNo INT NOT NULL,
|
||||||
|
tourneyId INT NOT NULL,
|
||||||
gametypeId INT NOT NULL,
|
gametypeId INT NOT NULL,
|
||||||
handStart REAL NOT NULL,
|
handStart REAL NOT NULL,
|
||||||
importTime REAL NOT NULL,
|
importTime REAL NOT NULL,
|
||||||
|
@ -3437,6 +3461,7 @@ class Sql:
|
||||||
tablename,
|
tablename,
|
||||||
gametypeid,
|
gametypeid,
|
||||||
sitehandno,
|
sitehandno,
|
||||||
|
tourneyId,
|
||||||
handstart,
|
handstart,
|
||||||
importtime,
|
importtime,
|
||||||
seats,
|
seats,
|
||||||
|
@ -3467,7 +3492,7 @@ class Sql:
|
||||||
VALUES
|
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)"""
|
||||||
|
|
||||||
|
|
||||||
self.query['store_hands_players'] = """INSERT INTO HandsPlayers (
|
self.query['store_hands_players'] = """INSERT INTO HandsPlayers (
|
||||||
|
|
|
@ -185,7 +185,7 @@ class Tourney(object):
|
||||||
def old_insert_from_Hand(self, db):
|
def old_insert_from_Hand(self, db):
|
||||||
""" Function to insert Hand into database
|
""" Function to insert Hand into database
|
||||||
Should not commit, and do minimal selects. Callers may want to cache commits
|
Should not commit, and do minimal selects. Callers may want to cache commits
|
||||||
db: a connected fpdb_db object"""
|
db: a connected Database object"""
|
||||||
# TODO:
|
# TODO:
|
||||||
# Players - base playerid and siteid tuple
|
# Players - base playerid and siteid tuple
|
||||||
sqlids = db.getSqlPlayerIDs([p[1] for p in self.players], self.siteId)
|
sqlids = db.getSqlPlayerIDs([p[1] for p in self.players], self.siteId)
|
||||||
|
|
|
@ -112,7 +112,6 @@ import GuiGraphViewer
|
||||||
import GuiSessionViewer
|
import GuiSessionViewer
|
||||||
import SQL
|
import SQL
|
||||||
import Database
|
import Database
|
||||||
import FpdbSQLQueries
|
|
||||||
import Configuration
|
import Configuration
|
||||||
import Exceptions
|
import Exceptions
|
||||||
|
|
||||||
|
|
|
@ -16,207 +16,6 @@
|
||||||
#In the "official" distribution you can find the license in
|
#In the "official" distribution you can find the license in
|
||||||
#agpl-3.0.txt in the docs folder of the package.
|
#agpl-3.0.txt in the docs folder of the package.
|
||||||
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
import logging
|
|
||||||
import math
|
|
||||||
from time import time, strftime
|
|
||||||
from Exceptions import *
|
|
||||||
|
|
||||||
try:
|
|
||||||
import sqlalchemy.pool as pool
|
|
||||||
use_pool = True
|
|
||||||
except ImportError:
|
|
||||||
logging.info("Not using sqlalchemy connection pool.")
|
|
||||||
use_pool = False
|
|
||||||
|
|
||||||
try:
|
|
||||||
from numpy import var
|
|
||||||
use_numpy = True
|
|
||||||
except ImportError:
|
|
||||||
logging.info("Not using numpy to define variance in sqlite.")
|
|
||||||
use_numpy = False
|
|
||||||
|
|
||||||
import FpdbSQLQueries
|
|
||||||
import Configuration
|
|
||||||
|
|
||||||
# Variance created as sqlite has a bunch of undefined aggregate functions.
|
|
||||||
|
|
||||||
class VARIANCE:
|
|
||||||
def __init__(self):
|
|
||||||
self.store = []
|
|
||||||
|
|
||||||
def step(self, value):
|
|
||||||
self.store.append(value)
|
|
||||||
|
|
||||||
def finalize(self):
|
|
||||||
return float(var(self.store))
|
|
||||||
|
|
||||||
class sqlitemath:
|
|
||||||
def mod(self, a, b):
|
|
||||||
return a%b
|
|
||||||
|
|
||||||
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 = {}
|
|
||||||
#end def __init__
|
|
||||||
|
|
||||||
def do_connect(self, config=None):
|
|
||||||
"""Connects a database using information in config"""
|
|
||||||
if config is None:
|
|
||||||
raise FpdbError('Configuration not defined')
|
|
||||||
|
|
||||||
self.settings = {}
|
|
||||||
self.settings['os'] = "linuxmac" if os.name != "nt" else "windows"
|
|
||||||
|
|
||||||
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,
|
|
||||||
user=None, password=None):
|
|
||||||
"""Connects a database with the given parameters"""
|
|
||||||
if backend is None:
|
|
||||||
raise FpdbError('Database backend not defined')
|
|
||||||
self.backend = backend
|
|
||||||
self.host = host
|
|
||||||
self.user = user
|
|
||||||
self.password = password
|
|
||||||
self.database = database
|
|
||||||
if backend == fpdb_db.MYSQL_INNODB:
|
|
||||||
import MySQLdb
|
|
||||||
if use_pool:
|
|
||||||
MySQLdb = pool.manage(MySQLdb, pool_size=5)
|
|
||||||
try:
|
|
||||||
self.db = MySQLdb.connect(host=host, user=user, passwd=password, db=database, use_unicode=True)
|
|
||||||
#TODO: Add port option
|
|
||||||
except MySQLdb.Error, ex:
|
|
||||||
if ex.args[0] == 1045:
|
|
||||||
raise FpdbMySQLAccessDenied(ex.args[0], ex.args[1])
|
|
||||||
elif ex.args[0] == 2002 or ex.args[0] == 2003: # 2002 is no unix socket, 2003 is no tcp socket
|
|
||||||
raise FpdbMySQLNoDatabase(ex.args[0], ex.args[1])
|
|
||||||
else:
|
|
||||||
print "*** WARNING UNKNOWN MYSQL ERROR", ex
|
|
||||||
elif backend == fpdb_db.PGSQL:
|
|
||||||
import psycopg2
|
|
||||||
import psycopg2.extensions
|
|
||||||
if use_pool:
|
|
||||||
psycopg2 = pool.manage(psycopg2, pool_size=5)
|
|
||||||
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
|
|
||||||
# If DB connection is made over TCP, then the variables
|
|
||||||
# host, user and password are required
|
|
||||||
# For local domain-socket connections, only DB name is
|
|
||||||
# needed, and everything else is in fact undefined and/or
|
|
||||||
# flat out wrong
|
|
||||||
# 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 == "localhost" or self.host == "127.0.0.1":
|
|
||||||
try:
|
|
||||||
self.db = psycopg2.connect(database = database)
|
|
||||||
connected = True
|
|
||||||
except:
|
|
||||||
# direct connection failed so try user/pass/... version
|
|
||||||
pass
|
|
||||||
if not connected:
|
|
||||||
try:
|
|
||||||
self.db = psycopg2.connect(host = host,
|
|
||||||
user = user,
|
|
||||||
password = password,
|
|
||||||
database = database)
|
|
||||||
except Exception, ex:
|
|
||||||
if 'Connection refused' in ex.args[0]:
|
|
||||||
# meaning eg. db not running
|
|
||||||
raise FpdbPostgresqlNoDatabase(errmsg = ex.args[0])
|
|
||||||
elif 'password authentication' in ex.args[0]:
|
|
||||||
raise FpdbPostgresqlAccessDenied(errmsg = ex.args[0])
|
|
||||||
else:
|
|
||||||
msg = ex.args[0]
|
|
||||||
print msg
|
|
||||||
raise FpdbError(msg)
|
|
||||||
elif backend == fpdb_db.SQLITE:
|
|
||||||
logging.info("Connecting to SQLite:%(database)s" % {'database':database})
|
|
||||||
import sqlite3
|
|
||||||
if use_pool:
|
|
||||||
sqlite3 = pool.manage(sqlite3, pool_size=1)
|
|
||||||
else:
|
|
||||||
logging.warning("SQLite won't work well without 'sqlalchemy' installed.")
|
|
||||||
|
|
||||||
if not os.path.isdir(Configuration.DIR_DATABASES) and not database == ":memory:":
|
|
||||||
print "Creating directory: '%s'" % (Configuration.DIR_DATABASES)
|
|
||||||
os.mkdir(Configuration.DIR_DATABASES)
|
|
||||||
database = os.path.join(Configuration.DIR_DATABASES, database)
|
|
||||||
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")
|
|
||||||
self.db.create_function("floor", 1, math.floor)
|
|
||||||
tmp = sqlitemath()
|
|
||||||
self.db.create_function("mod", 2, tmp.mod)
|
|
||||||
if use_numpy:
|
|
||||||
self.db.create_aggregate("variance", 1, VARIANCE)
|
|
||||||
else:
|
|
||||||
logging.warning("Some database functions will not work without NumPy support")
|
|
||||||
else:
|
|
||||||
raise FpdbError("unrecognised database backend:"+backend)
|
|
||||||
|
|
||||||
self.cursor = self.db.cursor()
|
|
||||||
# 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")
|
|
||||||
settings = self.cursor.fetchone()
|
|
||||||
if settings[0] != 118:
|
|
||||||
print "outdated or too new database version - please recreate tables"
|
|
||||||
self.wrongDbVersion = True
|
|
||||||
except:# _mysql_exceptions.ProgrammingError:
|
|
||||||
if database != ":memory:": print "failed to read settings table - please recreate tables"
|
|
||||||
self.wrongDbVersion = True
|
|
||||||
#end def connect
|
|
||||||
|
|
||||||
def disconnect(self, due_to_error=False):
|
|
||||||
"""Disconnects the DB"""
|
|
||||||
if due_to_error:
|
|
||||||
self.db.rollback()
|
|
||||||
else:
|
|
||||||
self.db.commit()
|
|
||||||
self.cursor.close()
|
|
||||||
self.db.close()
|
|
||||||
#end def disconnect
|
|
||||||
|
|
||||||
def reconnect(self, due_to_error=False):
|
|
||||||
"""Reconnects the DB"""
|
|
||||||
#print "started fpdb_db.reconnect"
|
|
||||||
self.disconnect(due_to_error)
|
|
||||||
self.connect(self.backend, self.host, self.database, self.user, self.password)
|
|
||||||
|
|
||||||
def get_backend_name(self):
|
|
||||||
"""Returns the name of the currently used backend"""
|
|
||||||
if self.backend==2:
|
|
||||||
return "MySQL InnoDB"
|
|
||||||
elif self.backend==3:
|
|
||||||
return "PostgreSQL"
|
|
||||||
elif self.backend==4:
|
|
||||||
return "SQLite"
|
|
||||||
else:
|
|
||||||
raise FpdbError("invalid backend")
|
|
||||||
#end def get_backend_name
|
|
||||||
|
|
||||||
def get_db_info(self):
|
|
||||||
return (self.host, self.database, self.user, self.password)
|
|
||||||
#end def get_db_info
|
|
||||||
|
|
||||||
#end class fpdb_db
|
#end class fpdb_db
|
||||||
|
|
|
@ -35,7 +35,6 @@ import gtk
|
||||||
|
|
||||||
# fpdb/FreePokerTools modules
|
# fpdb/FreePokerTools modules
|
||||||
|
|
||||||
import fpdb_db
|
|
||||||
import Database
|
import Database
|
||||||
import Configuration
|
import Configuration
|
||||||
import Exceptions
|
import Exceptions
|
||||||
|
|
|
@ -19,8 +19,11 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
# sys.path[0] holds the dir run_fpdb.py was in
|
# sys.path[0] holds the directory run_fpdb.py is in
|
||||||
sys.path[0] = sys.path[0]+os.sep+"pyfpdb"
|
sys.path[0] = sys.path[0]+os.sep+"pyfpdb"
|
||||||
|
os.chdir(sys.path[0])
|
||||||
|
#print "sys.path[0] =", sys.path[0], "cwd =", os.getcwd()
|
||||||
|
|
||||||
|
|
||||||
import fpdb
|
import fpdb
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user