Example #1
0
    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
Example #2
0
    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
Example #3
0
    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
Example #4
0
    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)
Example #5
0
    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)
Example #6
0
 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
Example #7
0
 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
Example #8
0
    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
Example #9
0
    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
Example #10
0
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))
Example #11
0
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))
Example #12
0
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))
Example #13
0
 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)
Example #14
0
 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
Example #15
0
 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
Example #16
0
        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,
Example #17
0
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
Example #18
0
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
Example #19
0
 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)
Example #20
0
    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
Example #21
0
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)