Psycopg2 errors syntaxerror syntax error at end of input

Reported by Tomas Janco tomas.janco@myinphinity.com I have found following problem with JDBC driver: When an updatable result set is created for a table without primary key, any update fails with e...

Reported by

Tomas Janco tomas.janco@myinphinity.com

I have found following problem with JDBC driver:
When an updatable result set is created for a table without primary key, any update fails with error: «syntax error at end of input»
The driver generates invalid SQL query to update the table.

JDBC driver version: 42.2.18 (jre8)
Server version: PostgreSQL 9.6.6, compiled by Visual C++ build 1800, 64-bit

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class TestPgSql {
/* test table schema:
CREATE TABLE public.sample
(
id integer,
value character varying(255) COLLATE pg_catalog.»default»
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
INSERT INTO public.sample(id, value)
VALUES (1, ‘abcd’);
*/

public static void main(String args[]) throws Exception {
    Connection conn = DriverManager.getConnection("jdbc:postgresql://localhost/...?user=....&password=....");
    String sql = "SELECT * FROM sample WHERE id = 1;";
    PreparedStatement stmt = conn.prepareStatement(sql, ResultSet.CONCUR_UPDATABLE, ResultSet.TYPE_FORWARD_ONLY);
    ResultSet rs = stmt.executeQuery();
    rs.next();
    rs.updateString("value", "something");
    rs.updateRow();
    rs.close();
}

}

Expected behavior:
The code successfully updates the table OR throws an error explaining primary key is not present in result set and is required for updatable result set.

Actual behavior:
Incorrect SQL command is generated internally: «UPDATE sample SET «value» = $1 WHERE «
The query is missing the WHERE condition expression.
This results in following exception being thrown:

Exception in thread «main» org.postgresql.util.PSQLException: ERROR: syntax error at end of input
Position: 39
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2553)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2285)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:323)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:473)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:393)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:164)
at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:130)
at org.postgresql.jdbc.PgResultSet.updateRow(PgResultSet.java:1445)
at TestPgSql.main(TestPgSql.java:35)

New in version 2.8.

Changed in version 2.8.4: added errors introduced in PostgreSQL 12

Changed in version 2.8.6: added errors introduced in PostgreSQL 13

Changed in version 2.9.2: added errors introduced in PostgreSQL 14

Changed in version 2.9.4: added errors introduced in PostgreSQL 15

This module exposes the classes psycopg raises upon receiving an error from
the database with a SQLSTATE value attached (available in the
pgcode attribute). The content of the module is generated
from the PostgreSQL source code and includes classes for every error defined
by PostgreSQL in versions between 9.1 and 15.

Every class in the module is named after what referred as “condition name” in
the documentation, converted to CamelCase: e.g. the error 22012,
division_by_zero is exposed by this module as the class DivisionByZero.

Every exception class is a subclass of one of the standard DB-API
exception
and expose the Error interface.
Each class’ superclass is what used to be raised by psycopg in versions before
the introduction of this module, so everything should be compatible with
previously written code catching one the DB-API class: if your code used to
catch IntegrityError to detect a duplicate entry, it will keep on working
even if a more specialised subclass such as UniqueViolation is raised.

The new classes allow a more idiomatic way to check and process a specific
error among the many the database may return. For instance, in order to check
that a table is locked, the following code could have been used previously:

try:
    cur.execute("LOCK TABLE mytable IN ACCESS EXCLUSIVE MODE NOWAIT")
except psycopg2.OperationalError as e:
    if e.pgcode == psycopg2.errorcodes.LOCK_NOT_AVAILABLE:
        locked = True
    else:
        raise

While this method is still available, the specialised class allows for a more
idiomatic error handler:

try:
    cur.execute("LOCK TABLE mytable IN ACCESS EXCLUSIVE MODE NOWAIT")
except psycopg2.errors.LockNotAvailable:
    locked = True
psycopg2.errors.lookup(code)

Lookup an error code and return its exception class.

Raise KeyError if the code is not found.

try:
    cur.execute("LOCK TABLE mytable IN ACCESS EXCLUSIVE MODE NOWAIT")
except psycopg2.errors.lookup("55P03"):
    locked = True

SQLSTATE exception classes¶

The following table contains the list of all the SQLSTATE classes exposed by
the module.

Note that, for completeness, the module also exposes all the
DB-API-defined exceptions and a few
psycopg-specific ones
exposed by the extensions
module, which are not listed here.

SQLSTATE

Exception

Base exception

Class 02: No Data (this is also a warning class per the SQL standard)

02000

NoData

DatabaseError

02001

NoAdditionalDynamicResultSetsReturned

DatabaseError

Class 03: SQL Statement Not Yet Complete

03000

SqlStatementNotYetComplete

DatabaseError

Class 08: Connection Exception

08000

ConnectionException

OperationalError

08001

SqlclientUnableToEstablishSqlconnection

OperationalError

08003

ConnectionDoesNotExist

OperationalError

08004

SqlserverRejectedEstablishmentOfSqlconnection

OperationalError

08006

ConnectionFailure

OperationalError

08007

TransactionResolutionUnknown

OperationalError

08P01

ProtocolViolation

OperationalError

Class 09: Triggered Action Exception

09000

TriggeredActionException

DatabaseError

Class 0A: Feature Not Supported

0A000

FeatureNotSupported

NotSupportedError

Class 0B: Invalid Transaction Initiation

0B000

InvalidTransactionInitiation

DatabaseError

Class 0F: Locator Exception

0F000

LocatorException

DatabaseError

0F001

InvalidLocatorSpecification

DatabaseError

Class 0L: Invalid Grantor

0L000

InvalidGrantor

DatabaseError

0LP01

InvalidGrantOperation

DatabaseError

Class 0P: Invalid Role Specification

0P000

InvalidRoleSpecification

DatabaseError

Class 0Z: Diagnostics Exception

0Z000

DiagnosticsException

DatabaseError

0Z002

StackedDiagnosticsAccessedWithoutActiveHandler

DatabaseError

Class 20: Case Not Found

20000

CaseNotFound

ProgrammingError

Class 21: Cardinality Violation

21000

CardinalityViolation

ProgrammingError

Class 22: Data Exception

22000

DataException

DataError

22001

StringDataRightTruncation

DataError

22002

NullValueNoIndicatorParameter

DataError

22003

NumericValueOutOfRange

DataError

22004

NullValueNotAllowed

DataError

22005

ErrorInAssignment

DataError

22007

InvalidDatetimeFormat

DataError

22008

DatetimeFieldOverflow

DataError

22009

InvalidTimeZoneDisplacementValue

DataError

2200B

EscapeCharacterConflict

DataError

2200C

InvalidUseOfEscapeCharacter

DataError

2200D

InvalidEscapeOctet

DataError

2200F

ZeroLengthCharacterString

DataError

2200G

MostSpecificTypeMismatch

DataError

2200H

SequenceGeneratorLimitExceeded

DataError

2200L

NotAnXmlDocument

DataError

2200M

InvalidXmlDocument

DataError

2200N

InvalidXmlContent

DataError

2200S

InvalidXmlComment

DataError

2200T

InvalidXmlProcessingInstruction

DataError

22010

InvalidIndicatorParameterValue

DataError

22011

SubstringError

DataError

22012

DivisionByZero

DataError

22013

InvalidPrecedingOrFollowingSize

DataError

22014

InvalidArgumentForNtileFunction

DataError

22015

IntervalFieldOverflow

DataError

22016

InvalidArgumentForNthValueFunction

DataError

22018

InvalidCharacterValueForCast

DataError

22019

InvalidEscapeCharacter

DataError

2201B

InvalidRegularExpression

DataError

2201E

InvalidArgumentForLogarithm

DataError

2201F

InvalidArgumentForPowerFunction

DataError

2201G

InvalidArgumentForWidthBucketFunction

DataError

2201W

InvalidRowCountInLimitClause

DataError

2201X

InvalidRowCountInResultOffsetClause

DataError

22021

CharacterNotInRepertoire

DataError

22022

IndicatorOverflow

DataError

22023

InvalidParameterValue

DataError

22024

UnterminatedCString

DataError

22025

InvalidEscapeSequence

DataError

22026

StringDataLengthMismatch

DataError

22027

TrimError

DataError

2202E

ArraySubscriptError

DataError

2202G

InvalidTablesampleRepeat

DataError

2202H

InvalidTablesampleArgument

DataError

22030

DuplicateJsonObjectKeyValue

DataError

22031

InvalidArgumentForSqlJsonDatetimeFunction

DataError

22032

InvalidJsonText

DataError

22033

InvalidSqlJsonSubscript

DataError

22034

MoreThanOneSqlJsonItem

DataError

22035

NoSqlJsonItem

DataError

22036

NonNumericSqlJsonItem

DataError

22037

NonUniqueKeysInAJsonObject

DataError

22038

SingletonSqlJsonItemRequired

DataError

22039

SqlJsonArrayNotFound

DataError

2203A

SqlJsonMemberNotFound

DataError

2203B

SqlJsonNumberNotFound

DataError

2203C

SqlJsonObjectNotFound

DataError

2203D

TooManyJsonArrayElements

DataError

2203E

TooManyJsonObjectMembers

DataError

2203F

SqlJsonScalarRequired

DataError

2203G

SqlJsonItemCannotBeCastToTargetType

DataError

22P01

FloatingPointException

DataError

22P02

InvalidTextRepresentation

DataError

22P03

InvalidBinaryRepresentation

DataError

22P04

BadCopyFileFormat

DataError

22P05

UntranslatableCharacter

DataError

22P06

NonstandardUseOfEscapeCharacter

DataError

Class 23: Integrity Constraint Violation

23000

IntegrityConstraintViolation

IntegrityError

23001

RestrictViolation

IntegrityError

23502

NotNullViolation

IntegrityError

23503

ForeignKeyViolation

IntegrityError

23505

UniqueViolation

IntegrityError

23514

CheckViolation

IntegrityError

23P01

ExclusionViolation

IntegrityError

Class 24: Invalid Cursor State

24000

InvalidCursorState

InternalError

Class 25: Invalid Transaction State

25000

InvalidTransactionState

InternalError

25001

ActiveSqlTransaction

InternalError

25002

BranchTransactionAlreadyActive

InternalError

25003

InappropriateAccessModeForBranchTransaction

InternalError

25004

InappropriateIsolationLevelForBranchTransaction

InternalError

25005

NoActiveSqlTransactionForBranchTransaction

InternalError

25006

ReadOnlySqlTransaction

InternalError

25007

SchemaAndDataStatementMixingNotSupported

InternalError

25008

HeldCursorRequiresSameIsolationLevel

InternalError

25P01

NoActiveSqlTransaction

InternalError

25P02

InFailedSqlTransaction

InternalError

25P03

IdleInTransactionSessionTimeout

InternalError

Class 26: Invalid SQL Statement Name

26000

InvalidSqlStatementName

OperationalError

Class 27: Triggered Data Change Violation

27000

TriggeredDataChangeViolation

OperationalError

Class 28: Invalid Authorization Specification

28000

InvalidAuthorizationSpecification

OperationalError

28P01

InvalidPassword

OperationalError

Class 2B: Dependent Privilege Descriptors Still Exist

2B000

DependentPrivilegeDescriptorsStillExist

InternalError

2BP01

DependentObjectsStillExist

InternalError

Class 2D: Invalid Transaction Termination

2D000

InvalidTransactionTermination

InternalError

Class 2F: SQL Routine Exception

2F000

SqlRoutineException

InternalError

2F002

ModifyingSqlDataNotPermitted

InternalError

2F003

ProhibitedSqlStatementAttempted

InternalError

2F004

ReadingSqlDataNotPermitted

InternalError

2F005

FunctionExecutedNoReturnStatement

InternalError

Class 34: Invalid Cursor Name

34000

InvalidCursorName

OperationalError

Class 38: External Routine Exception

38000

ExternalRoutineException

InternalError

38001

ContainingSqlNotPermitted

InternalError

38002

ModifyingSqlDataNotPermittedExt

InternalError

38003

ProhibitedSqlStatementAttemptedExt

InternalError

38004

ReadingSqlDataNotPermittedExt

InternalError

Class 39: External Routine Invocation Exception

39000

ExternalRoutineInvocationException

InternalError

39001

InvalidSqlstateReturned

InternalError

39004

NullValueNotAllowedExt

InternalError

39P01

TriggerProtocolViolated

InternalError

39P02

SrfProtocolViolated

InternalError

39P03

EventTriggerProtocolViolated

InternalError

Class 3B: Savepoint Exception

3B000

SavepointException

InternalError

3B001

InvalidSavepointSpecification

InternalError

Class 3D: Invalid Catalog Name

