{-# LANGUAGE RecordWildCards #-}-------------------------------------------------------------------------------- |-- Module: Database.PostgreSQL.Simple.TypeInfo-- Copyright: (c) 2013 Leon P Smith-- License: BSD3-- Maintainer: Leon P Smith <leon@melding-monads.com>-- Stability: experimental---- This module provides convenient and efficient access to parts of the-- @pg_type@ metatable. At the moment, this requires PostgreSQL 8.4 if-- you need to work with types that do not appear in-- 'Database.PostgreSQL.Simple.TypeInfo.Static'.---- The current scheme could be more efficient, especially for some use-- cases. In particular, connection pools that use many user-added-- types and connect to a set of servers with identical (or at least-- compatible) @pg_type@ and associated tables could share a common-- typeinfo cache, thus saving memory and communication between the-- client and server.--------------------------------------------------------------------------------moduleDatabase.PostgreSQL.Simple.TypeInfo(getTypeInfo,TypeInfo(..),Attribute(..))whereimportqualifiedData.ByteStringasBimportqualifiedData.IntMapasIntMapimportqualifiedData.VectorasVimportqualifiedData.Vector.MutableasMVimportControl.Concurrent.MVarimportControl.Exception(throw)importqualifiedDatabase.PostgreSQL.LibPQasPQimport{-# SOURCE #-}Database.PostgreSQL.SimpleimportDatabase.PostgreSQL.Simple.InternalimportDatabase.PostgreSQL.Simple.TypesimportDatabase.PostgreSQL.Simple.TypeInfo.TypesimportDatabase.PostgreSQL.Simple.TypeInfo.Static-- | Returns the metadata of the type with a particular oid. To find-- this data, 'getTypeInfo' first consults postgresql-simple's-- built-in 'staticTypeInfo' table, then checks the connection's-- typeinfo cache. Finally, the database's 'pg_type' table will-- be queried only if necessary, and the result will be stored-- in the connections's cache.getTypeInfo::Connection->PQ.Oid->IOTypeInfogetTypeInfoconn@Connection{..}oid=casestaticTypeInfooidofJustname->returnnameNothing->modifyMVarconnectionObjects$getTypeInfo'connoidgetTypeInfo'::Connection->PQ.Oid->TypeInfoCache->IO(TypeInfoCache,TypeInfo)getTypeInfo'connoidoidmap=caseIntMap.lookup(oid2intoid)oidmapofJusttypeinfo->return(oidmap,typeinfo)Nothing->donames<-queryconn"SELECT oid, typcategory, typdelim, typname,\
\ typelem, typrelid\
\ FROM pg_type WHERE oid = ?"(Onlyoid)(oidmap',typeInfo)<-casenamesof[]->return$throw(fatalError"invalid type oid")[(typoid,typcategory,typdelim,typname,typelem_,typrelid)]->docasetypcategoryof'A'->do(oidmap',typelem)<-getTypeInfo'conntypelem_oidmaplet!typeInfo=Array{..}return$!(oidmap',typeInfo)'R'->dorngsubtypeOids<-queryconn"SELECT rngsubtype\
\ FROM pg_range\
\ WHERE rngtypid = ?"(Onlyoid)caserngsubtypeOidsof[Onlyrngsubtype_]->do(oidmap',rngsubtype)<-getTypeInfo'connrngsubtype_oidmaplet!typeInfo=Range{..}return$!(oidmap',typeInfo)_->fail"range subtype query failed to return exactly one result"'C'->docols<-queryconn"SELECT attname, atttypid\
\ FROM pg_attribute\
\ WHERE attrelid = ?\
\ AND attnum > 0\
\ AND NOT attisdropped\
\ ORDER BY attnum"(Onlytyprelid)vec<-MV.new$!lengthcols(oidmap',attributes)<-getAttInfosconncolsoidmapvec0let!typeInfo=Composite{..}return$!(oidmap',typeInfo)_->dolet!typeInfo=Basic{..}return$!(oidmap,typeInfo)_->fail"typename query returned more than one result"-- oid is a primary key, so the query should-- never return more than one resultlet!oidmap''=IntMap.insert(oid2intoid)typeInfooidmap'return$!(oidmap'',typeInfo)getAttInfos::Connection->[(B.ByteString,PQ.Oid)]->TypeInfoCache->MV.IOVectorAttribute->Int->IO(TypeInfoCache,V.VectorAttribute)getAttInfosconncolsoidmapvecn=casecolsof[]->do!attributes<-V.unsafeFreezevecreturn$!(oidmap,attributes)((attname,attTypeOid):xs)->do(oidmap',atttype)<-getTypeInfo'connattTypeOidoidmapMV.writevecn$!Attribute{..}getAttInfosconnxsoidmap'vec(n+1)