def getquoted(self): obj = self._wrapped if isinstance(obj, six.text_type): obj = obj.encode(self.encoding) else: assert isinstance(obj, six.binary_type) string = obj length = len(string) to_length = (length * 2) + 1 to = ffi.new('char []', to_length) if not self._conn: libpq.PQescapeString(to, string, length) return b''.join([b"'", ffi.string(to), b"'"]) if PG_VERSION < 0x090000: err = ffi.new('int *') libpq.PQescapeStringConn( self._conn._pgconn, to, string, length, err) if self._conn and self._conn._equote: return b''.join([b"E'", ffi.string(to), b"'"]) return b''.join([b"'", ffi.string(to), b"'"]) data_pointer = libpq.PQescapeLiteral( self._conn._pgconn, string, length) data = ffi.string(data_pointer) libpq.PQfreemem(data_pointer) return data
def _pq_fetch(self): pgstatus = libpq.PQresultStatus(self._pgres) if pgstatus != libpq.PGRES_FATAL_ERROR: self._statusmessage = ffi.string(libpq.PQcmdStatus(self._pgres)) else: self._statusmessage = None self._no_tuples = True self._rownumber = 0 if pgstatus == libpq.PGRES_COMMAND_OK: rowcount = ffi.string(libpq.PQcmdTuples(self._pgres)) if not rowcount or not rowcount[0]: self._rowcount = -1 else: self._rowcount = int(rowcount) self._lastrowid = libpq.PQoidValue(self._pgres) self._clear_pgres() elif pgstatus == libpq.PGRES_TUPLES_OK: self._rowcount = libpq.PQntuples(self._pgres) return self._pq_fetch_tuples() elif pgstatus == libpq.PGRES_COPY_IN: return self._pq_fetch_copy_in() elif pgstatus == libpq.PGRES_COPY_OUT: return self._pq_fetch_copy_out() elif pgstatus == libpq.PGRES_EMPTY_QUERY: self._clear_pgres() raise ProgrammingError("can't execute an empty query") else: raise self._conn._create_exception(cursor=self)
def getquoted(self): obj = self._wrapped if isinstance(self._wrapped, unicode): obj = obj.encode(self.encoding) string = str(obj) length = len(string) if not self._conn: to = ffi.new('char []', ((length * 2) + 1)) libpq.PQescapeString(to, string, length) return "'%s'" % ffi.string(to) if PG_VERSION < 0x090000: to = ffi.new('char []', ((length * 2) + 1)) err = ffi.new('int *') libpq.PQescapeStringConn(self._conn._pgconn, to, string, length, err) if self._conn and self._conn._equote: return "E'%s'" % ffi.string(to) return "'%s'" % ffi.string(to) data_pointer = libpq.PQescapeLiteral(self._conn._pgconn, string, length) data = ffi.string(data_pointer) libpq.PQfreemem(data_pointer) return data
def getquoted(self): obj = self._wrapped if isinstance(self._wrapped, unicode): obj = obj.encode(self.encoding) string = str(obj) length = len(string) if not self._conn: to = ffi.new('char []', ((length * 2) + 1)) libpq.PQescapeString(to, string, length) return "'%s'" % ffi.string(to) if PG_VERSION < 0x090000: to = ffi.new('char []', ((length * 2) + 1)) err = ffi.new('int *') libpq.PQescapeStringConn( self._conn._pgconn, to, string, length, err) if self._conn and self._conn._equote: return "E'%s'" % ffi.string(to) return "'%s'" % ffi.string(to) data_pointer = libpq.PQescapeLiteral( self._conn._pgconn, string, length) data = ffi.string(data_pointer) libpq.PQfreemem(data_pointer) return data
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 _process_notifies(self): while True: pg_notify = libpq.PQnotifies(self._pgconn) if not pg_notify: break notify = Notify(pg_notify.be_pid, ffi.string(pg_notify.relname).decode(self._py_enc), ffi.string(pg_notify.extra).decode(self._py_enc)) self._notifies.append(notify) libpq.PQfreemem(pg_notify)
def _process_notifies(self): while True: pg_notify = libpq.PQnotifies(self._pgconn) if not pg_notify: break notify = Notify( pg_notify.be_pid, ffi.string(pg_notify.relname).decode(self._py_enc), ffi.string(pg_notify.extra).decode(self._py_enc)) self._notifies.append(notify) libpq.PQfreemem(pg_notify)
def getquoted(self): if self._wrapped is None: return b'NULL' to_length = ffi.new('size_t *') _wrapped = self._wrapped if isinstance(_wrapped, six.text_type): _wrapped = ascii_to_bytes(_wrapped) elif isinstance(_wrapped, _bytearray_types): _wrapped = six.binary_type(_wrapped) elif not six.PY3 and isinstance(_wrapped, buffer): _wrapped = bytes(_wrapped) _wrapped = ffi.new('unsigned char[]', _wrapped) if self._conn: data_pointer = libpq.PQescapeByteaConn( self._conn._pgconn, _wrapped, len(self._wrapped), to_length) else: data_pointer = libpq.PQescapeBytea( _wrapped, len(self._wrapped), to_length) data = ffi.string(data_pointer)[:to_length[0] - 1] libpq.PQfreemem(data_pointer) if self._conn and self._conn._equote: return b''.join([b"E'", data, b"'::bytea"]) return b''.join([b"'", data, b"'::bytea"])
def getquoted(self): if self._wrapped is None: return b'NULL' to_length = ffi.new('size_t *') _wrapped = self._wrapped if isinstance(_wrapped, six.text_type): _wrapped = unicode_to_bytes(_wrapped) elif isinstance(_wrapped, _bytearray_types): _wrapped = six.binary_type(_wrapped) elif not six.PY3 and isinstance(_wrapped, buffer): _wrapped = bytes(_wrapped) _wrapped = ffi.new('unsigned char[]', _wrapped) if self._conn: data_pointer = libpq.PQescapeByteaConn( self._conn._pgconn, _wrapped, len(self._wrapped), to_length) else: data_pointer = libpq.PQescapeBytea( _wrapped, len(self._wrapped), to_length) data = ffi.string(data_pointer)[:to_length[0] - 1] libpq.PQfreemem(data_pointer) if self._conn and self._conn._equote: return b''.join([b"E'", data, b"'::bytea"]) return b''.join([b"'", data, b"'::bytea"])
def _is_busy(self): with self._lock: if libpq.PQconsumeInput(self._pgconn) == 0: raise exceptions.OperationalError( ffi.string(libpq.PQerrorMessage(self._pgconn))) res = libpq.PQisBusy(self._pgconn) self._process_notifies() return res
def _pq_fetch_tuples(self): with self._conn._lock: self._nfields = libpq.PQnfields(self._pgres) self._no_tuples = False description = [] casts = [] fast_parsers = [] for i in xrange(self._nfields): ftype = libpq.PQftype(self._pgres, i) fsize = libpq.PQfsize(self._pgres, i) fmod = libpq.PQfmod(self._pgres, i) if fmod > 0: fmod -= 4 # TODO: sizeof(int) if fsize == -1: if ftype == 1700: # NUMERIC isize = fmod >> 16 else: isize = fmod else: isize = fsize if ftype == 1700: prec = (fmod >> 16) & 0xFFFF scale = fmod & 0xFFFF else: prec = scale = None casts.append(self._get_cast(ftype)) description.append(Column( name=ffi.string(libpq.PQfname(self._pgres, i))\ .decode(self._conn._py_enc), type_code=ftype, display_size=None, internal_size=isize, precision=prec, scale=scale, null_ok=None, )) fast_parser = None if is_32bits: # disable all fast parsers to avoid portability problems pass elif ftype == 21 or ftype == 23: fast_parser = libpq.PQEgetint elif ftype == 20: fast_parser = libpq.PQEgetlong elif ftype == 700: fast_parser = libpq.PQEgetfloat elif ftype == 701: fast_parser = libpq.PQEgetdouble fast_parsers.append(fast_parser) self._description = tuple(description) self._casts = casts self._fast_parsers = fast_parsers
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 __init__(self, dsn, **kwargs): self.dsn = dsn self.status = consts.STATUS_SETUP self._encoding = None self._py_enc = None self._closed = 0 self._cancel = ffi.NULL self._typecasts = {} self._tpc_xid = None self._notifies = [] self._autocommit = False self._pgconn = None self._equote = False self._lock = threading.RLock() self.notices = [] self.cursor_factory = None # The number of commits/rollbacks done so far self._mark = 0 if 'async' in kwargs: self._async = kwargs.pop('async') elif 'async_' in kwargs: self._async = kwargs.pop('async_') else: self._async = False items = [] items.extend([(k, v) for (k, v) in kwargs.items() if v is not None]) if items: raise TypeError("'%s' is an invalid keyword argument" % items[0][0]) 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, ffi.string(message).decode(self_ref()._py_enc or 'utf-8', 'replace'))) if not self._async: self._connect_sync() else: self._connect_async()
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, query) if not pgres or libpq.PQresultStatus(pgres) != libpq.PGRES_TUPLES_OK: raise exceptions.OperationalError("can't fetch %s" % name) rv = ffi.string(libpq.PQgetvalue(pgres, 0, 0)) libpq.PQclear(pgres) return rv
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 read(self, size=-1): """Read at most size bytes or to the end of the large object.""" if size < 0: where = self.tell() end = self.seek(0, os.SEEK_END) self.seek(where, os.SEEK_SET) size = end - where binary_mode = self._mode & consts.LOBJECT_BINARY if size == 0: return b'' if binary_mode else '' buf = ffi.new('char []', size) length = libpq.lo_read(self._conn._pgconn, self._fd, buf, size) if length < 0: return return ffi.buffer(buf, length)[:] if binary_mode else \ ffi.string(buf).decode(self._conn._py_enc)
def getquoted(self): if self._wrapped is None: return 'NULL' to_length = ffi.new('size_t *') _wrapped = ffi.new('unsigned char[]', str(self._wrapped)) if self._conn: data_pointer = libpq.PQescapeByteaConn( self._conn._pgconn, _wrapped, len(self._wrapped), to_length) else: data_pointer = libpq.PQescapeBytea( _wrapped, len(self._wrapped), to_length) data = ffi.string(data_pointer)[:to_length[0] - 1] libpq.PQfreemem(data_pointer) if self._conn and self._conn._equote: return r"E'%s'::bytea" % data return r"'%s'::bytea" % data
def _pq_fetch_tuples(self): with self._conn._lock: self._nfields = libpq.PQnfields(self._pgres) self._no_tuples = False description = [] casts = [] for i in xrange(self._nfields): ftype = libpq.PQftype(self._pgres, i) fsize = libpq.PQfsize(self._pgres, i) fmod = libpq.PQfmod(self._pgres, i) if fmod > 0: fmod -= 4 # TODO: sizeof(int) if fsize == -1: if ftype == 1700: # NUMERIC isize = fmod >> 16 else: isize = fmod else: isize = fsize if ftype == 1700: prec = (fmod >> 16) & 0xFFFF scale = fmod & 0xFFFF else: prec = scale = None casts.append(self._get_cast(ftype)) description.append(Column( name=ffi.string(libpq.PQfname(self._pgres, i)), type_code=ftype, display_size=None, internal_size=isize, precision=prec, scale=scale, null_ok=None, )) self._description = tuple(description) self._casts = casts
def getquoted(self): if self._wrapped is None: return 'NULL' to_length = ffi.new('size_t *') _wrapped = ffi.new('unsigned char[]', str(self._wrapped)) if self._conn: data_pointer = libpq.PQescapeByteaConn(self._conn._pgconn, _wrapped, len(self._wrapped), to_length) else: data_pointer = libpq.PQescapeBytea(_wrapped, len(self._wrapped), to_length) data = ffi.string(data_pointer)[:to_length[0] - 1] libpq.PQfreemem(data_pointer) if self._conn and self._conn._equote: return r"E'%s'::bytea" % data return r"'%s'::bytea" % data
def _iso_compatible_datestyle(self): ''' Return whether connection DateStyle is ISO-compatible ''' datestyle = libpq.PQparameterStatus(self._pgconn, b'DateStyle') return datestyle != ffi.NULL and \ ffi.string(datestyle).startswith(b'ISO')
def _get_field(self, field): if self._exc and self._exc._pgres: b = libpq.PQresultErrorField(self._exc._pgres, field) if b: return ffi.string(b)
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, ffi.string(message))) if not self._async: self._connect_sync() else: self._connect_async() def _connect_sync(self): self._pgconn = libpq.PQconnectdb(self.dsn) 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(
def cancel(self): err_length = 256 errbuf = ffi.new('char[]', err_length) if libpq.PQcancel(self._cancel, errbuf, err_length) == 0: raise exceptions.OperationalError(ffi.string(errbuf))
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
def _get_equote(self): ret = libpq.PQparameterStatus( self._pgconn, b'standard_conforming_strings') return ret and ffi.string(ret) == b'off' or False
def get_parameter_status(self, parameter): p = libpq.PQparameterStatus(self._pgconn, parameter) return ffi.string(p) if p != ffi.NULL else None
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 _get_equote(self): ret = libpq.PQparameterStatus(self._pgconn, b'standard_conforming_strings') return ret and ffi.string(ret) == b'off' or False
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,
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, ffi.string(message).decode(self_ref()._py_enc or 'utf-8', 'replace'))) 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,