SQLSTATE error classes implemented in C

The module is only used to export them to Python.
This commit is contained in:
Daniele Varrazzo 2019-02-07 11:36:44 +00:00
parent f1e73507d0
commit 30c1befa64
10 changed files with 571 additions and 1530 deletions

File diff suppressed because it is too large Load Diff

View File

@ -39,5 +39,7 @@ typedef struct {
} errorObject;
HIDDEN PyObject *error_text_from_chars(errorObject *self, const char *str);
HIDDEN BORROWED PyObject *exception_from_sqlstate(const char *sqlstate);
HIDDEN BORROWED PyObject *base_exception_from_sqlstate(const char *sqlstate);
#endif /* PSYCOPG_ERROR_H */

View File

@ -38,6 +38,104 @@ error_text_from_chars(errorObject *self, const char *str)
}
/* Return the Python exception corresponding to an SQLSTATE error
* code. A list of error codes can be found at:
* https://www.postgresql.org/docs/current/static/errcodes-appendix.html
*/
BORROWED PyObject *
exception_from_sqlstate(const char *sqlstate)
{
PyObject *exc;
/* First look up an exception of the proper class */
exc = PyDict_GetItemString(sqlstate_errors, sqlstate);
if (exc) {
return exc;
}
else {
PyErr_Clear();
return base_exception_from_sqlstate(sqlstate);
}
}
BORROWED PyObject *
base_exception_from_sqlstate(const char *sqlstate)
{
switch (sqlstate[0]) {
case '0':
switch (sqlstate[1]) {
case 'A': /* Class 0A - Feature Not Supported */
return NotSupportedError;
}
break;
case '2':
switch (sqlstate[1]) {
case '0': /* Class 20 - Case Not Found */
case '1': /* Class 21 - Cardinality Violation */
return ProgrammingError;
case '2': /* Class 22 - Data Exception */
return DataError;
case '3': /* Class 23 - Integrity Constraint Violation */
return IntegrityError;
case '4': /* Class 24 - Invalid Cursor State */
case '5': /* Class 25 - Invalid Transaction State */
return InternalError;
case '6': /* Class 26 - Invalid SQL Statement Name */
case '7': /* Class 27 - Triggered Data Change Violation */
case '8': /* Class 28 - Invalid Authorization Specification */
return OperationalError;
case 'B': /* Class 2B - Dependent Privilege Descriptors Still Exist */
case 'D': /* Class 2D - Invalid Transaction Termination */
case 'F': /* Class 2F - SQL Routine Exception */
return InternalError;
}
break;
case '3':
switch (sqlstate[1]) {
case '4': /* Class 34 - Invalid Cursor Name */
return OperationalError;
case '8': /* Class 38 - External Routine Exception */
case '9': /* Class 39 - External Routine Invocation Exception */
case 'B': /* Class 3B - Savepoint Exception */
return InternalError;
case 'D': /* Class 3D - Invalid Catalog Name */
case 'F': /* Class 3F - Invalid Schema Name */
return ProgrammingError;
}
break;
case '4':
switch (sqlstate[1]) {
case '0': /* Class 40 - Transaction Rollback */
return TransactionRollbackError;
case '2': /* Class 42 - Syntax Error or Access Rule Violation */
case '4': /* Class 44 - WITH CHECK OPTION Violation */
return ProgrammingError;
}
break;
case '5':
/* Class 53 - Insufficient Resources
Class 54 - Program Limit Exceeded
Class 55 - Object Not In Prerequisite State
Class 57 - Operator Intervention
Class 58 - System Error (errors external to PostgreSQL itself) */
if (!strcmp(sqlstate, "57014"))
return QueryCanceledError;
else
return OperationalError;
case 'F': /* Class F0 - Configuration File Error */
return InternalError;
case 'H': /* Class HV - Foreign Data Wrapper Error (SQL/MED) */
return OperationalError;
case 'P': /* Class P0 - PL/pgSQL Error */
return InternalError;
case 'X': /* Class XX - Internal Error */
return InternalError;
}
/* return DatabaseError as a fallback */
return DatabaseError;
}
static const char pgerror_doc[] =
"The error message returned by the backend, if available, else None";

View File

@ -77,130 +77,6 @@ strip_severity(const char *msg)
return msg;
}
/* Return a Python exception from a SQLSTATE from psycopg2.errors */
BORROWED static PyObject *
exception_from_module(const char *sqlstate)
{
PyObject *rv = NULL;
PyObject *m = NULL;
PyObject *map = NULL;
if (!(m = PyImport_ImportModule("psycopg2.errors"))) { goto exit; }
if (!(map = PyObject_GetAttrString(m, "_by_sqlstate"))) { goto exit; }
if (!PyDict_Check(map)) {
Dprintf("'psycopg2.errors._by_sqlstate' is not a dict!");
goto exit;
}
/* get the sqlstate class (borrowed reference), or fail trying. */
rv = PyDict_GetItemString(map, sqlstate);
exit:
/* We exit with a borrowed object, or a NULL but no error
* If an error did happen in this function, we don't want to clobber the
* database error. So better reporting it, albeit with the wrong class. */
PyErr_Clear();
Py_XDECREF(map);
Py_XDECREF(m);
return rv;
}
/* Returns the Python exception corresponding to an SQLSTATE error
code. A list of error codes can be found at:
https://www.postgresql.org/docs/current/static/errcodes-appendix.html */
BORROWED static PyObject *
exception_from_sqlstate(const char *sqlstate)
{
PyObject *exc;
/* First look up an exception of the proper class from the Python module */
exc = exception_from_module(sqlstate);
if (exc) {
return exc;
}
else {
PyErr_Clear();
}
/*
* IMPORTANT: if you change anything in this function you should change
* make_errors.py accordingly.
*/
switch (sqlstate[0]) {
case '0':
switch (sqlstate[1]) {
case 'A': /* Class 0A - Feature Not Supported */
return NotSupportedError;
}
break;
case '2':
switch (sqlstate[1]) {
case '0': /* Class 20 - Case Not Found */
case '1': /* Class 21 - Cardinality Violation */
return ProgrammingError;
case '2': /* Class 22 - Data Exception */
return DataError;
case '3': /* Class 23 - Integrity Constraint Violation */
return IntegrityError;
case '4': /* Class 24 - Invalid Cursor State */
case '5': /* Class 25 - Invalid Transaction State */
return InternalError;
case '6': /* Class 26 - Invalid SQL Statement Name */
case '7': /* Class 27 - Triggered Data Change Violation */
case '8': /* Class 28 - Invalid Authorization Specification */
return OperationalError;
case 'B': /* Class 2B - Dependent Privilege Descriptors Still Exist */
case 'D': /* Class 2D - Invalid Transaction Termination */
case 'F': /* Class 2F - SQL Routine Exception */
return InternalError;
}
break;
case '3':
switch (sqlstate[1]) {
case '4': /* Class 34 - Invalid Cursor Name */
return OperationalError;
case '8': /* Class 38 - External Routine Exception */
case '9': /* Class 39 - External Routine Invocation Exception */
case 'B': /* Class 3B - Savepoint Exception */
return InternalError;
case 'D': /* Class 3D - Invalid Catalog Name */
case 'F': /* Class 3F - Invalid Schema Name */
return ProgrammingError;
}
break;
case '4':
switch (sqlstate[1]) {
case '0': /* Class 40 - Transaction Rollback */
return TransactionRollbackError;
case '2': /* Class 42 - Syntax Error or Access Rule Violation */
case '4': /* Class 44 - WITH CHECK OPTION Violation */
return ProgrammingError;
}
break;
case '5':
/* Class 53 - Insufficient Resources
Class 54 - Program Limit Exceeded
Class 55 - Object Not In Prerequisite State
Class 57 - Operator Intervention
Class 58 - System Error (errors external to PostgreSQL itself) */
if (!strcmp(sqlstate, "57014"))
return QueryCanceledError;
else
return OperationalError;
case 'F': /* Class F0 - Configuration File Error */
return InternalError;
case 'H': /* Class HV - Foreign Data Wrapper Error (SQL/MED) */
return OperationalError;
case 'P': /* Class P0 - PL/pgSQL Error */
return InternalError;
case 'X': /* Class XX - Internal Error */
return InternalError;
}
/* return DatabaseError as a fallback */
return DatabaseError;
}
/* pq_raise - raise a python exception of the right kind

View File

@ -53,6 +53,9 @@ extern HIDDEN PyObject *Error, *Warning, *InterfaceError, *DatabaseError,
*IntegrityError, *DataError, *NotSupportedError;
extern HIDDEN PyObject *QueryCanceledError, *TransactionRollbackError;
/* sqlstate -> exception map */
extern HIDDEN PyObject *sqlstate_errors;
/* postgresql<->python encoding map */
extern HIDDEN PyObject *psycoEncodings;

