From 7dcc412d45a76975281bc5c2687acee484a2b6fb Mon Sep 17 00:00:00 2001 From: Balram Choudhary Date: Tue, 2 Jul 2024 11:45:17 +0530 Subject: [PATCH 1/3] Support for logging in ibm_db_dbi module Signed-off-by: Balram Choudhary --- README.md | 20 +++ ibm_db_dbi.py | 443 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 419 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index ec7c8be9..e255a07b 100644 --- a/README.md +++ b/README.md @@ -273,6 +273,26 @@ True True ``` +## Logging + +### Logging in ibm_db_dbi Module +You can enable logging in the ibm_db_dbi module to debug and trace activities. +Logging can be directed to the console or a specified file. + +To enable logging: +``` +import ibm_db_dbi as dbi + +# Log to console +dbi.debug() + +# Log to a file (e.g., log.txt) +dbi.debug("log.txt") +``` +Calling dbi.debug() without arguments will output logs to the console. + +Calling dbi.debug("log.txt") will log messages to the specified file (log.txt in this example). + ## Example of SSL Connection String * **Secure Database Connection using SSL/TSL** - ibm_db supports secure connection to Database Server over SSL same as ODBC/CLI driver. If you have SSL Certificate from server or an CA signed certificate, just use it in connection string as below: diff --git a/ibm_db_dbi.py b/ibm_db_dbi.py index 49774c53..1dbc292d 100644 --- a/ibm_db_dbi.py +++ b/ibm_db_dbi.py @@ -23,6 +23,23 @@ import types, string, time, datetime, decimal, sys import weakref +import logging + +logger = logging.getLogger(__name__) +log_enabled = False + + +def debug(filename=None): + global log_enabled + log_enabled = True # Set log_enabled to True when debug is called + # Configure logging + if filename: + if '.' not in filename: + filename += '.txt' + logging.basicConfig(filename=filename, level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s', filemode='w') + else: + logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s') + PY2 = sys.version_info < (3, ) @@ -445,14 +462,22 @@ def _retrieve_current_schema(dsn): ODBC_CURRENTSCHEMA_KEYWORD = 'CURRENTSCHEMA=' current_schema_value = None current_schema_start = dsn.find(ODBC_CURRENTSCHEMA_KEYWORD) + if log_enabled: + logger.debug(f"current_schema_start: {current_schema_start}") if current_schema_start > -1: current_schema_end = dsn.find(';', current_schema_start) + if log_enabled: + logger.debug(f"ODBC_CURRENTSCHEMA_KEYWORD: {ODBC_CURRENTSCHEMA_KEYWORD}") + logger.debug(f"current_schema_end: {current_schema_end}") current_schema_value = dsn[ (current_schema_start + len(ODBC_CURRENTSCHEMA_KEYWORD)) :current_schema_end ] + if log_enabled: + logger.debug(f"current_schema_value: {current_schema_value}") + return current_schema_value @@ -461,12 +486,16 @@ def _server_connect(dsn, user='', password='', host=''): """ if dsn is None: + if log_enabled: + logger.error("dsn value should not be None") raise InterfaceError("dsn value should not be None") if (not isinstance(dsn, string_types)) | \ (not isinstance(user, string_types)) | \ (not isinstance(password, string_types)) | \ (not isinstance(host, string_types)): + if log_enabled: + logger.error("Arguments should be of type string or unicode") raise InterfaceError("Arguments should be of type string or unicode") # If the dsn does not contain port and protocal adding database @@ -491,6 +520,8 @@ def _server_connect(dsn, user='', password='', host=''): try: conn = ibm_db.connect(dsn, '', '') except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred while connecting to server: {inst}") raise _get_exception(inst) return conn @@ -500,21 +531,31 @@ def createdb(database, dsn, user='', password='', host='', codeset='', mode=''): """ if database is None: + if log_enabled: + logger.error("createdb expects a not None database name value") raise InterfaceError("createdb expects a not None database name value") if (not isinstance(database, string_types)) | \ (not isinstance(codeset, string_types)) | \ (not isinstance(mode, string_types)): - raise InterfaceError("Arguments sould be string or unicode") + if log_enabled: + logger.error("Arguments should be string or unicode") + raise InterfaceError("Arguments should be string or unicode") conn = _server_connect(dsn, user=user, password=password, host=host) try: return_value = ibm_db.createdb(conn, database, codeset, mode) + if log_enabled: + logger.debug(f"Return value from ibm_db.createdb: {return_value}") except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred during database creation: {inst}") raise _get_exception(inst) finally: try: ibm_db.close(conn) except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred while closing connection: {inst}") raise _get_exception(inst) return return_value @@ -524,19 +565,29 @@ def dropdb(database, dsn, user='', password='', host=''): """ if database is None: + if log_enabled: + logger.error("dropdb expects a not None database name value") raise InterfaceError("dropdb expects a not None database name value") if (not isinstance(database, string_types)): - raise InterfaceError("Arguments sould be string or unicode") + if log_enabled: + logger.error("Arguments should be string or unicode") + raise InterfaceError("Arguments should be string or unicode") conn = _server_connect(dsn, user=user, password=password, host=host) try: return_value = ibm_db.dropdb(conn, database) + if log_enabled: + logger.debug(f"Return value from ibm_db.dropdb: {return_value}") except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred during database droping: {inst}") raise _get_exception(inst) finally: try: ibm_db.close(conn) except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred while closing connection: {inst}") raise _get_exception(inst) return return_value @@ -546,21 +597,31 @@ def recreatedb(database, dsn, user='', password='', host='', codeset='', mode='' """ if database is None: + if log_enabled: + logger.error("recreatedb expects a not None database name value") raise InterfaceError("recreatedb expects a not None database name value") if (not isinstance(database, string_types)) | \ (not isinstance(codeset, string_types)) | \ (not isinstance(mode, string_types)): - raise InterfaceError("Arguments sould be string or unicode") + if log_enabled: + logger.error("Arguments should be string or unicode") + raise InterfaceError("Arguments should be string or unicode") conn = _server_connect(dsn, user=user, password=password, host=host) try: return_value = ibm_db.recreatedb(conn, database, codeset, mode) + if log_enabled: + logger.debug(f"Return value from ibm_db.recreatedb: {return_value}") except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred during database recreation: {inst}") raise _get_exception(inst) finally: try: ibm_db.close(conn) except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred while closing connection: {inst}") raise _get_exception(inst) return return_value @@ -570,82 +631,112 @@ def createdbNX(database, dsn, user='', password='', host='', codeset='', mode='' """ if database is None: + if log_enabled: + logger.error("createdbNX expects a not None database name value") raise InterfaceError("createdbNX expects a not None database name value") if (not isinstance(database, string_types)) | \ (not isinstance(codeset, string_types)) | \ (not isinstance(mode, string_types)): - raise InterfaceError("Arguments sould be string or unicode") + if log_enabled: + logger.error("Arguments should be string or unicode") + raise InterfaceError("Arguments should be string or unicode") conn = _server_connect(dsn, user=user, password=password, host=host) try: return_value = ibm_db.createdbNX(conn, database, codeset, mode) + if log_enabled: + logger.debug(f"Return value from ibm_db.createdbNX: {return_value}") except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred during database createdbNX: {inst}") raise _get_exception(inst) finally: try: ibm_db.close(conn) except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred while closing connection: {inst}") raise _get_exception(inst) return return_value def connect(dsn, user='', password='', host='', database='', conn_options=None): - """This method creates a non persistent connection to the database. It returns + """This method creates a non-persistent connection to the database. It returns a ibm_db_dbi.Connection object. """ + try: + if log_enabled: + logger.debug(f"dsn: {dsn}, user: {user}, host: {host}, database: {database}, conn_options: {conn_options}") + + if dsn is None: + if log_enabled: + logger.error("connect expects a not None dsn value") + raise InterfaceError("connect expects a not None dsn value") + + if (not isinstance(dsn, string_types)) | \ + (not isinstance(user, string_types)) | \ + (not isinstance(password, string_types)) | \ + (not isinstance(host, string_types)) | \ + (not isinstance(database, string_types)): + if log_enabled: + logger.error("connect expects the first five arguments to" + " be of type string or unicode") + raise InterfaceError("connect expects the first five arguments to" + " be of type string or unicode") + if conn_options is not None: + if not isinstance(conn_options, dict): + if log_enabled: + logger.error("connect expects the sixth argument" + " (conn_options) to be of type dict") + raise InterfaceError("connect expects the sixth argument" + " (conn_options) to be of type dict") + if not SQL_ATTR_AUTOCOMMIT in conn_options: + conn_options[SQL_ATTR_AUTOCOMMIT] = SQL_AUTOCOMMIT_OFF + else: + conn_options = {SQL_ATTR_AUTOCOMMIT : SQL_AUTOCOMMIT_OFF} + + # If the dsn does not contain port and protocol adding database + # and hostname is no good. Add these when required, that is, + # if there is a '=' in the dsn. Else the dsn string is taken to be + # a DSN entry. + if dsn.find('=') != -1: + if dsn[len(dsn) - 1] != ';': + dsn = dsn + ";" + if database != '' and dsn.find('DATABASE=') == -1: + dsn = dsn + "DATABASE=" + database + ";" + if host != '' and dsn.find('HOSTNAME=') == -1: + dsn = dsn + "HOSTNAME=" + host + ";" + else: + dsn = "DSN=" + dsn + ";" - if dsn is None: - raise InterfaceError("connect expects a not None dsn value") - - if (not isinstance(dsn, string_types)) | \ - (not isinstance(user, string_types)) | \ - (not isinstance(password, string_types)) | \ - (not isinstance(host, string_types)) | \ - (not isinstance(database, string_types)): - raise InterfaceError("connect expects the first five arguments to" - " be of type string or unicode") - if conn_options is not None: - if not isinstance(conn_options, dict): - raise InterfaceError("connect expects the sixth argument" - " (conn_options) to be of type dict") - if not SQL_ATTR_AUTOCOMMIT in conn_options: - conn_options[SQL_ATTR_AUTOCOMMIT] = SQL_AUTOCOMMIT_OFF - else: - conn_options = {SQL_ATTR_AUTOCOMMIT : SQL_AUTOCOMMIT_OFF} - - # If the dsn does not contain port and protocal adding database - # and hostname is no good. Add these when required, that is, - # if there is a '=' in the dsn. Else the dsn string is taken to be - # a DSN entry. - if dsn.find('=') != -1: - if dsn[len(dsn) - 1] != ';': - dsn = dsn + ";" - if database != '' and dsn.find('DATABASE=') == -1: - dsn = dsn + "DATABASE=" + database + ";" - if host != '' and dsn.find('HOSTNAME=') == -1: - dsn = dsn + "HOSTNAME=" + host + ";" - else: - dsn = "DSN=" + dsn + ";" + if user != '' and dsn.find('UID=') == -1: + dsn = dsn + "UID=" + user + ";" + if password != '' and dsn.find('PWD=') == -1: + dsn = dsn + "PWD=" + password + ";" - if user != '' and dsn.find('UID=') == -1: - dsn = dsn + "UID=" + user + ";" - if password != '' and dsn.find('PWD=') == -1: - dsn = dsn + "PWD=" + password + ";" + if log_enabled: + logger.debug(f"Connection string: {dsn}") - try: conn = ibm_db.connect(dsn, '', '', conn_options) conn_object = Connection(conn) conn_object.set_current_schema(_retrieve_current_schema(dsn) or user) + if log_enabled: + logger.debug("Connection successful.") return conn_object except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred while connecting: {inst}") raise _get_exception(inst) + def pconnect(dsn, user='', password='', host='', database='', conn_options=None): """This method creates persistent connection to the database. It returns a ibm_db_dbi.Connection object. """ if dsn is None: + if log_enabled: + logger.error("connect expects a not None dsn value") raise InterfaceError("connect expects a not None dsn value") if (not isinstance(dsn, string_types)) | \ @@ -653,10 +744,14 @@ def pconnect(dsn, user='', password='', host='', database='', conn_options=None) (not isinstance(password, string_types)) | \ (not isinstance(host, string_types)) | \ (not isinstance(database, string_types)): + if log_enabled: + logger.error("connect expects the first five arguments to be of type string or unicode") raise InterfaceError("connect expects the first five arguments to" " be of type string or unicode") if conn_options is not None: if not isinstance(conn_options, dict): + if log_enabled: + logger.error("connect expects the sixth argument (conn_options) to be of type dict") raise InterfaceError("connect expects the sixth argument" " (conn_options) to be of type dict") if not SQL_ATTR_AUTOCOMMIT in conn_options: @@ -683,11 +778,17 @@ def pconnect(dsn, user='', password='', host='', database='', conn_options=None) if password != '' and dsn.find('PWD=') == -1: dsn = dsn + "PWD=" + password + ";" try: + if log_enabled: + logger.debug(f"Connecting to database with DSN: {dsn}") conn = ibm_db.pconnect(dsn, '', '', conn_options) + if log_enabled: + logger.debug("Connection established successfully") conn_object = Connection(conn) conn_object.set_current_schema(_retrieve_current_schema(dsn) or user) return conn_object except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred while connecting: {inst}") raise _get_exception(inst) class Connection(object): @@ -733,11 +834,20 @@ def close(self): self.rollback() try: if self.conn_handler is None: + if log_enabled: + logger.error("Connection cannot be closed; " + "connection is no longer active.") raise ProgrammingError("Connection cannot be closed; " "connection is no longer active.") else: + if log_enabled: + logger.debug(f"Closing connection: conn_handler={self.conn_handler}") return_value = ibm_db.close(self.conn_handler) + if log_enabled: + logger.debug("Connection closed.") except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred while closing connection: {inst}") raise _get_exception(inst) self.conn_handler = None for index in range(len(self._cursor_list)): @@ -756,7 +866,11 @@ def commit(self): """ try: return_value = ibm_db.commit(self.conn_handler) + if log_enabled: + logger.debug("Transaction committed.") except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred while committing transaction: {inst}") raise _get_exception(inst) return return_value @@ -767,7 +881,11 @@ def rollback(self): """ try: return_value = ibm_db.rollback(self.conn_handler) + if log_enabled: + logger.debug("Transaction rolled back.") except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred while rolling back transaction: {inst}") raise _get_exception(inst) return return_value @@ -777,6 +895,9 @@ def cursor(self): """ if self.conn_handler is None: + if log_enabled: + logger.error("Cursor cannot be returned; " + "connection is no longer active.") raise ProgrammingError("Cursor cannot be returned; " "connection is no longer active.") cursor = Cursor(self.conn_handler, self) @@ -788,6 +909,8 @@ def set_option(self, attr_dict): """Input: connection attribute dictionary Return: True on success or False on failure """ + if log_enabled: + logger.debug(f"Setting connection options: {attr_dict}") return ibm_db.set_option(self.conn_handler, attr_dict, 1) # Retrieves connection attributes values @@ -795,16 +918,22 @@ def get_option(self, attr_key): """Input: connection attribute key Return: current setting of the resource attribute requested """ + if log_enabled: + logger.debug(f"Getting connection option: {attr_key}") return ibm_db.get_option(self.conn_handler, attr_key, 1) # Sets FIX_RETURN_TYPE. Added for performance improvement def set_fix_return_type(self, is_on): try: + if log_enabled: + logger.debug(f"Setting fix return type to: {is_on}") if is_on: self.FIX_RETURN_TYPE = 1 else: self.FIX_RETURN_TYPE = 0 except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred while setting fix return type: {inst}") raise _get_exception(inst) return self.FIX_RETURN_TYPE @@ -814,12 +943,18 @@ def set_autocommit(self, is_on): Return: True on success or False on failure """ try: + if log_enabled: + logger.debug(f"Setting autocommit to: {is_on}") if is_on: is_set = ibm_db.set_option(self.conn_handler, {SQL_ATTR_AUTOCOMMIT : SQL_AUTOCOMMIT_ON}, 1) else: is_set = ibm_db.set_option(self.conn_handler, {SQL_ATTR_AUTOCOMMIT : SQL_AUTOCOMMIT_OFF}, 1) except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred while setting autocommit: {inst}") raise _get_exception(inst) + if log_enabled: + logger.debug(f"set_autocommit returns: {is_set}") return is_set # Sets connection attribute values @@ -829,8 +964,12 @@ def set_current_schema(self, schema_name): """ self.current_schema = schema_name try: + if log_enabled: + logger.debug(f"Setting current schema to: {schema_name}") is_set = ibm_db.set_option(self.conn_handler, {SQL_ATTR_CURRENT_SCHEMA : schema_name}, 1) except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred setting current schema: {inst}") raise _get_exception(inst) return is_set @@ -842,7 +981,11 @@ def get_current_schema(self): conn_schema = ibm_db.get_option(self.conn_handler, SQL_ATTR_CURRENT_SCHEMA, 1) if conn_schema is not None and conn_schema != '': self.current_schema = conn_schema + if log_enabled: + logger.debug(f"Current schema: {self.current_schema}") except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred while getting current schema: {inst}") raise _get_exception(inst) return self.current_schema @@ -854,7 +997,11 @@ def server_info(self): server_info = [] server_info.append(self.dbms_name) server_info.append(self.dbms_ver) + if log_enabled: + logger.debug(f"Server info: {server_info}") except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred while getting server info: {inst}") raise _get_exception(inst) return tuple(server_info) @@ -866,15 +1013,22 @@ def tables(self, schema_name=None, table_name=None): """Input: connection - ibm_db.IBM_DBConnection object Return: sequence of table metadata dicts for the specified schema """ - + if log_enabled: + logger.debug(f"Retrieving the tables for a specified schema") result = [] if schema_name is not None: schema_name = self.set_case("DB2_LUW", schema_name) + if log_enabled: + logger.debug(f"Schema name: {schema_name}") if table_name is not None: table_name = self.set_case("DB2_LUW", table_name) + if log_enabled: + logger.debug(f"Table name: {table_name}") try: stmt = ibm_db.tables(self.conn_handler, None, schema_name, table_name) + if log_enabled: + logger.debug(f"Statement to retrieve table: {stmt}") row = ibm_db.fetch_assoc(stmt) i = 0 while (row): @@ -883,6 +1037,8 @@ def tables(self, schema_name=None, table_name=None): row = ibm_db.fetch_assoc(stmt) ibm_db.free_result(stmt) except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred while retrieving the tables: {inst}") raise _get_exception(inst) return result @@ -904,14 +1060,22 @@ def indexes(self, unique=True, schema_name=None, table_name=None): 'ASC_OR_DESC': 'A' } """ + if log_enabled: + logger.debug(f"Retrieving metadata pertaining to index for specified schema/Table") result = [] if schema_name is not None: schema_name = self.set_case("DB2_LUW", schema_name) + if log_enabled: + logger.debug(f"Schema name: {schema_name}") if table_name is not None: table_name = self.set_case("DB2_LUW", table_name) + if log_enabled: + logger.debug(f"Table name: {table_name}") try: stmt = ibm_db.statistics(self.conn_handler, None, schema_name, table_name, unique) + if log_enabled: + logger.debug(f"Statement to retrieving metadata pertaining to index: {stmt}") row = ibm_db.fetch_assoc(stmt) i = 0 while (row): @@ -921,6 +1085,8 @@ def indexes(self, unique=True, schema_name=None, table_name=None): row = ibm_db.fetch_assoc(stmt) ibm_db.free_result(stmt) except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred while retrieving metadata pertaining to index: {inst}") raise _get_exception(inst) return result @@ -939,14 +1105,22 @@ def primary_keys(self, unique=True, schema_name=None, table_name=None): 'KEY_SEQ': 1 } """ + if log_enabled: + logger.debug(f"Retrieving metadata pertaining to primary keys for specified schema/Table") result = [] if schema_name is not None: schema_name = self.set_case("DB2_LUW", schema_name) + if log_enabled: + logger.debug(f"Schema name: {schema_name}") if table_name is not None: table_name = self.set_case("DB2_LUW", table_name) + if log_enabled: + logger.debug(f"Table name: {table_name}") try: stmt = ibm_db.primary_keys(self.conn_handler, None, schema_name, table_name) + if log_enabled: + logger.debug(f"Statement to retrieving metadata pertaining to primary keys: {stmt}") row = ibm_db.fetch_assoc(stmt) i = 0 while (row): @@ -955,6 +1129,8 @@ def primary_keys(self, unique=True, schema_name=None, table_name=None): row = ibm_db.fetch_assoc(stmt) ibm_db.free_result(stmt) except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred while retrieving metadata pertaining to primary keys: {inst}") raise _get_exception(inst) return result @@ -977,14 +1153,22 @@ def foreign_keys(self, unique=True, schema_name=None, table_name=None): 'FKTABLE_SCHEM': 'PYTHONIC' } """ + if log_enabled: + logger.debug(f"Retrieving metadata pertaining to foreign keys for specified schema/Table") result = [] if schema_name is not None: schema_name = self.set_case("DB2_LUW", schema_name) + if log_enabled: + logger.debug(f"Schema name: {schema_name}") if table_name is not None: table_name = self.set_case("DB2_LUW", table_name) + if log_enabled: + logger.debug(f"Table name: {table_name}") try: stmt = ibm_db.foreign_keys(self.conn_handler, None, None, None, None, schema_name, table_name) + if log_enabled: + logger.debug(f"Statement to retrieving metadata pertaining to foreign keys: {stmt}") row = ibm_db.fetch_assoc(stmt) i = 0 while (row): @@ -993,6 +1177,8 @@ def foreign_keys(self, unique=True, schema_name=None, table_name=None): row = ibm_db.fetch_assoc(stmt) ibm_db.free_result(stmt) except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred while retrieving metadata pertaining foreign keys: {inst}") raise _get_exception(inst) return result @@ -1016,14 +1202,22 @@ def columns(self, schema_name=None, table_name=None, column_names=None): 'DECIMAL_DIGITS': None } """ + if log_enabled: + logger.debug(f"Retrieving the columns for a specified schema/Table") result = [] if schema_name is not None: schema_name = self.set_case("DB2_LUW", schema_name) + if log_enabled: + logger.debug(f"Schema name: {schema_name}") if table_name is not None: table_name = self.set_case("DB2_LUW", table_name) + if log_enabled: + logger.debug(f"Table name: {table_name}") try: stmt = ibm_db.columns(self.conn_handler, None, schema_name, table_name) + if log_enabled: + logger.debug(f"Statement to retrieving the columns: {stmt}") row = ibm_db.fetch_assoc(stmt) i = 0 while (row): @@ -1044,6 +1238,8 @@ def columns(self, schema_name=None, table_name=None, column_names=None): include_columns.append(column) result = include_columns except Exception as inst: + if log_enabled: + logger.exception(f"An exception occurred while retrieving the columns: {inst}") raise _get_exception(inst) return result @@ -1075,6 +1271,10 @@ def __get_description(self): try: num_columns = ibm_db.num_fields(self.stmt_handler) + if log_enabled: + logger.info("Fetching column descriptions...") + logger.debug(f"Number of columns: {num_columns}") + """ If the execute statement did not produce a result set return None. """ if num_columns == False: @@ -1086,6 +1286,9 @@ def __get_description(self): column_index)) type = ibm_db.field_type(self.stmt_handler, column_index) type = type.upper() + if log_enabled: + logger.info(f"Processing column") + logger.debug(f"Column type: {type}") if STRING == type: column_desc.append(STRING) elif TEXT == type: @@ -1130,6 +1333,9 @@ def __get_description(self): self.__description.append(column_desc) except Exception as inst: + if self.log_enabled: + logger.exception(f"An exception occurred: {_get_exception(inst)}") + logger.debug("Full exception traceback:", exc_info=True) self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] @@ -1185,6 +1391,10 @@ def __init__(self, conn_handler, conn_object=None): self.__connection = conn_object self.messages = [] self.FIX_RETURN_TYPE = conn_object.FIX_RETURN_TYPE + if log_enabled: + logger.info("Cursor object initialized.") + logger.debug(f"Connection handler: {self.conn_handler}") + logger.debug(f"Connection object: {self.__connection}") # This method closes the statemente associated with the cursor object. # It takes no argument. @@ -1201,10 +1411,14 @@ def close(self): ''' #self.messages.append(ProgrammingError("Cursor cannot be closed; connection is no longer active.")) #raise self.messages[len(self.messages) - 1] + if log_enabled: + logger.warning("Cursor cannot be closed; connection is no longer active.") return None try: return_value = ibm_db.free_stmt(self.stmt_handler) except Exception as inst: + if log_enabled: + logger.error(f"Error occurred while closing cursor: {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] self.stmt_handler = None @@ -1215,10 +1429,14 @@ def close(self): self.__connection._cursor_list.remove(weakref.ref(self)) except: pass + if log_enabled: + logger.info("Cursor closed successfully.") return return_value # helper for calling procedure def _callproc_helper(self, procname, parameters=None): + if log_enabled: + logger.debug(f"Calling procedure: {procname}") if parameters is not None: buff = [] CONVERT_STR = (buffer) @@ -1229,18 +1447,28 @@ def _callproc_helper(self, procname, parameters=None): param = str(param) buff.append(param) parameters = tuple(buff) + if log_enabled: + logger.debug(f"Procedure parameters: {parameters}") try: result = ibm_db.callproc(self.conn_handler, procname,parameters) except Exception as inst: + if log_enabled: + logger.error(f"Error procedure '{procname}': {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] else: + if log_enabled: + logger.debug("Calling procedure without parameters.") try: result = ibm_db.callproc(self.conn_handler, procname) except Exception as inst: + if log_enabled: + logger.error(f"Error calling procedure '{procname}': {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] + if log_enabled: + logger.info(f"Procedure '{procname}' called successfully.") return result @@ -1250,15 +1478,23 @@ def callproc(self, procname, parameters=None): the stored procedure as arguments. """ + if log_enabled: + logger.debug(f"Calling callproc with procname={procname}, parameters={parameters}") self.messages = [] if not isinstance(procname, string_types): + if log_enabled: + logger.error("callproc expects the first argument to be of type String or Unicode.") self.messages.append(InterfaceError("callproc expects the first argument to be of type String or Unicode.")) raise self.messages[len(self.messages) - 1] if parameters is not None: if not isinstance(parameters, (list, tuple)): + if log_enabled: + logger.error("callproc expects the second argument to be of type list or tuple.") self.messages.append(InterfaceError("callproc expects the second argument to be of type list or tuple.")) raise self.messages[len(self.messages) - 1] result = self._callproc_helper(procname, parameters) + if log_enabled: + logger.debug(f"Result received from callproc helper: {result}") return_value = None self.__description = None self._all_stmt_handlers = [] @@ -1268,18 +1504,27 @@ def callproc(self, procname, parameters=None): else: self.stmt_handler = result self._result_set_produced = True + if log_enabled: + logger.debug( + f"callproc executed successfully. stmt_handler={self.stmt_handler}, return_value={return_value}") return return_value # Helper for preparing an SQL statement. def _prepare_helper(self, operation, parameters=None): try: ibm_db.free_stmt(self.stmt_handler) + if log_enabled: + logger.debug("Successfully freed existing statement handler.") except: pass try: self.stmt_handler = ibm_db.prepare(self.conn_handler, operation) + if log_enabled: + logger.debug(f"Successfully prepared statement with operation: {operation}") except Exception as inst: + if log_enabled: + logger.error(f"Error preparing statement with operation '{operation}': {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] @@ -1287,12 +1532,20 @@ def _prepare_helper(self, operation, parameters=None): def _set_cursor_helper(self): if (ibm_db.get_option(self.stmt_handler, ibm_db.SQL_ATTR_CURSOR_TYPE, 0) != ibm_db.SQL_CURSOR_FORWARD_ONLY): self._is_scrollable_cursor = True + if log_enabled: + logger.debug("Cursor type is scrollable.") else: self._is_scrollable_cursor = False + if log_enabled: + logger.debug("Cursor type is forward-only.") self._result_set_produced = False try: num_columns = ibm_db.num_fields(self.stmt_handler) + if log_enabled: + logger.debug(f"Number of columns retrieved: {num_columns}") except Exception as inst: + if log_enabled: + logger.error(f"Error getting number of columns: {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] if not num_columns: @@ -1315,6 +1568,8 @@ def _execute_helper(self, parameters=None): param = str(param) buff.append(param) parameters = tuple(buff) + if log_enabled: + logger.debug(f"Executing statement with parameters: {parameters}") try: return_value = ibm_db.execute(self.stmt_handler, parameters) if not return_value: @@ -1325,19 +1580,31 @@ def _execute_helper(self, parameters=None): self.messages.append(Error(str(ibm_db.stmt_errormsg()))) raise self.messages[len(self.messages) - 1] except Exception as inst: + if log_enabled: + logger.error(f"Error executing statement with parameters: {_get_exception(inst)} ") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] else: + if log_enabled: + logger.debug(f"Executing statement without parameters") try: return_value = ibm_db.execute(self.stmt_handler) if not return_value: if ibm_db.conn_errormsg() is not None: + if log_enabled: + error_msg = f"Connection error: {str(ibm_db.conn_errormsg())}" + logger.error(error_msg) self.messages.append(Error(str(ibm_db.conn_errormsg()))) raise self.messages[len(self.messages) - 1] if ibm_db.stmt_errormsg() is not None: + if log_enabled: + error_msg = f"Statement error: {str(ibm_db.conn_errormsg())}" + logger.error(error_msg) self.messages.append(Error(str(ibm_db.stmt_errormsg()))) raise self.messages[len(self.messages) - 1] except Exception as inst: + if log_enabled: + logger.error(f"Error executing statement without parameters: {_get_exception(inst)} ") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] return return_value @@ -1349,14 +1616,22 @@ def _set_rowcount(self): if not self._result_set_produced: try: counter = ibm_db.num_rows(self.stmt_handler) + if log_enabled: + logger.debug(f"Number of rows retrieved: {counter}") except Exception as inst: + if log_enabled: + logger.error(f"Error getting row count: {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] self.__rowcount = counter elif self._is_scrollable_cursor: try: counter = ibm_db.get_num_result(self.stmt_handler) + if log_enabled: + logger.debug(f"Number of rows retrieved: {counter}") except Exception as inst: + if log_enabled: + logger.error(f"Error getting row count: {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] if counter >= 0: @@ -1376,20 +1651,34 @@ def _get_last_identity_val(self): operation = 'SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1' try: stmt_handler = ibm_db.prepare(self.conn_handler, operation) + if log_enabled: + logger.debug(f"Preparing statement with operation: {operation}") if ibm_db.execute(stmt_handler): row = ibm_db.fetch_tuple(stmt_handler) if row[0] is not None: identity_val = int(row[0]) + if log_enabled: + logger.debug(f"Identity value retrieved: {identity_val}") else: identity_val = None + if log_enabled: + logger.debug("Identity value is None") else: if ibm_db.conn_errormsg() is not None: + if log_enabled: + error_msg = f"Connection error: {str(ibm_db.conn_errormsg())}" + logger.error(error_msg) self.messages.append(Error(str(ibm_db.conn_errormsg()))) raise self.messages[len(self.messages) - 1] if ibm_db.stmt_errormsg() is not None: + if log_enabled: + error_msg = f"Statement error: {str(ibm_db.stmt_errormsg())}" + logger.error(error_msg) self.messages.append(Error(str(ibm_db.stmt_errormsg()))) raise self.messages[len(self.messages) - 1] except Exception as inst: + if log_enabled: + logger.error(f"Error occured in getting identity value: {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] return identity_val @@ -1402,12 +1691,20 @@ def execute(self, operation, parameters=None): sequence of values to substitute for the parameter markers in the SQL statement as arguments. """ + if log_enabled: + logger.debug(f"Executing SQL operation: {operation}") + if parameters is not None: + logger.debug(f"SQL parameters: {parameters}") self.messages = [] if not isinstance(operation, string_types): + if log_enabled: + logger.error("execute expects the first argument [%s] to be of type String or Unicode." % operation ) self.messages.append(InterfaceError("execute expects the first argument [%s] to be of type String or Unicode." % operation )) raise self.messages[len(self.messages) - 1] if parameters is not None: if not isinstance(parameters, (list, tuple, dict)): + if log_enabled: + logger.error("execute parameters argument should be sequence.") self.messages.append(InterfaceError("execute parameters argument should be sequence.")) raise self.messages[len(self.messages) - 1] self.__description = None @@ -1415,6 +1712,8 @@ def execute(self, operation, parameters=None): self._prepare_helper(operation) self._execute_helper(parameters) self._set_cursor_helper() + if log_enabled: + logger.debug("SQL operation executed successfully.") return self._set_rowcount() def executemany(self, operation, seq_parameters): @@ -1424,15 +1723,24 @@ def executemany(self, operation, seq_parameters): and sequence of sequence of values to substitute for the parameter markers in the SQL statement as its argument. """ + if log_enabled: + logger.debug("Executing SQL operation in executemany: %s", operation) + logger.debug("Number of parameter sets: %d", len(seq_parameters)) self.messages = [] if not isinstance(operation, string_types): + if log_enabled: + logger.error(f"executemany expects the first argument to be of type String or Unicode.") self.messages.append(InterfaceError("executemany expects the first argument to be of type String or Unicode.")) raise self.messages[len(self.messages) - 1] if seq_parameters is None: + if log_enabled: + logger.error(f"executemany expects a not None seq_parameters value") self.messages.append(InterfaceError("executemany expects a not None seq_parameters value")) raise self.messages[len(self.messages) - 1] if not isinstance(seq_parameters, (list, tuple)): + if log_enabled: + logger.error(f"executemany expects the second argument to be of type list or tuple of sequence.") self.messages.append(InterfaceError("executemany expects the second argument to be of type list or tuple of sequence.")) raise self.messages[len(self.messages) - 1] @@ -1463,15 +1771,25 @@ def executemany(self, operation, seq_parameters): ibm_db.autocommit(self.conn_handler, autocommit) if self.__rowcount == -1: if ibm_db.conn_errormsg() is not None: + if log_enabled: + error_msg = f"Connection error: {str(ibm_db.conn_errormsg())}" + logger.error(error_msg) self.messages.append(Error(str(ibm_db.conn_errormsg()))) raise self.messages[len(self.messages) - 1] if ibm_db.stmt_errormsg() is not None: + if log_enabled: + error_msg = f"Statement error: {str(ibm_db.conn_errormsg())}" + logger.error(error_msg) self.messages.append(Error(str(ibm_db.stmt_errormsg()))) raise self.messages[len(self.messages) - 1] except Exception as inst: self._set_rowcount() self.messages.append(Error(inst)) + if log_enabled: + logger.error(f"Error in executemany: {inst}") raise self.messages[len(self.messages) - 1] + if log_enabled: + logger.debug("SQL operation executemany successfully.") return True def _fetch_helper(self, fetch_size=-1): @@ -1518,7 +1836,14 @@ def fetchone(self): executing an SQL statement which produces a result set. """ + if log_enabled: + logger.debug("Fetching one row from the database.") row_list = self._fetch_helper(1) + if log_enabled: + if len(row_list) == 0: + logger.debug("No rows fetched.") + else: + logger.debug("Row fetched successfully.") if len(row_list) == 0: return None else: @@ -1530,32 +1855,51 @@ def fetchmany(self, size=0): It takes the number of rows to fetch as an argument. If this is not provided it fetches self.arraysize number of rows. """ + if log_enabled: + logger.debug("Fetching %d rows from the database.", size) if not isinstance(size, int_types): + if log_enabled: + logger.exception("fetchmany expects argument type int or long.") self.messages.append(InterfaceError( "fetchmany expects argument type int or long.")) raise self.messages[len(self.messages) - 1] if size == 0: size = self.arraysize if size < -1: + if log_enabled: + logger.error("fetchmany argument size expected to be positive") self.messages.append(ProgrammingError("fetchmany argument size expected to be positive.")) raise self.messages[len(self.messages) - 1] + if log_enabled: + logger.debug("Fetched %d rows successfully.", len(self._fetch_helper(size))) return self._fetch_helper(size) def fetchall(self): """This method fetches all remaining rows from the database, after executing an SQL statement which produces a result set. """ - return self._fetch_helper() + if log_enabled: + logger.debug("Fetching all remaining rows from the database.") + rows_fetched = self._fetch_helper() + if log_enabled: + self.logger.debug("Fetched %d rows successfully.", len(rows_fetched)) + return rows_fetched def nextset(self): """This method can be used to get the next result set after executing a stored procedure, which produces multiple result sets. """ + if log_enabled: + logger.debug("Attempting to retrieve next result set.") self.messages = [] if self.stmt_handler is None: + if log_enabled: + logger.error("Please execute an SQL statement in order to get result sets.") self.messages.append(ProgrammingError("Please execute an SQL statement in order to get result sets.")) raise self.messages[len(self.messages) - 1] if self._result_set_produced == False: + if log_enabled: + logger.error("The last call to execute did not produce any result set.") self.messages.append(ProgrammingError("The last call to execute did not produce any result set.")) raise self.messages[len(self.messages) - 1] try: @@ -1566,6 +1910,8 @@ def nextset(self): self._all_stmt_handlers.append(self.stmt_handler) self.stmt_handler = ibm_db.next_result(self._all_stmt_handlers[0]) except Exception as inst: + if log_enabled: + logger.error(f"Error while retrieving next result set: {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] @@ -1573,6 +1919,9 @@ def nextset(self): self.stmt_handler = None if self.stmt_handler == None: return None + + if log_enabled: + logger.debug("Successfully retrieved next result set.") return True def setinputsizes(self, sizes): @@ -1587,6 +1936,8 @@ def setoutputsize(self, size, column=-1): # and binary data in a row tuple fetched from the database # to decimal and binary objects, for returning it to the user. def _fix_return_data_type(self, row): + if log_enabled: + logger.debug("Fixing return data types for row: %s", row) row_list = None for index in range(len(row)): if row[index] is not None: @@ -1605,11 +1956,15 @@ def _fix_return_data_type(self, row): row_list[index] = decimal.Decimal(str(row[index]).replace(",", ".")) except Exception as inst: + if log_enabled: + logger.error(f"Data type format error: {str(inst)}") self.messages.append(DataError("Data type format error: "+ str(inst))) raise self.messages[len(self.messages) - 1] if row_list is None: return row else: + if log_enabled: + logger.debug("Fixed return data types: %s", row_list) return tuple(row_list) def __enter__(self): From ca7e40f297755398d0a64262c832558926597aaf Mon Sep 17 00:00:00 2001 From: Balram Choudhary Date: Wed, 3 Jul 2024 12:06:27 +0530 Subject: [PATCH 2/3] Logging in ibm_db_dbi module Signed-off-by: Balram Choudhary --- ibm_db_dbi.py | 548 +++++++++++++++++++------------------------------- 1 file changed, 212 insertions(+), 336 deletions(-) diff --git a/ibm_db_dbi.py b/ibm_db_dbi.py index 1dbc292d..794353fa 100644 --- a/ibm_db_dbi.py +++ b/ibm_db_dbi.py @@ -41,6 +41,20 @@ def debug(filename=None): logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s') +def LogMsg(level, message): + if log_enabled: + if level == 1: + logger.debug(message) + elif level == 2: + logger.info(message) + elif level == 3: + logger.warning(message) + elif level == 4: + logger.error(message) + elif level == 5: + logger.exception(message) + + PY2 = sys.version_info < (3, ) if not PY2: @@ -462,22 +476,19 @@ def _retrieve_current_schema(dsn): ODBC_CURRENTSCHEMA_KEYWORD = 'CURRENTSCHEMA=' current_schema_value = None current_schema_start = dsn.find(ODBC_CURRENTSCHEMA_KEYWORD) - if log_enabled: - logger.debug(f"current_schema_start: {current_schema_start}") + message = f"current_schema_start: {current_schema_start}" + LogMsg(1, message) if current_schema_start > -1: current_schema_end = dsn.find(';', current_schema_start) - if log_enabled: - logger.debug(f"ODBC_CURRENTSCHEMA_KEYWORD: {ODBC_CURRENTSCHEMA_KEYWORD}") - logger.debug(f"current_schema_end: {current_schema_end}") + message = f"ODBC_CURRENTSCHEMA_KEYWORD: {ODBC_CURRENTSCHEMA_KEYWORD}" + LogMsg(1, message) + LogMsg(1, f"current_schema_end: {current_schema_end}") current_schema_value = dsn[ (current_schema_start + len(ODBC_CURRENTSCHEMA_KEYWORD)) :current_schema_end ] - - if log_enabled: - logger.debug(f"current_schema_value: {current_schema_value}") - + LogMsg(1, f"current_schema_value: {current_schema_value}") return current_schema_value @@ -486,16 +497,14 @@ def _server_connect(dsn, user='', password='', host=''): """ if dsn is None: - if log_enabled: - logger.error("dsn value should not be None") + LogMsg(4, "dsn value should not be None") raise InterfaceError("dsn value should not be None") if (not isinstance(dsn, string_types)) | \ (not isinstance(user, string_types)) | \ (not isinstance(password, string_types)) | \ (not isinstance(host, string_types)): - if log_enabled: - logger.error("Arguments should be of type string or unicode") + LogMsg(4, "Arguments should be of type string or unicode") raise InterfaceError("Arguments should be of type string or unicode") # If the dsn does not contain port and protocal adding database @@ -520,8 +529,8 @@ def _server_connect(dsn, user='', password='', host=''): try: conn = ibm_db.connect(dsn, '', '') except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred while connecting to server: {inst}") + message = f"An exception occurred while connecting to server: {inst}" + LogMsg(5, message) raise _get_exception(inst) return conn @@ -531,146 +540,129 @@ def createdb(database, dsn, user='', password='', host='', codeset='', mode=''): """ if database is None: - if log_enabled: - logger.error("createdb expects a not None database name value") + LogMsg(4, "createdb expects a not None database name value") raise InterfaceError("createdb expects a not None database name value") if (not isinstance(database, string_types)) | \ (not isinstance(codeset, string_types)) | \ (not isinstance(mode, string_types)): - if log_enabled: - logger.error("Arguments should be string or unicode") + LogMsg(4, "Arguments should be string or unicode") raise InterfaceError("Arguments should be string or unicode") conn = _server_connect(dsn, user=user, password=password, host=host) try: return_value = ibm_db.createdb(conn, database, codeset, mode) - if log_enabled: - logger.debug(f"Return value from ibm_db.createdb: {return_value}") + LogMsg(1, f"Return value from ibm_db.createdb: {return_value}") except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred during database creation: {inst}") + LogMsg(5, f"An exception occurred during database creation: {inst}") raise _get_exception(inst) finally: try: ibm_db.close(conn) except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred while closing connection: {inst}") + LogMsg(5, f"An exception occurred while closing connection: {inst}") raise _get_exception(inst) return return_value + def dropdb(database, dsn, user='', password='', host=''): """This method drops the specified database """ if database is None: - if log_enabled: - logger.error("dropdb expects a not None database name value") + LogMsg(4, "dropdb expects a not None database name value") raise InterfaceError("dropdb expects a not None database name value") - if (not isinstance(database, string_types)): - if log_enabled: - logger.error("Arguments should be string or unicode") + if not isinstance(database, string_types): + LogMsg(4, "Arguments should be string or unicode") raise InterfaceError("Arguments should be string or unicode") conn = _server_connect(dsn, user=user, password=password, host=host) try: return_value = ibm_db.dropdb(conn, database) - if log_enabled: - logger.debug(f"Return value from ibm_db.dropdb: {return_value}") + LogMsg(1, f"Return value from ibm_db.dropdb: {return_value}") except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred during database droping: {inst}") + LogMsg(5, f"An exception occurred during database droping: {inst}") raise _get_exception(inst) finally: try: ibm_db.close(conn) except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred while closing connection: {inst}") + LogMsg(5, f"An exception occurred while closing connection: {inst}") raise _get_exception(inst) return return_value + def recreatedb(database, dsn, user='', password='', host='', codeset='', mode=''): """This method drops and then recreate the database by using the specified database name, code set, and mode """ if database is None: - if log_enabled: - logger.error("recreatedb expects a not None database name value") + LogMsg(4, "recreatedb expects a not None database name value") raise InterfaceError("recreatedb expects a not None database name value") if (not isinstance(database, string_types)) | \ (not isinstance(codeset, string_types)) | \ (not isinstance(mode, string_types)): - if log_enabled: - logger.error("Arguments should be string or unicode") + LogMsg(4, "Arguments should be string or unicode") raise InterfaceError("Arguments should be string or unicode") conn = _server_connect(dsn, user=user, password=password, host=host) try: return_value = ibm_db.recreatedb(conn, database, codeset, mode) - if log_enabled: - logger.debug(f"Return value from ibm_db.recreatedb: {return_value}") + LogMsg(1, f"Return value from ibm_db.recreatedb: {return_value}") except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred during database recreation: {inst}") + LogMsg(5, f"An exception occurred during database recreation: {inst}") raise _get_exception(inst) finally: try: ibm_db.close(conn) except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred while closing connection: {inst}") + LogMsg(5, f"An exception occurred while closing connection: {inst}") raise _get_exception(inst) return return_value + def createdbNX(database, dsn, user='', password='', host='', codeset='', mode=''): """This method creates a database if it not exist by using the specified database name, code set, and mode """ if database is None: - if log_enabled: - logger.error("createdbNX expects a not None database name value") + LogMsg(4, "createdbNX expects a not None database name value") raise InterfaceError("createdbNX expects a not None database name value") if (not isinstance(database, string_types)) | \ (not isinstance(codeset, string_types)) | \ (not isinstance(mode, string_types)): - if log_enabled: - logger.error("Arguments should be string or unicode") + LogMsg(4, "Arguments should be string or unicode") raise InterfaceError("Arguments should be string or unicode") conn = _server_connect(dsn, user=user, password=password, host=host) try: return_value = ibm_db.createdbNX(conn, database, codeset, mode) - if log_enabled: - logger.debug(f"Return value from ibm_db.createdbNX: {return_value}") + LogMsg(1, f"Return value from ibm_db.createdbNX: {return_value}") except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred during database createdbNX: {inst}") + LogMsg(5, f"An exception occurred during database createdbNX: {inst}") raise _get_exception(inst) finally: try: ibm_db.close(conn) except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred while closing connection: {inst}") + LogMsg(5, f"An exception occurred while closing connection: {inst}") raise _get_exception(inst) return return_value + def connect(dsn, user='', password='', host='', database='', conn_options=None): """This method creates a non-persistent connection to the database. It returns a ibm_db_dbi.Connection object. """ try: - if log_enabled: - logger.debug(f"dsn: {dsn}, user: {user}, host: {host}, database: {database}, conn_options: {conn_options}") + message = f"dsn: {dsn}, user: {user}, host: {host}, database: {database}, conn_options: {conn_options}" + LogMsg(1, message) if dsn is None: - if log_enabled: - logger.error("connect expects a not None dsn value") + LogMsg(4, "connect expects a not None dsn value") raise InterfaceError("connect expects a not None dsn value") if (not isinstance(dsn, string_types)) | \ @@ -678,16 +670,14 @@ def connect(dsn, user='', password='', host='', database='', conn_options=None): (not isinstance(password, string_types)) | \ (not isinstance(host, string_types)) | \ (not isinstance(database, string_types)): - if log_enabled: - logger.error("connect expects the first five arguments to" - " be of type string or unicode") + message = "connect expects the first five arguments to be of type string or unicode" + LogMsg(4, message) raise InterfaceError("connect expects the first five arguments to" " be of type string or unicode") if conn_options is not None: if not isinstance(conn_options, dict): - if log_enabled: - logger.error("connect expects the sixth argument" - " (conn_options) to be of type dict") + message = "connect expects the sixth argument (conn_options) to be of type dict" + LogMsg(4, message) raise InterfaceError("connect expects the sixth argument" " (conn_options) to be of type dict") if not SQL_ATTR_AUTOCOMMIT in conn_options: @@ -714,18 +704,15 @@ def connect(dsn, user='', password='', host='', database='', conn_options=None): if password != '' and dsn.find('PWD=') == -1: dsn = dsn + "PWD=" + password + ";" - if log_enabled: - logger.debug(f"Connection string: {dsn}") + LogMsg(1, f"Connection string: {dsn}") conn = ibm_db.connect(dsn, '', '', conn_options) conn_object = Connection(conn) conn_object.set_current_schema(_retrieve_current_schema(dsn) or user) - if log_enabled: - logger.debug("Connection successful.") + LogMsg(1, "Connection successful.") return conn_object except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred while connecting: {inst}") + LogMsg(5,f"An exception occurred while connecting: {inst}") raise _get_exception(inst) @@ -735,8 +722,7 @@ def pconnect(dsn, user='', password='', host='', database='', conn_options=None) """ if dsn is None: - if log_enabled: - logger.error("connect expects a not None dsn value") + LogMsg(4, "connect expects a not None dsn value") raise InterfaceError("connect expects a not None dsn value") if (not isinstance(dsn, string_types)) | \ @@ -744,14 +730,12 @@ def pconnect(dsn, user='', password='', host='', database='', conn_options=None) (not isinstance(password, string_types)) | \ (not isinstance(host, string_types)) | \ (not isinstance(database, string_types)): - if log_enabled: - logger.error("connect expects the first five arguments to be of type string or unicode") + LogMsg(4, "connect expects the first five arguments to be of type string or unicode") raise InterfaceError("connect expects the first five arguments to" " be of type string or unicode") if conn_options is not None: if not isinstance(conn_options, dict): - if log_enabled: - logger.error("connect expects the sixth argument (conn_options) to be of type dict") + LogMsg(4, "connect expects the sixth argument (conn_options) to be of type dict") raise InterfaceError("connect expects the sixth argument" " (conn_options) to be of type dict") if not SQL_ATTR_AUTOCOMMIT in conn_options: @@ -778,17 +762,14 @@ def pconnect(dsn, user='', password='', host='', database='', conn_options=None) if password != '' and dsn.find('PWD=') == -1: dsn = dsn + "PWD=" + password + ";" try: - if log_enabled: - logger.debug(f"Connecting to database with DSN: {dsn}") + LogMsg(1, f"Connecting to database with DSN: {dsn}") conn = ibm_db.pconnect(dsn, '', '', conn_options) - if log_enabled: - logger.debug("Connection established successfully") + LogMsg(1, "Connection established successfully") conn_object = Connection(conn) conn_object.set_current_schema(_retrieve_current_schema(dsn) or user) return conn_object except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred while connecting: {inst}") + LogMsg(5, f"An exception occurred while connecting: {inst}") raise _get_exception(inst) class Connection(object): @@ -834,20 +815,15 @@ def close(self): self.rollback() try: if self.conn_handler is None: - if log_enabled: - logger.error("Connection cannot be closed; " - "connection is no longer active.") + LogMsg(4, "Connection cannot be closed; connection is no longer active.") raise ProgrammingError("Connection cannot be closed; " "connection is no longer active.") else: - if log_enabled: - logger.debug(f"Closing connection: conn_handler={self.conn_handler}") + LogMsg(1, f"Closing connection: conn_handler={self.conn_handler}") return_value = ibm_db.close(self.conn_handler) - if log_enabled: - logger.debug("Connection closed.") + LogMsg(1, "Connection closed.") except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred while closing connection: {inst}") + LogMsg(5, f"An exception occurred while closing connection: {inst}") raise _get_exception(inst) self.conn_handler = None for index in range(len(self._cursor_list)): @@ -866,11 +842,9 @@ def commit(self): """ try: return_value = ibm_db.commit(self.conn_handler) - if log_enabled: - logger.debug("Transaction committed.") + LogMsg(1, "Transaction committed.") except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred while committing transaction: {inst}") + LogMsg(5, f"An exception occurred while committing transaction: {inst}") raise _get_exception(inst) return return_value @@ -881,11 +855,9 @@ def rollback(self): """ try: return_value = ibm_db.rollback(self.conn_handler) - if log_enabled: - logger.debug("Transaction rolled back.") + LogMsg(1, "Transaction rolled back.") except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred while rolling back transaction: {inst}") + LogMsg(5, f"An exception occurred while rolling back transaction: {inst}") raise _get_exception(inst) return return_value @@ -895,9 +867,7 @@ def cursor(self): """ if self.conn_handler is None: - if log_enabled: - logger.error("Cursor cannot be returned; " - "connection is no longer active.") + LogMsg(4, "Cursor cannot be returned; connection is no longer active.") raise ProgrammingError("Cursor cannot be returned; " "connection is no longer active.") cursor = Cursor(self.conn_handler, self) @@ -909,8 +879,7 @@ def set_option(self, attr_dict): """Input: connection attribute dictionary Return: True on success or False on failure """ - if log_enabled: - logger.debug(f"Setting connection options: {attr_dict}") + LogMsg(1, f"Setting connection options: {attr_dict}") return ibm_db.set_option(self.conn_handler, attr_dict, 1) # Retrieves connection attributes values @@ -918,22 +887,19 @@ def get_option(self, attr_key): """Input: connection attribute key Return: current setting of the resource attribute requested """ - if log_enabled: - logger.debug(f"Getting connection option: {attr_key}") + LogMsg(1, f"Getting connection option: {attr_key}") return ibm_db.get_option(self.conn_handler, attr_key, 1) # Sets FIX_RETURN_TYPE. Added for performance improvement def set_fix_return_type(self, is_on): try: - if log_enabled: - logger.debug(f"Setting fix return type to: {is_on}") + LogMsg(1, f"Setting fix return type to: {is_on}") if is_on: self.FIX_RETURN_TYPE = 1 else: self.FIX_RETURN_TYPE = 0 except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred while setting fix return type: {inst}") + LogMsg(5, f"An exception occurred while setting fix return type: {inst}") raise _get_exception(inst) return self.FIX_RETURN_TYPE @@ -943,18 +909,15 @@ def set_autocommit(self, is_on): Return: True on success or False on failure """ try: - if log_enabled: - logger.debug(f"Setting autocommit to: {is_on}") + LogMsg(1, f"Setting autocommit to: {is_on}") if is_on: is_set = ibm_db.set_option(self.conn_handler, {SQL_ATTR_AUTOCOMMIT : SQL_AUTOCOMMIT_ON}, 1) else: is_set = ibm_db.set_option(self.conn_handler, {SQL_ATTR_AUTOCOMMIT : SQL_AUTOCOMMIT_OFF}, 1) except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred while setting autocommit: {inst}") + LogMsg(5, f"An exception occurred while setting autocommit: {inst}") raise _get_exception(inst) - if log_enabled: - logger.debug(f"set_autocommit returns: {is_set}") + LogMsg(1, f"set_autocommit returns: {is_set}") return is_set # Sets connection attribute values @@ -964,12 +927,10 @@ def set_current_schema(self, schema_name): """ self.current_schema = schema_name try: - if log_enabled: - logger.debug(f"Setting current schema to: {schema_name}") + LogMsg(1, f"Setting current schema to: {schema_name}") is_set = ibm_db.set_option(self.conn_handler, {SQL_ATTR_CURRENT_SCHEMA : schema_name}, 1) except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred setting current schema: {inst}") + LogMsg(5, f"An exception occurred setting current schema: {inst}") raise _get_exception(inst) return is_set @@ -981,11 +942,9 @@ def get_current_schema(self): conn_schema = ibm_db.get_option(self.conn_handler, SQL_ATTR_CURRENT_SCHEMA, 1) if conn_schema is not None and conn_schema != '': self.current_schema = conn_schema - if log_enabled: - logger.debug(f"Current schema: {self.current_schema}") + LogMsg(1, f"Current schema: {self.current_schema}") except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred while getting current schema: {inst}") + LogMsg(5, f"An exception occurred while getting current schema: {inst}") raise _get_exception(inst) return self.current_schema @@ -997,11 +956,9 @@ def server_info(self): server_info = [] server_info.append(self.dbms_name) server_info.append(self.dbms_ver) - if log_enabled: - logger.debug(f"Server info: {server_info}") + LogMsg(2, f"Server info: {server_info}") except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred while getting server info: {inst}") + LogMsg(5, f"An exception occurred while getting server info: {inst}") raise _get_exception(inst) return tuple(server_info) @@ -1013,22 +970,18 @@ def tables(self, schema_name=None, table_name=None): """Input: connection - ibm_db.IBM_DBConnection object Return: sequence of table metadata dicts for the specified schema """ - if log_enabled: - logger.debug(f"Retrieving the tables for a specified schema") + LogMsg(2, f"Retrieving the tables for a specified schema") result = [] if schema_name is not None: schema_name = self.set_case("DB2_LUW", schema_name) - if log_enabled: - logger.debug(f"Schema name: {schema_name}") + LogMsg(2, f"Schema name: {schema_name}") if table_name is not None: table_name = self.set_case("DB2_LUW", table_name) - if log_enabled: - logger.debug(f"Table name: {table_name}") + LogMsg(2, f"Table name: {table_name}") try: stmt = ibm_db.tables(self.conn_handler, None, schema_name, table_name) - if log_enabled: - logger.debug(f"Statement to retrieve table: {stmt}") + LogMsg(1, f"Statement to retrieve table: {stmt}") row = ibm_db.fetch_assoc(stmt) i = 0 while (row): @@ -1037,8 +990,7 @@ def tables(self, schema_name=None, table_name=None): row = ibm_db.fetch_assoc(stmt) ibm_db.free_result(stmt) except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred while retrieving the tables: {inst}") + LogMsg(5, f"An exception occurred while retrieving the tables: {inst}") raise _get_exception(inst) return result @@ -1060,22 +1012,18 @@ def indexes(self, unique=True, schema_name=None, table_name=None): 'ASC_OR_DESC': 'A' } """ - if log_enabled: - logger.debug(f"Retrieving metadata pertaining to index for specified schema/Table") + LogMsg(2, f"Retrieving metadata pertaining to index for specified schema/Table") result = [] if schema_name is not None: schema_name = self.set_case("DB2_LUW", schema_name) - if log_enabled: - logger.debug(f"Schema name: {schema_name}") + LogMsg(2, f"Schema name: {schema_name}") if table_name is not None: table_name = self.set_case("DB2_LUW", table_name) - if log_enabled: - logger.debug(f"Table name: {table_name}") + LogMsg(2, f"Table name: {table_name}") try: stmt = ibm_db.statistics(self.conn_handler, None, schema_name, table_name, unique) - if log_enabled: - logger.debug(f"Statement to retrieving metadata pertaining to index: {stmt}") + LogMsg(1, f"Statement to retrieving metadata pertaining to index: {stmt}") row = ibm_db.fetch_assoc(stmt) i = 0 while (row): @@ -1085,8 +1033,7 @@ def indexes(self, unique=True, schema_name=None, table_name=None): row = ibm_db.fetch_assoc(stmt) ibm_db.free_result(stmt) except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred while retrieving metadata pertaining to index: {inst}") + LogMsg(5, f"An exception occurred while retrieving metadata pertaining to index: {inst}") raise _get_exception(inst) return result @@ -1105,22 +1052,18 @@ def primary_keys(self, unique=True, schema_name=None, table_name=None): 'KEY_SEQ': 1 } """ - if log_enabled: - logger.debug(f"Retrieving metadata pertaining to primary keys for specified schema/Table") + LogMsg(2, f"Retrieving metadata pertaining to primary keys for specified schema/Table") result = [] if schema_name is not None: schema_name = self.set_case("DB2_LUW", schema_name) - if log_enabled: - logger.debug(f"Schema name: {schema_name}") + LogMsg(2, f"Schema name: {schema_name}") if table_name is not None: table_name = self.set_case("DB2_LUW", table_name) - if log_enabled: - logger.debug(f"Table name: {table_name}") + LogMsg(2, f"Table name: {table_name}") try: stmt = ibm_db.primary_keys(self.conn_handler, None, schema_name, table_name) - if log_enabled: - logger.debug(f"Statement to retrieving metadata pertaining to primary keys: {stmt}") + LogMsg(1, f"Statement to retrieving metadata pertaining to primary keys: {stmt}") row = ibm_db.fetch_assoc(stmt) i = 0 while (row): @@ -1129,8 +1072,7 @@ def primary_keys(self, unique=True, schema_name=None, table_name=None): row = ibm_db.fetch_assoc(stmt) ibm_db.free_result(stmt) except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred while retrieving metadata pertaining to primary keys: {inst}") + LogMsg(5, f"An exception occurred while retrieving metadata pertaining to primary keys: {inst}") raise _get_exception(inst) return result @@ -1153,22 +1095,18 @@ def foreign_keys(self, unique=True, schema_name=None, table_name=None): 'FKTABLE_SCHEM': 'PYTHONIC' } """ - if log_enabled: - logger.debug(f"Retrieving metadata pertaining to foreign keys for specified schema/Table") + LogMsg(2, f"Retrieving metadata pertaining to foreign keys for specified schema/Table") result = [] if schema_name is not None: schema_name = self.set_case("DB2_LUW", schema_name) - if log_enabled: - logger.debug(f"Schema name: {schema_name}") + LogMsg(2, f"Schema name: {schema_name}") if table_name is not None: table_name = self.set_case("DB2_LUW", table_name) - if log_enabled: - logger.debug(f"Table name: {table_name}") + LogMsg(2, f"Table name: {table_name}") try: stmt = ibm_db.foreign_keys(self.conn_handler, None, None, None, None, schema_name, table_name) - if log_enabled: - logger.debug(f"Statement to retrieving metadata pertaining to foreign keys: {stmt}") + LogMsg(1, f"Statement to retrieving metadata pertaining to foreign keys: {stmt}") row = ibm_db.fetch_assoc(stmt) i = 0 while (row): @@ -1177,8 +1115,7 @@ def foreign_keys(self, unique=True, schema_name=None, table_name=None): row = ibm_db.fetch_assoc(stmt) ibm_db.free_result(stmt) except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred while retrieving metadata pertaining foreign keys: {inst}") + LogMsg(5, f"An exception occurred while retrieving metadata pertaining foreign keys: {inst}") raise _get_exception(inst) return result @@ -1202,22 +1139,18 @@ def columns(self, schema_name=None, table_name=None, column_names=None): 'DECIMAL_DIGITS': None } """ - if log_enabled: - logger.debug(f"Retrieving the columns for a specified schema/Table") + LogMsg(2, f"Retrieving the columns for a specified schema/Table") result = [] if schema_name is not None: schema_name = self.set_case("DB2_LUW", schema_name) - if log_enabled: - logger.debug(f"Schema name: {schema_name}") + LogMsg(2, f"Schema name: {schema_name}") if table_name is not None: table_name = self.set_case("DB2_LUW", table_name) - if log_enabled: - logger.debug(f"Table name: {table_name}") + LogMsg(2, f"Table name: {table_name}") try: stmt = ibm_db.columns(self.conn_handler, None, schema_name, table_name) - if log_enabled: - logger.debug(f"Statement to retrieving the columns: {stmt}") + LogMsg(1, f"Statement to retrieving the columns: {stmt}") row = ibm_db.fetch_assoc(stmt) i = 0 while (row): @@ -1238,8 +1171,7 @@ def columns(self, schema_name=None, table_name=None, column_names=None): include_columns.append(column) result = include_columns except Exception as inst: - if log_enabled: - logger.exception(f"An exception occurred while retrieving the columns: {inst}") + LogMsg(5, f"An exception occurred while retrieving the columns: {inst}") raise _get_exception(inst) return result @@ -1271,9 +1203,8 @@ def __get_description(self): try: num_columns = ibm_db.num_fields(self.stmt_handler) - if log_enabled: - logger.info("Fetching column descriptions...") - logger.debug(f"Number of columns: {num_columns}") + LogMsg(2, "Fetching column descriptions...") + LogMsg(1, f"Number of columns: {num_columns}") """ If the execute statement did not produce a result set return None. """ @@ -1286,9 +1217,8 @@ def __get_description(self): column_index)) type = ibm_db.field_type(self.stmt_handler, column_index) type = type.upper() - if log_enabled: - logger.info(f"Processing column") - logger.debug(f"Column type: {type}") + LogMsg(2, f"Processing column") + LogMsg(1, f"Column type: {type}") if STRING == type: column_desc.append(STRING) elif TEXT == type: @@ -1333,9 +1263,8 @@ def __get_description(self): self.__description.append(column_desc) except Exception as inst: - if self.log_enabled: - logger.exception(f"An exception occurred: {_get_exception(inst)}") - logger.debug("Full exception traceback:", exc_info=True) + LogMsg(5, f"An exception occurred: {_get_exception(inst)}") + LogMsg(1, "Full exception traceback:", exc_info=True) self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] @@ -1391,10 +1320,9 @@ def __init__(self, conn_handler, conn_object=None): self.__connection = conn_object self.messages = [] self.FIX_RETURN_TYPE = conn_object.FIX_RETURN_TYPE - if log_enabled: - logger.info("Cursor object initialized.") - logger.debug(f"Connection handler: {self.conn_handler}") - logger.debug(f"Connection object: {self.__connection}") + LogMsg(2, "Cursor object initialized.") + LogMsg(1, f"Connection handler: {self.conn_handler}") + LogMsg(1, f"Connection object: {self.__connection}") # This method closes the statemente associated with the cursor object. # It takes no argument. @@ -1411,14 +1339,12 @@ def close(self): ''' #self.messages.append(ProgrammingError("Cursor cannot be closed; connection is no longer active.")) #raise self.messages[len(self.messages) - 1] - if log_enabled: - logger.warning("Cursor cannot be closed; connection is no longer active.") + LogMsg(3, "Cursor cannot be closed; connection is no longer active.") return None try: return_value = ibm_db.free_stmt(self.stmt_handler) except Exception as inst: - if log_enabled: - logger.error(f"Error occurred while closing cursor: {_get_exception(inst)}") + LogMsg(4, f"Error occurred while closing cursor: {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] self.stmt_handler = None @@ -1429,14 +1355,12 @@ def close(self): self.__connection._cursor_list.remove(weakref.ref(self)) except: pass - if log_enabled: - logger.info("Cursor closed successfully.") + LogMsg(2, "Cursor closed successfully.") return return_value # helper for calling procedure def _callproc_helper(self, procname, parameters=None): - if log_enabled: - logger.debug(f"Calling procedure: {procname}") + LogMsg(1, f"Calling procedure: {procname}") if parameters is not None: buff = [] CONVERT_STR = (buffer) @@ -1447,28 +1371,23 @@ def _callproc_helper(self, procname, parameters=None): param = str(param) buff.append(param) parameters = tuple(buff) - if log_enabled: - logger.debug(f"Procedure parameters: {parameters}") + LogMsg(1, f"Procedure parameters: {parameters}") try: result = ibm_db.callproc(self.conn_handler, procname,parameters) except Exception as inst: - if log_enabled: - logger.error(f"Error procedure '{procname}': {_get_exception(inst)}") + LogMsg(4, f"Error procedure '{procname}': {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] else: - if log_enabled: - logger.debug("Calling procedure without parameters.") + LogMsg(1, "Calling procedure without parameters.") try: result = ibm_db.callproc(self.conn_handler, procname) except Exception as inst: - if log_enabled: - logger.error(f"Error calling procedure '{procname}': {_get_exception(inst)}") + LogMsg(4, f"Error calling procedure '{procname}': {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] - if log_enabled: - logger.info(f"Procedure '{procname}' called successfully.") + LogMsg(2, f"Procedure '{procname}' called successfully.") return result @@ -1478,23 +1397,19 @@ def callproc(self, procname, parameters=None): the stored procedure as arguments. """ - if log_enabled: - logger.debug(f"Calling callproc with procname={procname}, parameters={parameters}") + LogMsg(1, f"Calling callproc with procname={procname}, parameters={parameters}") self.messages = [] if not isinstance(procname, string_types): - if log_enabled: - logger.error("callproc expects the first argument to be of type String or Unicode.") + LogMsg(4, "callproc expects the first argument to be of type String or Unicode.") self.messages.append(InterfaceError("callproc expects the first argument to be of type String or Unicode.")) raise self.messages[len(self.messages) - 1] if parameters is not None: if not isinstance(parameters, (list, tuple)): - if log_enabled: - logger.error("callproc expects the second argument to be of type list or tuple.") + LogMsg(4, "callproc expects the second argument to be of type list or tuple.") self.messages.append(InterfaceError("callproc expects the second argument to be of type list or tuple.")) raise self.messages[len(self.messages) - 1] result = self._callproc_helper(procname, parameters) - if log_enabled: - logger.debug(f"Result received from callproc helper: {result}") + LogMsg(1, f"Result received from callproc helper: {result}") return_value = None self.__description = None self._all_stmt_handlers = [] @@ -1504,8 +1419,7 @@ def callproc(self, procname, parameters=None): else: self.stmt_handler = result self._result_set_produced = True - if log_enabled: - logger.debug( + LogMsg(1, f"callproc executed successfully. stmt_handler={self.stmt_handler}, return_value={return_value}") return return_value @@ -1513,18 +1427,15 @@ def callproc(self, procname, parameters=None): def _prepare_helper(self, operation, parameters=None): try: ibm_db.free_stmt(self.stmt_handler) - if log_enabled: - logger.debug("Successfully freed existing statement handler.") + LogMsg(1, "Successfully freed existing statement handler.") except: pass try: self.stmt_handler = ibm_db.prepare(self.conn_handler, operation) - if log_enabled: - logger.debug(f"Successfully prepared statement with operation: {operation}") + LogMsg(1, f"Successfully prepared statement with operation: {operation}") except Exception as inst: - if log_enabled: - logger.error(f"Error preparing statement with operation '{operation}': {_get_exception(inst)}") + LogMsg(4, f"Error preparing statement with operation '{operation}': {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] @@ -1532,20 +1443,16 @@ def _prepare_helper(self, operation, parameters=None): def _set_cursor_helper(self): if (ibm_db.get_option(self.stmt_handler, ibm_db.SQL_ATTR_CURSOR_TYPE, 0) != ibm_db.SQL_CURSOR_FORWARD_ONLY): self._is_scrollable_cursor = True - if log_enabled: - logger.debug("Cursor type is scrollable.") + LogMsg(1, "Cursor type is scrollable.") else: self._is_scrollable_cursor = False - if log_enabled: - logger.debug("Cursor type is forward-only.") + LogMsg(1, "Cursor type is forward-only.") self._result_set_produced = False try: num_columns = ibm_db.num_fields(self.stmt_handler) - if log_enabled: - logger.debug(f"Number of columns retrieved: {num_columns}") + LogMsg(1, f"Number of columns retrieved: {num_columns}") except Exception as inst: - if log_enabled: - logger.error(f"Error getting number of columns: {_get_exception(inst)}") + LogMsg(4, f"Error getting number of columns: {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] if not num_columns: @@ -1568,43 +1475,41 @@ def _execute_helper(self, parameters=None): param = str(param) buff.append(param) parameters = tuple(buff) - if log_enabled: - logger.debug(f"Executing statement with parameters: {parameters}") + LogMsg(1, f"Executing statement with parameters: {parameters}") try: return_value = ibm_db.execute(self.stmt_handler, parameters) if not return_value: if ibm_db.conn_errormsg() is not None: + error_msg = f"Connection error: {str(ibm_db.conn_errormsg())}" + LogMsg(4, error_msg) self.messages.append(Error(str(ibm_db.conn_errormsg()))) raise self.messages[len(self.messages) - 1] if ibm_db.stmt_errormsg() is not None: + error_msg = f"Statement error: {str(ibm_db.conn_errormsg())}" + LogMsg(4, error_msg) self.messages.append(Error(str(ibm_db.stmt_errormsg()))) raise self.messages[len(self.messages) - 1] except Exception as inst: - if log_enabled: - logger.error(f"Error executing statement with parameters: {_get_exception(inst)} ") + LogMsg(4, f"Error executing statement with parameters: {_get_exception(inst)} ") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] else: - if log_enabled: - logger.debug(f"Executing statement without parameters") + LogMsg(1, f"Executing statement without parameters") try: return_value = ibm_db.execute(self.stmt_handler) if not return_value: if ibm_db.conn_errormsg() is not None: - if log_enabled: - error_msg = f"Connection error: {str(ibm_db.conn_errormsg())}" - logger.error(error_msg) + error_msg = f"Connection error: {str(ibm_db.conn_errormsg())}" + LogMsg(4, error_msg) self.messages.append(Error(str(ibm_db.conn_errormsg()))) raise self.messages[len(self.messages) - 1] if ibm_db.stmt_errormsg() is not None: - if log_enabled: - error_msg = f"Statement error: {str(ibm_db.conn_errormsg())}" - logger.error(error_msg) + error_msg = f"Statement error: {str(ibm_db.conn_errormsg())}" + LogMsg(4, error_msg) self.messages.append(Error(str(ibm_db.stmt_errormsg()))) raise self.messages[len(self.messages) - 1] except Exception as inst: - if log_enabled: - logger.error(f"Error executing statement without parameters: {_get_exception(inst)} ") + LogMsg(4, f"Error executing statement without parameters: {_get_exception(inst)} ") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] return return_value @@ -1616,22 +1521,18 @@ def _set_rowcount(self): if not self._result_set_produced: try: counter = ibm_db.num_rows(self.stmt_handler) - if log_enabled: - logger.debug(f"Number of rows retrieved: {counter}") + LogMsg(1, f"Number of rows retrieved: {counter}") except Exception as inst: - if log_enabled: - logger.error(f"Error getting row count: {_get_exception(inst)}") + LogMsg(4, f"Error getting row count: {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] self.__rowcount = counter elif self._is_scrollable_cursor: try: counter = ibm_db.get_num_result(self.stmt_handler) - if log_enabled: - logger.debug(f"Number of rows retrieved: {counter}") + LogMsg(1, f"Number of rows retrieved: {counter}") except Exception as inst: - if log_enabled: - logger.error(f"Error getting row count: {_get_exception(inst)}") + LogMsg(4, f"Error getting row count: {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] if counter >= 0: @@ -1651,34 +1552,28 @@ def _get_last_identity_val(self): operation = 'SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1' try: stmt_handler = ibm_db.prepare(self.conn_handler, operation) - if log_enabled: - logger.debug(f"Preparing statement with operation: {operation}") + LogMsg(1, f"Preparing statement with operation: {operation}") if ibm_db.execute(stmt_handler): row = ibm_db.fetch_tuple(stmt_handler) if row[0] is not None: identity_val = int(row[0]) - if log_enabled: - logger.debug(f"Identity value retrieved: {identity_val}") + LogMsg(1, f"Identity value retrieved: {identity_val}") else: identity_val = None - if log_enabled: - logger.debug("Identity value is None") + LogMsg(1, "Identity value is None") else: if ibm_db.conn_errormsg() is not None: - if log_enabled: - error_msg = f"Connection error: {str(ibm_db.conn_errormsg())}" - logger.error(error_msg) + error_msg = f"Connection error: {str(ibm_db.conn_errormsg())}" + LogMsg(4, error_msg) self.messages.append(Error(str(ibm_db.conn_errormsg()))) raise self.messages[len(self.messages) - 1] if ibm_db.stmt_errormsg() is not None: - if log_enabled: - error_msg = f"Statement error: {str(ibm_db.stmt_errormsg())}" - logger.error(error_msg) + error_msg = f"Statement error: {str(ibm_db.stmt_errormsg())}" + LogMsg(4, error_msg) self.messages.append(Error(str(ibm_db.stmt_errormsg()))) raise self.messages[len(self.messages) - 1] except Exception as inst: - if log_enabled: - logger.error(f"Error occured in getting identity value: {_get_exception(inst)}") + LogMsg(4, f"Error occured in getting identity value: {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] return identity_val @@ -1691,20 +1586,18 @@ def execute(self, operation, parameters=None): sequence of values to substitute for the parameter markers in the SQL statement as arguments. """ - if log_enabled: - logger.debug(f"Executing SQL operation: {operation}") - if parameters is not None: - logger.debug(f"SQL parameters: {parameters}") + LogMsg(1, f"Executing SQL operation: {operation}") + if parameters is not None: + LogMsg(1, f"SQL parameters: {parameters}") self.messages = [] if not isinstance(operation, string_types): - if log_enabled: - logger.error("execute expects the first argument [%s] to be of type String or Unicode." % operation ) + err_msg = "execute expects the first argument [%s] to be of type String or Unicode." % operation + LogMsg(4, err_msg) self.messages.append(InterfaceError("execute expects the first argument [%s] to be of type String or Unicode." % operation )) raise self.messages[len(self.messages) - 1] if parameters is not None: if not isinstance(parameters, (list, tuple, dict)): - if log_enabled: - logger.error("execute parameters argument should be sequence.") + LogMsg(4, "execute parameters argument should be sequence.") self.messages.append(InterfaceError("execute parameters argument should be sequence.")) raise self.messages[len(self.messages) - 1] self.__description = None @@ -1712,8 +1605,7 @@ def execute(self, operation, parameters=None): self._prepare_helper(operation) self._execute_helper(parameters) self._set_cursor_helper() - if log_enabled: - logger.debug("SQL operation executed successfully.") + LogMsg(2, "SQL operation executed successfully.") return self._set_rowcount() def executemany(self, operation, seq_parameters): @@ -1723,24 +1615,20 @@ def executemany(self, operation, seq_parameters): and sequence of sequence of values to substitute for the parameter markers in the SQL statement as its argument. """ - if log_enabled: - logger.debug("Executing SQL operation in executemany: %s", operation) - logger.debug("Number of parameter sets: %d", len(seq_parameters)) + LogMsg(1, "Executing SQL operation in executemany: %s", operation) + LogMsg(1, "Number of parameter sets: %d", len(seq_parameters)) self.messages = [] if not isinstance(operation, string_types): - if log_enabled: - logger.error(f"executemany expects the first argument to be of type String or Unicode.") + LogMsg(4, f"executemany expects the first argument to be of type String or Unicode.") self.messages.append(InterfaceError("executemany expects the first argument to be of type String or Unicode.")) raise self.messages[len(self.messages) - 1] if seq_parameters is None: - if log_enabled: - logger.error(f"executemany expects a not None seq_parameters value") + LogMsg(4, f"executemany expects a not None seq_parameters value") self.messages.append(InterfaceError("executemany expects a not None seq_parameters value")) raise self.messages[len(self.messages) - 1] if not isinstance(seq_parameters, (list, tuple)): - if log_enabled: - logger.error(f"executemany expects the second argument to be of type list or tuple of sequence.") + LogMsg(4, f"executemany expects the second argument to be of type list or tuple of sequence.") self.messages.append(InterfaceError("executemany expects the second argument to be of type list or tuple of sequence.")) raise self.messages[len(self.messages) - 1] @@ -1771,25 +1659,21 @@ def executemany(self, operation, seq_parameters): ibm_db.autocommit(self.conn_handler, autocommit) if self.__rowcount == -1: if ibm_db.conn_errormsg() is not None: - if log_enabled: - error_msg = f"Connection error: {str(ibm_db.conn_errormsg())}" - logger.error(error_msg) + error_msg = f"Connection error: {str(ibm_db.conn_errormsg())}" + LogMsg(4, error_msg) self.messages.append(Error(str(ibm_db.conn_errormsg()))) raise self.messages[len(self.messages) - 1] if ibm_db.stmt_errormsg() is not None: - if log_enabled: - error_msg = f"Statement error: {str(ibm_db.conn_errormsg())}" - logger.error(error_msg) + error_msg = f"Statement error: {str(ibm_db.conn_errormsg())}" + LogMsg(4, error_msg) self.messages.append(Error(str(ibm_db.stmt_errormsg()))) raise self.messages[len(self.messages) - 1] except Exception as inst: self._set_rowcount() self.messages.append(Error(inst)) - if log_enabled: - logger.error(f"Error in executemany: {inst}") + LogMsg(4, f"Error in executemany: {inst}") raise self.messages[len(self.messages) - 1] - if log_enabled: - logger.debug("SQL operation executemany successfully.") + LogMsg(2, "SQL operation executemany successfully.") return True def _fetch_helper(self, fetch_size=-1): @@ -1800,9 +1684,11 @@ def _fetch_helper(self, fetch_size=-1): If this is not provided it fetches all the remaining rows. """ if self.stmt_handler is None: + LogMsg(4, "Please execute an SQL statement in order to get a row from result set.") self.messages.append(ProgrammingError("Please execute an SQL statement in order to get a row from result set.")) raise self.messages[len(self.messages) - 1] - if self._result_set_produced == False: + if not self._result_set_produced: + LogMsg(4, "The last call to execute did not produce any result set.") self.messages.append(ProgrammingError("The last call to execute did not produce any result set.")) raise self.messages[len(self.messages) - 1] row_list = [] @@ -1813,8 +1699,11 @@ def _fetch_helper(self, fetch_size=-1): row = ibm_db.fetch_tuple(self.stmt_handler) except Exception as inst: if ibm_db.stmt_errormsg() is not None: + error_msg = f"Statement error: {str(ibm_db.stmt_errormsg())}" + LogMsg(4, error_msg) self.messages.append(Error(str(ibm_db.stmt_errormsg()))) else: + LogMsg(4, f"Error occured : {_get_exception(inst)}") self.messages.append(_get_exception(inst)) if len(row_list) == 0: raise self.messages[len(self.messages) - 1] @@ -1836,14 +1725,12 @@ def fetchone(self): executing an SQL statement which produces a result set. """ - if log_enabled: - logger.debug("Fetching one row from the database.") + LogMsg(2, "Fetching one row from the database.") row_list = self._fetch_helper(1) - if log_enabled: - if len(row_list) == 0: - logger.debug("No rows fetched.") - else: - logger.debug("Row fetched successfully.") + if len(row_list) == 0: + LogMsg(1, "No rows fetched.") + else: + LogMsg(1, "Row fetched successfully.") if len(row_list) == 0: return None else: @@ -1855,51 +1742,44 @@ def fetchmany(self, size=0): It takes the number of rows to fetch as an argument. If this is not provided it fetches self.arraysize number of rows. """ - if log_enabled: - logger.debug("Fetching %d rows from the database.", size) + LogMsg(1, "Fetching %d rows from the database.", size) if not isinstance(size, int_types): - if log_enabled: - logger.exception("fetchmany expects argument type int or long.") + LogMsg(5, "fetchmany expects argument type int or long.") self.messages.append(InterfaceError( "fetchmany expects argument type int or long.")) raise self.messages[len(self.messages) - 1] if size == 0: size = self.arraysize if size < -1: - if log_enabled: - logger.error("fetchmany argument size expected to be positive") + LogMsg(4, "fetchmany argument size expected to be positive") self.messages.append(ProgrammingError("fetchmany argument size expected to be positive.")) raise self.messages[len(self.messages) - 1] - if log_enabled: - logger.debug("Fetched %d rows successfully.", len(self._fetch_helper(size))) + message = "Fetched %d rows successfully.", len(self._fetch_helper(size)) + LogMsg(1, message) return self._fetch_helper(size) def fetchall(self): """This method fetches all remaining rows from the database, after executing an SQL statement which produces a result set. """ - if log_enabled: - logger.debug("Fetching all remaining rows from the database.") + LogMsg(2, "Fetching all remaining rows from the database.") rows_fetched = self._fetch_helper() - if log_enabled: - self.logger.debug("Fetched %d rows successfully.", len(rows_fetched)) + message = "Fetched %d rows successfully.", len(rows_fetched) + LogMsg(1, message) return rows_fetched def nextset(self): """This method can be used to get the next result set after executing a stored procedure, which produces multiple result sets. """ - if log_enabled: - logger.debug("Attempting to retrieve next result set.") + LogMsg(2, "Attempting to retrieve next result set.") self.messages = [] if self.stmt_handler is None: - if log_enabled: - logger.error("Please execute an SQL statement in order to get result sets.") + LogMsg(4, "Please execute an SQL statement in order to get result sets.") self.messages.append(ProgrammingError("Please execute an SQL statement in order to get result sets.")) raise self.messages[len(self.messages) - 1] if self._result_set_produced == False: - if log_enabled: - logger.error("The last call to execute did not produce any result set.") + LogMsg(4, "The last call to execute did not produce any result set.") self.messages.append(ProgrammingError("The last call to execute did not produce any result set.")) raise self.messages[len(self.messages) - 1] try: @@ -1910,8 +1790,7 @@ def nextset(self): self._all_stmt_handlers.append(self.stmt_handler) self.stmt_handler = ibm_db.next_result(self._all_stmt_handlers[0]) except Exception as inst: - if log_enabled: - logger.error(f"Error while retrieving next result set: {_get_exception(inst)}") + LogMsg(4, f"Error while retrieving next result set: {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] @@ -1920,8 +1799,7 @@ def nextset(self): if self.stmt_handler == None: return None - if log_enabled: - logger.debug("Successfully retrieved next result set.") + LogMsg(1, "Successfully retrieved next result set.") return True def setinputsizes(self, sizes): @@ -1936,8 +1814,8 @@ def setoutputsize(self, size, column=-1): # and binary data in a row tuple fetched from the database # to decimal and binary objects, for returning it to the user. def _fix_return_data_type(self, row): - if log_enabled: - logger.debug("Fixing return data types for row: %s", row) + message = "Fixing return data types for row: %s", row + LogMsg(1, message) row_list = None for index in range(len(row)): if row[index] is not None: @@ -1956,15 +1834,13 @@ def _fix_return_data_type(self, row): row_list[index] = decimal.Decimal(str(row[index]).replace(",", ".")) except Exception as inst: - if log_enabled: - logger.error(f"Data type format error: {str(inst)}") + LogMsg(4, f"Data type format error: {str(inst)}") self.messages.append(DataError("Data type format error: "+ str(inst))) raise self.messages[len(self.messages) - 1] if row_list is None: return row else: - if log_enabled: - logger.debug("Fixed return data types: %s", row_list) + LogMsg(1, "Fixed return data types: %s", row_list) return tuple(row_list) def __enter__(self): From afe6d5f1ac38303b794768e519adf4d18011366d Mon Sep 17 00:00:00 2001 From: Balram Choudhary Date: Wed, 3 Jul 2024 16:06:53 +0530 Subject: [PATCH 3/3] Logging in ibm_db_dbi module Signed-off-by: Balram Choudhary --- README.md | 9 +- ibm_db_dbi.py | 681 ++++++++++++++++++++++++++------------------------ 2 files changed, 365 insertions(+), 325 deletions(-) diff --git a/README.md b/README.md index e255a07b..6c5a040e 100644 --- a/README.md +++ b/README.md @@ -284,15 +284,20 @@ To enable logging: import ibm_db_dbi as dbi # Log to console -dbi.debug() +dbi.debug(True) # Log to a file (e.g., log.txt) dbi.debug("log.txt") + +# stop logging +dbi.debug(False) ``` -Calling dbi.debug() without arguments will output logs to the console. +Calling dbi.debug(True) with boolean True argument will output logs to the console. Calling dbi.debug("log.txt") will log messages to the specified file (log.txt in this example). +Calling dbi.debug(False) with boolean False argument will stop logging. + ## Example of SSL Connection String * **Secure Database Connection using SSL/TSL** - ibm_db supports secure connection to Database Server over SSL same as ODBC/CLI driver. If you have SSL Certificate from server or an CA signed certificate, just use it in connection string as below: diff --git a/ibm_db_dbi.py b/ibm_db_dbi.py index 794353fa..8dfe015b 100644 --- a/ibm_db_dbi.py +++ b/ibm_db_dbi.py @@ -28,30 +28,41 @@ logger = logging.getLogger(__name__) log_enabled = False +# Define macros for log levels +DEBUG = "DEBUG" +INFO = "INFO" +WARNING = "WARNING" +ERROR = "ERROR" +EXCEPTION = "EXCEPTION" -def debug(filename=None): + +def debug(option): global log_enabled - log_enabled = True # Set log_enabled to True when debug is called - # Configure logging - if filename: - if '.' not in filename: - filename += '.txt' - logging.basicConfig(filename=filename, level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s', filemode='w') + if isinstance(option, bool): + log_enabled = option + if log_enabled: + logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s') + elif isinstance(option, str): + log_enabled = True # Set log_enabled to True + if '.' not in option: + option += '.txt' + logging.basicConfig(filename=option, level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s', + filemode='w') else: - logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s') + print("Invalid argument in debug. Please give a boolean or a file name in string.") -def LogMsg(level, message): +def LogMsg(log_level, message): if log_enabled: - if level == 1: + if log_level == DEBUG: logger.debug(message) - elif level == 2: + elif log_level == INFO: logger.info(message) - elif level == 3: + elif log_level == WARNING: logger.warning(message) - elif level == 4: + elif log_level == ERROR: logger.error(message) - elif level == 5: + elif log_level == EXCEPTION: logger.exception(message) @@ -61,12 +72,14 @@ def LogMsg(level, message): buffer = memoryview if PY2: import exceptions + exception = exceptions.Exception else: exception = Exception if PY2: import __builtin__ + string_types = __builtin__.unicode, bytes int_types = __builtin__.long, int else: @@ -74,6 +87,7 @@ def LogMsg(level, message): int_types = int import ibm_db + __version__ = ibm_db.__version__ # Constants for specifying database connection options. @@ -116,13 +130,15 @@ class Error(exception): statement. """ + def __init__(self, message): """This is the constructor which take one string argument.""" self._message = message super(Error, self).__init__(message) + def __str__(self): """Converts the message to a string.""" - return 'ibm_db_dbi::'+str(self.__class__.__name__)+': '+str(self._message) + return 'ibm_db_dbi::' + str(self.__class__.__name__) + ': ' + str(self._message) class Warning(exception): @@ -130,13 +146,15 @@ class Warning(exception): warnings such as data truncations. """ + def __init__(self, message): """This is the constructor which take one string argument.""" self._message = message - super(Warning,self).__init__(message) + super(Warning, self).__init__(message) + def __str__(self): """Converts the message to a string.""" - return 'ibm_db_dbi::'+str(self.__class__.__name__)+': '+str(self._message) + return 'ibm_db_dbi::' + str(self.__class__.__name__) + ': ' + str(self._message) class InterfaceError(Error): @@ -176,6 +194,7 @@ class ProgrammingError(DatabaseError): """ pass + class IntegrityError(DatabaseError): """This exception is thrown when errors occur when the relational integrity of database fails, such as foreign key check fails. @@ -184,7 +203,7 @@ class IntegrityError(DatabaseError): pass -class DataError(DatabaseError): +class DataError(DatabaseError): """This exception is raised when errors due to data processing, occur, such as divide by zero. @@ -207,6 +226,7 @@ def Date(year, month, day): """ return datetime.date(year, month, day) + def Time(hour, minute, second): """This method can be used to get time object from integers, for inserting it into a TIME column in the database. @@ -214,6 +234,7 @@ def Time(hour, minute, second): """ return datetime.time(hour, minute, second) + def Timestamp(year, month, day, hour, minute, second): """This method can be used to get timestamp object from integers, for inserting it into a TIMESTAMP column in the database. @@ -221,6 +242,7 @@ def Timestamp(year, month, day, hour, minute, second): """ return datetime.datetime(year, month, day, hour, minute, second) + def DateFromTicks(ticks): """This method can be used to get date object from ticks seconds, for inserting it into a DATE column in the database. @@ -229,6 +251,7 @@ def DateFromTicks(ticks): time_tuple = time.localtime(ticks) return datetime.date(time_tuple[0], time_tuple[1], time_tuple[2]) + def TimeFromTicks(ticks): """This method can be used to get time object from ticks seconds, for inserting it into a TIME column in the database. @@ -237,6 +260,7 @@ def TimeFromTicks(ticks): time_tuple = time.localtime(ticks) return datetime.time(time_tuple[3], time_tuple[4], time_tuple[5]) + def TimestampFromTicks(ticks): """This method can be used to get timestamp object from ticks seconds, for inserting it into a TIMESTAMP column in the database. @@ -244,14 +268,15 @@ def TimestampFromTicks(ticks): """ time_tuple = time.localtime(ticks) return datetime.datetime(time_tuple[0], time_tuple[1], time_tuple[2], - time_tuple[3], time_tuple[4], time_tuple[5]) + time_tuple[3], time_tuple[4], time_tuple[5]) + def Binary(string): """This method can be used to store binary information, for inserting it into a binary type column in the database. """ - if not isinstance( string, (bytes, memoryview) ): + if not isinstance(string, (bytes, memoryview)): raise InterfaceError("Binary function expects type string argument.") return buffer(string) @@ -262,6 +287,7 @@ class DBAPITypeObject(frozenset): sequence argument of the execute method. """ + def __new__(cls, col_types): return frozenset.__new__(cls, col_types) @@ -278,7 +304,7 @@ def __cmp__(self, cmp): """ if cmp in self.col_types: return 0 - if sys.version_info < (3, ): + if sys.version_info < (3,): if cmp < self.col_types: return 1 else: @@ -303,13 +329,14 @@ def __ne__(self, cmp): def __hash__(self): return id(self) + # The user can use these objects to compare the database column types # with in order to determine the python type to provide in the # parameter sequence argument of the execute method. STRING = DBAPITypeObject(("CHARACTER", "CHAR", "VARCHAR", "CHARACTER VARYING", "CHAR VARYING", "STRING",)) -TEXT = DBAPITypeObject(("CLOB", "CHARACTER LARGE OBJECT", "CHAR LARGE OBJECT","DBCLOB")) +TEXT = DBAPITypeObject(("CLOB", "CHARACTER LARGE OBJECT", "CHAR LARGE OBJECT", "DBCLOB")) XML = DBAPITypeObject(("XML",)) @@ -333,6 +360,7 @@ def __hash__(self): BOOLEAN = DBAPITypeObject(("BOOLEAN",)) + # This method is used to determine the type of error that was # generated. It takes an exception instance as an argument, and # returns exception object of the appropriate type. @@ -340,19 +368,19 @@ def _get_exception(inst): # These tuple are used to determine the type of exceptions that are # thrown by the database. They store the SQLSTATE code and the # SQLSTATE class code(the 2 digit prefix of the SQLSTATE code) - warning_error_tuple = ('01', ) + warning_error_tuple = ('01',) data_error_tuple = ('02', '22', '10601', '10603', '10605', '10901', '10902', - '38552', '54') + '38552', '54') - operational_error_tuple = ( '08', '09', '10502', '10000', '10611', '38501', - '38503', '38553', '38H01', '38H02', '38H03', '38H04', - '38H05', '38H06', '38H07', '38H09', '38H0A') + operational_error_tuple = ('08', '09', '10502', '10000', '10611', '38501', + '38503', '38553', '38H01', '38H02', '38H03', '38H04', + '38H05', '38H06', '38H07', '38H09', '38H0A') - integrity_error_tuple = ('23', ) + integrity_error_tuple = ('23',) internal_error_tuple = ('24', '25', '26', '2D', '51', '57') - programming_error_tuple = ('08002', '07', 'OD', 'OF','OK','ON','10', '27', + programming_error_tuple = ('08002', '07', 'OD', 'OF', 'OK', 'ON', '10', '27', '28', '2E', '34', '36', '38', '39', '56', '42', '3B', '40', '44', '53', '55', '58', '5U', '21') @@ -360,46 +388,46 @@ def _get_exception(inst): # These tuple are used to determine the type of exceptions that are # thrown from the driver module. - interface_exceptions = ( "Supplied parameter is invalid", - "ATTR_CASE attribute must be one of " - "CASE_LOWER, CASE_UPPER, or CASE_NATURAL", - "Connection or statement handle must be passed in.", - "Param is not a tuple") - - programming_exceptions = ( "Connection is not active", - "qualifier must be a string", - "unique must be a boolean", - "Parameters not bound", - "owner must be a string", - "table_name must be a string", - "table type must be a string", - "column_name must be a string", - "Column ordinal out of range", - "procedure name must be a string", + interface_exceptions = ("Supplied parameter is invalid", + "ATTR_CASE attribute must be one of " + "CASE_LOWER, CASE_UPPER, or CASE_NATURAL", + "Connection or statement handle must be passed in.", + "Param is not a tuple") + + programming_exceptions = ("Connection is not active", + "qualifier must be a string", + "unique must be a boolean", + "Parameters not bound", + "owner must be a string", + "table_name must be a string", + "table type must be a string", + "column_name must be a string", + "Column ordinal out of range", + "procedure name must be a string", "Requested row number must be a positive value", - "Options Array must have string indexes") - - database_exceptions = ( "Binding Error", - "Column information cannot be retrieved: ", - "Column binding cannot be done: ", - "Failed to Determine XML Size: ") - - statement_exceptions = ( "Statement Execute Failed: ", - "Describe Param Failed: ", - "Sending data failed: ", - "Fetch Failure: ", - "SQLNumResultCols failed: ", - "SQLRowCount failed: ", - "SQLGetDiagField failed: ", - "Statement prepare Failed: ") - - operational_exceptions = ( "Connection Resource cannot be found", - "Failed to Allocate Memory", - "Describe Param Failed: ", - "Statement Execute Failed: ", - "Sending data failed: ", - "Failed to Allocate Memory for XML Data", - "Failed to Allocate Memory for LOB Data") + "Options Array must have string indexes") + + database_exceptions = ("Binding Error", + "Column information cannot be retrieved: ", + "Column binding cannot be done: ", + "Failed to Determine XML Size: ") + + statement_exceptions = ("Statement Execute Failed: ", + "Describe Param Failed: ", + "Sending data failed: ", + "Fetch Failure: ", + "SQLNumResultCols failed: ", + "SQLRowCount failed: ", + "SQLGetDiagField failed: ", + "Statement prepare Failed: ") + + operational_exceptions = ("Connection Resource cannot be found", + "Failed to Allocate Memory", + "Describe Param Failed: ", + "Statement Execute Failed: ", + "Sending data failed: ", + "Failed to Allocate Memory for XML Data", + "Failed to Allocate Memory for LOB Data") # First check if the exception is from the database. If it is # determine the SQLSTATE code which is used further to determine @@ -412,15 +440,14 @@ def _get_exception(inst): if message.startswith("Exception('"): if message.endswith("',)"): # python 2 message = message[11:] - message = message[:len(message)-3] - elif message.endswith("')"): # python 3 + message = message[:len(message) - 3] + elif message.endswith("')"): # python 3 message = message[11:] - message = message[:len(message)-2] - + message = message[:len(message) - 2] index = message.find('SQLSTATE=') - if( message != '') & (index != -1): - error_code = message[(index+9):(index+14)] + if (message != '') & (index != -1): + error_code = message[(index + 9):(index + 14)] prefix_code = error_code[:2] else: for key in interface_exceptions: @@ -445,26 +472,26 @@ def _get_exception(inst): # First check if the SQLSTATE is in the tuples, if not check # if the SQLSTATE class code is in the tuples to determine the # exception type. - if ( error_code in warning_error_tuple or - prefix_code in warning_error_tuple ): + if (error_code in warning_error_tuple or + prefix_code in warning_error_tuple): return Warning(message) - if ( error_code in data_error_tuple or - prefix_code in data_error_tuple ): + if (error_code in data_error_tuple or + prefix_code in data_error_tuple): return DataError(message) - if ( error_code in operational_error_tuple or - prefix_code in operational_error_tuple ): + if (error_code in operational_error_tuple or + prefix_code in operational_error_tuple): return OperationalError(message) - if ( error_code in integrity_error_tuple or - prefix_code in integrity_error_tuple ): + if (error_code in integrity_error_tuple or + prefix_code in integrity_error_tuple): return IntegrityError(message) - if ( error_code in internal_error_tuple or - prefix_code in internal_error_tuple ): + if (error_code in internal_error_tuple or + prefix_code in internal_error_tuple): return InternalError(message) - if ( error_code in programming_error_tuple or - prefix_code in programming_error_tuple ): + if (error_code in programming_error_tuple or + prefix_code in programming_error_tuple): return ProgrammingError(message) - if ( error_code in not_supported_error_tuple or - prefix_code in not_supported_error_tuple ): + if (error_code in not_supported_error_tuple or + prefix_code in not_supported_error_tuple): return NotSupportedError(message) return DatabaseError(message) @@ -477,18 +504,18 @@ def _retrieve_current_schema(dsn): current_schema_value = None current_schema_start = dsn.find(ODBC_CURRENTSCHEMA_KEYWORD) message = f"current_schema_start: {current_schema_start}" - LogMsg(1, message) + LogMsg(DEBUG, message) if current_schema_start > -1: current_schema_end = dsn.find(';', current_schema_start) message = f"ODBC_CURRENTSCHEMA_KEYWORD: {ODBC_CURRENTSCHEMA_KEYWORD}" - LogMsg(1, message) - LogMsg(1, f"current_schema_end: {current_schema_end}") + LogMsg(DEBUG, message) + LogMsg(DEBUG, f"current_schema_end: {current_schema_end}") current_schema_value = dsn[ - (current_schema_start + len(ODBC_CURRENTSCHEMA_KEYWORD)) - :current_schema_end - ] - LogMsg(1, f"current_schema_value: {current_schema_value}") + (current_schema_start + len(ODBC_CURRENTSCHEMA_KEYWORD)) + :current_schema_end + ] + LogMsg(DEBUG, f"current_schema_value: {current_schema_value}") return current_schema_value @@ -497,14 +524,14 @@ def _server_connect(dsn, user='', password='', host=''): """ if dsn is None: - LogMsg(4, "dsn value should not be None") + LogMsg(ERROR, "dsn value should not be None") raise InterfaceError("dsn value should not be None") if (not isinstance(dsn, string_types)) | \ - (not isinstance(user, string_types)) | \ - (not isinstance(password, string_types)) | \ - (not isinstance(host, string_types)): - LogMsg(4, "Arguments should be of type string or unicode") + (not isinstance(user, string_types)) | \ + (not isinstance(password, string_types)) | \ + (not isinstance(host, string_types)): + LogMsg(ERROR, "Arguments should be of type string or unicode") raise InterfaceError("Arguments should be of type string or unicode") # If the dsn does not contain port and protocal adding database @@ -521,7 +548,7 @@ def _server_connect(dsn, user='', password='', host=''): # attach = true is not valid against IDS. And attach is not needed for connect currently. #if dsn.find('attach=') == -1: - #dsn = dsn + "attach=true;" + #dsn = dsn + "attach=true;" if user != '' and dsn.find('UID=') == -1: dsn = dsn + "UID=" + user + ";" if password != '' and dsn.find('PWD=') == -1: @@ -530,36 +557,37 @@ def _server_connect(dsn, user='', password='', host=''): conn = ibm_db.connect(dsn, '', '') except Exception as inst: message = f"An exception occurred while connecting to server: {inst}" - LogMsg(5, message) + LogMsg(EXCEPTION, message) raise _get_exception(inst) return conn + def createdb(database, dsn, user='', password='', host='', codeset='', mode=''): """This method creates a database by using the specified database name, code set, and mode """ if database is None: - LogMsg(4, "createdb expects a not None database name value") + LogMsg(ERROR, "createdb expects a not None database name value") raise InterfaceError("createdb expects a not None database name value") if (not isinstance(database, string_types)) | \ - (not isinstance(codeset, string_types)) | \ - (not isinstance(mode, string_types)): - LogMsg(4, "Arguments should be string or unicode") + (not isinstance(codeset, string_types)) | \ + (not isinstance(mode, string_types)): + LogMsg(ERROR, "Arguments should be string or unicode") raise InterfaceError("Arguments should be string or unicode") conn = _server_connect(dsn, user=user, password=password, host=host) try: return_value = ibm_db.createdb(conn, database, codeset, mode) - LogMsg(1, f"Return value from ibm_db.createdb: {return_value}") + LogMsg(DEBUG, f"Return value from ibm_db.createdb: {return_value}") except Exception as inst: - LogMsg(5, f"An exception occurred during database creation: {inst}") + LogMsg(EXCEPTION, f"An exception occurred during database creation: {inst}") raise _get_exception(inst) finally: try: ibm_db.close(conn) except Exception as inst: - LogMsg(5, f"An exception occurred while closing connection: {inst}") + LogMsg(EXCEPTION, f"An exception occurred while closing connection: {inst}") raise _get_exception(inst) return return_value @@ -570,24 +598,24 @@ def dropdb(database, dsn, user='', password='', host=''): """ if database is None: - LogMsg(4, "dropdb expects a not None database name value") + LogMsg(ERROR, "dropdb expects a not None database name value") raise InterfaceError("dropdb expects a not None database name value") if not isinstance(database, string_types): - LogMsg(4, "Arguments should be string or unicode") + LogMsg(ERROR, "Arguments should be string or unicode") raise InterfaceError("Arguments should be string or unicode") conn = _server_connect(dsn, user=user, password=password, host=host) try: return_value = ibm_db.dropdb(conn, database) - LogMsg(1, f"Return value from ibm_db.dropdb: {return_value}") + LogMsg(DEBUG, f"Return value from ibm_db.dropdb: {return_value}") except Exception as inst: - LogMsg(5, f"An exception occurred during database droping: {inst}") + LogMsg(EXCEPTION, f"An exception occurred during database droping: {inst}") raise _get_exception(inst) finally: try: ibm_db.close(conn) except Exception as inst: - LogMsg(5, f"An exception occurred while closing connection: {inst}") + LogMsg(EXCEPTION, f"An exception occurred while closing connection: {inst}") raise _get_exception(inst) return return_value @@ -598,26 +626,26 @@ def recreatedb(database, dsn, user='', password='', host='', codeset='', mode='' """ if database is None: - LogMsg(4, "recreatedb expects a not None database name value") + LogMsg(ERROR, "recreatedb expects a not None database name value") raise InterfaceError("recreatedb expects a not None database name value") if (not isinstance(database, string_types)) | \ - (not isinstance(codeset, string_types)) | \ - (not isinstance(mode, string_types)): - LogMsg(4, "Arguments should be string or unicode") + (not isinstance(codeset, string_types)) | \ + (not isinstance(mode, string_types)): + LogMsg(ERROR, "Arguments should be string or unicode") raise InterfaceError("Arguments should be string or unicode") conn = _server_connect(dsn, user=user, password=password, host=host) try: return_value = ibm_db.recreatedb(conn, database, codeset, mode) - LogMsg(1, f"Return value from ibm_db.recreatedb: {return_value}") + LogMsg(DEBUG, f"Return value from ibm_db.recreatedb: {return_value}") except Exception as inst: - LogMsg(5, f"An exception occurred during database recreation: {inst}") + LogMsg(EXCEPTION, f"An exception occurred during database recreation: {inst}") raise _get_exception(inst) finally: try: ibm_db.close(conn) except Exception as inst: - LogMsg(5, f"An exception occurred while closing connection: {inst}") + LogMsg(EXCEPTION, f"An exception occurred while closing connection: {inst}") raise _get_exception(inst) return return_value @@ -628,26 +656,26 @@ def createdbNX(database, dsn, user='', password='', host='', codeset='', mode='' """ if database is None: - LogMsg(4, "createdbNX expects a not None database name value") + LogMsg(ERROR, "createdbNX expects a not None database name value") raise InterfaceError("createdbNX expects a not None database name value") if (not isinstance(database, string_types)) | \ - (not isinstance(codeset, string_types)) | \ - (not isinstance(mode, string_types)): - LogMsg(4, "Arguments should be string or unicode") + (not isinstance(codeset, string_types)) | \ + (not isinstance(mode, string_types)): + LogMsg(ERROR, "Arguments should be string or unicode") raise InterfaceError("Arguments should be string or unicode") conn = _server_connect(dsn, user=user, password=password, host=host) try: return_value = ibm_db.createdbNX(conn, database, codeset, mode) - LogMsg(1, f"Return value from ibm_db.createdbNX: {return_value}") + LogMsg(DEBUG, f"Return value from ibm_db.createdbNX: {return_value}") except Exception as inst: - LogMsg(5, f"An exception occurred during database createdbNX: {inst}") + LogMsg(EXCEPTION, f"An exception occurred during database createdbNX: {inst}") raise _get_exception(inst) finally: try: ibm_db.close(conn) except Exception as inst: - LogMsg(5, f"An exception occurred while closing connection: {inst}") + LogMsg(EXCEPTION, f"An exception occurred while closing connection: {inst}") raise _get_exception(inst) return return_value @@ -659,31 +687,31 @@ def connect(dsn, user='', password='', host='', database='', conn_options=None): """ try: message = f"dsn: {dsn}, user: {user}, host: {host}, database: {database}, conn_options: {conn_options}" - LogMsg(1, message) + LogMsg(DEBUG, message) if dsn is None: - LogMsg(4, "connect expects a not None dsn value") + LogMsg(ERROR, "connect expects a not None dsn value") raise InterfaceError("connect expects a not None dsn value") if (not isinstance(dsn, string_types)) | \ - (not isinstance(user, string_types)) | \ - (not isinstance(password, string_types)) | \ - (not isinstance(host, string_types)) | \ - (not isinstance(database, string_types)): + (not isinstance(user, string_types)) | \ + (not isinstance(password, string_types)) | \ + (not isinstance(host, string_types)) | \ + (not isinstance(database, string_types)): message = "connect expects the first five arguments to be of type string or unicode" - LogMsg(4, message) + LogMsg(ERROR, message) raise InterfaceError("connect expects the first five arguments to" - " be of type string or unicode") + " be of type string or unicode") if conn_options is not None: if not isinstance(conn_options, dict): message = "connect expects the sixth argument (conn_options) to be of type dict" - LogMsg(4, message) + LogMsg(ERROR, message) raise InterfaceError("connect expects the sixth argument" " (conn_options) to be of type dict") if not SQL_ATTR_AUTOCOMMIT in conn_options: conn_options[SQL_ATTR_AUTOCOMMIT] = SQL_AUTOCOMMIT_OFF else: - conn_options = {SQL_ATTR_AUTOCOMMIT : SQL_AUTOCOMMIT_OFF} + conn_options = {SQL_ATTR_AUTOCOMMIT: SQL_AUTOCOMMIT_OFF} # If the dsn does not contain port and protocol adding database # and hostname is no good. Add these when required, that is, @@ -704,15 +732,15 @@ def connect(dsn, user='', password='', host='', database='', conn_options=None): if password != '' and dsn.find('PWD=') == -1: dsn = dsn + "PWD=" + password + ";" - LogMsg(1, f"Connection string: {dsn}") + LogMsg(DEBUG, f"Connection string: {dsn}") conn = ibm_db.connect(dsn, '', '', conn_options) conn_object = Connection(conn) conn_object.set_current_schema(_retrieve_current_schema(dsn) or user) - LogMsg(1, "Connection successful.") + LogMsg(INFO, "Connection successful.") return conn_object except Exception as inst: - LogMsg(5,f"An exception occurred while connecting: {inst}") + LogMsg(EXCEPTION, f"An exception occurred while connecting: {inst}") raise _get_exception(inst) @@ -722,26 +750,26 @@ def pconnect(dsn, user='', password='', host='', database='', conn_options=None) """ if dsn is None: - LogMsg(4, "connect expects a not None dsn value") + LogMsg(ERROR, "connect expects a not None dsn value") raise InterfaceError("connect expects a not None dsn value") if (not isinstance(dsn, string_types)) | \ - (not isinstance(user, string_types)) | \ - (not isinstance(password, string_types)) | \ - (not isinstance(host, string_types)) | \ - (not isinstance(database, string_types)): - LogMsg(4, "connect expects the first five arguments to be of type string or unicode") + (not isinstance(user, string_types)) | \ + (not isinstance(password, string_types)) | \ + (not isinstance(host, string_types)) | \ + (not isinstance(database, string_types)): + LogMsg(ERROR, "connect expects the first five arguments to be of type string or unicode") raise InterfaceError("connect expects the first five arguments to" - " be of type string or unicode") + " be of type string or unicode") if conn_options is not None: if not isinstance(conn_options, dict): - LogMsg(4, "connect expects the sixth argument (conn_options) to be of type dict") + LogMsg(ERROR, "connect expects the sixth argument (conn_options) to be of type dict") raise InterfaceError("connect expects the sixth argument" " (conn_options) to be of type dict") if not SQL_ATTR_AUTOCOMMIT in conn_options: conn_options[SQL_ATTR_AUTOCOMMIT] = SQL_AUTOCOMMIT_OFF else: - conn_options = {SQL_ATTR_AUTOCOMMIT : SQL_AUTOCOMMIT_OFF} + conn_options = {SQL_ATTR_AUTOCOMMIT: SQL_AUTOCOMMIT_OFF} # If the dsn does not contain port and protocal adding database # and hostname is no good. Add these when required, that is, @@ -762,21 +790,23 @@ def pconnect(dsn, user='', password='', host='', database='', conn_options=None) if password != '' and dsn.find('PWD=') == -1: dsn = dsn + "PWD=" + password + ";" try: - LogMsg(1, f"Connecting to database with DSN: {dsn}") + LogMsg(DEBUG, f"Connecting to database with DSN: {dsn}") conn = ibm_db.pconnect(dsn, '', '', conn_options) - LogMsg(1, "Connection established successfully") + LogMsg(INFO, "Connection established successfully") conn_object = Connection(conn) conn_object.set_current_schema(_retrieve_current_schema(dsn) or user) return conn_object except Exception as inst: - LogMsg(5, f"An exception occurred while connecting: {inst}") + LogMsg(EXCEPTION, f"An exception occurred while connecting: {inst}") raise _get_exception(inst) + class Connection(object): """This class object represents a connection between the database and the application. """ + def __init__(self, conn_handler): """Constructor for Connection object. It takes ibm_db connection handler as an argument. @@ -792,7 +822,7 @@ def __init__(self, conn_handler): self.FIX_RETURN_TYPE = 1 # This method is used to get the DBMS_NAME - def __get_dbms_name( self ): + def __get_dbms_name(self): return self.__dbms_name # This attribute specifies the DBMS_NAME @@ -800,7 +830,7 @@ def __get_dbms_name( self ): dbms_name = property(__get_dbms_name, None, None, "") # This method is used to get the DBMS_ver - def __get_dbms_ver( self ): + def __get_dbms_ver(self): return self.__dbms_ver # This attribute specifies the DBMS_ver @@ -815,20 +845,20 @@ def close(self): self.rollback() try: if self.conn_handler is None: - LogMsg(4, "Connection cannot be closed; connection is no longer active.") + LogMsg(ERROR, "Connection cannot be closed; connection is no longer active.") raise ProgrammingError("Connection cannot be closed; " - "connection is no longer active.") + "connection is no longer active.") else: - LogMsg(1, f"Closing connection: conn_handler={self.conn_handler}") + LogMsg(DEBUG, f"Closing connection: conn_handler={self.conn_handler}") return_value = ibm_db.close(self.conn_handler) - LogMsg(1, "Connection closed.") + LogMsg(INFO, "Connection closed.") except Exception as inst: - LogMsg(5, f"An exception occurred while closing connection: {inst}") + LogMsg(EXCEPTION, f"An exception occurred while closing connection: {inst}") raise _get_exception(inst) self.conn_handler = None for index in range(len(self._cursor_list)): if (self._cursor_list[index]() != None): - tmp_cursor = self._cursor_list[index]() + tmp_cursor = self._cursor_list[index]() tmp_cursor.conn_handler = None tmp_cursor.stmt_handler = None tmp_cursor._all_stmt_handlers = None @@ -842,9 +872,9 @@ def commit(self): """ try: return_value = ibm_db.commit(self.conn_handler) - LogMsg(1, "Transaction committed.") + LogMsg(INFO, "Transaction committed.") except Exception as inst: - LogMsg(5, f"An exception occurred while committing transaction: {inst}") + LogMsg(EXCEPTION, f"An exception occurred while committing transaction: {inst}") raise _get_exception(inst) return return_value @@ -855,9 +885,9 @@ def rollback(self): """ try: return_value = ibm_db.rollback(self.conn_handler) - LogMsg(1, "Transaction rolled back.") + LogMsg(INFO, "Transaction rolled back.") except Exception as inst: - LogMsg(5, f"An exception occurred while rolling back transaction: {inst}") + LogMsg(EXCEPTION, f"An exception occurred while rolling back transaction: {inst}") raise _get_exception(inst) return return_value @@ -867,9 +897,9 @@ def cursor(self): """ if self.conn_handler is None: - LogMsg(4, "Cursor cannot be returned; connection is no longer active.") + LogMsg(ERROR, "Cursor cannot be returned; connection is no longer active.") raise ProgrammingError("Cursor cannot be returned; " - "connection is no longer active.") + "connection is no longer active.") cursor = Cursor(self.conn_handler, self) self._cursor_list.append(weakref.ref(cursor)) return cursor @@ -879,7 +909,7 @@ def set_option(self, attr_dict): """Input: connection attribute dictionary Return: True on success or False on failure """ - LogMsg(1, f"Setting connection options: {attr_dict}") + LogMsg(DEBUG, f"Setting connection options: {attr_dict}") return ibm_db.set_option(self.conn_handler, attr_dict, 1) # Retrieves connection attributes values @@ -887,19 +917,19 @@ def get_option(self, attr_key): """Input: connection attribute key Return: current setting of the resource attribute requested """ - LogMsg(1, f"Getting connection option: {attr_key}") + LogMsg(DEBUG, f"Getting connection option: {attr_key}") return ibm_db.get_option(self.conn_handler, attr_key, 1) # Sets FIX_RETURN_TYPE. Added for performance improvement def set_fix_return_type(self, is_on): try: - LogMsg(1, f"Setting fix return type to: {is_on}") + LogMsg(DEBUG, f"Setting fix return type to: {is_on}") if is_on: self.FIX_RETURN_TYPE = 1 else: self.FIX_RETURN_TYPE = 0 except Exception as inst: - LogMsg(5, f"An exception occurred while setting fix return type: {inst}") + LogMsg(EXCEPTION, f"An exception occurred while setting fix return type: {inst}") raise _get_exception(inst) return self.FIX_RETURN_TYPE @@ -909,15 +939,15 @@ def set_autocommit(self, is_on): Return: True on success or False on failure """ try: - LogMsg(1, f"Setting autocommit to: {is_on}") + LogMsg(DEBUG, f"Setting autocommit to: {is_on}") if is_on: - is_set = ibm_db.set_option(self.conn_handler, {SQL_ATTR_AUTOCOMMIT : SQL_AUTOCOMMIT_ON}, 1) + is_set = ibm_db.set_option(self.conn_handler, {SQL_ATTR_AUTOCOMMIT: SQL_AUTOCOMMIT_ON}, 1) else: - is_set = ibm_db.set_option(self.conn_handler, {SQL_ATTR_AUTOCOMMIT : SQL_AUTOCOMMIT_OFF}, 1) + is_set = ibm_db.set_option(self.conn_handler, {SQL_ATTR_AUTOCOMMIT: SQL_AUTOCOMMIT_OFF}, 1) except Exception as inst: - LogMsg(5, f"An exception occurred while setting autocommit: {inst}") + LogMsg(EXCEPTION, f"An exception occurred while setting autocommit: {inst}") raise _get_exception(inst) - LogMsg(1, f"set_autocommit returns: {is_set}") + LogMsg(DEBUG, f"set_autocommit returns: {is_set}") return is_set # Sets connection attribute values @@ -927,10 +957,10 @@ def set_current_schema(self, schema_name): """ self.current_schema = schema_name try: - LogMsg(1, f"Setting current schema to: {schema_name}") - is_set = ibm_db.set_option(self.conn_handler, {SQL_ATTR_CURRENT_SCHEMA : schema_name}, 1) + LogMsg(DEBUG, f"Setting current schema to: {schema_name}") + is_set = ibm_db.set_option(self.conn_handler, {SQL_ATTR_CURRENT_SCHEMA: schema_name}, 1) except Exception as inst: - LogMsg(5, f"An exception occurred setting current schema: {inst}") + LogMsg(EXCEPTION, f"An exception occurred setting current schema: {inst}") raise _get_exception(inst) return is_set @@ -942,9 +972,9 @@ def get_current_schema(self): conn_schema = ibm_db.get_option(self.conn_handler, SQL_ATTR_CURRENT_SCHEMA, 1) if conn_schema is not None and conn_schema != '': self.current_schema = conn_schema - LogMsg(1, f"Current schema: {self.current_schema}") + LogMsg(DEBUG, f"Current schema: {self.current_schema}") except Exception as inst: - LogMsg(5, f"An exception occurred while getting current schema: {inst}") + LogMsg(EXCEPTION, f"An exception occurred while getting current schema: {inst}") raise _get_exception(inst) return self.current_schema @@ -956,9 +986,9 @@ def server_info(self): server_info = [] server_info.append(self.dbms_name) server_info.append(self.dbms_ver) - LogMsg(2, f"Server info: {server_info}") + LogMsg(INFO, f"Server info: {server_info}") except Exception as inst: - LogMsg(5, f"An exception occurred while getting server info: {inst}") + LogMsg(EXCEPTION, f"An exception occurred while getting server info: {inst}") raise _get_exception(inst) return tuple(server_info) @@ -970,27 +1000,27 @@ def tables(self, schema_name=None, table_name=None): """Input: connection - ibm_db.IBM_DBConnection object Return: sequence of table metadata dicts for the specified schema """ - LogMsg(2, f"Retrieving the tables for a specified schema") + LogMsg(INFO, f"Retrieving the tables for a specified schema") result = [] if schema_name is not None: schema_name = self.set_case("DB2_LUW", schema_name) - LogMsg(2, f"Schema name: {schema_name}") + LogMsg(INFO, f"Schema name: {schema_name}") if table_name is not None: table_name = self.set_case("DB2_LUW", table_name) - LogMsg(2, f"Table name: {table_name}") + LogMsg(INFO, f"Table name: {table_name}") try: stmt = ibm_db.tables(self.conn_handler, None, schema_name, table_name) - LogMsg(1, f"Statement to retrieve table: {stmt}") + LogMsg(DEBUG, f"Statement to retrieve table: {stmt}") row = ibm_db.fetch_assoc(stmt) i = 0 while (row): - result.append( row ) + result.append(row) i += 1 row = ibm_db.fetch_assoc(stmt) ibm_db.free_result(stmt) except Exception as inst: - LogMsg(5, f"An exception occurred while retrieving the tables: {inst}") + LogMsg(EXCEPTION, f"An exception occurred while retrieving the tables: {inst}") raise _get_exception(inst) return result @@ -1012,28 +1042,28 @@ def indexes(self, unique=True, schema_name=None, table_name=None): 'ASC_OR_DESC': 'A' } """ - LogMsg(2, f"Retrieving metadata pertaining to index for specified schema/Table") + LogMsg(INFO, f"Retrieving metadata pertaining to index for specified schema/Table") result = [] if schema_name is not None: schema_name = self.set_case("DB2_LUW", schema_name) - LogMsg(2, f"Schema name: {schema_name}") + LogMsg(INFO, f"Schema name: {schema_name}") if table_name is not None: table_name = self.set_case("DB2_LUW", table_name) - LogMsg(2, f"Table name: {table_name}") + LogMsg(INFO, f"Table name: {table_name}") try: stmt = ibm_db.statistics(self.conn_handler, None, schema_name, table_name, unique) - LogMsg(1, f"Statement to retrieving metadata pertaining to index: {stmt}") + LogMsg(INFO, f"Statement to retrieving metadata pertaining to index: {stmt}") row = ibm_db.fetch_assoc(stmt) i = 0 while (row): if row['TYPE'] == SQL_INDEX_OTHER: - result.append( row ) + result.append(row) i += 1 row = ibm_db.fetch_assoc(stmt) ibm_db.free_result(stmt) except Exception as inst: - LogMsg(5, f"An exception occurred while retrieving metadata pertaining to index: {inst}") + LogMsg(EXCEPTION, f"An exception occurred while retrieving metadata pertaining to index: {inst}") raise _get_exception(inst) return result @@ -1052,27 +1082,27 @@ def primary_keys(self, unique=True, schema_name=None, table_name=None): 'KEY_SEQ': 1 } """ - LogMsg(2, f"Retrieving metadata pertaining to primary keys for specified schema/Table") + LogMsg(INFO, f"Retrieving metadata pertaining to primary keys for specified schema/Table") result = [] if schema_name is not None: schema_name = self.set_case("DB2_LUW", schema_name) - LogMsg(2, f"Schema name: {schema_name}") + LogMsg(INFO, f"Schema name: {schema_name}") if table_name is not None: table_name = self.set_case("DB2_LUW", table_name) - LogMsg(2, f"Table name: {table_name}") + LogMsg(INFO, f"Table name: {table_name}") try: stmt = ibm_db.primary_keys(self.conn_handler, None, schema_name, table_name) - LogMsg(1, f"Statement to retrieving metadata pertaining to primary keys: {stmt}") + LogMsg(DEBUG, f"Statement to retrieving metadata pertaining to primary keys: {stmt}") row = ibm_db.fetch_assoc(stmt) i = 0 while (row): - result.append( row ) + result.append(row) i += 1 row = ibm_db.fetch_assoc(stmt) ibm_db.free_result(stmt) except Exception as inst: - LogMsg(5, f"An exception occurred while retrieving metadata pertaining to primary keys: {inst}") + LogMsg(EXCEPTION, f"An exception occurred while retrieving metadata pertaining to primary keys: {inst}") raise _get_exception(inst) return result @@ -1095,27 +1125,27 @@ def foreign_keys(self, unique=True, schema_name=None, table_name=None): 'FKTABLE_SCHEM': 'PYTHONIC' } """ - LogMsg(2, f"Retrieving metadata pertaining to foreign keys for specified schema/Table") + LogMsg(INFO, f"Retrieving metadata pertaining to foreign keys for specified schema/Table") result = [] if schema_name is not None: schema_name = self.set_case("DB2_LUW", schema_name) - LogMsg(2, f"Schema name: {schema_name}") + LogMsg(INFO, f"Schema name: {schema_name}") if table_name is not None: table_name = self.set_case("DB2_LUW", table_name) - LogMsg(2, f"Table name: {table_name}") + LogMsg(INFO, f"Table name: {table_name}") try: stmt = ibm_db.foreign_keys(self.conn_handler, None, None, None, None, schema_name, table_name) - LogMsg(1, f"Statement to retrieving metadata pertaining to foreign keys: {stmt}") + LogMsg(DEBUG, f"Statement to retrieving metadata pertaining to foreign keys: {stmt}") row = ibm_db.fetch_assoc(stmt) i = 0 while (row): - result.append( row ) + result.append(row) i += 1 row = ibm_db.fetch_assoc(stmt) ibm_db.free_result(stmt) except Exception as inst: - LogMsg(5, f"An exception occurred while retrieving metadata pertaining foreign keys: {inst}") + LogMsg(EXCEPTION, f"An exception occurred while retrieving metadata pertaining foreign keys: {inst}") raise _get_exception(inst) return result @@ -1139,22 +1169,22 @@ def columns(self, schema_name=None, table_name=None, column_names=None): 'DECIMAL_DIGITS': None } """ - LogMsg(2, f"Retrieving the columns for a specified schema/Table") + LogMsg(INFO, f"Retrieving the columns for a specified schema/Table") result = [] if schema_name is not None: schema_name = self.set_case("DB2_LUW", schema_name) - LogMsg(2, f"Schema name: {schema_name}") + LogMsg(INFO, f"Schema name: {schema_name}") if table_name is not None: table_name = self.set_case("DB2_LUW", table_name) - LogMsg(2, f"Table name: {table_name}") + LogMsg(INFO, f"Table name: {table_name}") try: stmt = ibm_db.columns(self.conn_handler, None, schema_name, table_name) - LogMsg(1, f"Statement to retrieving the columns: {stmt}") + LogMsg(DEBUG, f"Statement to retrieving the columns: {stmt}") row = ibm_db.fetch_assoc(stmt) i = 0 while (row): - result.append( row ) + result.append(row) i += 1 row = ibm_db.fetch_assoc(stmt) ibm_db.free_result(stmt) @@ -1171,7 +1201,7 @@ def columns(self, schema_name=None, table_name=None, column_names=None): include_columns.append(column) result = include_columns except Exception as inst: - LogMsg(5, f"An exception occurred while retrieving the columns: {inst}") + LogMsg(EXCEPTION, f"An exception occurred while retrieving the columns: {inst}") raise _get_exception(inst) return result @@ -1203,8 +1233,8 @@ def __get_description(self): try: num_columns = ibm_db.num_fields(self.stmt_handler) - LogMsg(2, "Fetching column descriptions...") - LogMsg(1, f"Number of columns: {num_columns}") + LogMsg(INFO, "Fetching column descriptions...") + LogMsg(DEBUG, f"Number of columns: {num_columns}") """ If the execute statement did not produce a result set return None. """ @@ -1214,11 +1244,11 @@ def __get_description(self): for column_index in range(num_columns): column_desc = [] column_desc.append(ibm_db.field_name(self.stmt_handler, - column_index)) + column_index)) type = ibm_db.field_type(self.stmt_handler, column_index) type = type.upper() - LogMsg(2, f"Processing column") - LogMsg(1, f"Column type: {type}") + LogMsg(INFO, f"Processing column") + LogMsg(DEBUG, f"Column type: {type}") if STRING == type: column_desc.append(STRING) elif TEXT == type: @@ -1247,24 +1277,24 @@ def __get_description(self): column_desc.append(BOOLEAN) column_desc.append(ibm_db.field_display_size( - self.stmt_handler, column_index)) + self.stmt_handler, column_index)) column_desc.append(ibm_db.field_display_size( - self.stmt_handler, column_index)) + self.stmt_handler, column_index)) column_desc.append(ibm_db.field_precision( - self.stmt_handler, column_index)) + self.stmt_handler, column_index)) column_desc.append(ibm_db.field_scale(self.stmt_handler, - column_index)) + column_index)) column_desc.append(ibm_db.field_nullable( - self.stmt_handler, column_index)) + self.stmt_handler, column_index)) self.__description.append(column_desc) except Exception as inst: - LogMsg(5, f"An exception occurred: {_get_exception(inst)}") - LogMsg(1, "Full exception traceback:", exc_info=True) + LogMsg(EXCEPTION, f"An exception occurred: {_get_exception(inst)}") + LogMsg(DEBUG, "Full exception traceback:", exc_info=True) self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] @@ -1273,16 +1303,16 @@ def __get_description(self): # This attribute provides the metadata information of the columns # in the result set produced by the last execute function. It is # a read only attribute. - description = property(fget = __get_description) + description = property(fget=__get_description) # This method is used to get the rowcount attribute. - def __get_rowcount( self ): + def __get_rowcount(self): return self.__rowcount - def __iter__( self ): + def __iter__(self): return self - def __next__( self ): + def __next__(self): row = self.fetchone() if row == None: raise StopIteration @@ -1296,7 +1326,7 @@ def __next__( self ): rowcount = property(__get_rowcount, None, None, "") # This method is used to get the Connection object - def __get_connection( self ): + def __get_connection(self): return self.__connection # This attribute specifies the connection object. @@ -1320,9 +1350,9 @@ def __init__(self, conn_handler, conn_object=None): self.__connection = conn_object self.messages = [] self.FIX_RETURN_TYPE = conn_object.FIX_RETURN_TYPE - LogMsg(2, "Cursor object initialized.") - LogMsg(1, f"Connection handler: {self.conn_handler}") - LogMsg(1, f"Connection object: {self.__connection}") + LogMsg(INFO, "Cursor object initialized.") + LogMsg(DEBUG, f"Connection handler: {self.conn_handler}") + LogMsg(DEBUG, f"Connection object: {self.__connection}") # This method closes the statemente associated with the cursor object. # It takes no argument. @@ -1339,12 +1369,12 @@ def close(self): ''' #self.messages.append(ProgrammingError("Cursor cannot be closed; connection is no longer active.")) #raise self.messages[len(self.messages) - 1] - LogMsg(3, "Cursor cannot be closed; connection is no longer active.") + LogMsg(WARNING, "Cursor cannot be closed; connection is no longer active.") return None try: return_value = ibm_db.free_stmt(self.stmt_handler) except Exception as inst: - LogMsg(4, f"Error occurred while closing cursor: {_get_exception(inst)}") + LogMsg(ERROR, f"Error occurred while closing cursor: {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] self.stmt_handler = None @@ -1355,12 +1385,12 @@ def close(self): self.__connection._cursor_list.remove(weakref.ref(self)) except: pass - LogMsg(2, "Cursor closed successfully.") + LogMsg(INFO, "Cursor closed successfully.") return return_value # helper for calling procedure def _callproc_helper(self, procname, parameters=None): - LogMsg(1, f"Calling procedure: {procname}") + LogMsg(DEBUG, f"Calling procedure: {procname}") if parameters is not None: buff = [] CONVERT_STR = (buffer) @@ -1371,45 +1401,45 @@ def _callproc_helper(self, procname, parameters=None): param = str(param) buff.append(param) parameters = tuple(buff) - LogMsg(1, f"Procedure parameters: {parameters}") + LogMsg(DEBUG, f"Procedure parameters: {parameters}") try: - result = ibm_db.callproc(self.conn_handler, procname,parameters) + result = ibm_db.callproc(self.conn_handler, procname, parameters) except Exception as inst: - LogMsg(4, f"Error procedure '{procname}': {_get_exception(inst)}") + LogMsg(ERROR, f"Error procedure '{procname}': {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] else: - LogMsg(1, "Calling procedure without parameters.") + LogMsg(DEBUG, "Calling procedure without parameters.") try: result = ibm_db.callproc(self.conn_handler, procname) except Exception as inst: - LogMsg(4, f"Error calling procedure '{procname}': {_get_exception(inst)}") + LogMsg(ERROR, f"Error calling procedure '{procname}': {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] - LogMsg(2, f"Procedure '{procname}' called successfully.") + LogMsg(INFO, f"Procedure '{procname}' called successfully.") return result - def callproc(self, procname, parameters=None): """This method can be used to execute a stored procedure. It takes the name of the stored procedure and the parameters to the stored procedure as arguments. """ - LogMsg(1, f"Calling callproc with procname={procname}, parameters={parameters}") + LogMsg(DEBUG, f"Calling callproc with procname={procname}, parameters={parameters}") self.messages = [] if not isinstance(procname, string_types): - LogMsg(4, "callproc expects the first argument to be of type String or Unicode.") + LogMsg(ERROR, "callproc expects the first argument to be of type String or Unicode.") self.messages.append(InterfaceError("callproc expects the first argument to be of type String or Unicode.")) raise self.messages[len(self.messages) - 1] if parameters is not None: if not isinstance(parameters, (list, tuple)): - LogMsg(4, "callproc expects the second argument to be of type list or tuple.") - self.messages.append(InterfaceError("callproc expects the second argument to be of type list or tuple.")) + LogMsg(ERROR, "callproc expects the second argument to be of type list or tuple.") + self.messages.append( + InterfaceError("callproc expects the second argument to be of type list or tuple.")) raise self.messages[len(self.messages) - 1] result = self._callproc_helper(procname, parameters) - LogMsg(1, f"Result received from callproc helper: {result}") + LogMsg(DEBUG, f"Result received from callproc helper: {result}") return_value = None self.__description = None self._all_stmt_handlers = [] @@ -1419,23 +1449,23 @@ def callproc(self, procname, parameters=None): else: self.stmt_handler = result self._result_set_produced = True - LogMsg(1, - f"callproc executed successfully. stmt_handler={self.stmt_handler}, return_value={return_value}") + LogMsg(DEBUG, + f"callproc executed successfully. stmt_handler={self.stmt_handler}, return_value={return_value}") return return_value # Helper for preparing an SQL statement. def _prepare_helper(self, operation, parameters=None): try: ibm_db.free_stmt(self.stmt_handler) - LogMsg(1, "Successfully freed existing statement handler.") + LogMsg(DEBUG, "Successfully freed existing statement handler.") except: pass try: self.stmt_handler = ibm_db.prepare(self.conn_handler, operation) - LogMsg(1, f"Successfully prepared statement with operation: {operation}") + LogMsg(DEBUG, f"Successfully prepared statement with operation: {operation}") except Exception as inst: - LogMsg(4, f"Error preparing statement with operation '{operation}': {_get_exception(inst)}") + LogMsg(ERROR, f"Error preparing statement with operation '{operation}': {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] @@ -1443,16 +1473,16 @@ def _prepare_helper(self, operation, parameters=None): def _set_cursor_helper(self): if (ibm_db.get_option(self.stmt_handler, ibm_db.SQL_ATTR_CURSOR_TYPE, 0) != ibm_db.SQL_CURSOR_FORWARD_ONLY): self._is_scrollable_cursor = True - LogMsg(1, "Cursor type is scrollable.") + LogMsg(INFO, "Cursor type is scrollable.") else: self._is_scrollable_cursor = False - LogMsg(1, "Cursor type is forward-only.") + LogMsg(INFO, "Cursor type is forward-only.") self._result_set_produced = False try: num_columns = ibm_db.num_fields(self.stmt_handler) - LogMsg(1, f"Number of columns retrieved: {num_columns}") + LogMsg(DEBUG, f"Number of columns retrieved: {num_columns}") except Exception as inst: - LogMsg(4, f"Error getting number of columns: {_get_exception(inst)}") + LogMsg(ERROR, f"Error getting number of columns: {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] if not num_columns: @@ -1475,41 +1505,41 @@ def _execute_helper(self, parameters=None): param = str(param) buff.append(param) parameters = tuple(buff) - LogMsg(1, f"Executing statement with parameters: {parameters}") + LogMsg(DEBUG, f"Executing statement with parameters: {parameters}") try: return_value = ibm_db.execute(self.stmt_handler, parameters) if not return_value: if ibm_db.conn_errormsg() is not None: error_msg = f"Connection error: {str(ibm_db.conn_errormsg())}" - LogMsg(4, error_msg) + LogMsg(ERROR, error_msg) self.messages.append(Error(str(ibm_db.conn_errormsg()))) raise self.messages[len(self.messages) - 1] if ibm_db.stmt_errormsg() is not None: error_msg = f"Statement error: {str(ibm_db.conn_errormsg())}" - LogMsg(4, error_msg) + LogMsg(ERROR, error_msg) self.messages.append(Error(str(ibm_db.stmt_errormsg()))) raise self.messages[len(self.messages) - 1] except Exception as inst: - LogMsg(4, f"Error executing statement with parameters: {_get_exception(inst)} ") + LogMsg(ERROR, f"Error executing statement with parameters: {_get_exception(inst)} ") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] else: - LogMsg(1, f"Executing statement without parameters") + LogMsg(DEBUG, f"Executing statement without parameters") try: return_value = ibm_db.execute(self.stmt_handler) if not return_value: if ibm_db.conn_errormsg() is not None: error_msg = f"Connection error: {str(ibm_db.conn_errormsg())}" - LogMsg(4, error_msg) + LogMsg(ERROR, error_msg) self.messages.append(Error(str(ibm_db.conn_errormsg()))) raise self.messages[len(self.messages) - 1] if ibm_db.stmt_errormsg() is not None: error_msg = f"Statement error: {str(ibm_db.conn_errormsg())}" - LogMsg(4, error_msg) + LogMsg(ERROR, error_msg) self.messages.append(Error(str(ibm_db.stmt_errormsg()))) raise self.messages[len(self.messages) - 1] except Exception as inst: - LogMsg(4, f"Error executing statement without parameters: {_get_exception(inst)} ") + LogMsg(ERROR, f"Error executing statement without parameters: {_get_exception(inst)} ") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] return return_value @@ -1521,18 +1551,18 @@ def _set_rowcount(self): if not self._result_set_produced: try: counter = ibm_db.num_rows(self.stmt_handler) - LogMsg(1, f"Number of rows retrieved: {counter}") + LogMsg(DEBUG, f"Number of rows retrieved: {counter}") except Exception as inst: - LogMsg(4, f"Error getting row count: {_get_exception(inst)}") + LogMsg(ERROR, f"Error getting row count: {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] self.__rowcount = counter elif self._is_scrollable_cursor: try: counter = ibm_db.get_num_result(self.stmt_handler) - LogMsg(1, f"Number of rows retrieved: {counter}") + LogMsg(DEBUG, f"Number of rows retrieved: {counter}") except Exception as inst: - LogMsg(4, f"Error getting row count: {_get_exception(inst)}") + LogMsg(ERROR, f"Error getting row count: {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] if counter >= 0: @@ -1552,31 +1582,32 @@ def _get_last_identity_val(self): operation = 'SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1' try: stmt_handler = ibm_db.prepare(self.conn_handler, operation) - LogMsg(1, f"Preparing statement with operation: {operation}") + LogMsg(DEBUG, f"Preparing statement with operation: {operation}") if ibm_db.execute(stmt_handler): row = ibm_db.fetch_tuple(stmt_handler) if row[0] is not None: identity_val = int(row[0]) - LogMsg(1, f"Identity value retrieved: {identity_val}") + LogMsg(DEBUG, f"Identity value retrieved: {identity_val}") else: identity_val = None - LogMsg(1, "Identity value is None") + LogMsg(DEBUG, "Identity value is None") else: if ibm_db.conn_errormsg() is not None: error_msg = f"Connection error: {str(ibm_db.conn_errormsg())}" - LogMsg(4, error_msg) + LogMsg(ERROR, error_msg) self.messages.append(Error(str(ibm_db.conn_errormsg()))) raise self.messages[len(self.messages) - 1] if ibm_db.stmt_errormsg() is not None: error_msg = f"Statement error: {str(ibm_db.stmt_errormsg())}" - LogMsg(4, error_msg) + LogMsg(ERROR, error_msg) self.messages.append(Error(str(ibm_db.stmt_errormsg()))) raise self.messages[len(self.messages) - 1] except Exception as inst: - LogMsg(4, f"Error occured in getting identity value: {_get_exception(inst)}") + LogMsg(ERROR, f"Error occured in getting identity value: {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] return identity_val + last_identity_val = property(_get_last_identity_val, None, None, "") def execute(self, operation, parameters=None): @@ -1586,18 +1617,19 @@ def execute(self, operation, parameters=None): sequence of values to substitute for the parameter markers in the SQL statement as arguments. """ - LogMsg(1, f"Executing SQL operation: {operation}") + LogMsg(DEBUG, f"Executing SQL operation: {operation}") if parameters is not None: - LogMsg(1, f"SQL parameters: {parameters}") + LogMsg(DEBUG, f"SQL parameters: {parameters}") self.messages = [] if not isinstance(operation, string_types): err_msg = "execute expects the first argument [%s] to be of type String or Unicode." % operation - LogMsg(4, err_msg) - self.messages.append(InterfaceError("execute expects the first argument [%s] to be of type String or Unicode." % operation )) + LogMsg(ERROR, err_msg) + self.messages.append( + InterfaceError("execute expects the first argument [%s] to be of type String or Unicode." % operation)) raise self.messages[len(self.messages) - 1] if parameters is not None: if not isinstance(parameters, (list, tuple, dict)): - LogMsg(4, "execute parameters argument should be sequence.") + LogMsg(ERROR, "execute parameters argument should be sequence.") self.messages.append(InterfaceError("execute parameters argument should be sequence.")) raise self.messages[len(self.messages) - 1] self.__description = None @@ -1605,7 +1637,7 @@ def execute(self, operation, parameters=None): self._prepare_helper(operation) self._execute_helper(parameters) self._set_cursor_helper() - LogMsg(2, "SQL operation executed successfully.") + LogMsg(INFO, "SQL operation executed successfully.") return self._set_rowcount() def executemany(self, operation, seq_parameters): @@ -1615,21 +1647,23 @@ def executemany(self, operation, seq_parameters): and sequence of sequence of values to substitute for the parameter markers in the SQL statement as its argument. """ - LogMsg(1, "Executing SQL operation in executemany: %s", operation) - LogMsg(1, "Number of parameter sets: %d", len(seq_parameters)) + LogMsg(DEBUG, "Executing SQL operation in executemany: %s", operation) + LogMsg(DEBUG, "Number of parameter sets: %d", len(seq_parameters)) self.messages = [] if not isinstance(operation, string_types): - LogMsg(4, f"executemany expects the first argument to be of type String or Unicode.") - self.messages.append(InterfaceError("executemany expects the first argument to be of type String or Unicode.")) + LogMsg(ERROR, f"executemany expects the first argument to be of type String or Unicode.") + self.messages.append( + InterfaceError("executemany expects the first argument to be of type String or Unicode.")) raise self.messages[len(self.messages) - 1] if seq_parameters is None: - LogMsg(4, f"executemany expects a not None seq_parameters value") + LogMsg(ERROR, f"executemany expects a not None seq_parameters value") self.messages.append(InterfaceError("executemany expects a not None seq_parameters value")) raise self.messages[len(self.messages) - 1] if not isinstance(seq_parameters, (list, tuple)): - LogMsg(4, f"executemany expects the second argument to be of type list or tuple of sequence.") - self.messages.append(InterfaceError("executemany expects the second argument to be of type list or tuple of sequence.")) + LogMsg(ERROR, f"executemany expects the second argument to be of type list or tuple of sequence.") + self.messages.append( + InterfaceError("executemany expects the second argument to be of type list or tuple of sequence.")) raise self.messages[len(self.messages) - 1] CONVERT_STR = (buffer) @@ -1651,7 +1685,7 @@ def executemany(self, operation, seq_parameters): self._prepare_helper(operation) try: autocommit = ibm_db.autocommit(self.conn_handler) - if autocommit != 0: + if autocommit != 0: ibm_db.autocommit(self.conn_handler, 0) self.__rowcount = ibm_db.execute_many(self.stmt_handler, seq_parameters) if autocommit != 0: @@ -1660,20 +1694,20 @@ def executemany(self, operation, seq_parameters): if self.__rowcount == -1: if ibm_db.conn_errormsg() is not None: error_msg = f"Connection error: {str(ibm_db.conn_errormsg())}" - LogMsg(4, error_msg) + LogMsg(ERROR, error_msg) self.messages.append(Error(str(ibm_db.conn_errormsg()))) raise self.messages[len(self.messages) - 1] if ibm_db.stmt_errormsg() is not None: error_msg = f"Statement error: {str(ibm_db.conn_errormsg())}" - LogMsg(4, error_msg) + LogMsg(ERROR, error_msg) self.messages.append(Error(str(ibm_db.stmt_errormsg()))) raise self.messages[len(self.messages) - 1] except Exception as inst: self._set_rowcount() self.messages.append(Error(inst)) - LogMsg(4, f"Error in executemany: {inst}") + LogMsg(ERROR, f"Error in executemany: {inst}") raise self.messages[len(self.messages) - 1] - LogMsg(2, "SQL operation executemany successfully.") + LogMsg(INFO, "SQL operation executemany successfully.") return True def _fetch_helper(self, fetch_size=-1): @@ -1684,26 +1718,27 @@ def _fetch_helper(self, fetch_size=-1): If this is not provided it fetches all the remaining rows. """ if self.stmt_handler is None: - LogMsg(4, "Please execute an SQL statement in order to get a row from result set.") - self.messages.append(ProgrammingError("Please execute an SQL statement in order to get a row from result set.")) + LogMsg(ERROR, "Please execute an SQL statement in order to get a row from result set.") + self.messages.append( + ProgrammingError("Please execute an SQL statement in order to get a row from result set.")) raise self.messages[len(self.messages) - 1] if not self._result_set_produced: - LogMsg(4, "The last call to execute did not produce any result set.") + LogMsg(ERROR, "The last call to execute did not produce any result set.") self.messages.append(ProgrammingError("The last call to execute did not produce any result set.")) - raise self.messages[len(self.messages) - 1] + raise self.messages[len(self.messages) - 1] row_list = [] rows_fetched = 0 while (fetch_size == -1) or \ - (fetch_size != -1 and rows_fetched < fetch_size): + (fetch_size != -1 and rows_fetched < fetch_size): try: row = ibm_db.fetch_tuple(self.stmt_handler) except Exception as inst: if ibm_db.stmt_errormsg() is not None: error_msg = f"Statement error: {str(ibm_db.stmt_errormsg())}" - LogMsg(4, error_msg) + LogMsg(ERROR, error_msg) self.messages.append(Error(str(ibm_db.stmt_errormsg()))) else: - LogMsg(4, f"Error occured : {_get_exception(inst)}") + LogMsg(ERROR, f"Error occured : {_get_exception(inst)}") self.messages.append(_get_exception(inst)) if len(row_list) == 0: raise self.messages[len(self.messages) - 1] @@ -1725,12 +1760,12 @@ def fetchone(self): executing an SQL statement which produces a result set. """ - LogMsg(2, "Fetching one row from the database.") + LogMsg(INFO, "Fetching one row from the database.") row_list = self._fetch_helper(1) if len(row_list) == 0: - LogMsg(1, "No rows fetched.") + LogMsg(DEBUG, "No rows fetched.") else: - LogMsg(1, "Row fetched successfully.") + LogMsg(DEBUG, "Row fetched successfully.") if len(row_list) == 0: return None else: @@ -1742,44 +1777,44 @@ def fetchmany(self, size=0): It takes the number of rows to fetch as an argument. If this is not provided it fetches self.arraysize number of rows. """ - LogMsg(1, "Fetching %d rows from the database.", size) + LogMsg(DEBUG, "Fetching %d rows from the database.", size) if not isinstance(size, int_types): - LogMsg(5, "fetchmany expects argument type int or long.") - self.messages.append(InterfaceError( "fetchmany expects argument type int or long.")) + LogMsg(EXCEPTION, "fetchmany expects argument type int or long.") + self.messages.append(InterfaceError("fetchmany expects argument type int or long.")) raise self.messages[len(self.messages) - 1] if size == 0: size = self.arraysize if size < -1: - LogMsg(4, "fetchmany argument size expected to be positive") + LogMsg(ERROR, "fetchmany argument size expected to be positive") self.messages.append(ProgrammingError("fetchmany argument size expected to be positive.")) raise self.messages[len(self.messages) - 1] message = "Fetched %d rows successfully.", len(self._fetch_helper(size)) - LogMsg(1, message) + LogMsg(DEBUG, message) return self._fetch_helper(size) def fetchall(self): """This method fetches all remaining rows from the database, after executing an SQL statement which produces a result set. """ - LogMsg(2, "Fetching all remaining rows from the database.") + LogMsg(INFO, "Fetching all remaining rows from the database.") rows_fetched = self._fetch_helper() message = "Fetched %d rows successfully.", len(rows_fetched) - LogMsg(1, message) + LogMsg(DEBUG, message) return rows_fetched def nextset(self): """This method can be used to get the next result set after executing a stored procedure, which produces multiple result sets. """ - LogMsg(2, "Attempting to retrieve next result set.") + LogMsg(INFO, "Attempting to retrieve next result set.") self.messages = [] if self.stmt_handler is None: - LogMsg(4, "Please execute an SQL statement in order to get result sets.") + LogMsg(ERROR, "Please execute an SQL statement in order to get result sets.") self.messages.append(ProgrammingError("Please execute an SQL statement in order to get result sets.")) raise self.messages[len(self.messages) - 1] - if self._result_set_produced == False: - LogMsg(4, "The last call to execute did not produce any result set.") + if not self._result_set_produced: + LogMsg(ERROR, "The last call to execute did not produce any result set.") self.messages.append(ProgrammingError("The last call to execute did not produce any result set.")) raise self.messages[len(self.messages) - 1] try: @@ -1790,16 +1825,16 @@ def nextset(self): self._all_stmt_handlers.append(self.stmt_handler) self.stmt_handler = ibm_db.next_result(self._all_stmt_handlers[0]) except Exception as inst: - LogMsg(4, f"Error while retrieving next result set: {_get_exception(inst)}") + LogMsg(ERROR, f"Error while retrieving next result set: {_get_exception(inst)}") self.messages.append(_get_exception(inst)) raise self.messages[len(self.messages) - 1] - if self.stmt_handler == False: + if not self.stmt_handler: self.stmt_handler = None - if self.stmt_handler == None: + if self.stmt_handler is None: return None - LogMsg(1, "Successfully retrieved next result set.") + LogMsg(INFO, "Successfully retrieved next result set.") return True def setinputsizes(self, sizes): @@ -1815,7 +1850,7 @@ def setoutputsize(self, size, column=-1): # to decimal and binary objects, for returning it to the user. def _fix_return_data_type(self, row): message = "Fixing return data types for row: %s", row - LogMsg(1, message) + LogMsg(DEBUG, message) row_list = None for index in range(len(row)): if row[index] is not None: @@ -1834,13 +1869,13 @@ def _fix_return_data_type(self, row): row_list[index] = decimal.Decimal(str(row[index]).replace(",", ".")) except Exception as inst: - LogMsg(4, f"Data type format error: {str(inst)}") - self.messages.append(DataError("Data type format error: "+ str(inst))) + LogMsg(ERROR, f"Data type format error: {str(inst)}") + self.messages.append(DataError("Data type format error: " + str(inst))) raise self.messages[len(self.messages) - 1] if row_list is None: return row else: - LogMsg(1, "Fixed return data types: %s", row_list) + LogMsg(DEBUG, "Fixed return data types: %s", row_list) return tuple(row_list) def __enter__(self):