3D000

InvalidCatalogName

ProgrammingError

Class 3F: Invalid Schema Name

3F000

InvalidSchemaName

ProgrammingError

Class 40: Transaction Rollback

40000

TransactionRollback

OperationalError

40001

SerializationFailure

OperationalError

40002

TransactionIntegrityConstraintViolation

OperationalError

40003

StatementCompletionUnknown

OperationalError

40P01

DeadlockDetected

OperationalError

Class 42: Syntax Error or Access Rule Violation

42000

SyntaxErrorOrAccessRuleViolation

ProgrammingError

42501

InsufficientPrivilege

ProgrammingError

42601

SyntaxError

ProgrammingError

42602

InvalidName

ProgrammingError

42611

InvalidColumnDefinition

ProgrammingError

42622

NameTooLong

ProgrammingError

42701

DuplicateColumn

ProgrammingError

42702

AmbiguousColumn

ProgrammingError

42703

UndefinedColumn

ProgrammingError

42704

UndefinedObject

ProgrammingError

42710

DuplicateObject

ProgrammingError

42712

DuplicateAlias

ProgrammingError

42723

DuplicateFunction

ProgrammingError

42725

AmbiguousFunction

ProgrammingError

42803

GroupingError

ProgrammingError

42804

DatatypeMismatch

ProgrammingError

42809

WrongObjectType

ProgrammingError

42830

InvalidForeignKey

ProgrammingError

42846

CannotCoerce

ProgrammingError

42883

UndefinedFunction

ProgrammingError

428C9

GeneratedAlways

ProgrammingError

42939

ReservedName

ProgrammingError

42P01

UndefinedTable

ProgrammingError

42P02

UndefinedParameter

ProgrammingError

42P03

DuplicateCursor

ProgrammingError

42P04

DuplicateDatabase

ProgrammingError

42P05

DuplicatePreparedStatement

ProgrammingError

42P06

DuplicateSchema

ProgrammingError

42P07

DuplicateTable

ProgrammingError

42P08

AmbiguousParameter

ProgrammingError

42P09

AmbiguousAlias

ProgrammingError

42P10

InvalidColumnReference

ProgrammingError

42P11

InvalidCursorDefinition

ProgrammingError

42P12

InvalidDatabaseDefinition

ProgrammingError

42P13

InvalidFunctionDefinition

ProgrammingError

42P14

InvalidPreparedStatementDefinition

ProgrammingError

42P15

InvalidSchemaDefinition

ProgrammingError

42P16

InvalidTableDefinition

ProgrammingError

42P17

InvalidObjectDefinition

ProgrammingError

42P18

IndeterminateDatatype

ProgrammingError

42P19

InvalidRecursion

ProgrammingError

42P20

WindowingError

ProgrammingError

42P21

CollationMismatch

ProgrammingError

42P22

IndeterminateCollation

ProgrammingError

Class 44: WITH CHECK OPTION Violation

44000

WithCheckOptionViolation

ProgrammingError

Class 53: Insufficient Resources

53000

InsufficientResources

OperationalError

53100

DiskFull

OperationalError

53200

OutOfMemory

OperationalError

53300

TooManyConnections

OperationalError

53400

ConfigurationLimitExceeded

OperationalError

Class 54: Program Limit Exceeded

54000

ProgramLimitExceeded

OperationalError

54001

StatementTooComplex

OperationalError

54011

TooManyColumns

OperationalError

54023

TooManyArguments

OperationalError

Class 55: Object Not In Prerequisite State

55000

ObjectNotInPrerequisiteState

OperationalError

55006

ObjectInUse

OperationalError

55P02

CantChangeRuntimeParam

OperationalError

55P03

LockNotAvailable

OperationalError

55P04

UnsafeNewEnumValueUsage

OperationalError

Class 57: Operator Intervention

57000

OperatorIntervention

OperationalError

57014

QueryCanceled

OperationalError

57P01

AdminShutdown

OperationalError

57P02

CrashShutdown

OperationalError

57P03

CannotConnectNow

OperationalError

57P04

DatabaseDropped

OperationalError

57P05

IdleSessionTimeout

OperationalError

Class 58: System Error (errors external to PostgreSQL itself)

58000

SystemError

OperationalError

58030

IoError

OperationalError

58P01

UndefinedFile

OperationalError

58P02

DuplicateFile

OperationalError

Class 72: Snapshot Failure

72000

SnapshotTooOld

DatabaseError

Class F0: Configuration File Error

F0000

ConfigFileError

InternalError

F0001

LockFileExists

InternalError

Class HV: Foreign Data Wrapper Error (SQL/MED)

HV000

FdwError

OperationalError

HV001

FdwOutOfMemory

OperationalError

HV002

FdwDynamicParameterValueNeeded

OperationalError

HV004

FdwInvalidDataType

OperationalError

HV005

FdwColumnNameNotFound

OperationalError

HV006

FdwInvalidDataTypeDescriptors

OperationalError

HV007

FdwInvalidColumnName

OperationalError

HV008

FdwInvalidColumnNumber

OperationalError

HV009

FdwInvalidUseOfNullPointer

OperationalError

HV00A

FdwInvalidStringFormat

OperationalError

HV00B

FdwInvalidHandle

OperationalError

HV00C

FdwInvalidOptionIndex

OperationalError

HV00D

FdwInvalidOptionName

OperationalError

HV00J

FdwOptionNameNotFound

OperationalError

HV00K

FdwReplyHandle

OperationalError

HV00L

FdwUnableToCreateExecution

OperationalError

HV00M

FdwUnableToCreateReply

OperationalError

HV00N

FdwUnableToEstablishConnection

OperationalError

HV00P

FdwNoSchemas

OperationalError

HV00Q

FdwSchemaNotFound

OperationalError

HV00R

FdwTableNotFound

OperationalError

HV010

FdwFunctionSequenceError

OperationalError

HV014

FdwTooManyHandles

OperationalError

HV021

FdwInconsistentDescriptorInformation

OperationalError

HV024

FdwInvalidAttributeValue

OperationalError

HV090

FdwInvalidStringLengthOrBufferLength

OperationalError

HV091

FdwInvalidDescriptorFieldIdentifier

OperationalError

Class P0: PL/pgSQL Error

P0000

PlpgsqlError

InternalError

P0001

RaiseException

InternalError

P0002

NoDataFound

InternalError

P0003

TooManyRows

InternalError

P0004

AssertFailure

InternalError

Class XX: Internal Error

XX000

InternalError_

InternalError

XX001

DataCorrupted

InternalError

XX002

IndexCorrupted

InternalError

Introduction

This article will provide a brief overview of how you can better handle PostgreSQL Python exceptions while using the psycopg2 adapter in your code. Make sure that the psycopg2 package is installed on your machine using the PIP3 package manager for Python 3 using the following command:

We’ll also be building a function from scratch that prints detailed information about the psycopg2 exceptions by accessing several of its exception library attributes. It should be noted, however, that this is mostly for educational and debugging purposes, and it should be noted that, in the implementation phase your website or application, you may want to handle them less explicitly.

Catching and handling exceptions in Python

A Python script will terminate as soon as an exception or error is raised, but there is a try-except block (that works in a similar fashion to the try {} catch(err) {} code block in PHP or JavaScript) that will allow you to catch the exception, handle it, and then respond to it with more code within the except: part of the indentation block.

The following code allows you to catch all exceptions, as a wildcard, and print them out without having to explicitly mention the exact exception:

1
2
3
4
5
6

try:
    a = 1234
    print (a + » hello world»)
except Exception as error:
    print («Oops! An exception has occured:», error)
    print («Exception TYPE:», type(error))

the except Exception as error: bit will allow you to handle any exception, and return the exception information as a TypeError class object using Python’s as keyword.

Screenshot of Python IDLE returning exception information in a try-except indentation block

Exception libraries for the psycopg2 Python adapter

Some of the two most commonly occurring exceptions in the psycopg2 library are the OperationalError and ProgrammingError exception classes.

An OperationalError typically occurs when the parameters passed to the connect() method are incorrect, or if the server runs out of memory, or if a piece of datum cannot be found, etc.

A ProgrammingError happens when there is a syntax error in the SQL statement string passed to the psycopg2 execute() method, or if a SQL statement is executed to delete a non-existent table, or an attempt is made to create a table that already exists, and exceptions of that nature.

Complete list of the psycopg2 exception classes

Here’s the complete list of all of psycopg2 exception classes:

InterfaceError, DatabaseError, DataError, OperationalError, IntegrityError, InternalError, ProgrammingError, and NotSupportedError.

Brief overview of PostgreSQL Error Codes

There is an extensive list of over 200 error codes on the postgresql.org website that describes, in detail, each five-character SQL exception.

In the psycopg2 adapter library you can return the code by accessing the exception’s pgcode attribute. It should be an alpha-numeric string, five characters in length, that corresponds to an exception in the PostgreSQL Error Codes table.

Here’s some example code showing how one can access the attribute for the PostgreSQL error code:

1
2
3
4
5

try:
        cursor.execute(«INVALID SQL STATEMENT»)
    except Exception as err:
        print («Oops! An exception has occured:», error)
        print («Exception TYPE:», type(error))

Import the exception libraries for the psycopg2 Python adapter

You’ll need to import the following libraries at the beginning of your Python script:

1
2
3
4
5
6
7
8

# import sys to get more detailed Python exception info
import sys

# import the connect library for psycopg2
from psycopg2 import connect

# import the error handling libraries for psycopg2
from psycopg2 import OperationalError, errorcodes, errors

Get the psycopg2 version string

Older versions of the psycopg2 adapter may handle some exceptions differently. Here’s some code that imports the __version__ attribute string for the psycopg2 library and prints it:

1
2
3
4
5

# import the psycopg2 library’s __version__ string
from psycopg2 import __version__ as psycopg2_version

# print the version string for psycopg2
print («psycopg2 version:», psycopg2_version, «n«)

Screenshot of Python's IDLE getting the version string for psycopg2

Define a Python function to handle and print psycopg2 SQL exceptions

The code in this section will define a Python function that will take a Python TypeError object class and parse, both the psycopg2 and native Python, exception attributes from it in order to print the details of the exception:

Define the ‘print_psycopg2_exception()’ Python function

Use Python’s def keyword to define a new function and make it accept a TypeError Python object class as its only parameter:

1
2

# define a function that handles and parses psycopg2 exceptions
def print_psycopg2_exception(err):

Use Python’s built-in ‘sys’ library to get more detailed exception information

The next bit of code grabs the traceback information for the exception, including the line number in the code that the error occurred on, by calling the sys library’s exc_info() method:

1
2
3
4
5

   

# get details about the exception
    err_type, err_obj, traceback = sys.exc_info()

    # get the line number when exception occured
    line_num = traceback.tb_lineno

Print the details for the psycopg2 exception

Use Python’s print() function to print the details of the psycopg2 exception that was passed to the function call:

1
2
3
4
5
6
7
8
9
10

   

# print the connect() error
    print («npsycopg2 ERROR:», err, «on line number:», line_num)
    print («psycopg2 traceback:», traceback, «— type:», err_type)

    # psycopg2 extensions.Diagnostics object attribute
    print («nextensions.Diagnostics:», err.diag)

    # print the pgcode and pgerror exceptions
    print («pgerror:», err.pgerror)
    print («pgcode:», err.pgcode, «n«)

Handle psycopg2 exceptions that occur while connecting to PostgreSQL

Now that the function has been defined it’s time to test it out by running some psycopg2 code. The following Python code attempts to make a connection to PostgreSQL in a try-except indentation block, and, in the case of an exception, passes the TypeError Python object to the print_psycopg2_exception() function defined earlier:

1
2
3
4
5
6
7
8
9
10
11
12
13
14

# declare a new PostgreSQL connection object
try:
    conn = connect(
        dbname = «python_test»,
        user = «WRONG_USER»,
        host = «localhost»,
        password = «mypass»
    )
except OperationalError as err:
    # pass exception to function
    print_psycopg2_exception(err)

    # set the connection to ‘None’ in case of error
    conn = None

NOTE: The above code will give the connection object a value of None in the case of an exception.

If the username string, passed to the user parameter, doesn’t match any of the users for the PostgreSQL server then the function should print something that closely resembles the following:

1
2
3
4
5
6
7
8

psycopg2 ERROR: FATAL:  password authentication failed for user «WRONG_USER»
FATAL:  password authentication failed for user «WRONG_USER»
 on line number: 43
psycopg2 traceback: <traceback object at 0x7fa361660a88> — type: <class ‘psycopg2.OperationalError’>

extensions.Diagnostics: <psycopg2.extensions.Diagnostics object at 0x7fa3646e1558>
pgerror: None
pgcode: None

Handle psycopg2 exceptions that occur while executing SQL statements

If the code to connect to PostgreSQL didn’t have any problems, and no exceptions were raised, then test out the function again. The following code purposely attempts to use a cursor object to execute() a SQL statement with bad syntax:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# if the connection was successful
if conn != None:

    # declare a cursor object from the connection
    cursor = conn.cursor()
    print («cursor object:», cursor, «n«)

    # catch exception for invalid SQL statement
    try:
        cursor.execute(«INVALID SQL STATEMENT»)
    except Exception as err:
        # pass exception to function
        print_psycopg2_exception(err)

        # rollback the previous transaction before starting another
        conn.rollback()

The print_psycopg2_exception() function should print a response that resembles the following:

1
2
3
4
5
6
7
8
9
10
11
12

psycopg2 ERROR: syntax error at or near «INVALID»
LINE 1: INVALID SQL STATEMENT
        ^
 on line number: 90
psycopg2 traceback: <traceback object at 0x7f58dd244188> — type: <class ‘psycopg2.errors.SyntaxError’>

extensions.Diagnostics: <psycopg2.extensions.Diagnostics object at 0x7f58e0018558>
pgerror: ERROR:  syntax error at or near «INVALID»
LINE 1: INVALID SQL STATEMENT
        ^

pgcode: 42601

The 42601 PostgreSQL code indicates that the exception resulted from a syntax error in the SQL statement:

Screenshot of the PostgreSQL Error Codes web page in a browser tab

Catch ‘InFailedSqlTransaction’ psycopg2 exceptions

This last bit of Python code will raise a InFailedSqlTransaction exception if the last PostgreSQL transaction, with the bad SQL statement, wasn’t rolled back using the connection object’s rollback() method:

1
2
3
4
5
6

# returns ‘psycopg2.errors.InFailedSqlTransaction’ if rollback() not called
    try:
        cursor.execute(«SELECT * FROM some_table;»)
    except errors.InFailedSqlTransaction as err:
        # pass exception to function
        print_psycopg2_exception(err)

Conclusion

The psycopg2 library adapter for PostgreSQL has an extensive list of exception Python classes, and this article only covered a few of them just to give a general idea of how you can handle such exceptions in your own Python script.

Just the Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

# import sys to get more detailed Python exception info
import sys

# import the connect library for psycopg2
from psycopg2 import connect

# import the error handling libraries for psycopg2
from psycopg2 import OperationalError, errorcodes, errors

# import the psycopg2 library’s __version__ string
from psycopg2 import __version__ as psycopg2_version
«`python
#!/usr/bin/python3
# -*- coding: utf-8 -*-

# import sys to get more detailed Python exception info
import sys

# import the connect library for psycopg2
from psycopg2 import connectDoes NOT need TextBroker to re-write

# import the error handling libraries for psycopg2
from psycopg2 import OperationalError, errorcodes, errors

# import the psycopg2 library’s __version__ string
from psycopg2 import __version__ as psycopg2_version

# print the version string for psycopg2
print («psycopg2 version:», psycopg2_version, «n«)

# define a function that handles and parses psycopg2 exceptions
def print_psycopg2_exception(err):
    # get details about the exception
    err_type, err_obj, traceback = sys.exc_info()

    # get the line number when exception occured
    line_num = traceback.tb_lineno

    # print the connect() error
    print («npsycopg2 ERROR:», err, «on line number:», line_num)
    print («psycopg2 traceback:», traceback, «— type:», err_type)

    # psycopg2 extensions.Diagnostics object attribute
    print («nextensions.Diagnostics:», err.diag)

    # print the pgcode and pgerror exceptions
    print («pgerror:», err.pgerror)
    print («pgcode:», err.pgcode, «n«)

try:
    conn = connect(
        dbname = «python_test»,
        user = «objectrocket»,
        host = «localhost»,
        password = «mypass»
    )
except OperationalError as err:
    # pass exception to function
    print_psycopg2_exception(err)

    # set the connection to ‘None’ in case of error
    conn = None

# if the connection was successful
if conn != None:

    # declare a cursor object from the connection
    cursor = conn.cursor()
    print («cursor object:», cursor, «n«)

    # catch exception for invalid SQL statement
    try:
        cursor.execute(«INVALID SQL STATEMENT»)
    except Exception as err:
        # pass exception to function
        print_psycopg2_exception(err)

        # rollback the previous transaction before starting another
        conn.rollback()

    # execute a PostgreSQL command to get all rows in a table
    # returns ‘psycopg2.errors.InFailedSqlTransaction’ if rollback() not called
    try:
        cursor.execute(«SELECT * FROM some_table;»)
    except errors.InFailedSqlTranroughsaction as err:
        # pass exception to function
        print_psycopg2_exception(err)

    # close the cursor object to avoid memory leaks
    cursor.close()

    # close the connection object also
    conn.close()

Pilot the ObjectRocket Platform Free!

Try Fully-Managed CockroachDB, Elasticsearch, MongoDB, PostgreSQL (Beta) or Redis.

Get Started

EDIT: IN THE END, I’VE FOUND A WAY AROUND IT

I don’t know what I’m doing wrong with my syntax.

with engine.connect() as connection:
    # sanity check, this line works just fine:
    insert = connection.execute("INSERT INTO books (isbn, name, author, year) VALUES ('12345', 'ABCD', 'ABCD', '1234')")
    
    # now with the main file:
    with open('books.csv') as file:
        reader = csv.reader(file)
        next(reader)
        for isbn, name, author, year in reader:
            connection.execute('''INSERT INTO books (isbn, name, author, year) VALUES (? ? ? ?)''', (isbn, name, author, year)) 
'''
other kind of query I've tried:
sql_statement = "INSERT INTO books (isbn, name, author, year) VALUES (:isbn, :name, :author, :year)" 
values = {'isbn': isbn, 'name': name, 'author': author, 'year': year}
connection.execute(sql_statement, values)
'''

When I try to run I get this error:

2020-04-16 01:40:47,082 INFO sqlalchemy.engine.base.Engine INSERT INTO books (isbn, name, author, year) VALUES (:isbn, :name, :author, :year)
2020-04-16 01:40:47,082 INFO sqlalchemy.engine.base.Engine {'isbn': '0380795272', 'name': 'Krondor: The Betrayal', 'author': 'Raymond E. Feist', 'year': '1998'}
2020-04-16 01:40:47,309 INFO sqlalchemy.engine.base.Engine ROLLBACK
[...]
psycopg2.errors.SyntaxError: syntax error at or near ":"
LINE 1: ...ERT INTO books (isbn, name, author, year) VALUES (:isbn, :na...
                                                             ^
The above exception was the direct cause of the following exception:
[...]
sqlalchemy.exc.ProgrammingError: (psycopg2.errors.SyntaxError) syntax error at or near ":"
LINE 1: ...ERT INTO books (isbn, name, author, year) VALUES (:isbn, :na...
                                                             ^

[SQL: INSERT INTO books (isbn, name, author, year) VALUES (:isbn, :name, :author, :year)]
[parameters: {'isbn': '0380795272', 'name': 'Krondor: The Betrayal', 'author': 'Raymond E. Feist', 'year': '1998'}]
(Background on this error at: http://sqlalche.me/e/f405)
[Finished in 2.9s]

I’ve read a lot about PostgreSQL parameters but still can’t figure out what I’m doing wrong.

EDIT: This way it works. I’m not entirely sure about what solved it. Maybe the reader wasn’t passing the dict the way the query was expecting, maybe the «text» attribute for the statement solved the placeholder problem…. I’d still like to know what could be done better. (I forgot to mention, I’m not supposed to use ORM, only raw SQL queries). It is taking forever to send 5k queries because I couldn’t use «commit()», but at least it is working.

import csv
import sqlalchemy
from sqlalchemy import create_engine, text

engine = create_engine('[database_url', echo=True)

with engine.connect() as connection:
    with open('books.csv') as file:
        reader = csv.reader(file)
        next(reader)
        data = []
        for isbn, name, author, year in reader:
            data.append({"isbn": isbn, "name": name, "author": author, "year": year})
        statement = text("INSERT INTO books (isbn, name, author, year) VALUES (:isbn, :name, :author, :year)")
        for line in data:
            connection.execute(statement, **line)

Понравилась статья? Поделить с друзьями:
  • Pstocapt3 write error
  • Pst corrupt как исправить
  • Psram id read error
  • Psqlexception error duplicate key value violates unique constraint
  • Psqlexception error deadlock detected