View File

@ -62,6 +62,8 @@
#include "psycopg/adapter_datetime.h"
HIDDEN PyObject *psycoEncodings = NULL;
HIDDEN PyObject *sqlstate_errors = NULL;
#ifdef PSYCOPG_DEBUG
HIDDEN int psycopg_debug_enabled = 0;
#endif
@ -671,7 +673,7 @@ static struct {
RAISES_NEG static int
errors_init(PyObject *module)
basic_errors_init(PyObject *module)
{
/* the names of the exceptions here reflect the organization of the
psycopg2 module and not the fact the the original error objects
@ -680,6 +682,7 @@ errors_init(PyObject *module)
int i;
PyObject *dict = NULL;
PyObject *str = NULL;
PyObject *errmodule = NULL;
int rv = -1;
Dprintf("psycopgmodule: initializing basic exceptions");
@ -707,6 +710,10 @@ errors_init(PyObject *module)
Py_CLEAR(dict);
}
if (!(errmodule = PyImport_ImportModule("psycopg2.errors"))) {
goto exit;
}
for (i = 0; exctable[i].name; i++) {
char *name;
if (NULL == exctable[i].exc) { continue; }
@ -720,17 +727,102 @@ errors_init(PyObject *module)
Py_DECREF(*exctable[i].exc);
goto exit;
}
Py_INCREF(*exctable[i].exc);
if (0 > PyModule_AddObject(errmodule, name, *exctable[i].exc)) {
Py_DECREF(*exctable[i].exc);
goto exit;
}
}
rv = 0;
exit:
Py_XDECREF(errmodule);
Py_XDECREF(str);
Py_XDECREF(dict);
return rv;
}
/* mapping between sqlstate and exception name */
static struct {
char *sqlstate;
char *name;
} sqlstate_table[] = {
#include "sqlstate_errors.h"
{NULL} /* Sentinel */
};
RAISES_NEG static int
sqlstate_errors_init(PyObject *module)
{
int i;
char namebuf[120];
char prefix[] = "psycopg2.errors.";
char *suffix;
size_t bufsize;
PyObject *exc = NULL;
PyObject *errmodule = NULL;
int rv = -1;
Dprintf("psycopgmodule: initializing sqlstate exceptions");
if (sqlstate_errors) {
PyErr_SetString(PyExc_SystemError,
"sqlstate_errors_init(): already called");
goto exit;
}
if (!(errmodule = PyImport_ImportModule("psycopg2.errors"))) {
goto exit;
}
if (!(sqlstate_errors = PyDict_New())) {
goto exit;
}
Py_INCREF(sqlstate_errors);
if (0 > PyModule_AddObject(module, "sqlstate_errors", sqlstate_errors)) {
Py_DECREF(sqlstate_errors);
return -1;
}
strcpy(namebuf, prefix);
suffix = namebuf + sizeof(prefix) - 1;
bufsize = sizeof(namebuf) - sizeof(prefix) - 1;
/* If this 0 gets deleted the buffer was too small. */
namebuf[sizeof(namebuf) - 1] = '\0';
for (i = 0; sqlstate_table[i].sqlstate; i++) {
PyObject *base;
base = base_exception_from_sqlstate(sqlstate_table[i].sqlstate);
strncpy(suffix, sqlstate_table[i].name, bufsize);
if (namebuf[sizeof(namebuf) - 1] != '\0') {
PyErr_SetString(
PyExc_SystemError, "sqlstate_errors_init(): buffer too small");
goto exit;
}
if (!(exc = PyErr_NewException(namebuf, base, NULL))) {
goto exit;
}
if (0 > PyDict_SetItemString(
sqlstate_errors, sqlstate_table[i].sqlstate, exc)) {
goto exit;
}
if (0 > PyModule_AddObject(errmodule, sqlstate_table[i].name, exc)) {
goto exit;
}
exc = NULL; /* ref stolen by the module */
}
rv = 0;
exit:
Py_XDECREF(errmodule);
Py_XDECREF(exc);
return rv;
}
RAISES_NEG static int
add_module_constants(PyObject *module)
{
@ -1012,7 +1104,8 @@ INIT_MODULE(_psycopg)(void)
if (0 > encodings_init(module)) { goto exit; }
if (0 > typecast_init(module)) { goto exit; }
if (0 > adapters_init(module)) { goto exit; }
if (0 > errors_init(module)) { goto exit; }
if (0 > basic_errors_init(module)) { goto exit; }
if (0 > sqlstate_errors_init(module)) { goto exit; }
Dprintf("psycopgmodule: module initialization complete");

318
psycopg/sqlstate_errors.h Normal file
View File

@ -0,0 +1,318 @@
/*
* Autogenerated by 'scripts/make_errors.py'.
*/
/* Class 02 - No Data (this is also a warning class per the SQL standard) */
{"02000", "NoData"},
{"02001", "NoAdditionalDynamicResultSetsReturned"},
/* Class 03 - SQL Statement Not Yet Complete */
{"03000", "SqlStatementNotYetComplete"},
/* Class 08 - Connection Exception */
{"08000", "ConnectionException"},
{"08001", "SqlclientUnableToEstablishSqlconnection"},
{"08003", "ConnectionDoesNotExist"},
{"08004", "SqlserverRejectedEstablishmentOfSqlconnection"},
{"08006", "ConnectionFailure"},
{"08007", "TransactionResolutionUnknown"},
{"08P01", "ProtocolViolation"},
/* Class 09 - Triggered Action Exception */
{"09000", "TriggeredActionException"},
/* Class 0A - Feature Not Supported */
{"0A000", "FeatureNotSupported"},
/* Class 0B - Invalid Transaction Initiation */
{"0B000", "InvalidTransactionInitiation"},
/* Class 0F - Locator Exception */
{"0F000", "LocatorException"},
{"0F001", "InvalidLocatorSpecification"},
/* Class 0L - Invalid Grantor */
{"0L000", "InvalidGrantor"},
{"0LP01", "InvalidGrantOperation"},
/* Class 0P - Invalid Role Specification */
{"0P000", "InvalidRoleSpecification"},
/* Class 0Z - Diagnostics Exception */
{"0Z000", "DiagnosticsException"},
{"0Z002", "StackedDiagnosticsAccessedWithoutActiveHandler"},
/* Class 20 - Case Not Found */
{"20000", "CaseNotFound"},
/* Class 21 - Cardinality Violation */
{"21000", "CardinalityViolation"},
/* Class 22 - Data Exception */
{"22000", "DataException"},
{"22001", "StringDataRightTruncation"},
{"22002", "NullValueNoIndicatorParameter"},
{"22003", "NumericValueOutOfRange"},
{"22004", "NullValueNotAllowed"},
{"22005", "ErrorInAssignment"},
{"22007", "InvalidDatetimeFormat"},
{"22008", "DatetimeFieldOverflow"},
{"22009", "InvalidTimeZoneDisplacementValue"},
{"2200B", "EscapeCharacterConflict"},
{"2200C", "InvalidUseOfEscapeCharacter"},
{"2200D", "InvalidEscapeOctet"},
{"2200F", "ZeroLengthCharacterString"},
{"2200G", "MostSpecificTypeMismatch"},
{"2200H", "SequenceGeneratorLimitExceeded"},
{"2200L", "NotAnXmlDocument"},
{"2200M", "InvalidXmlDocument"},
{"2200N", "InvalidXmlContent"},
{"2200S", "InvalidXmlComment"},
{"2200T", "InvalidXmlProcessingInstruction"},
{"22010", "InvalidIndicatorParameterValue"},
{"22011", "SubstringError"},
{"22012", "DivisionByZero"},
{"22013", "InvalidPrecedingOrFollowingSize"},
{"22014", "InvalidArgumentForNtileFunction"},
{"22015", "IntervalFieldOverflow"},
{"22016", "InvalidArgumentForNthValueFunction"},
{"22018", "InvalidCharacterValueForCast"},
{"22019", "InvalidEscapeCharacter"},
{"2201B", "InvalidRegularExpression"},
{"2201E", "InvalidArgumentForLogarithm"},
{"2201F", "InvalidArgumentForPowerFunction"},
{"2201G", "InvalidArgumentForWidthBucketFunction"},
{"2201W", "InvalidRowCountInLimitClause"},
{"2201X", "InvalidRowCountInResultOffsetClause"},
{"22021", "CharacterNotInRepertoire"},
{"22022", "IndicatorOverflow"},
{"22023", "InvalidParameterValue"},
{"22024", "UnterminatedCString"},
{"22025", "InvalidEscapeSequence"},
{"22026", "StringDataLengthMismatch"},
{"22027", "TrimError"},
{"2202E", "ArraySubscriptError"},
{"2202G", "InvalidTablesampleRepeat"},
{"2202H", "InvalidTablesampleArgument"},
{"22P01", "FloatingPointException"},
{"22P02", "InvalidTextRepresentation"},
{"22P03", "InvalidBinaryRepresentation"},
{"22P04", "BadCopyFileFormat"},
{"22P05", "UntranslatableCharacter"},
{"22P06", "NonstandardUseOfEscapeCharacter"},
/* Class 23 - Integrity Constraint Violation */
{"23000", "IntegrityConstraintViolation"},
{"23001", "RestrictViolation"},
{"23502", "NotNullViolation"},
{"23503", "ForeignKeyViolation"},
{"23505", "UniqueViolation"},
{"23514", "CheckViolation"},
{"23P01", "ExclusionViolation"},
/* Class 24 - Invalid Cursor State */
{"24000", "InvalidCursorState"},
/* Class 25 - Invalid Transaction State */
{"25000", "InvalidTransactionState"},
{"25001", "ActiveSqlTransaction"},
{"25002", "BranchTransactionAlreadyActive"},
{"25003", "InappropriateAccessModeForBranchTransaction"},
{"25004", "InappropriateIsolationLevelForBranchTransaction"},
{"25005", "NoActiveSqlTransactionForBranchTransaction"},
{"25006", "ReadOnlySqlTransaction"},
{"25007", "SchemaAndDataStatementMixingNotSupported"},
{"25008", "HeldCursorRequiresSameIsolationLevel"},
{"25P01", "NoActiveSqlTransaction"},
{"25P02", "InFailedSqlTransaction"},
{"25P03", "IdleInTransactionSessionTimeout"},
/* Class 26 - Invalid SQL Statement Name */
{"26000", "InvalidSqlStatementName"},
/* Class 27 - Triggered Data Change Violation */
{"27000", "TriggeredDataChangeViolation"},
/* Class 28 - Invalid Authorization Specification */
{"28000", "InvalidAuthorizationSpecification"},
{"28P01", "InvalidPassword"},
/* Class 2B - Dependent Privilege Descriptors Still Exist */
{"2B000", "DependentPrivilegeDescriptorsStillExist"},
{"2BP01", "DependentObjectsStillExist"},
/* Class 2D - Invalid Transaction Termination */
{"2D000", "InvalidTransactionTermination"},
/* Class 2F - SQL Routine Exception */
{"2F000", "SqlRoutineException"},
{"2F002", "ModifyingSqlDataNotPermitted"},
{"2F003", "ProhibitedSqlStatementAttempted"},
{"2F004", "ReadingSqlDataNotPermitted"},
{"2F005", "FunctionExecutedNoReturnStatement"},
/* Class 34 - Invalid Cursor Name */
{"34000", "InvalidCursorName"},
/* Class 38 - External Routine Exception */
{"38000", "ExternalRoutineException"},
{"38001", "ContainingSqlNotPermitted"},
{"38002", "ModifyingSqlDataNotPermittedExt"},
{"38003", "ProhibitedSqlStatementAttemptedExt"},
{"38004", "ReadingSqlDataNotPermittedExt"},
/* Class 39 - External Routine Invocation Exception */
{"39000", "ExternalRoutineInvocationException"},
{"39001", "InvalidSqlstateReturned"},
{"39004", "NullValueNotAllowedExt"},
{"39P01", "TriggerProtocolViolated"},
{"39P02", "SrfProtocolViolated"},
{"39P03", "EventTriggerProtocolViolated"},
/* Class 3B - Savepoint Exception */
{"3B000", "SavepointException"},
{"3B001", "InvalidSavepointSpecification"},
/* Class 3D - Invalid Catalog Name */
{"3D000", "InvalidCatalogName"},
/* Class 3F - Invalid Schema Name */
{"3F000", "InvalidSchemaName"},
/* Class 40 - Transaction Rollback */
{"40000", "TransactionRollback"},
{"40001", "SerializationFailure"},
{"40002", "TransactionIntegrityConstraintViolation"},
{"40003", "StatementCompletionUnknown"},
{"40P01", "DeadlockDetected"},
/* Class 42 - Syntax Error or Access Rule Violation */
{"42000", "SyntaxErrorOrAccessRuleViolation"},
{"42501", "InsufficientPrivilege"},
{"42601", "SyntaxError"},
{"42602", "InvalidName"},
{"42611", "InvalidColumnDefinition"},
{"42622", "NameTooLong"},
{"42701", "DuplicateColumn"},
{"42702", "AmbiguousColumn"},
{"42703", "UndefinedColumn"},
{"42704", "UndefinedObject"},
{"42710", "DuplicateObject"},
{"42712", "DuplicateAlias"},
{"42723", "DuplicateFunction"},
{"42725", "AmbiguousFunction"},
{"42803", "GroupingError"},
{"42804", "DatatypeMismatch"},
{"42809", "WrongObjectType"},
{"42830", "InvalidForeignKey"},
{"42846", "CannotCoerce"},
{"42883", "UndefinedFunction"},
{"428C9", "GeneratedAlways"},
{"42939", "ReservedName"},
{"42P01", "UndefinedTable"},
{"42P02", "UndefinedParameter"},
{"42P03", "DuplicateCursor"},
{"42P04", "DuplicateDatabase"},
{"42P05", "DuplicatePreparedStatement"},
{"42P06", "DuplicateSchema"},
{"42P07", "DuplicateTable"},
{"42P08", "AmbiguousParameter"},
{"42P09", "AmbiguousAlias"},
{"42P10", "InvalidColumnReference"},
{"42P11", "InvalidCursorDefinition"},
{"42P12", "InvalidDatabaseDefinition"},
{"42P13", "InvalidFunctionDefinition"},
{"42P14", "InvalidPreparedStatementDefinition"},
{"42P15", "InvalidSchemaDefinition"},
{"42P16", "InvalidTableDefinition"},
{"42P17", "InvalidObjectDefinition"},
{"42P18", "IndeterminateDatatype"},
{"42P19", "InvalidRecursion"},
{"42P20", "WindowingError"},
{"42P21", "CollationMismatch"},
{"42P22", "IndeterminateCollation"},
/* Class 44 - WITH CHECK OPTION Violation */
{"44000", "WithCheckOptionViolation"},
/* Class 53 - Insufficient Resources */
{"53000", "InsufficientResources"},
{"53100", "DiskFull"},
{"53200", "OutOfMemory"},
{"53300", "TooManyConnections"},
{"53400", "ConfigurationLimitExceeded"},
/* Class 54 - Program Limit Exceeded */
{"54000", "ProgramLimitExceeded"},
{"54001", "StatementTooComplex"},
{"54011", "TooManyColumns"},
{"54023", "TooManyArguments"},
/* Class 55 - Object Not In Prerequisite State */
{"55000", "ObjectNotInPrerequisiteState"},
{"55006", "ObjectInUse"},
{"55P02", "CantChangeRuntimeParam"},
{"55P03", "LockNotAvailable"},
/* Class 57 - Operator Intervention */
{"57000", "OperatorIntervention"},
{"57014", "QueryCanceled"},
{"57P01", "AdminShutdown"},
{"57P02", "CrashShutdown"},
{"57P03", "CannotConnectNow"},
{"57P04", "DatabaseDropped"},
/* Class 58 - System Error (errors external to PostgreSQL itself) */
{"58000", "SystemError"},
{"58030", "IoError"},
{"58P01", "UndefinedFile"},
{"58P02", "DuplicateFile"},
/* Class 72 - Snapshot Failure */
{"72000", "SnapshotTooOld"},
/* Class F0 - Configuration File Error */
{"F0000", "ConfigFileError"},
{"F0001", "LockFileExists"},
/* Class HV - Foreign Data Wrapper Error (SQL/MED) */
{"HV000", "FdwError"},
{"HV001", "FdwOutOfMemory"},
{"HV002", "FdwDynamicParameterValueNeeded"},
{"HV004", "FdwInvalidDataType"},
{"HV005", "FdwColumnNameNotFound"},
{"HV006", "FdwInvalidDataTypeDescriptors"},
{"HV007", "FdwInvalidColumnName"},
{"HV008", "FdwInvalidColumnNumber"},
{"HV009", "FdwInvalidUseOfNullPointer"},
{"HV00A", "FdwInvalidStringFormat"},
{"HV00B", "FdwInvalidHandle"},
{"HV00C", "FdwInvalidOptionIndex"},
{"HV00D", "FdwInvalidOptionName"},
{"HV00J", "FdwOptionNameNotFound"},
{"HV00K", "FdwReplyHandle"},
{"HV00L", "FdwUnableToCreateExecution"},
{"HV00M", "FdwUnableToCreateReply"},
{"HV00N", "FdwUnableToEstablishConnection"},
{"HV00P", "FdwNoSchemas"},
{"HV00Q", "FdwSchemaNotFound"},
{"HV00R", "FdwTableNotFound"},
{"HV010", "FdwFunctionSequenceError"},
{"HV014", "FdwTooManyHandles"},
{"HV021", "FdwInconsistentDescriptorInformation"},
{"HV024", "FdwInvalidAttributeValue"},
{"HV090", "FdwInvalidStringLengthOrBufferLength"},
{"HV091", "FdwInvalidDescriptorFieldIdentifier"},
/* Class P0 - PL/pgSQL Error */
{"P0000", "PlpgsqlError"},
{"P0001", "RaiseException"},
{"P0002", "NoDataFound"},
{"P0003", "TooManyRows"},
{"P0004", "AssertFailure"},
/* Class XX - Internal Error */
{"XX000", "InternalError_"},
{"XX001", "DataCorrupted"},
{"XX002", "IndexCorrupted"},

View File

@ -17,6 +17,7 @@ The script can be run at a new PostgreSQL release to refresh the module.
# License for more details.
from __future__ import print_function
import os
import re
import sys
import urllib2
@ -24,34 +25,19 @@ from collections import defaultdict
def main():
if len(sys.argv) != 2:
print("usage: %s /path/to/errors.py" % sys.argv[0], file=sys.stderr)
return 2
filename = os.path.join(
os.path.dirname(__file__), "../psycopg/sqlstate_errors.h")
filename = sys.argv[1]
file_start = read_base_file(filename)
# If you add a version to the list fix the docs (in errors.rst)
classes, errors = fetch_errors(
['9.1', '9.2', '9.3', '9.4', '9.5', '9.6', '10', '11'])
f = open(filename, "w")
for line in file_start:
print(line, file=f)
print("/*\n * Autogenerated by 'scripts/make_errors.py'.\n */\n", file=f)
for line in generate_module_data(classes, errors):
print(line, file=f)
def read_base_file(filename):
rv = []
for line in open(filename):
rv.append(line.rstrip("\n"))
if line.startswith("# autogenerated"):
return rv
raise ValueError("can't find the separator. Is this the right file?")
def parse_errors_txt(url):
classes = {}
errors = defaultdict(dict)
@ -112,12 +98,7 @@ def fetch_errors(versions):
def generate_module_data(classes, errors):
tmpl = """
@for_sqlstate(%(errcode)r)
class %(cls)s(%(base)s):
pass\
"""
tmpl = '{"%(errcode)s", "%(cls)s"},'
specific = {
'38002': 'ModifyingSqlDataNotPermittedExt',
'38003': 'ProhibitedSqlStatementAttemptedExt',
@ -137,7 +118,7 @@ class %(cls)s(%(base)s):
# success and warning - never raised
continue
yield "\n\n# %s" % clslabel
yield "\n/* %s */" % clslabel
for errcode, errlabel in sorted(errors[clscode].items()):
if errcode in specific:
@ -150,81 +131,9 @@ class %(cls)s(%(base)s):
yield tmpl % {
'cls': clsname,
'base': get_base_class_name(errcode),
'errcode': errcode
}
def get_base_class_name(errcode):
"""
This is a python porting of exception_from_sqlstate code in pqpath.c
"""
if errcode[0] == '0':
if errcode[1] == 'A': # Class 0A - Feature Not Supported
return 'NotSupportedError'
elif errcode[0] == '2':
if errcode[1] in '01':
# Class 20 - Case Not Found
# Class 21 - Cardinality Violation
return 'ProgrammingError'
elif errcode[1] == '2': # Class 22 - Data Exception
return 'DataError'
elif errcode[1] == '3': # Class 23 - Integrity Constraint Violation
return 'IntegrityError'
elif errcode[1] in '45':
# Class 24 - Invalid Cursor State
# Class 25 - Invalid Transaction State
return 'InternalError'
elif errcode[1] in '678':
# Class 26 - Invalid SQL Statement Name
# Class 27 - Triggered Data Change Violation
# Class 28 - Invalid Authorization Specification
return 'OperationalError'
elif errcode[1] in 'BDF':
# Class 2B - Dependent Privilege Descriptors Still Exist
# Class 2D - Invalid Transaction Termination
# Class 2F - SQL Routine Exception
return 'InternalError'
elif errcode[0] == '3':
if errcode[1] == '4': # Class 34 - Invalid Cursor Name
return 'OperationalError'
if errcode[1] in '89B':
# Class 38 - External Routine Exception
# Class 39 - External Routine Invocation Exception
# Class 3B - Savepoint Exception
return 'InternalError'
if errcode[1] in 'DF':
# Class 3D - Invalid Catalog Name
# Class 3F - Invalid Schema Name
return 'ProgrammingError'
elif errcode[0] == '4':
if errcode[1] == '0': # Class 40 - Transaction Rollback
return 'TransactionRollbackError'
if errcode[1] in '24':
# Class 42 - Syntax Error or Access Rule Violation
# Class 44 - WITH CHECK OPTION Violation
return 'ProgrammingError'
elif errcode[0] == '5':
if errcode == "57014":
return 'QueryCanceledError'
# Class 53 - Insufficient Resources
# Class 54 - Program Limit Exceeded
# Class 55 - Object Not In Prerequisite State
# Class 57 - Operator Intervention
# Class 58 - System Error (errors external to PostgreSQL itself)
else:
return 'OperationalError'
elif errcode[0] == 'F': # Class F0 - Configuration File Error
return 'InternalError'
elif errcode[0] == 'H': # Class HV - Foreign Data Wrapper Error (SQL/MED)
return 'OperationalError'
elif errcode[0] == 'P': # Class P0 - PL/pgSQL Error
return 'InternalError'
elif errcode[0] == 'X': # Class XX - Internal Error
return 'InternalError'
return 'DatabaseError'
if __name__ == '__main__':
sys.exit(main())

View File

@ -515,7 +515,7 @@ depends = [
'adapter_list.h', 'adapter_pboolean.h', 'adapter_pdecimal.h',
'adapter_pint.h', 'adapter_pfloat.h', 'adapter_qstring.h',
'microprotocols.h', 'microprotocols_proto.h',
'typecast.h', 'typecast_binary.h',
'typecast.h', 'typecast_binary.h', 'sqlstate_errors.h',
# included sources
'typecast_array.c', 'typecast_basic.c', 'typecast_binary.c',

View File

@ -43,14 +43,14 @@ class ErrorsTests(ConnectingTestCase):
def test_exception_class_fallback(self):
cur = self.conn.cursor()
from psycopg2 import errors
x = errors._by_sqlstate.pop('42P01')
from psycopg2._psycopg import sqlstate_errors
x = sqlstate_errors.pop('42P01')
try:
cur.execute("select * from nonexist")
except psycopg2.Error as exc:
e = exc
finally:
errors._by_sqlstate['42P01'] = x
sqlstate_errors['42P01'] = x
self.assertEqual(type(e), self.conn.ProgrammingError)
@ -62,6 +62,25 @@ class ErrorsTests(ConnectingTestCase):
with self.assertRaises(KeyError):
errors.lookup('XXXXX')
def test_has_base_exceptions(self):
import psycopg2
from psycopg2 import errors
excs = []
for n in dir(psycopg2):
obj = getattr(psycopg2, n)
if isinstance(obj, type) and issubclass(obj, StandardError):
excs.append(obj)
self.assert_(len(excs) > 8, str(excs))
excs.append(psycopg2.extensions.QueryCanceledError)
excs.append(psycopg2.extensions.TransactionRollbackError)
for exc in excs:
self.assert_(hasattr(errors, exc.__name__))
self.assert_(getattr(errors, exc.__name__) is exc)
def test_suite():
return unittest.TestLoader().loadTestsFromName(__name__)