CONPY-205: Inconsistent exceptions

- All parameter exceptions are now ProgrammingErrors
- A dictionary now might contain more keys than
  placeholders in statement
- Fixed unhandled exception when using dictionary as parameter
This commit is contained in:
Georg Richter
2022-05-25 18:47:03 +02:00
parent 0a7f751f68
commit 30c8f33b08
6 changed files with 92 additions and 54 deletions

View File

@ -136,7 +136,7 @@ class ConnectionPool(object):
if connection is not None and \
not isinstance(connection, mariadb.connections.Connection):
raise TypeError("Passed parameter is not a connection object")
raise mariadb.ProgrammingError("Passed parameter is not a connection object")
if connection == None and len(self._conn_args) == 0:
raise mariadb.PoolError("Can't get configuration for pool %s" % \

View File

@ -248,11 +248,11 @@ class Connection(mariadb._mariadb.connection):
"""
def __new__(self, format_id, transaction_id, branch_qualifier):
if not isinstance(format_id, int):
raise TypeError("argument 1 must be int, not %s", type(format_id).__name__)
raise mariadb.ProgrammingError("argument 1 must be int, not %s", type(format_id).__name__)
if not isinstance(transaction_id, str):
raise TypeError("argument 2 must be str, not %s", type(transaction_id).__mane__)
raise mariadb.ProgrammingError("argument 2 must be str, not %s", type(transaction_id).__mane__)
if not isinstance(branch_qualifier, str):
raise TypeError("argument 3 must be str, not %s", type(transaction_id).__name__)
raise mariadb.ProgrammingError("argument 3 must be str, not %s", type(transaction_id).__name__)
if len(transaction_id) > _MAX_TPC_XID_SIZE:
raise mariadb.ProgrammingError("Maximum length of transaction_id exceeded.")
if len(branch_qualifier) > _MAX_TPC_XID_SIZE:
@ -278,7 +278,7 @@ class Connection(mariadb._mariadb.connection):
self._check_closed()
if type(xid).__name__ != "xid":
raise TypeError("argument 1 must be xid not %s", type(xid).__name__)
raise mariadb.ProgrammingError("argument 1 must be xid not %s", type(xid).__name__)
stmt= "XA BEGIN '%s','%s',%s" % (xid[1], xid[2], xid[0])
try:
self._execute_command(stmt)
@ -314,7 +314,7 @@ class Connection(mariadb._mariadb.connection):
if xid is None and self.tpc_state != TPC_STATE.PREPARE:
raise mariadb.ProgrammingError("Transaction is not prepared.")
if xid and type(xid).__name__ != "xid":
raise TypeError("argument 1 must be xid not %s" % type(xid).__name__)
raise mariadb.ProgrammingError("argument 1 must be xid not %s" % type(xid).__name__)
if self.tpc_state < TPC_STATE.PREPARE:
stmt= "XA END '%s','%s',%s" % (xid[1], xid[2], xid[0])
@ -396,7 +396,7 @@ class Connection(mariadb._mariadb.connection):
if self.tpc_state == TPC_STATE.NONE:
raise mariadb.ProgrammingError("Transaction not started.")
if xid and type(xid).__name__ != "xid":
raise TypeError("argument 1 must be xid not %s" % type(xid).__name__)
raise mariadb.ProgrammingError("argument 1 must be xid not %s" % type(xid).__name__)
if not xid:
xid= self._xid

View File

@ -138,19 +138,22 @@ class Cursor(mariadb._mariadb.cursor):
if self._paramstyle == PARAMSTYLE_QMARK or \
self._paramstyle == PARAMSTYLE_FORMAT:
if not isinstance(self._data, (tuple,list)):
raise mariadb.ProgrammingError("Data arguent nust be Tuple or List")
raise mariadb.ProgrammingError("Data argument must be Tuple or List")
if self._paramstyle == PARAMSTYLE_PYFORMAT and\
not isinstance(self._data, dict):
raise mariadb.ProgrammingError("Data arguent nust be Dictionary")
# check if number of place holders matches the number of
# supplied elements in data tuple
if self._paramlist and ((not self._data and len(self._paramlist) > 0) or \
(len(self._data) != len(self._paramlist))):
raise mariadb.DataError("Number of parameters in statement (%s)"\
" doesn't match the number of data elements (%s)."\
% (len(self._paramlist), len(self._data)))
if self._paramstyle == PARAMSTYLE_PYFORMAT:
if not isinstance(self._data, dict):
raise mariadb.ProgrammingError("Data argument must be Dictionary")
for i in range(0, len(self._keys)):
if self._keys[i] not in self._data:
raise mariadb.ProgrammingError("Dictionary doesn't contain key '%s'" % self._keys[i])
else:
# check if number of place holders matches the number of
# supplied elements in data tuple
if self._paramlist and ((not self._data and len(self._paramlist) > 0) or \
(len(self._data) != len(self._paramlist))):
raise mariadb.ProgrammingError("Number of parameters in statement (%s)"\
" doesn't match the number of data elements (%s)."\
% (len(self._paramlist), len(self._data)))
def callproc(self, sp: str, data: Sequence =()):
"""
@ -258,17 +261,8 @@ class Cursor(mariadb._mariadb.cursor):
if do_parse:
self._parse_execute(statement, (data))
if data and len(data) != self.paramcount:
raise mariadb.DataError("Invalid number of parameters.")
self._description= None
# check if data parameters are passed in correct format
if (self._paramstyle == PARAMSTYLE_PYFORMAT and not isinstance(data, dict)):
raise TypeError("Argument 2 must be Dict")
elif self._paramstyle < PARAMSTYLE_PYFORMAT and (not isinstance(data, (tuple, list))):
raise TypeError("Argument 2 must be Tuple or List")
if len(data):
self._data= data
else:
@ -316,7 +310,7 @@ class Cursor(mariadb._mariadb.cursor):
self.check_closed()
if not parameters or not len(parameters):
raise TypeError("No data provided")
raise mariadb.ProgrammingError("No data provided")
# clear pending results
if self.field_count:
@ -460,19 +454,19 @@ class Cursor(mariadb._mariadb.cursor):
"with a buffered result set.")
if mode != "absolute" and mode != "relative":
raise mariadb.DataError("Invalid or unknown scroll mode specified.")
raise mariadb.ProgrammingError("Invalid or unknown scroll mode specified.")
if value == 0 and mode != "absolute":
raise mariadb.DataError("Invalid position value 0.")
raise mariadb.ProgrammingError("Invalid position value 0.")
if mode == "relative":
if self.rownumber + value < 0 or \
self.rownumber + value > self.rowcount:
raise mariadb.DataError("Position value is out of range.")
raise mariadb.ProgrammingError("Position value is out of range.")
new_pos= self.rownumber + value
else:
if value < 0 or value >= self.rowcount:
raise mariadb.DataError("Position value is out of range.")
raise mariadb.ProgrammingError("Position value is out of range.")
new_pos= value
self._seek(new_pos);

