[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [kajongg/sid] src: Ruleset: better SQL. Query: Do not repeat on failure.
From: Wolfgang Rohdewald <wolfgang () rohdewald ! de>
Date: 2013-10-31 21:21:08
Message-ID: E1Vbzfw-0002lj-La () scm ! kde ! org
[Download RAW message or body]
Git commit afeebc695ed4f5c8b798f80230855206574a0984 by Wolfgang Rohdewald.
Committed on 30/10/2013 at 11:57.
Pushed by wrohdewald into branch 'sid'.
Ruleset: better SQL. Query: Do not repeat on failure.
- if the hash already exists in DB, use its rulesetId
- if getting a rulesetId fails because of concurrent clients, repeat the entire \
transaction and not the single Query
- use only one big SQL statement for writing all rules. This is much faster.
- editing a rule: Do not delete/insert but update
M +28 -29 src/query.py
M +27 -18 src/rule.py
M +1 -1 src/util.py
http://commits.kde.org/kajongg/afeebc695ed4f5c8b798f80230855206574a0984
diff --git a/src/query.py b/src/query.py
index a05f8e7..91abdec 100644
--- a/src/query.py
+++ b/src/query.py
@@ -23,13 +23,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA \
02110-1301, USA.
"""
-import os, sys, time, datetime, traceback, random
+import os, sys, datetime, traceback, random
from collections import defaultdict
from PyQt4.QtCore import QVariant, QString
-from util import logInfo, logWarning, logException, logDebug, appdataDir, m18ncE, \
xToUtf8 +from util import logInfo, logWarning, logException, logError, logDebug, \
appdataDir, m18ncE, xToUtf8 from common import Options, Internal, Debug, IntDict
from PyQt4.QtSql import QSqlQuery, QSqlDatabase, QSql
+class QueryException(Exception):
+ """as the name says"""
+ def __init__(self, msg):
+ Exception.__init__(self, msg)
class DBHandle(QSqlDatabase):
"""a handle with our preferred configuration"""
@@ -407,7 +411,7 @@ class Query(object):
localServerName = m18ncE('kajongg name for local game server', 'Local Game')
- def __init__(self, cmdList, args=None, dbHandle=None, silent=False, \
mayFail=False): + def __init__(self, cmdList, args=None, dbHandle=None, \
silent=False, mayFail=False, failSilent=False):
"""we take a list of sql statements. Only the last one is allowed to be
a select statement.
Do prepared queries by passing a single query statement in cmdList
@@ -426,39 +430,34 @@ class Query(object):
cmdList = list([cmdList])
self.cmdList = cmdList
for cmd in cmdList:
- retryCount = 0
- while retryCount < 100:
- self.lastError = None
- if preparedQuery:
- self.query.prepare(cmd)
- if not isinstance(args[0], list):
- args = list([args])
- for dataSet in args:
- if not silent:
- _, utf8Args = xToUtf8(u'', dataSet)
- logDebug("{cmd} [{args}]".format(cmd=cmd, args=", \
".join(utf8Args)))
- for value in dataSet:
- self.query.addBindValue(QVariant(value))
- self.success = self.query.exec_()
- if not self.success:
- break
- else:
+ self.lastError = None
+ if preparedQuery:
+ self.query.prepare(cmd)
+ if not isinstance(args[0], list):
+ args = list([args])
+ for dataSet in args:
if not silent:
- logDebug('%s %s' % (self.dbHandle.name, cmd))
- self.success = self.query.exec_(cmd)
- if self.success or self.query.lastError().number() not in (5, 6):
- # 5: database locked, 6: table locked. Where can we get symbols \
for this?
- break
- time.sleep(0.1)
- retryCount += 1
+ _, utf8Args = xToUtf8(u'', dataSet)
+ logDebug("{cmd} [{args}]".format(cmd=cmd, args=", \
".join(utf8Args))) + for value in dataSet:
+ self.query.addBindValue(QVariant(value))
+ self.success = self.query.exec_()
+ if not self.success:
+ break
+ else:
+ if not silent:
+ logDebug('%s %s' % (self.dbHandle.name, cmd))
+ self.success = self.query.exec_(cmd)
if not self.success:
self.lastError = unicode(self.query.lastError().text())
self.msg = 'ERROR in %s: %s' % (self.dbHandle.databaseName(), \
self.lastError) if mayFail:
- if not silent:
+ if not failSilent:
logDebug(self.msg)
else:
- logException(self.msg)
+ if not failSilent:
+ logError(self.msg)
+ raise QueryException(self.msg)
return
self.records = None
self.fields = None
diff --git a/src/rule.py b/src/rule.py
index 7d496ba..35a672e 100644
--- a/src/rule.py
+++ b/src/rule.py
@@ -27,7 +27,7 @@ from hashlib import md5
from PyQt4.QtCore import QVariant
from util import m18n, m18nc, m18nE, english, logException
-from query import Query, Transaction
+from query import Query, QueryException, Transaction
import rulecode
@@ -573,30 +573,39 @@ into a situation where you have to pay a penalty"""))
"""update rule in database"""
self.__hash = None # invalidate, will be recomputed when needed
with Transaction():
- Query("DELETE FROM rule WHERE ruleset=? and name=?", \
list([self.rulesetId, english(rule.name)]))
- self.saveRule(rule)
+ record = self.ruleRecord(rule)
+ Query("UPDATE rule SET name=?, definition=?, points=?, doubles=?, \
limits=?, parameter=? " + "WHERE ruleset=? AND list=? AND \
position=?", + record[3:] + record[:3])
Query("UPDATE ruleset SET hash=? WHERE id=?", list([self.hash, \
self.rulesetId]))
- def saveRule(self, rule):
- """save only rule in database"""
- Query('INSERT INTO rule(ruleset, list, position, name, definition, '
- 'points, doubles, limits, parameter)'
- ' VALUES(?,?,?,?,?,?,?,?,?)',
- self.ruleRecord(rule))
-
def save(self, minus=False):
"""save the ruleset to the database.
- It always gets a new id, as it does not yet exist in database.
+ If it does not yet exist in database, give it a new id
If the name already exists in the database, also give it a new name"""
- assert self.rulesetId == 0, self
- with Transaction():
- self.rulesetId, self.name = self._newKey(minus)
- Query('INSERT INTO ruleset(id,name,hash,description) VALUES(?,?,?,?)',
- list([self.rulesetId, english(self.name), self.hash, \
self.description])) + for _ in range(10):
+ try:
+ qData = Query("select id from ruleset where hash=?", \
list([self.hash])).records + if qData:
+ # is already in database
+ self.rulesetId = qData[0][0]
+ return
+ with Transaction():
+ self.rulesetId, self.name = self._newKey(minus)
+ Query('INSERT INTO ruleset(id,name,hash,description) \
VALUES(?,?,?,?)', + list([self.rulesetId, english(self.name), \
self.hash, self.description]), + failSilent=True)
+ cmd = 'INSERT INTO rule(ruleset, list, position, name, \
definition, ' \ + 'points, doubles, limits, parameter) \
VALUES {}'.format( + ', '.join(['(?,?,?,?,?,?,?,?,?)'] * \
len(self.allRules))) + args = sum((list(self.ruleRecord(x)) for x \
in self.allRules), []) + Query(cmd, args)
+ except QueryException:
+ pass
+ else:
+ break
# do not put this into the transaction, keep it as short as possible. \
sqlite3/Qt
# has problems if two processes are trying to do the same here (kajonggtest)
- for rule in self.allRules:
- self.saveRule(rule)
@staticmethod
def availableRulesets():
diff --git a/src/util.py b/src/util.py
index 14f39f6..8f17c81 100644
--- a/src/util.py
+++ b/src/util.py
@@ -227,7 +227,7 @@ def logWarning(msg, withGamePrefix=True):
def logException(exception, withGamePrefix=True):
"""logs error message and re-raises exception"""
- logMessage(exception, logging.ERROR, True, showStack=True, \
withGamePrefix=withGamePrefix) + logError(exception, \
withGamePrefix=withGamePrefix) if isinstance(exception, (str, unicode)):
msg = exception.encode('utf-8', 'replace')
exception = Exception(msg)
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic