|
|
cbf076 |
|
|
|
cbf076 |
import datetime
|
|
|
cbf076 |
import traceback
|
|
|
4656ad |
import MySQLdb.cursors
|
|
|
4656ad |
|
|
|
4656ad |
from db.parser import parse
|
|
|
4656ad |
|
|
|
4656ad |
|
|
|
4656ad |
class Cursor:
|
|
|
4656ad |
def __init__(self, connection, internal):
|
|
|
4656ad |
self.connection = connection
|
|
|
4656ad |
self.typebytype = self.connection.pool.server.dbtypebytype
|
|
|
4656ad |
self.typebychar = self.connection.pool.server.dbtypebychar
|
|
|
4656ad |
self.internal = internal
|
|
|
4656ad |
self.entered = None
|
|
|
4656ad |
self.iterator = None
|
|
|
4656ad |
|
|
|
4656ad |
def get_internal(self):
|
|
|
4656ad |
return self.internal if self.entered is None else self.entered
|
|
|
4656ad |
|
|
|
4656ad |
def __enter__(self):
|
|
|
4656ad |
self.entered = self.internal.__enter__()
|
|
|
4656ad |
return self
|
|
|
4656ad |
|
|
|
4656ad |
def __exit__(self, exc_type, exc_value, traceback):
|
|
|
4656ad |
self.entered.__exit__(exc_type, exc_value, traceback)
|
|
|
4656ad |
self.entered = None
|
|
|
4656ad |
|
|
|
4656ad |
def __iter__(self):
|
|
|
4656ad |
self.iterator = iter(self.get_internal())
|
|
|
4656ad |
return self
|
|
|
4656ad |
|
|
|
4656ad |
def __next__(self):
|
|
|
4656ad |
data = next(self.iterator)
|
|
|
4656ad |
if type(data) is dict:
|
|
|
4656ad |
for k, v in data.items():
|
|
|
4656ad |
t = self.typebytype.get( type(v) )
|
|
|
4656ad |
if t: data[k] = t.from_db(self, v)
|
|
|
4656ad |
else:
|
|
|
4656ad |
orig = data
|
|
|
4656ad |
data = list()
|
|
|
4656ad |
for v in orig:
|
|
|
4656ad |
t = self.typebytype.get( type(v) )
|
|
|
4656ad |
data.append(t.from_db(self, v) if t else v)
|
|
|
4656ad |
return data
|
|
|
4656ad |
|
|
|
4656ad |
def execute(self, sql = None, *args, **kvargs):
|
|
|
4656ad |
if args or kvargs:
|
|
|
4656ad |
sql = parse(self.typebychar, self.connection, sql, *args, **kvargs)
|
|
|
4656ad |
self.get_internal().execute(sql)
|
|
|
cbf076 |
|
|
|
cbf076 |
|
|
|
cbf076 |
class Connection:
|
|
|
cbf076 |
def __init__(self, pool, internal, readonly = True):
|
|
|
cbf076 |
self.pool = pool
|
|
|
cbf076 |
self.internal = internal
|
|
|
cbf076 |
self.readonly = readonly
|
|
|
cbf076 |
self.finished = True
|
|
|
cbf076 |
self.begin()
|
|
|
cbf076 |
|
|
|
4656ad |
def cursor(self, as_dict = False):
|
|
|
cbf076 |
assert not self.finished
|
|
|
4656ad |
cursorclass = MySQLdb.cursors.DictCursor if as_dict else MySQLdb.cursors.Cursor
|
|
|
4656ad |
cursor = Cursor(self, self.internal.cursor(cursorclass))
|
|
|
4656ad |
return cursor
|
|
|
4656ad |
def cursor_list(self):
|
|
|
4656ad |
return self.cursor(False)
|
|
|
4656ad |
def cursor_dict(self):
|
|
|
4656ad |
return self.cursor(True)
|
|
|
4656ad |
|
|
|
4656ad |
def query(self, as_dict, sql = None, *args, **kvargs):
|
|
|
4656ad |
with self.cursor(as_dict) as cursor:
|
|
|
4656ad |
cursor.execute(sql, *args, **kvargs)
|
|
|
4656ad |
return list(cursor)
|
|
|
4656ad |
def query_list(self, sql = None, *args, **kvargs):
|
|
|
4656ad |
return self.query(False, sql, *args, **kvargs)
|
|
|
4656ad |
def query_dict(self, sql = None, *args, **kvargs):
|
|
|
4656ad |
return self.query(True, sql, *args, **kvargs)
|
|
|
4656ad |
|
|
|
4656ad |
def execute(self, sql = None, *args, **kvargs):
|
|
|
4656ad |
with self.cursor() as cursor:
|
|
|
4656ad |
cursor.execute(sql, *args, **kvargs)
|
|
|
cbf076 |
|
|
|
cbf076 |
def insert_id(self, *args, **kwargs):
|
|
|
cbf076 |
assert not self.finished
|
|
|
cbf076 |
return self.internal.insert_id(*args, **kwargs)
|
|
|
cbf076 |
|
|
|
cbf076 |
def escape(self, *args, **kwargs):
|
|
|
cbf076 |
r = self.internal.escape(*args, **kwargs)
|
|
|
cbf076 |
return r.decode("utf8") if type(r) is bytes else r
|
|
|
cbf076 |
|
|
|
cbf076 |
def escape_string(self, *args, **kwargs):
|
|
|
cbf076 |
r = self.internal.escape_string(*args, **kwargs)
|
|
|
cbf076 |
return r.decode("utf8") if type(r) is bytes else r
|
|
|
cbf076 |
|
|
|
cbf076 |
def begin(self):
|
|
|
cbf076 |
assert self.finished
|
|
|
cbf076 |
self.finished = False
|
|
|
cbf076 |
if self.readonly:
|
|
|
4656ad |
self.execute("SET TRANSACTION ISOLATION LEVEL REPEATABLE READ")
|
|
|
4656ad |
self.execute("START TRANSACTION READ ONLY, WITH CONSISTENT SNAPSHOT")
|
|
|
cbf076 |
else:
|
|
|
4656ad |
self.execute("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE")
|
|
|
4656ad |
self.execute("START TRANSACTION READ WRITE, WITH CONSISTENT SNAPSHOT")
|
|
|
4656ad |
self.now = datetime.datetime.now(datetime.timezone.utc)
|
|
|
cbf076 |
|
|
|
cbf076 |
def commit(self):
|
|
|
cbf076 |
assert not self.finished
|
|
|
cbf076 |
self.internal.commit()
|
|
|
cbf076 |
self.finished = True
|
|
|
cbf076 |
|
|
|
cbf076 |
def rollback(self):
|
|
|
cbf076 |
assert not self.finished
|
|
|
cbf076 |
self.internal.rollback()
|
|
|
cbf076 |
self.finished = True
|
|
|
cbf076 |
|
|
|
cbf076 |
def release(self):
|
|
|
cbf076 |
if not self.finished:
|
|
|
cbf076 |
try: self.rollback()
|
|
|
cbf076 |
except Exception as e:
|
|
|
cbf076 |
print(traceback.format_exc())
|
|
|
cbf076 |
print(e)
|