В 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
original post http://vasnake.blogspot.com/2013/06/psycopg2-cursor-description.html
Комментариев нет:
Отправить комментарий