Changeset 876


Ignore:
Timestamp:
Jul 14, 2016, 8:21:19 AM (3 years ago)
Author:
cito
Message:

Fixed issues when remote server version < 9.0

Though this is not officially supported and tested,
sometimes you just have to access those legacy databases.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/pg.py

    r872 r876  
    904904    def __missing__(self, typ):
    905905        """Create a cast function if it is not cached.
    906        
     906
    907907        Note that this class never raises a KeyError,
    908908        but returns None when no special cast function exists.
     
    10501050        simple: the simple PyGreSQL type name
    10511051        typtype: b = base type, c = composite type etc.
    1052         category: A = Array, b =Boolean, C = Composite etc.
     1052        category: A = Array, b = Boolean, C = Composite etc.
    10531053        delim: delimiter for array types
    10541054        relid: corresponding table for composite types
     
    10831083        self.query = db.query
    10841084        self.escape_string = db.escape_string
     1085        if db.server_version < 80400:
     1086            # older remote databases (not officially supported)
     1087            self._query_pg_type = (
     1088                "SELECT oid, typname, typname::text::regtype,"
     1089                " typtype, null as typcategory, typdelim, typrelid"
     1090                " FROM pg_type WHERE oid=%s::regtype")
     1091        else:
     1092            self._query_pg_type = (
     1093                "SELECT oid, typname, typname::regtype,"
     1094                " typtype, typcategory, typdelim, typrelid"
     1095                " FROM pg_type WHERE oid=%s::regtype")
    10851096
    10861097    def add(self, oid, pgtype, regtype,
     
    11051116        """Get the type info from the database if it is not cached."""
    11061117        try:
    1107             res = self.query("SELECT oid, typname, typname::regtype,"
    1108                 " typtype, typcategory, typdelim, typrelid"
    1109                 " FROM pg_type WHERE oid=%s::regtype" %
    1110                 (_quote_if_unqualified('$1', key),), (key,)).getresult()
     1118            q = self._query_pg_type % (_quote_if_unqualified('$1', key),)
     1119            res = self.query(q, (key,)).getresult()
    11111120        except ProgrammingError:
    11121121            res = None
     
    13801389        self.adapter = Adapter(self)
    13811390        self.dbtypes = DbTypes(self)
     1391        if db.server_version < 80400:
     1392            # support older remote data bases
     1393            self._query_attnames = (
     1394                "SELECT a.attname, t.oid, t.typname, t.typname::text::regtype,"
     1395                " t.typtype, null as typcategory, t.typdelim, t.typrelid"
     1396                " FROM pg_attribute a"
     1397                " JOIN pg_type t ON t.oid = a.atttypid"
     1398                " WHERE a.attrelid = %s::regclass AND %s"
     1399                " AND NOT a.attisdropped ORDER BY a.attnum")
     1400        else:
     1401            self._query_attnames = (
     1402                "SELECT a.attname, t.oid, t.typname, t.typname::regtype,"
     1403                " t.typtype, t.typcategory, t.typdelim, t.typrelid"
     1404                " FROM pg_attribute a"
     1405                " JOIN pg_type t ON t.oid = a.atttypid"
     1406                " WHERE a.attrelid = %s::regclass AND %s"
     1407                " AND NOT a.attisdropped ORDER BY a.attnum")
    13821408        db.set_cast_hook(self.dbtypes.typecast)
    13831409        self.debug = None  # For debugging scripts, this can be set
     
    18061832            if with_oid:
    18071833                q = "(%s OR a.attname = 'oid')" % q
    1808             q = ("SELECT a.attname, t.oid, t.typname, t.typname::regtype,"
    1809                 " t.typtype, t.typcategory, t.typdelim, t.typrelid"
    1810                 " FROM pg_attribute a"
    1811                 " JOIN pg_type t ON t.oid = a.atttypid"
    1812                 " WHERE a.attrelid = %s::regclass AND %s"
    1813                 " AND NOT a.attisdropped ORDER BY a.attnum") % (
    1814                     _quote_if_unqualified('$1', table), q)
     1834            q = self._query_attnames % (_quote_if_unqualified('$1', table), q)
    18151835            names = self.db.query(q, (table,)).getresult()
    18161836            types = self.dbtypes
  • trunk/pgdb.py

    r875 r876  
    632632        self._typecasts.get_fields = self.get_fields
    633633        self._typecasts.connection = cnx
     634        if cnx.server_version < 80400:
     635            # older remote databases (not officially supported)
     636            self._query_pg_type = ("SELECT oid, typname,"
     637                " typlen, typtype, null as typcategory, typdelim, typrelid"
     638                " FROM pg_type WHERE oid=%s")
     639        else:
     640            self._query_pg_type = ("SELECT oid, typname,"
     641                " typlen, typtype, typcategory, typdelim, typrelid"
     642                " FROM pg_type WHERE oid=%s")
    634643
    635644    def __missing__(self, key):
     
    639648        else:
    640649            if '.' not in key and '"' not in key:
    641                 key = '"%s"' % key
    642             oid = "'%s'::regtype" % self._escape_string(key)
     650                key = '"%s"' % (key,)
     651            oid = "'%s'::regtype" % (self._escape_string(key),)
    643652        try:
    644             self._src.execute("SELECT oid, typname,"
    645                  " typlen, typtype, typcategory, typdelim, typrelid"
    646                 " FROM pg_type WHERE oid=%s" % oid)
     653            self._src.execute(self._query_pg_type % (oid,))
    647654        except ProgrammingError:
    648655            res = None
     
    650657            res = self._src.fetch(1)
    651658        if not res:
    652             raise KeyError('Type %s could not be found' % key)
     659            raise KeyError('Type %s could not be found' % (key,))
    653660        res = res[0]
    654661        type_code = TypeCode.create(int(res[0]), res[1],
     
    674681        self._src.execute("SELECT attname, atttypid"
    675682            " FROM pg_attribute WHERE attrelid=%s AND attnum>0"
    676             " AND NOT attisdropped ORDER BY attnum" % typ.relid)
     683            " AND NOT attisdropped ORDER BY attnum" % (typ.relid,))
    677684        return [FieldInfo(name, self.get(int(oid)))
    678685            for name, oid in self._src.fetch(-1)]
     
    773780            else:
    774781                value = self._cnx.escape_string(value)
    775             return "'%s'" % value
     782            return "'%s'" % (value,)
    776783        if isinstance(value, float):
    777784            if isinf(value):
     
    784791        if isinstance(value, datetime):
    785792            if value.tzinfo:
    786                 return "'%s'::timestamptz" % value
    787             return "'%s'::timestamp" % value
     793                return "'%s'::timestamptz" % (value,)
     794            return "'%s'::timestamp" % (value,)
    788795        if isinstance(value, date):
    789             return "'%s'::date" % value
     796            return "'%s'::date" % (value,)
    790797        if isinstance(value, time):
    791798            if value.tzinfo:
    792                 return "'%s'::timetz" % value
     799                return "'%s'::timetz" % (value,)
    793800            return "'%s'::time" % value
    794801        if isinstance(value, timedelta):
    795             return "'%s'::interval" % value
     802            return "'%s'::interval" % (value,)
    796803        if isinstance(value, Uuid):
    797             return "'%s'::uuid" % value
     804            return "'%s'::uuid" % (value,)
    798805        if isinstance(value, list):
    799806            # Quote value as an ARRAY constructor. This is better than using
     
    806813            q = self._quote
    807814            try:
    808                 return 'ARRAY[%s]' % ','.join(str(q(v)) for v in value)
     815                return 'ARRAY[%s]' % (','.join(str(q(v)) for v in value),)
    809816            except UnicodeEncodeError:  # Python 2 with non-ascii values
    810                 return u'ARRAY[%s]' % ','.join(unicode(q(v)) for v in value)
     817                return u'ARRAY[%s]' % (','.join(unicode(q(v)) for v in value),)
    811818        if isinstance(value, tuple):
    812819            # Quote as a ROW constructor.  This is better than using a record
     
    817824            q = self._quote
    818825            try:
    819                 return '(%s)' % ','.join(str(q(v)) for v in value)
     826                return '(%s)' % (','.join(str(q(v)) for v in value),)
    820827            except UnicodeEncodeError:  # Python 2 with non-ascii values
    821                 return u'(%s)' % ','.join(unicode(q(v)) for v in value)
     828                return u'(%s)' % (','.join(unicode(q(v)) for v in value),)
    822829        try:
    823830            value = value.__pg_repr__()
    824831        except AttributeError:
    825832            raise InterfaceError(
    826                 'Do not know how to adapt type %s' % type(value))
     833                'Do not know how to adapt type %s' % (type(value),))
    827834        if isinstance(value, (tuple, list)):
    828835            value = self._quote(value)
     
    10371044            if isinstance(stream, basestring):
    10381045                if not isinstance(stream, input_type):
    1039                     raise ValueError("The input must be %s" % type_name)
     1046                    raise ValueError("The input must be %s" % (type_name,))
    10401047                if not binary_format:
    10411048                    if isinstance(stream, str):
     
    10551062                        if not isinstance(chunk, input_type):
    10561063                            raise ValueError(
    1057                                 "Input stream must consist of %s" % type_name)
     1064                                "Input stream must consist of %s"
     1065                                % (type_name,))
    10581066                        if isinstance(chunk, str):
    10591067                            if not chunk.endswith('\n'):
     
    11221130        operation.append("from stdin")
    11231131        if options:
    1124             operation.append('(%s)' % ','.join(options))
     1132            operation.append('(%s)' % (','.join(options),))
    11251133        operation = ' '.join(operation)
    11261134
     
    12171225        operation.append("to stdout")
    12181226        if options:
    1219             operation.append('(%s)' % ','.join(options))
     1227            operation.append('(%s)' % (','.join(options),))
    12201228        operation = ' '.join(operation)
    12211229
     
    13051313                    return namedtuple('Row', colnames, rename=True)._make
    13061314                except TypeError:  # Python 2.6 and 3.0 do not support rename
    1307                     colnames = [v if v.isalnum() else 'column_%d' % n
     1315                    colnames = [v if v.isalnum() else 'column_%d' % (n,)
    13081316                             for n, v in enumerate(colnames)]
    13091317                    return namedtuple('Row', colnames)._make
    13101318            except ValueError:  # there is still a problem with the field names
    1311                 colnames = ['column_%d' % n for n in range(len(colnames))]
     1319                colnames = ['column_%d' % (n,) for n in range(len(colnames))]
    13121320                return namedtuple('Row', colnames)._make
    13131321
     
    14941502            value = str(value)
    14951503            if not value or ' ' in value:
    1496                 value = "'%s'" % value.replace(
    1497                     "'", "\\'").replace('\\', '\\\\')
     1504                value = "'%s'" % (value.replace(
     1505                    "'", "\\'").replace('\\', '\\\\'),)
    14981506            dbname.append('%s=%s' % (kw, value))
    14991507        dbname = ' '.join(dbname)
     
    16701678        s = cls._re_escape.sub(r'\\\1', s)
    16711679        if quote:
    1672             s = '"%s"' % s
     1680            s = '"%s"' % (s,)
    16731681        return s
    16741682
  • trunk/tests/test_classic.py

    r823 r876  
    3636    db.query("SET TIME ZONE 'EST5EDT'")
    3737    db.query("SET DEFAULT_WITH_OIDS=FALSE")
     38    db.query("SET CLIENT_MIN_MESSAGES=WARNING")
    3839    db.query("SET STANDARD_CONFORMING_STRINGS=FALSE")
    39     db.query("SET CLIENT_MIN_MESSAGES=WARNING")
    4040    return db
    4141
  • trunk/tests/test_classic_connection.py

    r871 r876  
    18191819    @classmethod
    18201820    def setUpClass(cls):
    1821         query = connect().query
     1821        db = connect()
     1822        query = db.query
    18221823        query('set client_encoding=sql_ascii')
    18231824        query('set standard_conforming_strings=off')
    1824         query('set bytea_output=escape')
     1825        try:
     1826            query('set bytea_output=escape')
     1827        except pg.ProgrammingError:
     1828            if db.server_version >= 90000:
     1829                raise  # ignore for older server versions
     1830        db.close()
    18251831        cls.cls_set_up = True
    18261832
  • trunk/tests/test_classic_dbwrapper.py

    r872 r876  
    418418        query = self.db.query
    419419        query('set client_encoding=utf8')
    420         query('set standard_conforming_strings=on')
    421420        query("set lc_monetary='C'")
    422421        query("set datestyle='ISO,YMD'")
    423         query('set bytea_output=hex')
     422        query('set standard_conforming_strings=on')
     423        try:
     424            query('set bytea_output=hex')
     425        except pg.ProgrammingError:
     426            if self.db.server_version >= 90000:
     427                raise  # ignore for older server versions
    424428
    425429    def tearDown(self):
     
    722726        self.assertEqual(g('default_with_oids'), dwi)
    723727        self.assertEqual(g('standard_conforming_strings'), scs)
     728        db.close()
    724729
    725730    def testResetParameterAll(self):
     
    742747        self.assertEqual(g('default_with_oids'), dwi)
    743748        self.assertEqual(g('standard_conforming_strings'), scs)
     749        db.close()
    744750
    745751    def testSetParameterLocal(self):
     
    782788        r = self.db.get_parameter('datestyle')
    783789        self.assertEqual(r, default_datestyle)
     790        db.close()
    784791
    785792    def testReopen(self):
     
    800807        r = self.db.get_parameter('datestyle')
    801808        self.assertEqual(r, default_datestyle)
     809        db.close()
    802810
    803811    def testCreateTable(self):
     
    39553963        cls.set_option('namedresult', None)
    39563964        cls.set_option('jsondecode', None)
    3957         cls.regtypes = not DB().use_regtypes()
     3965        db = DB()
     3966        cls.regtypes = not db.use_regtypes()
     3967        db.close()
    39583968        super(TestDBClassNonStdOpts, cls).setUpClass()
    39593969
Note: See TracChangeset for help on using the changeset viewer.