def _create_exception(self, pgres=None, msg=None, cursor=None): """Return the appropriate exception instance for the current status. IMPORTANT: the new exception takes ownership of pgres: if pgres is passed as parameter, the callee must delete its pointer (e.g. it may be set to null). If there is a pgres in the cursor it is "stolen": the cursor will have it set to Null. """ assert pgres is None or cursor is None, \ "cannot specify pgres and cursor together" if cursor and cursor._pgres: pgres, cursor._pgres = cursor._pgres, ffi.NULL exc_type = exceptions.OperationalError code = pgmsg = None # If no custom message is passed then get the message from postgres. # If pgres is available then we first try to get the message for the # last command, and then the error message for the connection if pgres: pgmsg = libpq.PQresultErrorMessage(pgres) pgmsg = bytes_to_ascii(ffi.string(pgmsg)) if pgmsg else None # Get the correct exception class based on the error code code = libpq.PQresultErrorField(pgres, libpq.PG_DIAG_SQLSTATE) if code != ffi.NULL: code = bytes_to_ascii(ffi.string(code)) exc_type = util.get_exception_for_sqlstate(code) else: code = None exc_type = exceptions.DatabaseError if not pgmsg: pgmsg = libpq.PQerrorMessage(self._pgconn) pgmsg = bytes_to_ascii(ffi.string(pgmsg)) if pgmsg else None if msg is None and pgmsg: msg = pgmsg for prefix in ("ERROR: ", "FATAL: ", "PANIC: "): if msg.startswith(prefix): msg = msg[len(prefix):] break # Clear the connection if the status is CONNECTION_BAD (fatal error) if self._pgconn and libpq.PQstatus( self._pgconn) == libpq.CONNECTION_BAD: self._closed = 2 exc = exc_type(msg) exc.pgcode = code exc.pgerror = pgmsg exc.cursor = cursor exc._pgres = pgres return exc
def parse(self, s, cur, _bsdec=_re.compile(r"\\(.)", _re.UNICODE)): """Parse an hstore representation in a Python string. The hstore is represented as something like:: "a"=>"1", "b"=>"2" with backslash-escaped strings. """ if s is None: return None rv = {} start = 0 if six.PY3 and isinstance(s, six.binary_type): s = s.decode(_ext.encodings[cur.connection.encoding]) \ if cur else bytes_to_ascii(s) for m in self._re_hstore.finditer(s): if m is None or m.start() != start: raise psycopg2.InterfaceError( "error parsing hstore pair at char %d" % start) k = _bsdec.sub(r'\1', m.group(1), _re.UNICODE) v = m.group(2) if v is not None: v = _bsdec.sub(r'\1', v, _re.UNICODE) rv[k] = v start = m.end() if start < len(s): raise psycopg2.InterfaceError( "error parsing hstore: unparsed data after char %d" % start) return rv
def set_session(self, isolation_level=None, readonly=None, deferrable=None, autocommit=None): if isolation_level is not None: if isinstance(isolation_level, int): if isolation_level < 1 or isolation_level > 4: raise ValueError('isolation level must be between 1 and 4') isolation_level = _isolevels[isolation_level] elif isinstance(isolation_level, six.string_types): if isinstance(isolation_level, six.binary_type): isolation_level = bytes_to_ascii(isolation_level) isolation_level = isolation_level.lower() if not isolation_level or isolation_level not in _isolevels: raise ValueError("bad value for isolation level: '%s'" % isolation_level) else: raise TypeError("bad isolation level: '%r'" % isolation_level) if self.server_version < 80000: if isolation_level == 'read uncommitted': isolation_level = 'read committed' elif isolation_level == 'repeatable read': isolation_level = 'serializable' self._set_guc("default_transaction_isolation", isolation_level) if readonly is not None: self._set_guc_onoff('default_transaction_read_only', readonly) if deferrable is not None: self._set_guc_onoff('default_transaction_deferrable', deferrable) if autocommit is not None: self._autocommit = bool(autocommit)
def _get_field(self, field): from psycopg2cffi._impl.adapters import bytes_to_ascii if self._exc and self._exc._pgres: b = libpq.PQresultErrorField(self._exc._pgres, field) if b: b = ffi.string(b) if six.PY3: # py2 tests insist on str here b = bytes_to_ascii(b) return b
def _get_guc(self, name): """Return the value of a configuration parameter.""" with self._lock: query = 'SHOW %s' % name if _green_callback: pgres = self._execute_green(query) else: pgres = libpq.PQexec(self._pgconn, ascii_to_bytes(query)) if not pgres or libpq.PQresultStatus(pgres) != libpq.PGRES_TUPLES_OK: raise exceptions.OperationalError("can't fetch %s" % name) rv = bytes_to_ascii(ffi.string(libpq.PQgetvalue(pgres, 0, 0))) libpq.PQclear(pgres) return rv
def parse_date(value, length, cursor): if value is None: return None if isinstance(value, six.text_type): value = ascii_to_bytes(value) if value == b'infinity': return datetime.date.max elif value == b'-infinity': return datetime.date.min try: return datetime.date(*[int(x) for x in value.split(b'-')]) except (TypeError, ValueError): if value.endswith(b'BC'): raise ValueError('BC dates not supported') raise DataError("bad datetime: '%s'" % bytes_to_ascii(value))
def parse_datetime(value, length, cursor): if value is None: return None if isinstance(value, six.text_type): value = ascii_to_bytes(value) if value == b'infinity': return datetime.datetime.max elif value == b'-infinity': return datetime.datetime.min try: date, time = value.split(b' ') date_args = date.split(b'-') return datetime.datetime(int(date_args[0]), int(date_args[1]), int(date_args[2]), *_parse_time_to_args(time, cursor)) except (TypeError, ValueError): if value.endswith(b'BC'): raise ValueError('BC dates not supported') raise DataError("bad datetime: '%s'" % bytes_to_ascii(value))
def parse_datetime(value, length, cursor): if value is None: return None if isinstance(value, six.text_type): value = ascii_to_bytes(value) if value == b'infinity': return datetime.datetime.max elif value == b'-infinity': return datetime.datetime.min try: date, time = value.split(b' ') date_args = date.split(b'-') return datetime.datetime( int(date_args[0]), int(date_args[1]), int(date_args[2]), *_parse_time_to_args(time, cursor)) except (TypeError, ValueError): if value.endswith(b'BC'): raise ValueError('BC dates not supported') raise DataError("bad datetime: '%s'" % bytes_to_ascii(value))
def _to_unicode(self, s, cur): if s is None: return None else: return s.decode(_ext.encodings[cur.connection.encoding]) \ if cur else bytes_to_ascii(s)
def get_parameter_status(self, parameter): p = libpq.PQparameterStatus(self._pgconn, ascii_to_bytes(parameter)) return bytes_to_ascii(ffi.string(p)) if p != ffi.NULL else None
self._lock = threading.RLock() self.notices = [] self.cursor_factory = None # The number of commits/rollbacks done so far self._mark = 0 self._async = async self._async_status = consts.ASYNC_DONE self._async_cursor = None self_ref = weakref.ref(self) self._notice_callback = ffi.callback( 'void(void *, const char *)', lambda arg, message: self_ref()._process_notice( arg, bytes_to_ascii(ffi.string(message)))) if not self._async: self._connect_sync() else: self._connect_async() def _connect_sync(self): self._pgconn = libpq.PQconnectdb(self.dsn.encode('utf-8')) if not self._pgconn: raise exceptions.OperationalError('PQconnectdb() failed') elif libpq.PQstatus(self._pgconn) == libpq.CONNECTION_BAD: raise self._create_exception() # Register notice processor libpq.PQsetNoticeProcessor(self._pgconn, self._notice_callback,
def get_exception_for_sqlstate(code): """Translate the sqlstate to a relevant exception. See for a list of possible errors: http://www.postgresql.org/docs/current/static/errcodes-appendix.html """ if isinstance(code, six.binary_type): code = bytes_to_ascii(code) if code[0] == '0': # Class 0A - Feature Not Supported if code[1] == 'A': return exceptions.NotSupportedError elif code[0] == '2': # Class 20 - Case Not Found # Class 21 - Cardinality Violation if code[1] in '01': return exceptions.ProgrammingError # Class 22 - Data Exception if code[1] == '2': return exceptions.DataError # Class 23 - Integrity Constraint Violation if code[1] == '3': return exceptions.IntegrityError # Class 24 - Invalid Cursor State # Class 25 - Invalid Transaction State if code[1] in '45': return exceptions.InternalError # Class 26 - Invalid SQL Statement Name # Class 27 - Triggered Data Change Violation # Class 28 - Invalid Authorization Specification if code[1] in '678': return exceptions.OperationalError # Class 2B - Dependent Privilege Descriptors Still Exist # Class 2D - Invalid Transaction Termination # Class 2F - SQL Routine Exception if code[1] in 'BDF': return exceptions.InternalError elif code[0] == '3': # Class 34 - Invalid Cursor Name if code[1] == '4': return exceptions.OperationalError # Class 38 - External Routine Exception # Class 39 - External Routine Invocation Exception # Class 3B - Savepoint Exception if code[1] in '89B': return exceptions.InternalError # Class 3D - Invalid Catalog Name # Class 3F - Invalid Schema Name if code[1] in 'DF': return exceptions.ProgrammingError elif code[0] == '4': # Class 40 - Transaction Rollback if code[1] == '0': return exceptions.TransactionRollbackError # Class 42 - Syntax Error or Access Rule Violation # Class 44 - WITH CHECK OPTION Violation if code[1] in '24': return exceptions.ProgrammingError elif code[0] == '5': if code == '57014': return exceptions.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) return exceptions.OperationalError elif code[0] == 'F': # Class F0 - Configuration File Error return exceptions.InternalError elif code[0] == 'H': # Class HV - Foreign Data Wrapper Error (SQL/MED) return exceptions.OperationalError elif code[0] == 'P': # Class P0 - PL/pgSQL Error return exceptions.InternalError elif code[0] == 'X': # Class XX - Internal Error return exceptions.InternalError # Fallback exception return exceptions.DatabaseError
def get_exception_for_sqlstate(code): """Translate the sqlstate to a relevant exception. See for a list of possible errors: http://www.postgresql.org/docs/current/static/errcodes-appendix.html """ if isinstance(code, six.binary_type): code = bytes_to_ascii(code) if code[0] == "0": # Class 0A - Feature Not Supported if code[1] == "A": return exceptions.NotSupportedError elif code[0] == "2": # Class 20 - Case Not Found # Class 21 - Cardinality Violation if code[1] in "01": return exceptions.ProgrammingError # Class 22 - Data Exception if code[1] == "2": return exceptions.DataError # Class 23 - Integrity Constraint Violation if code[1] == "3": return exceptions.IntegrityError # Class 24 - Invalid Cursor State # Class 25 - Invalid Transaction State if code[1] in "45": return exceptions.InternalError # Class 26 - Invalid SQL Statement Name # Class 27 - Triggered Data Change Violation # Class 28 - Invalid Authorization Specification if code[1] in "678": return exceptions.OperationalError # Class 2B - Dependent Privilege Descriptors Still Exist # Class 2D - Invalid Transaction Termination # Class 2F - SQL Routine Exception if code[1] in "BDF": return exceptions.InternalError elif code[0] == "3": # Class 34 - Invalid Cursor Name if code[1] == "4": return exceptions.OperationalError # Class 38 - External Routine Exception # Class 39 - External Routine Invocation Exception # Class 3B - Savepoint Exception if code[1] in "89B": return exceptions.InternalError # Class 3D - Invalid Catalog Name # Class 3F - Invalid Schema Name if code[1] in "DF": return exceptions.ProgrammingError elif code[0] == "4": # Class 40 - Transaction Rollback if code[1] == "0": return exceptions.TransactionRollbackError # Class 42 - Syntax Error or Access Rule Violation # Class 44 - WITH CHECK OPTION Violation if code[1] in "24": return exceptions.ProgrammingError elif code[0] == "5": if code == "57014": return exceptions.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) return exceptions.OperationalError elif code[0] == "F": # Class F0 - Configuration File Error return exceptions.InternalError elif code[0] == "H": # Class HV - Foreign Data Wrapper Error (SQL/MED) return exceptions.OperationalError elif code[0] == "P": # Class P0 - PL/pgSQL Error return exceptions.InternalError elif code[0] == "X": # Class XX - Internal Error return exceptions.InternalError # Fallback exception return exceptions.DatabaseError
def _create_exception(self, pgres=None, msg=None, cursor=None): """Return the appropriate exception instance for the current status. IMPORTANT: the new exception takes ownership of pgres: if pgres is passed as parameter, the callee must delete its pointer (e.g. it may be set to null). If there is a pgres in the cursor it is "stolen": the cursor will have it set to Null. """ assert pgres is None or cursor is None, \ "cannot specify pgres and cursor together" if cursor and cursor._pgres: pgres, cursor._pgres = cursor._pgres, ffi.NULL exc_type = exceptions.OperationalError code = pgmsg = None # _py_enc can be not initialized yet in case of errors when # establishing the connection err_enc = self._py_enc or 'utf-8' # If no custom message is passed then get the message from postgres. # If pgres is available then we first try to get the message for the # last command, and then the error message for the connection if pgres: pgmsg = libpq.PQresultErrorMessage(pgres) pgmsg = ffi.string(pgmsg).decode(err_enc, 'replace') \ if pgmsg else None # Get the correct exception class based on the error code code = libpq.PQresultErrorField(pgres, libpq.LIBPQ_DIAG_SQLSTATE) if code != ffi.NULL: code = bytes_to_ascii(ffi.string(code)) exc_type = util.get_exception_for_sqlstate(code) else: code = None exc_type = exceptions.DatabaseError if not pgmsg: pgmsg = libpq.PQerrorMessage(self._pgconn) pgmsg = ffi.string(pgmsg).decode(err_enc, 'replace') \ if pgmsg else None if msg is None and pgmsg: msg = pgmsg for prefix in ("ERROR: ", "FATAL: ", "PANIC: "): if msg.startswith(prefix): msg = msg[len(prefix):] break # Clear the connection if the status is CONNECTION_BAD (fatal error) if self._pgconn and libpq.PQstatus(self._pgconn) == libpq.CONNECTION_BAD: self._closed = 2 exc = exc_type(msg) exc.pgcode = code exc.pgerror = pgmsg exc.cursor = cursor exc._pgres = pgres return exc
def parse_decimal(value, length, cursor): if value is None: return None if isinstance(value, six.binary_type): value = bytes_to_ascii(value) return decimal.Decimal(value)