View File

@ -884,7 +884,7 @@ mariadb_get_parameter(MrdbCursor *self,
if (row_nr > (self->array_size - 1) ||
column_nr > (self->parseinfo.paramcount - 1))
{
mariadb_throw_exception(self->stmt, Mariadb_DataError, 0,
mariadb_throw_exception(self->stmt, Mariadb_ProgrammingError, 0,
"Can't access data at row %d, column %d",
row_nr + 1, column_nr + 1);
goto end;
@ -892,7 +892,7 @@ mariadb_get_parameter(MrdbCursor *self,
if (!(row= ListOrTuple_GetItem(self->data, row_nr)))
{
mariadb_throw_exception(self->stmt, Mariadb_DataError, 0,
mariadb_throw_exception(self->stmt, Mariadb_ProgrammingError, 0,
"Can't access row number %d", row_nr + 1);
goto end;
}
@ -904,7 +904,7 @@ mariadb_get_parameter(MrdbCursor *self,
{
if (!(column= ListOrTuple_GetItem(row, column_nr)))
{
mariadb_throw_exception(self->stmt, Mariadb_DataError, 0,
mariadb_throw_exception(self->stmt, Mariadb_ProgrammingError, 0,
"Can't access column number %d at row %d",
column_nr + 1, row_nr + 1);
goto end;
@ -916,7 +916,7 @@ mariadb_get_parameter(MrdbCursor *self,
key= PyTuple_GetItem(self->parseinfo.keys, column_nr);
if (!PyDict_Contains(row, key))
{
mariadb_throw_exception(self->stmt, Mariadb_DataError, 0,
mariadb_throw_exception(self->stmt, Mariadb_ProgrammingError, 0,
"Can't find key in parameter data");
goto end;
}
@ -928,7 +928,7 @@ mariadb_get_parameter(MrdbCursor *self,
{
if (!(caps & (MARIADB_CLIENT_STMT_BULK_OPERATIONS >> 32)))
{
mariadb_throw_exception(NULL, Mariadb_DataError, 0,
mariadb_throw_exception(NULL, Mariadb_NotSupportedError, 0,
"MariaDB %s doesn't support indicator variables. "\
"Required version is 10.2.6 or newer",
mysql_get_server_info(self->stmt->mysql));
@ -984,13 +984,13 @@ mariadb_get_parameter_info(MrdbCursor *self,
{
if (rc == 1)
{
mariadb_throw_exception(NULL, Mariadb_DataError, 0,
mariadb_throw_exception(NULL, Mariadb_ProgrammingError, 0,
"Can't retrieve column information for parameter %d",
column_nr);
}
if (rc == 2)
{
mariadb_throw_exception(NULL, Mariadb_DataError, 0,
mariadb_throw_exception(NULL, Mariadb_NotSupportedError, 0,
"Data type '%s' in column %d not supported in MariaDB Connector/Python",
Py_TYPE(paramvalue.value)->tp_name, column_nr);
}
@ -1007,7 +1007,7 @@ mariadb_get_parameter_info(MrdbCursor *self,
memset(&pinfo, 0, sizeof(MrdbParamInfo));
if (mariadb_get_column_info(paramvalue.value, &pinfo) && !paramvalue.indicator)
{
mariadb_throw_exception(NULL, Mariadb_DataError, 1,
mariadb_throw_exception(NULL, Mariadb_ProgrammingError, 1,
"Invalid parameter type at row %d, column %d",
i+1, column_nr + 1);
return 1;
@ -1043,7 +1043,7 @@ mariadb_get_parameter_info(MrdbCursor *self,
param->buffer_type= MYSQL_TYPE_NEWDECIMAL;
break;
}
mariadb_throw_exception(NULL, Mariadb_DataError, 1,
mariadb_throw_exception(NULL, Mariadb_ProgrammingError, 1,
"Invalid parameter type at row %d, column %d",
i+1, column_nr + 1);
return 1;
@ -1116,7 +1116,7 @@ mariadb_check_bulk_parameters(MrdbCursor *self,
(!CHECK_TYPE(obj, &PyTuple_Type) &&
!CHECK_TYPE(obj, &PyList_Type)))
{
mariadb_throw_exception(NULL, Mariadb_DataError, 0,
mariadb_throw_exception(NULL, Mariadb_ProgrammingError, 0,
"Invalid parameter type in row %d. "\
" (Row data must be provided as tuple(s))", i+1);
return 1;
@ -1124,7 +1124,7 @@ mariadb_check_bulk_parameters(MrdbCursor *self,
if (self->parseinfo.paramstyle == PYFORMAT &&
!CHECK_TYPE(obj, &PyDict_Type))
{
mariadb_throw_exception(NULL, Mariadb_DataError, 0,
mariadb_throw_exception(NULL, Mariadb_ProgrammingError, 0,
"Invalid parameter type in row %d. "\
" (Row data must be provided as dict)", i+1);
return 1;
@ -1134,7 +1134,7 @@ mariadb_check_bulk_parameters(MrdbCursor *self,
(self->parseinfo.paramstyle != PYFORMAT &&
self->parseinfo.paramcount != ListOrTuple_Size(obj)))
{
mariadb_throw_exception(self->stmt, Mariadb_DataError, 1,
mariadb_throw_exception(self->stmt, Mariadb_ProgrammingError, 1,
"Invalid number of parameters in row %d", i+1);
return 1;
}
@ -1179,7 +1179,7 @@ mariadb_check_execute_parameters(MrdbCursor *self,
if (!self->parseinfo.paramcount)
{
mariadb_throw_exception(NULL, Mariadb_DataError, 0,
mariadb_throw_exception(NULL, Mariadb_ProgrammingError, 0,
"Invalid number of parameters");
goto error;
}

View File

@ -96,8 +96,8 @@ MrdbConnection_sets[]=
GETTER_EXCEPTION("NotSupportedError", Mariadb_NotSupportedError, exception_notsupported__doc__),
GETTER_EXCEPTION("InternalError", Mariadb_InternalError, exception_internal__doc__),
GETTER_EXCEPTION("OperationalError", Mariadb_OperationalError, exception_operational__doc__),
GETTER_EXCEPTION("PoolError", Mariadb_OperationalError, exception_pool__doc__),
GETTER_EXCEPTION("DataError", Mariadb_OperationalError, exception_data__doc__),
GETTER_EXCEPTION("PoolError", Mariadb_PoolError, exception_pool__doc__),
GETTER_EXCEPTION("DataError", Mariadb_DataError, exception_data__doc__),
{NULL}
};

View File

@ -404,7 +404,7 @@ class TestCursor(unittest.TestCase):
tpl = (1, 2, 3)
try:
cursor.execute("INSERT INTO dyncol1 VALUES (?)", tpl)
except mariadb.DataError:
except mariadb.ProgrammingError:
pass
del cursor
@ -491,7 +491,7 @@ class TestCursor(unittest.TestCase):
try:
cursor.execute("INSERT INTO test.t1(fname, sname) VALUES (?, ?)",
(("Walker", "Percy"), ("Flannery", "O'Connor")))
except (mariadb.ProgrammingError, mariadb.DataError):
except (mariadb.ProgrammingError, mariadb.NotSupportedError):
pass
del cursor
@ -502,7 +502,7 @@ class TestCursor(unittest.TestCase):
try:
cursor.scroll(0)
except mariadb.DataError:
except mariadb.ProgrammingError:
pass
cursor.scroll(2, mode='relative')
@ -530,7 +530,7 @@ class TestCursor(unittest.TestCase):
try:
cursor.scroll(-2, mode='absolute')
except mariadb.DataError:
except mariadb.ProgrammingError:
pass
del cursor
@ -1158,14 +1158,14 @@ class TestCursor(unittest.TestCase):
cursor = conn.cursor()
try:
cursor.execute("SELECT /*!50701 ? */", (1,))
except mariadb.DataError:
except mariadb.ProgrammingError:
pass
del cursor
cursor = conn.cursor()
try:
cursor.execute("SELECT /*!250701 ? */", (1,))
except mariadb.DataError:
except mariadb.ProgrammingError:
pass
del cursor
@ -1234,6 +1234,50 @@ class TestCursor(unittest.TestCase):
conn.close()
def test_conpy205(self):
conn= create_connection()
cursor= conn.cursor()
cursor.execute("select %(name)s", {"name" : "Marc"})
row= cursor.fetchone()
self.assertEqual(row[0], "Marc")
cursor.execute("select %(name)s", {"name" : "Marc", "noname" : "unknown"})
row= cursor.fetchone()
self.assertEqual(row[0], "Marc")
try:
cursor.execute("select ?", {"noname" : "unknown"})
except (mariadb.ProgrammingError):
pass
try:
cursor.execute("select %(name)s", (1,))
except (mariadb.ProgrammingError):
pass
try:
cursor.execute("select %(name)s", {"noname" : "unknown"})
except (mariadb.ProgrammingError):
pass
try:
cursor.execute("select ?")
except (mariadb.ProgrammingError):
pass
try:
cursor.execute("select ?,?,?", (1,2))
except (mariadb.ProgrammingError):
pass
try:
cursor.execute("select ?,?,?", (1,2,3,4))
except (mariadb.ProgrammingError):
pass
cursor.close()
def test_conpy91(self):
with create_connection() as connection:
with connection.cursor() as cursor: