Записки программиста, обо всем и ни о чем. Но, наверное, больше профессионального.

2013-06-03

Psycopg2 cursor description

В Mapfeatureserver у меня есть код, который решает, что делать с текущей колонкой выборки (из БД), на основании типа данных в этой колонке. А работа с БД построена на использовании пакета Psycopg2.
Выглядит это примерно так:
    import psycopg2
    import psycopg2.extensions
    psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
    psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)

    conn = psycopg2.connect("host=vags101 port=5432 dbname=postgisdb user=mfs password=12345678 connect_timeout=10 client_encoding=utf8")
    conn.autocommit = True
    cur = conn.cursor()

    cur.execute("""
        select * from mfsdata.patching limit 1;
    """)
    for descr in cur.description:
        if descr.type_code in GEOMETRY_TYPES:
            print 'geometry data'

Это, конечно, очень удобно, когда выборка содержит не только кортежи с данными, но и метаданные. Всё, как в спецификации Python Database API Specification v2.0.
Но есть, как выяснилось, проблема. Фишка в том, что от системы к системе эти коды (cursor.description.type_code) могут меняться, поэтому полагаться на заранее составленный список кодов нельзя.

Документация на Psycopg2 говорит следующее:

type_code: the PostgreSQL OID of the column. You can use the pg_type system table to get more informations about the type. This is the value used by Psycopg to decide what Python type use to represent the value. See also Type casting of SQL types into Python objects.


То есть, код типа это, фактически, идентификатор записи в реестре pg_type, причем повторяемости этих идентификаторов для разных систем можно ожидать только для стандартных типов данных.

Небольшая демонстрация реального положения вещей для таблицы «mfsdata.patching»:
    import psycopg2
    import psycopg2.extensions
    psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
    psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)

    conn = psycopg2.connect("host=vags101 port=5432 dbname=postgisdb user=mfs password=12345678 connect_timeout=10 client_encoding=utf8")
    conn.autocommit = True
    cur = conn.cursor()

    cur.execute("""
        select * from mfsdata.patching limit 1;
    """)
    for rec in cur.description:
        print "Field name: '%s', field type_code: '%s'" % (rec.name, rec.type_code)

    cur.execute("""
        SELECT attname, atttypid FROM pg_attribute WHERE attrelid = 'mfsdata.patching'::regclass;
    """)
    for rec in cur:
        print "(Field name, field type_code): '%s'" % (rec,)

    cur.execute("""
        select pg_type.oid as type_code, pg_type.typname as type_name, pg_attribute.attname as field_name
            from pg_type, pg_attribute
            where pg_type.oid = pg_attribute.atttypid and pg_attribute.attrelid = 'mfsdata.patching'::regclass;
    """)
    for rec in cur:
        print "(type_code, type name, field name): '%s'" % (rec,)

В связи с ненадежностью решения на списках type_code возникает вопрос — как определять тип поля в выборке?

Одно из решений описано тут http://initd.org/psycopg/docs/advanced.html#type-casting-from-sql-to-python - при загрузке модуля зарегистрировать интересующие типы данных вручную.

Но в моем случае, проще будет воспользоваться заранее созданным файлом метаданных слоя. Там, по спецификации, есть описания полей с указанием их типов.

original post http://vasnake.blogspot.com/2013/06/psycopg2-cursor-description.html

Комментариев нет:

Отправить комментарий

Архив блога

Ярлыки

linux (241) python (191) citation (186) web-develop (170) gov.ru (159) video (124) бытовуха (115) sysadm (100) GIS (97) Zope(Plone) (88) бурчалки (84) Book (83) programming (82) грабли (77) Fun (76) development (73) windsurfing (72) Microsoft (64) hiload (62) internet provider (57) opensource (57) security (57) опыт (55) movie (52) Wisdom (51) ML (47) driving (45) hardware (45) language (45) money (42) JS (41) curse (40) bigdata (39) DBMS (38) ArcGIS (34) history (31) PDA (30) howto (30) holyday (29) Google (27) Oracle (27) tourism (27) virtbox (27) health (26) vacation (24) AI (23) Autodesk (23) SQL (23) humor (23) Java (22) knowledge (22) translate (20) CSS (19) cheatsheet (19) hack (19) Apache (16) Klaipeda (15) Manager (15) web-browser (15) Никонов (15) functional programming (14) happiness (14) music (14) todo (14) PHP (13) course (13) scala (13) weapon (13) HTTP. Apache (12) SSH (12) frameworks (12) hero (12) im (12) settings (12) HTML (11) SciTE (11) USA (11) crypto (11) game (11) map (11) HTTPD (9) ODF (9) Photo (9) купи/продай (9) benchmark (8) documentation (8) 3D (7) CS (7) DNS (7) NoSQL (7) cloud (7) django (7) gun (7) matroska (7) telephony (7) Microsoft Office (6) VCS (6) bluetooth (6) pidgin (6) proxy (6) Donald Knuth (5) ETL (5) NVIDIA (5) Palanga (5) REST (5) bash (5) flash (5) keyboard (5) price (5) samba (5) CGI (4) LISP (4) RoR (4) cache (4) car (4) display (4) holywar (4) nginx (4) pistol (4) spark (4) xml (4) Лебедев (4) IDE (3) IE8 (3) J2EE (3) NTFS (3) RDP (3) holiday (3) mount (3) Гоблин (3) кухня (3) урюк (3) AMQP (2) ERP (2) IE7 (2) NAS (2) Naudoc (2) PDF (2) address (2) air (2) british (2) coffee (2) fitness (2) font (2) ftp (2) fuckup (2) messaging (2) notify (2) sharepoint (2) ssl/tls (2) stardict (2) tests (2) tunnel (2) udev (2) APT (1) Baltic (1) CRUD (1) Canyonlands (1) Cyprus (1) DVDShrink (1) Jabber (1) K9Copy (1) Matlab (1) Portugal (1) VBA (1) WD My Book (1) autoit (1) bike (1) cannabis (1) chat (1) concurrent (1) dbf (1) ext4 (1) idioten (1) join (1) krusader (1) license (1) life (1) migration (1) mindmap (1) navitel (1) pneumatic weapon (1) quiz (1) regexp (1) robot (1) science (1) seaside (1) serialization (1) shore (1) spatial (1) tie (1) vim (1) Науру (1) крысы (1) налоги (1) пианино (1)