cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# -*- coding: utf-8 -*-
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# $Id$
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync"""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncTest Manager - Database Interface.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync"""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync__copyright__ = \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync"""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncCopyright (C) 2012-2014 Oracle Corporation
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncThis file is part of VirtualBox Open Source Edition (OSE), as
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncavailable from http://www.virtualbox.org. This file is free software;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncyou can redistribute it and/or modify it under the terms of the GNU
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncGeneral Public License (GPL) as published by the Free Software
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncFoundation, in version 2 as it comes in the "COPYING" file of the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncVirtualBox OSE distribution. VirtualBox OSE is distributed in the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsynchope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncThe contents of this file may alternatively be used under the terms
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncof the Common Development and Distribution License Version 1.0
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync(CDDL) only, as it comes in the "COPYING.CDDL" file of the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncVirtualBox OSE distribution, in which case the provisions of the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncCDDL are applicable instead of those of the GPL.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncYou may elect to license modified versions of this file under the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncterms and conditions of either the GPL or the CDDL or both.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync"""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync__version__ = "$Revision$"
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# Standard python imports.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncimport datetime;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncimport os;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncimport psycopg2;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncimport psycopg2.extensions;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncimport sys;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# Validation Kit imports.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom common import utils, webutils;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager import config;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# Fix psycho unicode handling in psycopg2 with python 2.x.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncif sys.version_info[0] < 3:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync psycopg2.extensions.register_type(psycopg2.extensions.UNICODE);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncdef isDbTimestampInfinity(tsValue):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Checks if tsValue is an infinity timestamp.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ## @todo improve this test...
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return tsValue.year >= 9999;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncdef isDbTimestamp(oValue):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Checks if oValue is a DB timestamp object.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if isinstance(oValue, datetime.datetime):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return True;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if utils.isString(oValue):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ## @todo detect strings as well.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return False;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return getattr(oValue, 'pydatetime', None) != None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncdef dbTimestampToDatetime(oValue):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Converts a database timestamp to a datetime instance.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if isinstance(oValue, datetime.datetime):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return oValue;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if utils.isString(oValue):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise Exception('TODO');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return oValue.pydatetime();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncdef dbTimestampToZuluDatetime(oValue):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Converts a database timestamp to a zulu datetime instance.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync tsValue = dbTimestampToDatetime(oValue);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if tsValue.tzinfo is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync class UTC(datetime.tzinfo):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """UTC TZ Info Class"""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def utcoffset(self, _):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return datetime.timedelta(0);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def tzname(self, _):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return "UTC";
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def dst(self, _):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return datetime.timedelta(0);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync tsValue = tsValue.astimezone(UTC());
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return tsValue;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncclass TMDatabaseIntegrityException(Exception):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Herolds a database integrity error up the callstack.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Do NOT use directly, only thru TMDatabaseConnection.integrityException.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Otherwise, we won't be able to log the issue.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync pass;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncclass TMDatabaseCursor(object):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ Cursor wrapper class. """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def __init__(self, oDb, oCursor):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb = oDb;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oCursor = oCursor;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def execute(self, sOperation, aoArgs = None):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ See TMDatabaseConnection.execute()"""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return self._oDb.executeInternal(self._oCursor, sOperation, aoArgs, utils.getCallerName());
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def callProc(self, sProcedure, aoArgs = None):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ See TMDatabaseConnection.callProc()"""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return self._oDb.callProcInternal(self._oCursor, sProcedure, aoArgs, utils.getCallerName());
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def fetchOne(self):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Wrapper around Psycopg2.cursor.fetchone."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return self._oCursor.fetchone();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def fetchMany(self, cRows = None):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Wrapper around Psycopg2.cursor.fetchmany."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return self._oCursor.fetchmany(cRows if cRows is not None else self._oCursor.arraysize);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def fetchAll(self):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Wrapper around Psycopg2.cursor.fetchall."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return self._oCursor.fetchall();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def getRowCount(self):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Wrapper around Psycopg2.cursor.rowcount."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return self._oCursor.rowcount;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def formatBindArgs(self, sStatement, aoArgs):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Wrapper around Psycopg2.cursor.mogrify."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oRet = self._oCursor.mogrify(sStatement, aoArgs);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if sys.version_info[0] >= 3 and not isinstance(oRet, str):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oRet = oRet.decode('utf-8');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return oRet;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync @staticmethod
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def isTsInfinity(tsValue):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ Checks if tsValue is an infinity timestamp. """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return isDbTimestampInfinity(tsValue);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncclass TMDatabaseConnection(object):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Test Manager Database Access class.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync This class contains no logic, just raw access abstraction and utilities,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync as well as some debug help and some statistics.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def __init__(self, fnDPrint = None, oSrvGlue = None):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Database connection wrapper.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync The fnDPrint is for debug logging of all database activity.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Raises an exception on failure.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sAppName = '%s-%s' % (os.getpid(), os.path.basename(sys.argv[0]),)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if len(sAppName) >= 64:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sAppName = sAppName[:64];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync os.environ['PGAPPNAME'] = sAppName;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dArgs = \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync { \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'database': config.g_ksDatabaseName,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'user': config.g_ksDatabaseUser,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'password': config.g_ksDatabasePassword,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # 'application_name': sAppName, - Darn stale debian! :/
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync };
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if config.g_ksDatabaseAddress is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dArgs['host'] = config.g_ksDatabaseAddress;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if config.g_ksDatabasePort is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dArgs['port'] = config.g_ksDatabasePort;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oConn = psycopg2.connect(**dArgs); # pylint: disable=W0142
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oConn.set_client_encoding('UTF-8');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oCursor = self._oConn.cursor();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oExplainConn = None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oExplainCursor = None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if config.g_kfWebUiSqlTraceExplain and config.g_kfWebUiSqlTrace:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oExplainConn = psycopg2.connect(**dArgs); # pylint: disable=W0142
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oExplainConn.set_client_encoding('UTF-8');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oExplainCursor = self._oExplainConn.cursor();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._fTransaction = False;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._tsCurrent = None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._tsCurrentMinusOne = None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync assert self.isAutoCommitting() is False;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Debug and introspection.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._fnDPrint = fnDPrint;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._aoTraceBack = [];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Exception class handles.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.oXcptError = psycopg2.Error;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oSrvGlue is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oSrvGlue.registerDebugInfoCallback(self.debugInfoCallback);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def isAutoCommitting(self):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ Work around missing autocommit attribute in older versions."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return getattr(self._oConn, 'autocommit', False);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def close(self):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Closes the connection and renders all cursors useless.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if self._oCursor is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oCursor.close();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oCursor = None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if self._oConn is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oConn.close();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oConn = None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if self._oExplainCursor is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oExplainCursor.close();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oExplainCursor = None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if self._oExplainConn is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oExplainConn.close();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oExplainConn = None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _startedTransaction(self):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Called to work the _fTransaction and related variables when starting
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync a transaction.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._fTransaction = True;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._tsCurrent = None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._tsCurrentMinusOne = None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _endedTransaction(self):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Called to work the _fTransaction and related variables when ending
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync a transaction.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._fTransaction = False;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._tsCurrent = None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._tsCurrentMinusOne = None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def begin(self):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Currently just for marking where a transaction starts in the code.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync assert self._oConn is not None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync assert self.isAutoCommitting() is False;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._aoTraceBack.append([utils.timestampNano(), 'START TRANSACTION', 0, 0, utils.getCallerName(), None]);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._startedTransaction();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return True;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def commit(self, sCallerName = None):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ Wrapper around Psycopg2.connection.commit."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync assert self._fTransaction is True;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync nsStart = utils.timestampNano();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oRc = self._oConn.commit();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cNsElapsed = utils.timestampNano() - nsStart;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if sCallerName is None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sCallerName = utils.getCallerName();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._aoTraceBack.append([nsStart, 'COMMIT', cNsElapsed, 0, sCallerName, None]);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._endedTransaction();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return oRc;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def maybeCommit(self, fCommit):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Commits if fCommit is True.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns True if committed, False if not.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if fCommit is True:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.commit(utils.getCallerName());
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return True;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return False;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def rollback(self):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ Wrapper around Psycopg2.connection.rollback."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync nsStart = utils.timestampNano();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oRc = self._oConn.rollback();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cNsElapsed = utils.timestampNano() - nsStart;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._aoTraceBack.append([nsStart, 'ROLLBACK', cNsElapsed, 0, utils.getCallerName(), None]);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._endedTransaction();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return oRc;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Internal cursor workers.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def executeInternal(self, oCursor, sOperation, aoArgs, sCallerName):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Execute a query or command.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Mostly a wrapper around the psycopg2 cursor method with the same name,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync but collect data for traceback.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if aoArgs is None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aoArgs = list();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sBound = oCursor.mogrify(unicode(sOperation), aoArgs);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if sys.version_info[0] >= 3 and not isinstance(sBound, str):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sBound = sBound.decode('utf-8');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aasExplain = None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if self._oExplainCursor is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync try:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if config.g_kfWebUiSqlTraceExplainTiming:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oExplainCursor.execute('EXPLAIN (ANALYZE, BUFFERS, COSTS, VERBOSE, TIMING) ' + sBound);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oExplainCursor.execute('EXPLAIN (ANALYZE, BUFFERS, COSTS, VERBOSE) ' + sBound);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync except Exception as oXcpt:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aasExplain = [ ['Explain exception: '], [str(oXcpt)]];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync try: self._oExplainConn.rollback();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync except: pass;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aasExplain = self._oExplainCursor.fetchall();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync nsStart = utils.timestampNano();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync try:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oRc = oCursor.execute(sBound);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync except Exception as oXcpt:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cNsElapsed = utils.timestampNano() - nsStart;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._aoTraceBack.append([nsStart, 'oXcpt=%s; Statement: %s' % (oXcpt, sBound), cNsElapsed, 0, sCallerName, None]);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if self._fnDPrint is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._fnDPrint('db::execute %u ns, caller %s: oXcpt=%s; Statement: %s'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync % (cNsElapsed, sCallerName, oXcpt, sBound));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cNsElapsed = utils.timestampNano() - nsStart;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if self._fTransaction is False and not self.isAutoCommitting(): # Even SELECTs starts transactions with psycopg2, see FAQ.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._aoTraceBack.append([nsStart, '[START TRANSACTION]', 0, 0, sCallerName, None]);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._startedTransaction();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._aoTraceBack.append([nsStart, sBound, cNsElapsed, oCursor.rowcount, sCallerName, aasExplain]);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if self._fnDPrint is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._fnDPrint('db::execute %u ns, caller %s: "\n%s"' % (cNsElapsed, sCallerName, sBound));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if self.isAutoCommitting():
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._aoTraceBack.append([nsStart, '[AUTO COMMIT]', 0, 0, sCallerName, None]);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return oRc;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def callProcInternal(self, oCursor, sProcedure, aoArgs, sCallerName):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Call a stored procedure.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Mostly a wrapper around the psycopg2 cursor method 'callproc', but
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync collect data for traceback.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if aoArgs is None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aoArgs = list();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync nsStart = utils.timestampNano();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync try:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oRc = oCursor.callproc(sProcedure, aoArgs);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync except Exception as oXcpt:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cNsElapsed = utils.timestampNano() - nsStart;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._aoTraceBack.append([nsStart, 'oXcpt=%s; Calling: %s(%s)' % (oXcpt, sProcedure, aoArgs),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cNsElapsed, 0, sCallerName, None]);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if self._fnDPrint is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._fnDPrint('db::callproc %u ns, caller %s: oXcpt=%s; Calling: %s(%s)'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync % (cNsElapsed, sCallerName, oXcpt, sProcedure, aoArgs));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cNsElapsed = utils.timestampNano() - nsStart;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if self._fTransaction is False and not self.isAutoCommitting(): # Even SELECTs starts transactions with psycopg2, see FAQ.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._aoTraceBack.append([nsStart, '[START TRANSACTION]', 0, 0, sCallerName, None]);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._startedTransaction();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._aoTraceBack.append([nsStart, '%s(%s)' % (sProcedure, aoArgs), cNsElapsed, oCursor.rowcount, sCallerName, None]);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if self._fnDPrint is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._fnDPrint('db::callproc %u ns, caller %s: "%s(%s)"' % (cNsElapsed, sCallerName, sProcedure, aoArgs));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if self.isAutoCommitting():
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._aoTraceBack.append([nsStart, '[AUTO COMMIT]', 0, 0, sCallerName, sCallerName, None]);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return oRc;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _fetchOne(self, oCursor):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Wrapper around Psycopg2.cursor.fetchone."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oRow = oCursor.fetchone()
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if self._fnDPrint is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._fnDPrint('db:fetchOne returns: %s' % (oRow,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return oRow;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _fetchMany(self, oCursor, cRows):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Wrapper around Psycopg2.cursor.fetchmany."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return oCursor.fetchmany(cRows if cRows is not None else oCursor.arraysize);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _fetchAll(self, oCursor):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Wrapper around Psycopg2.cursor.fetchall."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return oCursor.fetchall()
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _getRowCountWorker(self, oCursor):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Wrapper around Psycopg2.cursor.rowcount."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return oCursor.rowcount;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Default cursor access.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def execute(self, sOperation, aoArgs = None):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Execute a query or command.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Mostly a wrapper around the psycopg2 cursor method with the same name,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync but collect data for traceback.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return self.executeInternal(self._oCursor, sOperation, aoArgs, utils.getCallerName());
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def callProc(self, sProcedure, aoArgs = None):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Call a stored procedure.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Mostly a wrapper around the psycopg2 cursor method 'callproc', but
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync collect data for traceback.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return self.callProcInternal(self._oCursor, sProcedure, aoArgs, utils.getCallerName());
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def fetchOne(self):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Wrapper around Psycopg2.cursor.fetchone."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return self._oCursor.fetchone();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def fetchMany(self, cRows = None):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Wrapper around Psycopg2.cursor.fetchmany."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return self._oCursor.fetchmany(cRows if cRows is not None else self._oCursor.arraysize);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def fetchAll(self):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Wrapper around Psycopg2.cursor.fetchall."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return self._oCursor.fetchall();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def getRowCount(self):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Wrapper around Psycopg2.cursor.rowcount."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return self._oCursor.rowcount;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def formatBindArgs(self, sStatement, aoArgs):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Wrapper around Psycopg2.cursor.mogrify."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oRet = self._oCursor.mogrify(sStatement, aoArgs);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if sys.version_info[0] >= 3 and not isinstance(oRet, str):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oRet = oRet.decode('utf-8');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return oRet;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def getCurrentTimestamps(self):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns the current timestamp and the current timestamp minus one tick.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync This will start a transaction if necessary.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if self._tsCurrent is None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.execute('SELECT CURRENT_TIMESTAMP, CURRENT_TIMESTAMP - INTERVAL \'1 microsecond\'');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync (self._tsCurrent, self._tsCurrentMinusOne) = self.fetchOne();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return (self._tsCurrent, self._tsCurrentMinusOne);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def getCurrentTimestamp(self):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns the current timestamp.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync This will start a transaction if necessary.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if self._tsCurrent is None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.getCurrentTimestamps();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return self._tsCurrent;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def getCurrentTimestampMinusOne(self):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns the current timestamp minus one tick.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync This will start a transaction if necessary.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if self._tsCurrentMinusOne is None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.getCurrentTimestamps();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return self._tsCurrentMinusOne;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Additional cursors.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def openCursor(self):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Opens a new cursor (TMDatabaseCursor).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oCursor = self._oConn.cursor();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return TMDatabaseCursor(self, oCursor);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Utilities.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync @staticmethod
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def isTsInfinity(tsValue):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ Checks if tsValue is an infinity timestamp. """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return isDbTimestampInfinity(tsValue);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Error stuff.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def integrityException(self, sMessage):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Database integrity reporter and exception factory.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns an TMDatabaseIntegrityException which the caller can raise.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ## @todo Create a new database connection and log the issue in the SystemLog table.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ## Alternatively, rollback whatever is going on and do it using the current one.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return TMDatabaseIntegrityException(sMessage);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Debugging.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def dprint(self, sText):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Debug output.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if not self._fnDPrint:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return False;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._fnDPrint(sText);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return True;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def debugHtmlReport(self, tsStart = 0):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Used to get a SQL activity dump as HTML, usually for WuiBase._sDebug.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cNsElapsed = 0;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync for aEntry in self._aoTraceBack:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cNsElapsed += aEntry[2];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sDebug = '<h3>SQL Debug Log (total time %s ns):</h3>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync '<table class="tmsqltable">\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' <tr>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' <th>No.</th>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' <th>Timestamp (ns)</th>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' <th>Elapsed (ns)</th>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' <th>Rows Returned</th>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' <th>Command</th>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' <th>Caller</th>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' </tr>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync % (utils.formatNumber(cNsElapsed, '&nbsp;'),);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync iEntry = 0;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync for aEntry in self._aoTraceBack:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync iEntry += 1;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sDebug += ' <tr>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' <td align="right">%s</td>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' <td align="right">%s</td>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' <td align="right">%s</td>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' <td align="right">%s</td>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' <td><pre>%s</pre></td>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' <td>%s</td>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' </tr>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync % (iEntry,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync utils.formatNumber(aEntry[0] - tsStart, '&nbsp;'),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync utils.formatNumber(aEntry[2], '&nbsp;'),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync utils.formatNumber(aEntry[3], '&nbsp;'),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync webutils.escapeElem(aEntry[1]),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync webutils.escapeElem(aEntry[4]),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync );
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if aEntry[5] is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sDebug += ' <tr>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' <td colspan="6"><pre style="white-space: pre-wrap;">%s</pre></td>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' </tr>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync % (webutils.escapeElem('\n'.join([aoRow[0] for aoRow in aEntry[5]])),);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sDebug += '</table>';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return sDebug;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def debugTextReport(self, tsStart = 0):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Used to get a SQL activity dump as text.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cNsElapsed = 0;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync for aEntry in self._aoTraceBack:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cNsElapsed += aEntry[2];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sHdr = 'SQL Debug Log (total time %s ns)' % (utils.formatNumber(cNsElapsed),);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sDebug = sHdr + '\n' + '-' * len(sHdr) + '\n';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync iEntry = 0;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync for aEntry in self._aoTraceBack:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync iEntry += 1;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sHdr = 'Query #%s Timestamp: %s ns Elapsed: %s ns Rows: %s Caller: %s' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync % ( iEntry,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync utils.formatNumber(aEntry[0] - tsStart),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync utils.formatNumber(aEntry[2]),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync utils.formatNumber(aEntry[3]),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aEntry[4], );
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sDebug += '\n' + sHdr + '\n' + '-' * len(sHdr) + '\n';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sDebug += aEntry[1];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if sDebug[-1] != '\n':
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sDebug += '\n';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if aEntry[5] is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sDebug += 'Explain:\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' %s\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync % ( '\n'.join([aoRow[0] for aoRow in aEntry[5]]),);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return sDebug;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def debugInfoCallback(self, oGlue, fHtml):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ Called back by the glue code on error. """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oGlue.write('\n');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if not fHtml: oGlue.write(self.debugTextReport());
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else: oGlue.write(self.debugHtmlReport());
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oGlue.write('\n');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return True;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def debugEnableExplain(self):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ Enabled explain. """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if self._oExplainConn is None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dArgs = \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync { \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'database': config.g_ksDatabaseName,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'user': config.g_ksDatabaseUser,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'password': config.g_ksDatabasePassword,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # 'application_name': sAppName, - Darn stale debian! :/
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync };
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if config.g_ksDatabaseAddress is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dArgs['host'] = config.g_ksDatabaseAddress;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if config.g_ksDatabasePort is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dArgs['port'] = config.g_ksDatabasePort;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oExplainConn = psycopg2.connect(**dArgs); # pylint: disable=W0142
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oExplainCursor = self._oExplainConn.cursor();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return True;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync