3 8\B@sdZddlmZmZddlTeZddlZddlZddl Z ddl m Z m Z m Z m Z mZddlmZddlmZmZddlmZdd lmZdd lmZdd lmZdd lmZdd lm Z!m"Z#ddl$m%Z%ye&Wne'k re(Z&YnXye)Wne'k re*e+fZ)YnXyddlm,Z,Wnbe-k rddlm.Z.yddl/m0Z0Wn$e-k rtGdddZ0YnXdddZ,YnXyddlm1Z1Wn*e-k re2Z1Gddde2Z3YnXGddde1Z3yddl4m5Z5Wn*e-k r ddl4m6Z6ddZ7Yn XddZ7ydd l m8Z8Wn:e-k r`Gd!d"d"eZ8e8e dd#e8_9d$Z:YnXd%Z:e2d&d'd(d)d*d&d+d)d)d)d, Z;d-d.ZGd3d4d4e2Z?e?Z@d5d6ZAGd7d8d8eBZCGd9d:d:e+ZDGd;d<dd>ZFGd?d@d@e*ZGGdAdBdBZHdCdDZIdEdFZJdGdHZKdIdJZLdKdLZMdMdNZNdOdPZOedQZPdRdSZQdTdUZRdVdWZSedXZTedYZUedZZVed[ZWd\d]ZXGd^d_d_e2ZYd`daZZdbdcZ[Gdddedee*Z\Gdfdgdge2Z]edhZ^e,didjdkdla_dmdnZ`dodpZadqdrZbdsdtZcdudvZdGdwdxdxZeeffdydzZgd{d|Zhd}d~Ziejeeke!eleaebecedGdddemZnddZoGdddZpeqdkrerdeerderedS)aZPyGreSQL classic interface. This pg module implements some basic database management stuff. It includes the _pg module and builds on it, providing the higher level wrapper class named DB with additional functionality. This is known as the "classic" ("old style") PyGreSQL interface. For a DB-API 2 compliant interface use the newer pgdb module. )print_functiondivision)*N)datetimedatetime timedeltatzinfo)Decimal)isnanisinf) namedtuple) iskeyword) itemgetter)partial)compile)loadsdumps)UUID) lru_cache)update_wrapper)RLockc@seZdZddZddZdS)rcCsdS)N)selfrr#/tmp/tmpsg3uicd2/lib64/python/pg.py __enter__@szRLock.__enter__cCsdS)Nr)rexctypeexcinstexctbrrr__exit__BszRLock.__exit__N)__name__ __module__ __qualname__rrrrrrr?srcsfdd}|S)z:Simplified functools.lru_cache decorator for one argument.cstijtg}|dg||ddg|dd<dkrLfdd}n2dkrhfdd}nfdd}|_t|S)NFrcs |}|S)Nr)argres)functionrrwrapperRsz-lru_cache..decorator..wrappercs*|}|k r|S|}||<|S)Nr)r$r%)cacher&getsentinelrrr'Xs  c s8f|}|dk rfd}|\}}}}||d<||d<|d}||d<|d<||d<||d<|SWdQRX|}\}}|krn|r|} || d<|| d<| d}d<|d} |d} d|d<|d<| =| |<nB|d}||||g}||d<|d<|<tkr*dd<WdQRX|S)NrT)len) r$linkrootprevnextZ_argr%lastfullZoldrootZoldargZoldres)r(r&r)lockmaxsize root_fullrrr'bsB   )objectr)r __wrapped__r)r&r0r')r6)r(r&r)r5r7r*r decoratorGs $zlru_cache..decoratorr)r6r:r)r6rrDs Br) OrderedDictc@sleZdZdZddZddZddZdd Zd d Zd d Z ddZ ddZ ddZ ddZ eddZdS)AttrDictz@Simple read-only ordered dictionary for storing attribute names.cOst|dks|rt|r |dng}t|tr2tt|}dd|D|_tj||d|_|j}||_ |_ ||_ |_ |_ dS)Nr+rcSsg|] }|dqS)rr).0itemrrr sz%AttrDict.__init__..T)r. TypeError isinstancedictlist_keys__init__ _read_only_read_only_errorclearupdatepop setdefaultpopitem)rargskwitemserrorrrrrEs   zAttrDict.__init__cCs |jr|jtj|||dS)N)rFrGrB __setitem__)rkeyvaluerrrrQszAttrDict.__setitem__cCs|jr|jtj||dS)N)rFrGrB __delitem__)rrRrrrrTszAttrDict.__delitem__cCs t|jS)N)iterrD)rrrr__iter__szAttrDict.__iter__cCs t|jS)N)rCrD)rrrrkeyssz AttrDict.keyscsfddDS)Ncsg|] }|qSrr)r=rR)rrrr?sz#AttrDict.values..r)rr)rrvaluesszAttrDict.valuescsfddDS)Ncsg|]}||fqSrr)r=rR)rrrr?sz"AttrDict.items..r)rr)rrrOszAttrDict.itemscCs|jS)N)rV)rrrriterkeysszAttrDict.iterkeyscCs t|jS)N)rUrX)rrrr itervaluesszAttrDict.itervaluescCs t|jS)N)rUrO)rrrr iteritemsszAttrDict.iteritemscOs tddS)NzThis object is read-only)r@)rMrNrrrrGszAttrDict._read_only_errorN)r r!r"__doc__rErQrTrVrWrXrOrYrZr[ staticmethodrGrrrrr<sr<c@s4eZdZdZddZddZddZedd Zd S) r<z@Simple read-only ordered dictionary for storing attribute names.cOsFd|_tj|f||d|_|j}||_|_||_|_|_dS)NFT) rFr;rErGrHrIrJrKrL)rrMrNrPrrrrEs  zAttrDict.__init__cCs |jr|jtj|||dS)N)rFrGr;rQ)rrRrSrrrrQszAttrDict.__setitem__cCs|jr|jtj||dS)N)rFrGr;rT)rrRrrrrTszAttrDict.__delitem__cOs tddS)NzThis object is read-only)r@)rMrNrrrrGszAttrDict._read_only_errorN) r r!r"r\rErQrTr]rGrrrrr<s ) signature) getargspeccCs t|jS)N)r_rM)funcrrrget_argssracCstt|jS)N)rCr^ parameters)r`rrrras)timezonec@s2eZdZdZd ddZddZddZd d ZdS) rczSimple timezone implementation.NcCsf||_|s\|jjd|jjd}|dkrBt| d\}}| }nt|d\}}d||f}||_dS)Ni<rz UTC%+03d:%02d)offsetdayssecondsdivmodname)rreriminuteshoursrrrrEs ztimezone.__init__cCs|jS)N)re)rdtrrr utcoffsetsztimezone.utcoffsetcCs|jS)N)ri)rrlrrrtznamesztimezone.tznamecCsdS)Nr)rrlrrrdstsz timezone.dst)N)r r!r"r\rErmrnrorrrrrcs  rcUTCFTz+0100z+0200z-0500z+0000z-1000z-0700) ZCETZEETESTGMTZHSTZMETMSTZUCTrpZWETcCs6|jdr*t|dkr|dS|jddStj|dS) N+-Z00:z+0000)rtru) startswithr.replace _timezonesr))tzrrr_timezone_as_offsets    r}cCsNt|}dt|ddt|dd}|ddkr>| }tt|d|S)Nrdr+r-rvrru)rj)r}intrcr)r|rjrrr _get_timezones $ rcCsd|S)z Build oid key from a table name.zoid(%s)r)tablerrr_oid_key'src @s<eZdZdZdddddddd d d d d ZddZddZdS) _SimpleTypesz6Dictionary mapping pg_type names to simple type names.boolbyteaz?date interval time timetz timestamp timestamptz abstime reltimez float4 float8zcid int2 int4 int8 oid xidhstorez json jsonbuuidnumericmoneyzbpchar char name text varchar) rrrfloatr~rjsonrnumrtextcCsFx@|jjD]2\}}x(|jD]}|||<d||d|<qWq WdS)Nz%s[]z_%s)_typesrOsplit)rtyprWrRrrrrE9sz_SimpleTypes.__init__cCsdS)Nrr)rrRrrr __missing__@sz_SimpleTypes.__missing__N)r r!r"r\rrErrrrrr,srcCs t|trd|krd|fS|S)a#Quote parameter representing a qualified name. Puts a quote_ident() call around the give parameter unless the name contains a dot, in which case the name is ambiguous (could be a qualified name or just a name with a dot in it) and must be quoted manually by the caller. .zquote_ident(%s))rA basestring)paramrirrr_quote_if_unqualifiedFs rc@seZdZdZdddZdS)_ParameterListz0Helper class for building typed parameter lists.NcCs0|j||}t|tr|S|j|dt|S)zTypecast value with known database type and build parameter list. If this is a literal value, it will be returned as is. Otherwise, a placeholder will be returned and the parameter list will be augmented. z$%d)adaptrALiteralappendr.)rrSrrrraddVs    z_ParameterList.add)N)r r!r"r\rrrrrrSsrc@seZdZdZdS)Byteaz'Wrapper class for marking Bytea values.N)r r!r"r\rrrrrcsrc@s,eZdZdZedZeddZddZdS)Hstorez(Wrapper class for marking hstore values.z^[Nn][Uu][Ll][Ll]$|[ ,=>]cCs8|dkr dS|sdS|jdd}|jj|r4d|}|S)NNULLz"""z\"z"%s")rz _re_quotesearch)clssrrr_quotels  z Hstore._quotecs"|jdjfdd|jDS)N,c3s&|]\}}d||fVqdS)z%s=>%sNr)r=kv)qrr ysz!Hstore.__str__..)rjoinrO)rr)rr__str__wszHstore.__str__N) r r!r"r\regexr classmethodrrrrrrrgs rc@seZdZdZddZdS)Jsonz&Wrapper class for marking Json values.cCs ||_dS)N)obj)rrrrrrEsz Json.__init__N)r r!r"r\rErrrrr|src@seZdZdZdS)rz-Wrapper class for marking literal SQL values.N)r r!r"r\rrrrrsrc@sneZdZdZedjZedjZedZ edZ edZ Z ddZ ed d Zed d Zed dZeZZZddZddZeddZeZeddZeddZeZZZddZddZ ddZ!d:d d!Z"ed"d#Z#ed$d%Z$ed&d'Z%e&d(e'd)e(d)e)d*e*d+e+d+e,d,e-d-e.d.e/d.e0d.e1d.i Z2ed/d0Z3ed1d2Z4d;d4d5Z5d6d7Z6d.Nnullz""z"%s"z\\\1) rArC_adapt_text_arrayrstr_re_array_quoter_re_array_escapesub)rrr)rrrs  zAdapter._adapt_text_arraycsdt|tr,|jddjfdd|DS|dkr8dSt|trX|sJdS|j|jk}|r`dSdS) z Adapt a boolean array parameter.z{%s}rc3s|]}|VqdS)Nr)r=r)rrrrsz,Adapter._adapt_bool_array..Nrrr)rArC_adapt_bool_arrayrrrr)rrr)rrrs  zAdapter._adapt_bool_arraycsFt|tr,|jddjfdd|DS| r>|dkr>dSt|S)z Adapt a numeric array parameter.z{%s}rc3s|]}|VqdS)Nr)r=r)rrrrsz+Adapter._adapt_num_array..rr)rArC_adapt_num_arrayrr)rrr)rrrs  zAdapter._adapt_num_arraycsJt|tr*ddjfdd|DdS|dkr6dSjj|jdd S) zAdapt a bytea array parameter.{,c3s|]}j|VqdS)N)_adapt_bytea_array)r=r)rrrrsz-Adapter._adapt_bytea_array..}Nsnull\s\\)rArCrrrrz)rrr)rrrs   zAdapter._adapt_bytea_arraycslt|tr,|jddjfdd|DS|s4dSt|tsJ|jj|}|jj|rhd|j j d|}|S)zAdapt a json array parameter.z{%s}rc3s|]}|VqdS)Nr)r=r)rrrrsz,Adapter._adapt_json_array..rz"%s"z\\\1) rArC_adapt_json_arrayrrrrrrrr)rrr)rrrs    zAdapter._adapt_json_arraycCs|j|j}t|t|kr*td||j}g}xt||D]x\}}|||}|dkr`d}nN|sjd}nDt|trttk r|j d}nt|}|j j |rd|j j d|}|j|q@Wdd j|S) z)Adapt a record parameter with given type.z"Record parameter %s has wrong sizeNrxz""asciiz"%s"z\\\1z(%s)r) get_attnamesrXr.r@rziprAbytesrdecode_re_record_quoter_re_record_escaperrr)rrrrrSrrrr _adapt_records&     zAdapter._adapt_recordNcCs|dk rt|t r|r$|j|}n|j|p0d}}t|dd}|rN||}|dkrXnj|dkrxt|tr|j||}nJ|jdrt|trt|d|dd }||}nt|d|}||}|S) z'Adapt a value with known database type.NrZ __pg_str__recordz[]z_adapt_%s_arrayr,z _adapt_%s) rArget_simple_nameguess_simple_typegetattrtuplerendswithrC)rrSrsimpleZpg_strrrrrrs&      z Adapter.adaptcCst|}||_|S)z9Create a simple database type with given attribute names.)DbTyper)rirrrr simple_type/szAdapter.simple_typecCst|tr|jSt|S)z'Get the simple name of a database type.)rArr _simpletypes)rrrrr6s zAdapter.get_simple_namecCst|tr|jSiS)z5Get the attribute names of a composite database type.)rArattnames)rrrrr=s zAdapter.get_attnamesrrrr~rrrcs|jjtrSttr&dSttr4dSttrBdStttfrTdStt rbdStt rpdStt t t tfrdSttrd|jpdfSttr|j|jfd d }d }||_|Sd S) z5Try to guess which database type the given value has.rrrr~rrrz%s[]cstfddtDS)Nc3s*|]"\}}t|d|fVqdS)r+N)r)r=nr)guessrrrroszBAdapter.guess_simple_type..get_attnames..)r< enumerate)r)rrrSrrrnsz/Adapter.guess_simple_type..get_attnamesrN)_frequent_simple_typesr)typerArrrr~longrr rrrrrCguess_simple_base_typerrr _get_attnames)rrSrrr)rrrSrrSs4       zAdapter.guess_simple_typecCs:x4|D],}t|tr |j|}n |j|}|r|SqWdS)z,Try to guess the base type of a given array.N)rArCrr)rrSrrrrrrvs     zAdapter.guess_simple_base_typeFcs|dkr dSt|tr|St|trD|jj|}ttk r|jd}n@t|trj|j r\|j S|jj |}nt|t t t tfrt|}t|tr|jj|}d|St|tr|rdSdSt|trt|r|dkrdSd St|rd S|St|tttfr|St|tr:|j|rd nd }|d jfdd|DSt|trh|jdd jfdd|DSt|dd}|stdt||}t|ttfr|j|}|S)z>Adapt a value that is put into the SQL and needs to be quoted.Nrrz'%s'truefalserz '-Infinity'z 'Infinity'z'NaN'z[%s]z ARRAY[%s]rc3s|]}t|ddVqdS)T)nestedN)r)r=r)rrrrsz'Adapter.adapt_inline..z(%s)c3s|]}t|VqdS)N)r)r=r)rrrrsZ __pg_repr__z Do not know how to adapt type %s)rArrrrrrrrencoderrrrrrZ escape_stringrrr r r~rr rC adapt_inlinerrrZInterfaceErrorr)rrSrrZpg_reprr)rrrsT              zAdapter.adapt_inlinecCst}|j|_|S)zReturn a parameter list for parameters with known database types. The list has an add(value, typ) method that will build up the list and return either the literal value or a placeholder. )rr)rparamsrrrparameter_listszAdapter.parameter_listc ss |gfS|rrtd|j}tttfr|rP|jfddD}n^|jrtttf szttkrtdfddt D}nfddD}|t|;}ntt ri}t j d}xJD]B}||=y ||Wn"t k r|||<YnXd||<qW||rR|jt fdd j D}n\|jrtt srtdt fd d tD}nt fd d tD}||;}ntd ||fS) z9Format a database query using the given values and types.z(Typed parameters must be sent separatelycsg|] }|qSrr)r=rS)rrrr?sz(Adapter.format_query..z!The values and types do not matchcsg|]\}}||qSrr)r=rSr)rrrr?scsg|] }|qSrr)r=rS)rrrr?srxc3s|]\}}||fVqdS)Nr)r=rRrS)rrrrsz'Adapter.format_query..c3s&|]}||j|fVqdS)N)r))r=rR)rtypesrXrrrsc3s|]}||fVqdS)Nr)r=rR)rrXrrrsz0The values must be passed as tuple, list or dict) ValueErrorrrArCrrrr.r@rrBfromkeysKeyErrorrOsorted) rcommandrXrinlinerliteralsZ used_valuesrRr)rrrrXr format_querysX         zAdapter.format_query)N)F)NNF)8r r!r"r\ frozensetrrrrrrrrrErrrr]rZ _adapt_intZ _adapt_floatZ _adapt_moneyrrrZ_adapt_date_arrayrrZ_adapt_int_arrayZ_adapt_float_arrayZ_adapt_money_arrayrrrrrrrrrrrr~rrr rrrrrrrrrrrrrrrsT               # - rcCsts |S|ddkS)zCast a boolean value.rr)get_bool)rSrrr cast_boolsrcCst}|s|S||S)zCast a JSON value.)get_jsondecode)rScastrrr cast_jsonsrcCstpt|S)zCast a numeric value.) get_decimalr)rSrrrcast_numsrcCsPt}|s|S|dkr"|j|d}|jdd}djdd|D}tpJt|S)zCast a money value.r(rurxcss"|]}|js|dkr|VqdS)z.-N)isdigit)r=crrrr szcast_money..)Zget_decimal_pointrzrrr)rSZpointrrr cast_moneys  rcCsdd|jDS)zCast an int2vector value.cSsg|] }t|qSr)r~)r=rrrrr?sz#cast_int2vector..)r)rSrrrcast_int2vectorsrcCsh|dkrtjS|dkrtjS|j}|ddkr6tjS|d}t|dkrPtjS|j}tj||jS)zCast a date value.z -infinityinfinityr+BCr )rminmaxrr. date_formatrstrptime)rS connectionfmtrrr cast_dates  rcCs$t|dkrdnd}tj||jS)zCast a time value.z %H:%M:%S.%fz%H:%M:%S)r.rr r)rSrrrr cast_time(srz (.*)([+-].*)cCsxtj|}|r|j\}}nd}t|dkr0dnd}tr\|t|7}|d7}tj||jStj||jj t |dS)zCast a timetz value.z+0000rz %H:%M:%S.%fz%H:%M:%Sz%z)r ) _re_timezonematchgroupsr. _has_timezoner}rr timetzrzr)rSr|rrrr cast_timetz1s  rcCs|dkrtjS|dkrtjS|j}|ddkr6tjS|j}|jdrt|dkr|dd}t|dd krvtjS|jd rd nd t|dd krdnddg}n2t|ddkrtjS|t|dd krdndg}tjdj |dj |S)zCast a timestamp value.z -infinityrr+rz-%Yr,rvr-z%dz%d %bz%b %drz %H:%M:%S.%fz%H:%M:%Sz%Yrr r) rr r rr rr.ryr r)rSr rrrrcast_timestampAs$  rcCs|dkrtjS|dkrtjS|j}|ddkr6tjS|j}|jdrt|dkr|dd}t|dd krvtjS|jd rd nd t|dd krdnddg}|dd|d}}n|jdrtj |d}|r|j \|d<}nd}n|dd|d}}t|ddkrtjS|t|dd kr4dndg}t rp|j t ||j dtjdj|dj|Stjdj|dj|jt|dS)zCast a timestamptz value.z -infinityrr+rz-%Yr,Nr-rz%dz%d %bz%b %drz %H:%M:%S.%fz%H:%M:%Sz%Yz%Y-z+0000rrz%zr)r rrrrr)rr r rr rr.ryrrrrrr}r rrzr)rSr rr|rrrcast_timestamptzXs<    rzm(?:([+-])?([0-9]+)-([0-9]+) ?)?(?:([+-]?[0-9]+)(?!:) ?)?(?:([+-])?([0-9]+):([0-9]+):([0-9]+)(?:\.([0-9]+))?)?z(?:([+-]?[0-9]+) ?years? ?)?(?:([+-]?[0-9]+) ?mons? ?)?(?:([+-]?[0-9]+) ?days? ?)?(?:([+-])?([0-9]+):([0-9]+):([0-9]+)(?:\.([0-9]+))?)?z@ ?(?:([+-]?[0-9]+) ?years? ?)?(?:([+-]?[0-9]+) ?mons? ?)?(?:([+-]?[0-9]+) ?days? ?)?(?:([+-]?[0-9]+) ?hours? ?)?(?:([+-]?[0-9]+) ?mins? ?)?(?:([+-])?([0-9]+)(?:\.([0-9]+))? ?secs?)? ?(ago)?zP(?:([+-]?[0-9]+)Y)?(?:([+-]?[0-9]+)M)?(?:([+-]?[0-9]+)D)?(?:T(?:([+-]?[0-9]+)H)?(?:([+-]?[0-9]+)M)?(?:([+-])?([0-9]+)(?:\.([0-9]+))?S)?)?c Cs8tj|}|rbdd|jD}|jddk}dd|D}|\}}}}}}} |r^| }| } ntj|}|rdd|jddD|jd }} |jddk}| rd d|Dn d d|D}|\}}}}}}} |r| }| } n(tj|}|rht|jrhd d|jD}|jd dk} dd|D}|\}}}}}}} | r| }| }| }| } ntj|}|rt|jrdd|jD}|jddk} |jd dk} dd|D}|\}}}}}}} | r| }| }| r| }| }| }| } n t d||d|d|7}t ||||| dS)zCast an interval value.cSsg|] }|pdqS)0r)r=drrrr?sz!cast_interval..rvrucSsg|] }t|qSr)r~)r=rrrrr?scSsg|] }|pdqS)rr)r=rrrrr?sNr cSsg|]}t| qSr)r~)r=rrrrr?scSsg|] }t|qSr)r~)r=rrrrr?scSsg|] }|pdqS)rr)r=rrrrr?sr-cSsg|] }t|qSr)r~)r=rrrrr?scSsg|] }|pdqS)rr)r=rrrrr?srcSsg|] }t|qSr)r~)r=rrrrr?szCannot parse interval: %sim)rfrkrjrg microseconds) _re_interval_iso_8601rrrJ_re_interval_postgres_verbosegroup_re_interval_postgresany_re_interval_sql_standardrr) rSmZsecs_agoZyearsZmonsrfrkZminsZsecsZusecsZagoZ hours_agoZ years_agorrr cast_intervals`   &     r(c@seZdZdZeeeeeeeeeeeee e e e e e e eeeeeeeeeedZdZddZeddZdd Zdd d Zd d ZdddZ e!ddZ"e!ddZ#ddZ$ddZ%ddZ&ddZ'dS) TypecastsaDictionary mapping database types to typecast functions. The cast functions get passed the string representation of a value in the database which they need to convert to a Python object. The passed string will never be None since NULL values are already handled before the cast function is called. Note that the basic types are already handled by the C extension. They only need to be handled here as record or array components. )charZbpcharrirZvarcharrrZint2Zint4serialZint8oidrrZjsonbZfloat4Zfloat8rrrintervalrr timestampZ timestamptzZ int2vectorranyarrayrNcst|tstd|jj|}|r:j|}||<nl|jdrl|dd}j|}|r||<n:j|}|rfdd|j D}j |||}||<|S)zCreate a cast function if it is not cached. Note that this class never raises a KeyError, but returns None when no special cast function exists. zInvalid type: %s_r+Ncsg|]}|jqSr)pgtype)r=r)rrrr?sz)Typecasts.__missing__..) rArr@defaultsr)_add_connectionrycreate_array_castrrXcreate_record_cast)rrrZ base_castrcastsr)rrrs"         zTypecasts.__missing__c Cs:y t|}Wnttfk r$dSXd|ddkSdS)z9Check if a typecast function needs a connection argument.Fr r+N)rar@r)r`rMrrr_needs_connection s  zTypecasts._needs_connectioncCs&|j s|j| r|St||jdS)z@Add a connection argument to the typecast function if necessary.)r )r r7r)rrrrrr3szTypecasts._add_connectioncCs ||p |S)z6Get the typecast function for the given database type.r)rrdefaultrrrr)sz Typecasts.getcCst|tr|g}|dkrDxf|D] }|j|d|jd|dqWnGet the default typecast function for the given database type.)r2r))rrrrr get_default;szTypecasts.get_defaultcCst|tr|g}|j}|dkrJx`|D] }|j|d|jd|dq$Wn6t|sZtdx$|D]}|||<|jd|dq`WdS)z?Set a default typecast function for the given database type(s).Nz_%szCast parameter must be callable)rArr2rJr9r@)rrrr2rrrr set_default@s    zTypecasts.set_defaultcCsiS)zReturn the fields for the given record type. This method will be replaced with the get_attnames() method of DbTypes. r)rrrrrrQszTypecasts.get_attnamescCsdS)zwReturn the current date format. This method will be replaced with the dateformat() method of DbTypes. z%Y-%m-%dr)rrrr dateformatXszTypecasts.dateformatcs|dfdd}|S)z1Create an array typecast for the given base cast.r/cs |S)Nr)r)basecast cast_arrayrrrbsz)Typecasts.create_array_cast..castr)rr?rr)r?r@rr4_szTypecasts.create_array_castcs&|dt||fdd}|S)z>Create a named record typecast for the given fields and casts.rcs|S)Nr)r) cast_recordr6rrrrjsz*Typecasts.create_record_cast..cast)r )rrifieldsr6rr)rAr6rrr5fs zTypecasts.create_record_cast)N)N)(r r!r"r\rrunescape_bytear~rZ cast_hstorerrrrrr(rrrrrrr@rAr2r rr]r7r3r)r:r;rr<r=rr>r4r5rrrrr)s4       r)cCs tj|S)z@Get the global typecast function for the given database type(s).)r)r<)rrrr get_typecastosrDcCstj||dS)zSet a global typecast function for the given database type(s). Note that connections cache cast functions. To be sure a global change is picked up by a running connection, call db.db_types.reset_typecast(). N)r)r=)rrrrr set_typecasttsrEc@seZdZdZeddZdS)raOClass augmenting the simple type name with additional info. The following additional information is provided: oid: the PostgreSQL type OID pgtype: the internal PostgreSQL data type name regtype: the registered PostgreSQL data type name simple: the more coarse-grained PyGreSQL type name typtype: b = base type, c = composite type etc. category: A = Array, b = Boolean, C = Composite etc. delim: delimiter for array types relid: corresponding table for composite types attnames: attributes for composite types cCs |j|S)z6Get names and types of the fields of a composite type.)r)rrrrrszDbType.attnamesN)r r!r"r\propertyrrrrrr}srcspeZdZdZedjZfddZddZddZ dd d Z d d Z ddZ ddZ dddZddZZS)DbTypeszCache for PostgreSQL data types. This cache maps type OIDs and names to DbType objects containing information on the associated database type. z>int float num money int2 int4 int8 float4 float8 numeric moneycsXtt|jtj||_d|_t|_|j |j_ |j|j_ |j dkrNd|_ nd|_ dS)z%Initialize type cache for connection.Fi:zSELECT oid, typname, typname::text::regtype, typtype, null as typcategory, typdelim, typrelid FROM pg_type WHERE oid=%s::regtypezrSELECT oid, typname, typname::regtype, typtype, typcategory, typdelim, typrelid FROM pg_type WHERE oid=%s::regtypeN) superrGrErr_db _regtypesr) _typecastsrr server_version_query_pg_type)rr) __class__rrrEs    zDbTypes.__init__c Csn||kr||S|rdnt|}t|jr,|n|} || _|| _|| _|| _|| _|| _|| _ || _ |j | _ | S)z3Create a PostgreSQL type name with additional info.r) rrrJr,rr1regtypetyptypecategorydelimrelidrr) rr,r1rOrPrQrRrSrrrrrrsz DbTypes.addc Cs~y*|jtd|f}|jj||fj}Wntk rBd}YnX|sTtd||d}|j|}|||j<||j <|S)z8Get the type info from the database if it is not cached.z$1NzType %s could not be foundr) rMrrIquery getresultProgrammingErrorrrr,r1)rrRrr%rrrrrs   zDbTypes.__missing__Nc Cs"y||Stk r|SXdS)z&Get the type even if it is not cached.N)r)rrRr8rrrr)sz DbTypes.getcCs8t|ts|j|}|sdS|js&dS|jj|jddS)z6Get names and types of the fields of a composite type.NF)with_oid)rArr)rSrIr)rrrrrrs  zDbTypes.get_attnamescCs |jj|S)z6Get the typecast function for the given database type.)rKr))rrrrrrDszDbTypes.get_typecastcCs|jj||dS)z;Set a typecast function for the specified database type(s).N)rKr:)rrrrrrrEszDbTypes.set_typecastcCs|jj|dS)z?Reset the typecast function for the specified database type(s).N)rKr;)rrrrrreset_typecastszDbTypes.reset_typecastcCsV|dkr dSt|ts*|j|}|r*|j}|r8|j|nd}| sJ|tkrN|S||S)z:Cast the given value according to the given database type.N)rArr)r1rDr)rrSrrrrrtypecasts  zDbTypes.typecast)N)N)r r!r"r\rr _num_typesrErrr)rrDrErXrY __classcell__rr)rNrrGs     rGz^[A-Za-z][_a-zA-Z0-9]*$i)r6cCs|yDytd|ddjStk r@ddt|D}td|jSXWn2tk rvddtt|D}td|jSXdS)z>Get a namedtuple factory for row results with the given names.ZRowT)renamecSs2g|]*\}}tj|r$t| r$|nd|fqS)z column_%d) _re_fieldnamerr)r=rrrrrr? sz _row_factory..cSsg|]}d|fqS)z column_%dr)r=rrrrr?sN)r _maker@rrranger.)namesrrr _row_factorys racCst|tjadS)zwChange the size of the namedtuple factory cache. If maxsize is set to None, the cache can grow without bound. N)rrar9)r6rrrset_row_factory_sizesrbccs*|j}x|D]}tt||VqWdS)z0Get query result as an iterator of dictionaries.N) listfieldsrBr)rrBrrrr _dictiters reccs(t|j}x|D]}||VqWdS)z0Get query result as an iterator of named tuples.N)rarc)rrowrdrrr _namediter&s  rgcCst|jt|S)z0Get next row from query result as a named tuple.)rarcr2)rrrr _namednext-srhccsx|D]}|dVqWdS)z1Get query result as an iterator of scalar values.rNr)rrdrrr _scalariter2s ric@s0eZdZdZddZddZddZdd Zd S) _MemoryQueryz)Class that embodies a given query result.cCs||_t||_dS)z4Create query from given result rows and field names.N)resultrrB)rrkrBrrrrE;sz_MemoryQuery.__init__cCs|jS)z,Return the stored field names of this query.)rB)rrrrrc@sz_MemoryQuery.listfieldscCs|jS)z'Return the stored result of this query.)rk)rrrrrUDsz_MemoryQuery.getresultcCs t|jS)N)rUrk)rrrrrVHsz_MemoryQuery.__iter__N)r r!r"r\rErcrUrVrrrrrj8s rjcCs||}d|_|S)z3Return DatabaseError with empty sqlstate attribute.N)Zsqlstate)msgrrPrrr _db_errorLsrmcCs t|tS)zReturn InternalError.)rm InternalError)rlrrr _int_errorSsrocCs t|tS)zReturn ProgrammingError.)rmrV)rlrrr _prg_errorXsrpc@sLeZdZdZdddZddZddZd d Zd d ZdddZ ddZ dS)NotificationHandlerz;A PostgreSQL client-side asynchronous notification handler.NcCsB||_||_|pd||_d|_||_|dkr2i}||_||_dS)aInitialize the notification handler. You must pass a PyGreSQL database connection, the name of an event (notification channel) to listen for and a callback function. You can also specify a dictionary arg_dict that will be passed as the single argument to the callback function, and a timeout value in seconds (a floating point number denotes fractions of seconds). If it is absent or None, the callers will never time out. If the timeout is reached, the callback function will be called with a single argument that is None. If you set the timeout to zero, the handler will poll notifications synchronously and return. You can specify the name of the event that will be used to signal the handler to stop listening as stop_event. By default, it will be the event name prefixed with 'stop_'. zstop_%sFN)revent stop_event listeningcallbackarg_dicttimeout)rrrrrurvrwrsrrrrEiszNotificationHandler.__init__cCs |jdS)N)unlisten)rrrr__del__szNotificationHandler.__del__cCs"|jr|j|jjd|_dS)z(Stop listening and close the connection.N)rrxclose)rrrrrzs zNotificationHandler.closecCs4|js0|jjd|j|jjd|jd|_dS)z1Start listening for the event and the stop event.z listen "%s"TN)rtrrTrrrs)rrrrlistenszNotificationHandler.listencCs4|jr0|jjd|j|jjd|jd|_dS)z0Stop listening for the event and the stop event.z unlisten "%s"FN)rtrrTrrrs)rrrrrxszNotificationHandler.unlistenFcCsB|jr>|s|j}d|r|jn|j}|r4|d|7}|j|SdS)aGenerate a notification. Optionally, you can pass a payload with the notification. If you set the stop flag, a stop notification will be sent that will cause the handler to stop listening. Note: If the notification handler is running in another thread, you must pass a different database connection since PyGreSQL database connections are not thread-safe. z notify "%s"z, '%s'N)rtrrsrrrT)rrstoppayloadrrrrnotifys  zNotificationHandler.notifycCs|j|jdk}|s"|jjg}x|jr|sDtj|gg|jdrx|jr|jj}|s\P|\}}}||j|jfkr|j t d|j|j|f||jkr|j |j j |||d|j |j qFW|rPq$|j |j dq$WdS)asInvoke the notification handler. The handler is a loop that listens for notifications on the event and stop event channels. When either of these notifications are received, its associated 'pid', 'event' and 'extra' (the payload passed with the notification) are inserted into its arg_dict dictionary and the callback is invoked with this dictionary as a single argument. When the handler receives a stop event, it stops listening to both events and return. In the special case that the timeout of the handler has been set to zero, the handler will poll all events synchronously and return. If will keep listening until it receives a stop event. Note: If you run this loop in another thread, don't use the same database connection for database operations in the main thread. rz1Listening for "%s" and "%s", but notified of "%s")pidrrextraN)r{rwrfilenortselectZ getnotifyrrrsrxrmrvrIru)rpollZrlistZnoticerrrrrrr__call__s0     zNotificationHandler.__call__)NNNN)NFN) r r!r"r\rEryrzr{rxr~rrrrrrqfs  rqcOstjdtddt||S)z8Same as NotificationHandler, under the traditional name.z7pgnotify is deprecated, use NotificationHandler insteadr,) stacklevel)warningswarnDeprecationWarningrq)rMrNrrrpgnotifys rc@seZdZdZdZddZddZddZd d Zd d Z d dZ ddZ ddZ e ddZddZe eZddZddZddZddZdd Zd`d!d"ZeZd#d$ZeZdad%d&ZeZd'd(Zd)d*Zd+d,Zdbd.d/Zd0d1Z dcd2d3Z!d4d5Z"d6d7Z#ddd8d9Z$ded:d;Z%dfdd?Z'dgd@dAZ(dhdBdCZ)didEdFZ*djdGdHZ+dkdJdKZ,dldLdMZ-dmdNdOZ.dndPdQZ/dodRdSZ0dpdTdUZ1dqdVdWZ2drdXdYZ3dsdZd[Z4dtd\d]Z5dud^d_Z6dS)vDBz*Wrapper class for the _pg connection type.Nc Os&| rt|dkr|jd}n | r:t|dkr:|d}nd}|rtt|trT|j}n y |j}Wntk rrYnX| st|d st|d rt||}||f|_ d|_ n ||_ d|_ ||_|j|_ d|_ i|_ i|_i|_t||_t||_|jdkrd |_nd |_|j|jjd|_dS) zCreate a new connection You can pass either the connection parameters or an existing _pg or pgdb connection. This allows you to use the methods of the classic pg interface with a DB-API 2 pgdb connection. r+rrNrTTFi:zSELECT a.attname, t.oid, t.typname, t.typname::text::regtype, t.typtype, null as typcategory, t.typdelim, t.typrelid FROM pg_attribute a JOIN pg_type t ON t.oid = a.atttypid WHERE a.attrelid = %s::regclass AND %s AND NOT a.attisdropped ORDER BY a.attnumzSELECT a.attname, t.oid, t.typname, t.typname::regtype, t.typtype, t.typcategory, t.typdelim, t.typrelid FROM pg_attribute a JOIN pg_type t ON t.oid = a.atttypid WHERE a.attrelid = %s::regclass AND %s AND NOT a.attisdropped ORDER BY a.attnum)r.r)rArrZ_cnxAttributeErrorhasattrconnect_db_args _closeableZdbnamerJ _attnames_pkeys _privilegesradapterrGdbtypesrL_query_attnames set_cast_hookrYdebug)rrMrNrrrrrEs>         z DB.__init__cCs|jrt|j|StddS)NzConnection is not valid)rrro)rrirrr __getattr__)s zDB.__getattr__cCs0t|jj}|j|j|jt|jt|S)N)r:rN__dict__rIdirrr)rattrsrrr__dir__0s  z DB.__dir__cCs |j|S)z9Enter the runtime context. This will start a transaction.)begin)rrrrr9sz DB.__enter__cCs.|dkr"|dkr"|dkr"|jn|jdS)z8Exit the runtime context. This will end the transaction.N)commitrollback)retZevtbrrrr>s z DB.__exit__cCsxy |j}Wntk r"d}YnX|rty|jdWntk rJYnX|jrty |jWntk rrYnXdS)N)rrrr@rrzrn)rrrrrryEs   z DB.__del__cGsv|jrrdjdd|D}t|jtr6t|j|n.writeN)rrrArprintrrr9)rrMrrrr _do_debugWs    z DB._do_debugcCsd|kr|j|}|S)aEscape a qualified name. Escapes the name for use as an SQL identifier, unless the name contains a dot, in which case the name is ambiguous (could be a qualified name or just a name with a dot in it) and must be quoted manually by the caller. r)escape_identifier)rrrrr_escape_qualified_nameds zDB._escape_qualified_namecCstrt|S|rdSdS)z%Get boolean value corresponding to d.rr)rr)rrrr _make_boolpsz DB._make_boolcCsdjddt|dDS)z'Create a human readable parameter list.z, css|]\}}d||fVqdS)z$%d=%rNr)r=rrrrrrwsz"DB._list_params..r+)rr)rrrrr _list_paramsuszDB._list_paramscCstpt|S)z.Decode a JSON string coming from the database.)r jsondecode)rrrrr decode_jsonszDB.decode_jsoncCst|S)z(Encode a JSON string for use within SQL.) jsonencode)rrrrrrszDB.encode_jsonc CsP|j}|rDy|jdWntk r,YnX|jr<|jd|_ntddS)zClose the database connection.NzConnection already closed)rrr@rrzro)rrrrrrzszDB.closecCs|jr|jjntddS)zReset connection with current parameters. All derived queries and large objects derived from this connection will not be usable after this call. zConnection already closedN)rr;ro)rrrrr;s zDB.resetcCsZ|jrNt|jd|jd}|jr8|jjd|jj|j|jj||_n|j|_dS)zReopen connection to the database. Used in case we need another connection to the same database. Note that we can still reopen a database that we have closed. rr+N)rrrrrrzrrY)rrrrrreopens  z DB.reopencCsd}|r|d|7}|j|S)zBegin a transaction.ZBEGINr)rT)rmodeqstrrrrrs zDB.begincCs |jdS)zCommit the current transaction.ZCOMMIT)rT)rrrrrsz DB.commitcCsd}|r|d|7}|j|S)z"Roll back the current transaction.ZROLLBACKz TO )rT)rrirrrrrs z DB.rollbackcCs|jd|S)z6Define a new savepoint within the current transaction.z SAVEPOINT )rT)rrirrr savepointsz DB.savepointcCs|jd|S)z'Destroy a previously defined savepoint.zRELEASE )rT)rrirrrreleasesz DB.releasecCs`t|tr|g}d}n@t|ttfr*g}n,t|ttfr>i}nt|trN|}ntd|sbtdt|trping}x|D]x}t|tr|jj nd}|std|dkrd}|j j |j }tdd|D}Pt|tr|||<qz|j |qzWxd|D]\}d |f}|j j |j d d }|dkr2|}n$t|trJ|j |n ||||<qW|S) a/Get the value of a run-time parameter. If the parameter is a string, the return value will also be a string that is the current setting of the run-time parameter with that name. You can get several parameters at once by passing a list, set or dict. When passing a list of parameter names, the return value will be a corresponding list of parameter settings. When passing a set of parameter names, a new dict will be returned, mapping these parameter names to their settings. Finally, if you pass a dict as parameter, its values will be set to the current parameter settings corresponding to its keys. By passing the special name 'all' as the parameter, you can get a dict of all existing configuration parameters. Nz1The parameter must be a string, list, set or dictzNo parameter has been specifiedzInvalid parameterallzSHOW ALLcss|]}|ddVqdS)Nr,r)r=rSrrrrsz#DB.get_parameter..zSHOW %sr)rArrCrr:rrBr@striprrrTrUr)r parameterrXrrRrrrSrrr get_parametersH          zDB.get_parameterFcCst|tr||i}nt|ttfrNt|ttfr@tt||}qtj||}nt|ttfrt|ttttfrt|}t |dkr|j }|dkpt|tst dtj||}n$t|tr|dk rt dnt d|st di}xl|j D]`\}}t|tr|jjnd}|s"t d|dkrH|dk r>t d ddi}P|||<qW|r^d nd }xR|j D]F\}}|dkrd ||f}nd |||f}|j||jj|qlWdS)aSet the value of a run-time parameter. If the parameter and the value are strings, the run-time parameter will be set to that value. If no value or None is passed as a value, then the run-time parameter will be restored to its default value. You can set several parameters at once by passing a list of parameter names, together with a single value that all parameters should be set to or with a corresponding list of values. You can also pass the parameters as a set if you only provide a single value. Finally, you can pass a dict with parameter names as keys. In this case, you should not pass a value, since the values for the parameters will be taken from the dict. By passing the special name 'all' as the parameter, you can reset all existing settable run-time parameters to their default values. If you set local to True, then the command takes effect for only the current transaction. After commit() or rollback(), the session-level setting takes effect again. Setting local to True will appear to have no effect if it is executed outside a transaction, since the transaction will end immediately. r+Nz8A single value must be specified when parameter is a setzszDB.pkey..)rRcss|]}|dVqdS)rNr)r=rfrrrrszDB.pkey..) rrHrrrrrTrUr.rrrA)rrZ compositeflushZpkeyspkeyrr)rrrs*       zDB.pkeycCsdd|jjdjDS)z$Get list of databases in the system.cSsg|] }|dqS)rr)r=rrrrr?sz$DB.get_databases..zSELECT datname FROM pg_database)rrTrU)rrrr get_databasesszDB.get_databasescCslg}|r&|jddjdd|D|s4|jd|rFddj|nd}d |}d d |jj|jDS) a`Get list of relations in connected database of specified kinds. If kinds is None or empty, all kinds of relations are returned. Otherwise kinds can be a string or sequence of type letters specifying which kind of relations you want to list. Set the system flag if you want to get the system relations as well. zr.relkind IN (%s)rcss|]}d|VqdS)z'%s'Nr)r=rrrrrsz#DB.get_relations..z?s.nspname NOT SIMILAR TO 'pg/_%|information/_schema' ESCAPE '/'z WHERE %sz AND rxzSELECT quote_ident(s.nspname)||'.'||quote_ident(r.relname) FROM pg_class r JOIN pg_namespace s ON s.oid = r.relnamespace%s ORDER BY s.nspname, r.relnamecSsg|] }|dqS)rr)r=rdrrrr?sz$DB.get_relations..)rrrrTrU)rZkindssystemwhererrrr get_relationss  zDB.get_relationscCs |jd|S)zReturn list of tables in connected database. Set the system flag if you want to get the system tables as well. rd)r)rrrrr get_tablessz DB.get_tablesTc s|j}|r|j|jdy ||}Wnttk rd}|rHd|}|jtd||f}|jj||fj}|j fdd|D}t |}|||<YnX|S)atGiven the name of a table, dig out the set of attribute names. Returns a read-only dictionary of attribute names (the names are the keys, the values are the names of the attributes' types) with the column names in the proper order if you iterate over it. If flush is set, then the internal cache for attribute names will be flushed. This may be necessary after the database schema or the search path has been changed. By default, only a limited number of simple types will be returned. You can get the registered types after calling use_regtypes(True). z#The attnames cache has been flushedz a.attnum > 0z(%s OR a.attname = 'oid')z$1c3s(|] }|dj|ddfVqdS)rr+N)r)r=ri)rrrr%sz"DB.get_attnames..) rrHrrrrrrTrUrr<)rrrWrrr`rr)rrr s"  zDB.get_attnamescCsH|dkr|jjSt|}||jjkr@||j_|jj|jj|SdS)z;Use registered type names instead of simplified type names.N)rrJrrrH)rZregtypesrrr use_regtypes*s   zDB.use_regtypesrc Cs|j}|r|j|jd|j}y|||f}Wn\tk rdtd|f}|jj|||f}|jdd|j dk}||||f<YnX|S)zCheck whether current user has specified table privilege. If flush is set, then the internal cache for table privileges will be flushed. This may be necessary after privileges have been changed. z%The privileges cache has been flushedz"SELECT has_table_privilege(%s, $2)z$1rT) rrHrrrrrrTrUr)rrZ privilegerZ privilegesretrrrrhas_table_privilege6s zDB.has_table_privilegec s@|jdr|ddj}|j|dkr4t|nd}|rLt|trL|f}|rvttrv|krvdkrv|d<|sy|j|d}Wn<tk r|rttrdkrd}n t d|Yn:Xttot |j  r|odkrd}ntdttsLtt t fs$gt|tkr>tdtt||jj}|j|j|rld nd}d jfd d |D}dkr|rd|<d=d ||j||f}|j|||jj||}|j} | std|||j|fx6| djD]&\} } |r.| dkr.|} | | <qWS)aGet a row from a database table or view. This method is the basic mechanism to get a single row. It assumes that the keyname specifies a unique row. It must be the name of a single column or a tuple of column names. If the keyname is not specified, then the primary key for the table is used. If row is a dictionary, then the value for the key is taken from it. Otherwise, the row must be a single value or a tuple of values corresponding to the passed keyname or primary key. The fetched row from the table will be returned as a new dictionary or used to replace the existing values when row was passed as a dictionary. The OID is also put into the dictionary if the table has one, but in order to allow the caller to work with multiple tables, it is munged as "oid(table)" using the actual name of the table. rNr+r,TzTable %s has no primary keyz*Missing value in row for specified keynamez,Differing number of items in keyname and rowzoid, *z AND c3s,|]$}d|||fVqdS)z%s = %sNr)r=r)rrcolrfrrrszDB.get..z"SELECT %s FROM %s WHERE %s LIMIT 1z%No such record in %s where %s with %srr)r,)r,)rrstriprrrArrBrrrpr:issubsetrrCr.rrrrrrrrrrT dictresultrmrrO) rrrfkeynameqoidrwhatrrr%rrSr)rrrrfrr)Ksd         zDB.getcKs`|jdr|dd j}|dkr&i}|j|d|kr>|d=|j|}d|krXt|nd}|jj}|j}|j}gg} } x:|D]2} | |kr| j || | j ||| || qW| st ddj | dj | } } |rdnd} d|j || | | f} |j | ||jj| |} | j}|r\x6|d jD]&\} }|rN| dkrN|} ||| <q2W|S) adInsert a row into a database table. This method inserts a row into a table. The name of the table must be passed as the first parameter. The other parameters are used for providing the data of the row that shall be inserted into the table. If a dictionary is supplied as the second parameter, it starts with that. Otherwise it uses a blank dictionary. Either way the dictionary is updated from the keywords. The dictionary is then reloaded with the values actually inserted in order to pick up values modified by rules, triggers, etc. rNr+r,z$No column found that can be insertedz, zoid, *z,INSERT INTO %s (%s) VALUES (%s) RETURNING %srr)rrrIrrrrrrrrprrrrrTrrO)rrrfrNrrrrrr`rXrrrr%rSrrrinserts@        z DB.insertc s|jdr|ddj}|j|dkr4t|nd}dkrFindkrTd=j||r~|kr~dkr~|d<|rdkrd}nHy|j|d}Wn tk rtd|YnXt|j std|j j }|j |j djfd d |D}dkr.|r(d|<d=g}t|}xFD]>} | kr@| |kr@|jd | | | fq@W|sSd j|}|rd nd} d|j|||| f} |j| ||jj| |} | j} | rx6| djD]&\} } |r | dkr |} | | <qWS)aUpdate an existing row in a database table. Similar to insert, but updates an existing row. The update is based on the primary key of the table or the OID value as munged by get() or passed as keyword. The OID will take precedence if provided, so that it is possible to update the primary key itself. The dictionary is then modified to reflect any changes caused by the update due to triggers, rules, default values, etc. rNr+r,TzTable %s has no primary keyz$Missing value for primary key in rowz AND c3s,|]$}d|||fVqdS)z%s = %sNr)r=r)rrrrfrrrszDB.update..z%s = %sz, zoid, *z&UPDATE %s SET %s WHERE %s RETURNING %srr)r,)rrrrrIrrrpr:rrrrrrrrrrrTrrO)rrrfrNrrrrrXrrrr%rSr)rrrrfrrIs`          *  z DB.updatec s|jdr|ddj}|dkr&i}d|kr4|d=d|krB|d=|j|}d|kr\t|nd}|jj}|j}|jggg}} } x:|D]2} | |kr|j| | j||| || qWdj |dj | }} y|j |d} Wn"t k r t d|YnXdj fdd | D} g}t | } | jdxX|D]P} | | kr@|j| d}|r@t|tsxd | }|jd | |fq@W| s|S|rd dj |nd }|rdnd}d|j||| | ||f}|j||y|jj||}Wn,tk r(|jdkr"t dYnX|j}|rrxD|djD]&\} }|rb| dkrb|} ||| <qFWn |j|||S)aInsert a row into a database table with conflict resolution This method inserts a row into a table, but instead of raising a ProgrammingError exception in case a row with the same primary key already exists, an update will be executed instead. This will be performed as a single atomic operation on the database, so race conditions can be avoided. Like the insert method, the first parameter is the name of the table and the second parameter can be used to pass the values to be inserted as a dictionary. Unlike the insert und update statement, keyword parameters are not used to modify the dictionary, but to specify which columns shall be updated in case of a conflict, and in which way: A value of False or None means the column shall not be updated, a value of True means the column shall be updated with the value that has been proposed for insertion, i.e. has been passed as value in the dictionary. Columns that are not specified by keywords but appear as keys in the dictionary are also updated like in the case keywords had been passed with the value True. So if in the case of a conflict you want to update every column that has been passed in the dictionary row, you would call upsert(table, row). If you don't want to do anything in case of a conflict, i.e. leave the existing row as it is, call upsert(table, row, **dict.fromkeys(row)). If you need more fine-grained control of what gets updated, you can also pass strings in the keyword parameters. These strings will be used as SQL expressions for the update columns. In these expressions you can refer to the value that already exists in the table by prefixing the column name with "included.", and to the value that has been proposed for insertion by prefixing the column name with the "excluded." The dictionary is modified in any case to reflect the values in the database after the operation has completed. Note: The method uses the PostgreSQL "upsert" feature which is only available since PostgreSQL 9.5. rNr+r,z, TzTable %s has no primary keyc3s|]}|VqdS)Nr)r=r)rrrrD szDB.upsert..z excluded.%sz%s = %sz update set %sZnothingzoid, *zOINSERT INTO %s AS included (%s) VALUES (%s) ON CONFLICT (%s) DO %s RETURNING %siaz7Upsert operation is not supported by PostgreSQL versionrr)rrrrrrrrrrrrrpr:r)rArrrrrTrVrLrrO)rrrfrNrrrrr`rXZupdatesrrtargetrIrSZdorrr%r)rrupsert sr+               z DB.upsertcCst|dkr i}|j|}xX|jD]L\}}|dkr2q |j}|tjkrLd||<q |dkrd|jd||<q d||<q W|S)ahClear all the attributes to values determined by the types. Numeric types are set to 0, Booleans are set to false, and everything else is set to the empty string. If the row argument is present, it is used as the row dictionary and any entries matching attribute names are cleared with everything else left unchanged. Nr,rrFrx)rrOrrGrZr)rrrfrrrrrrrHi s     zDB.clearc sb|jdr|dd j}|j|dkr4t|nd}dkrFindkrTd=j||r~|kr~dkr~|d<|rdkrd }nHy|j|d}Wn tk rtd|YnXt|j std|j j }|j |j djfd d |D}dkr.|r(d|<d=d |j||f}|j|||jj||} t| S)a#Delete an existing row in a database table. This method deletes the row from a table. It deletes based on the primary key of the table or the OID value as munged by get() or passed as keyword. The OID will take precedence if provided. The return value is the number of deleted rows (i.e. 0 if the row did not exist and 1 if the row was deleted). Note that if the row cannot be deleted because e.g. it is still referenced by another table, this method raises a ProgrammingError. rNr+r,TzTable %s has no primary keyz$Missing value for primary key in rowz AND c3s,|]$}d|||fVqdS)z%s = %sNr)r=r)rrrrfrrr szDB.delete..zDELETE FROM %s WHERE %sr)r,)rrrrrIrrrpr:rrrrrrrrrrTr~) rrrfrNrrrrrr%r)rrrrfrdelete sB          z DB.deletec Cst|tr||i}|g}n^t|ttfrTt|ttfrFtt||}qxtj||}n$t|ttfrptj||}nt d|dkpt|t t fst d|dkpt|t t fst dg}x|D]x}|j |}|dkpt|t t fst d|j dr|rtd|ddj}|j|}|r,d |}|j|qWd d j|g}|rX|jd |rh|jd dj|}|j||jj|S)aEmpty a table or set of tables. This method quickly removes all rows from the given table or set of tables. It has the same effect as an unqualified DELETE on each table, but since it does not actually scan the tables it is faster. Furthermore, it reclaims disk space immediately, rather than requiring a subsequent VACUUM operation. This is most useful on large tables. If restart is set to True, sequences owned by columns of the truncated table(s) are automatically restarted. If cascade is set to True, it also truncates all tables that have foreign-key references to any of the named tables. If the parameter only is not set to True, all the descendant tables (if any) will also be truncated. Optionally, a '*' can be specified after the table name to explicitly indicate that descendant tables are included. z'The table must be a string, list or setNz#Invalid type for the restart optionz#Invalid type for the cascade optionz Invalid type for the only optionrz)Contradictory table name and only optionsr+zONLY %sZTRUNCATEz, zRESTART IDENTITYZCASCADErr)rArrCrrBrrr:rr@rr~r)rrrrrrrrrT) rrZrestartZcascadeonlyZtablesrurrrrtruncate sH         z DB.truncatec Cs||s td|r.)r@rArCrrmaprextendrrrVrrrrrTZ namedresult) rrrrorderlimitrescalarrr%rrr get_as_list sH      zDB.get_as_listc  s|s td|sFy|j|d}Wn$ttfk rDtd|YnXt|trX|g}nt|ttfsntd|rt|ttfrdj t t |}|dkr|}nd}d|d |g} |rt|ttfrd j t t |}| j d |g|dkr|}|rt|ttfrdj t t |}| j d |g|r2| j d ||rF| j d|dj | } |j| |jj| } | j} |rxtnt} | s| St|| j} j| stdgg} x.t| D]"\}}|kr| nj |qWt| dk}t| }t || }|rddd}n tdk}|s4|r>t}ndfdd}d}t || }|sl|r|rtt||}|rfdd| D} tt|| }| t||S)a-Get a table as a dictionary. This method is similar to get_as_list(), but returns the table as a Python dict instead of a Python list, which can be even more convenient. The primary key column(s) of the table will be used as the keys of the dictionary, while the other column(s) will be the corresponding values. The keys will be named tuples if the table has a composite primary key. The rows will be also named tuples unless the 'scalar' option has been set to True. With the optional parameter 'keyname' you can specify an alternative set of columns to be used as the keys of the dictionary. It must be set as a string, list or a tuple. If the Python version supports it, the dictionary will be an OrderedDict using the order specified with the 'order' parameter or the key column(s) if not specified. You can set 'order' to False if you don't care about the ordering. In this case the returned dictionary will be an ordinary one. zThe table name is missingTzTable %s has no primary keyz+The keyname must be a string, list or tuplez, Nrrrz AND rzORDER BYzLIMIT %dz OFFSET %drzMissing keyname in rowr+Frcs |fS)Nr)rf)rowindrrr| sz DB.get_as_dict..csg|]}|kr|qSrr)r=r)keysetrrr? sz"DB.get_as_dict..)r@rrrVrprArrCrrrrrrrrrTrUr;rBr:rcrrr.rrgrjr)rrrrrrrrerrr%rrBZkeyindirZkeytupleZgetkeyrWZrowtupleZgetrowZrowsr)rrr get_as_dict, s                zDB.get_as_dictcCst||||||S)z:Get notification handler that will run the given callback.)rq)rrrrurvrwrsrrrnotification_handler szDB.notification_handler)N)N)NF)NNF)N)N)FF)NF)F)TF)N)rF)N)N)N)N)N)N)FFF)NNNNNF)NNNNNNF)NNN)7r r!r"r\rrErrrrryrrr]rrrCrrrzr;rrstartrendrabortrrrrrTrrrrrrrrrrrrr)rrIrrHrrrrrrrrrrsj<      : G  *    K . > g  1 8 A [r__main__zPyGreSQL versionrx)r#)sr\ __future__rr_pgversion __version__rrrrrrrr Zdecimalr mathr r collectionsr keywordroperatorr functoolsrrerrrrrrrrrr NameErrorr~rrrr ImportErrorr_threadrr;rBr<inspectr^r_rarcutcrr{r}rrrrrrCrrrrrrrrrrrrrrrrrr&r$r"r!r(r)rDrErrGr]rarbrergrhrirjZ DatabaseErrorrmrorpZ set_decimalZset_jsondecodeZset_query_helpersr8rqrrr rrrrrs         J6    j %; k  y 1