o ^< @sXdZddlmZmZzddlTWnTeydddlZddlZejdkraej dkraej d ej D],Z ej ej e dr^eej e  ddlTWdn1sWwYnq2nYnweZgd ZddlZddlZddlZdd lmZmZmZmZmZdd lmZdd lm Z m!Z!dd l"m#Z#ddl$m%Z%ddl&m'Z'ddl(m)Z)ddl*m+Z,ddl-m.Z/m0Z1ddl2m3Z3ze4Wn e5ye6Z4Ynwze7Wn e5ye8e9fZ7Ynwzddl(m:Z:Wn/eyddl(m;Z;zddlZ>Wney5e?Z>Gddde?Z@Yn wGddde>Z@zdd lAmBZBWneyZdd!lAmCZCd"d#ZDYnwd$d#ZDzdd%lmEZEWneyGd&d'd'eZEeEedd(eE_Fd)ZGYnwd*ZGe?d+d,d-d.d/d+d0d.d.d.d1 ZHd2d3ZId4d5ZJd6d7ZKGd8d9d9e?ZLeLZMd:d;ZNGdd?d?e9ZQGd@dAdAe?ZRGdBdCdCZSGdDdEdEe8ZTGdFdGdGZUdHdIZVdJdKZWdLdMZXdNdOZYdPdQZZdRdSZ[dTdUZ\e,dVZ]dWdXZ^dYdZZ_d[d\Z`e,d]Zae,d^Zbe,d_Zce,d`ZddadbZeGdcdddde?ZfdedfZgdgdhZhGdidjdje8ZiGdkdldle?Zje,dmZke:dndodpdqaldrdsZmdtduZndvdwZodxdyZpdzd{ZqGd|d}d}Zresfd~dZtddZuddZveweexe/eyeneoepeqGdddezZ{ddZ|GdddZ}e~dkredeedeedSdS)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)*Nnt)PATHz libpq.dll)BDBAdapterNotificationHandler TypecastsByteaHstoreJsonLiteralErrorWarning DataError DatabaseErrorIntegrityErrorInterfaceError InternalErrorInvalidResultErrorMultipleResultsError NoResultErrorNotSupportedErrorOperationalErrorProgrammingErrorINV_READ INV_WRITESEEK_CURSEEK_ENDSEEK_SET TRANS_ACTIVE TRANS_IDLE TRANS_INERROR TRANS_INTRANS TRANS_UNKNOWN cast_array cast_hstore cast_recordconnect escape_bytea escape_stringunescape_bytea get_arrayget_boolget_bytea_escaped get_datestyle get_decimalget_decimal_point get_defbase get_defhost get_defopt get_defport get_defuserget_jsondecode set_arrayset_boolset_bytea_escaped set_datestyle set_decimalset_decimal_point set_defbase set_defhost set_defopt set_defpasswd set_defport set_defuserset_jsondecodeset_query_helpersversion __version__)datetimedatetime timedeltatzinfo)Decimal)isnanisinf namedtuple) iskeyword) itemgetter)partial)compile)loadsdumps)UUID) lru_cache)update_wrapper)RLockc@seZdZddZddZdS)r^cCdSNselfrara$/usr/lib/python3/dist-packages/pg.py __enter__hzRLock.__enter__cCr_r`ra)rcexctypeexcinstexctbrarard__exit__jrfzRLock.__exit__N)__name__ __module__ __qualname__rerjrararardr^gs r^csfdd}|S)z:Simplified functools.lru_cache decorator for one argument.cstijtg}|dg||ddg|dd<dkr&fdd}ndur4fdd}n fdd}|_t|S)NFrcs |}|Sr`raargres)functionrardwrapperzsz-lru_cache..decorator..wrappercs*|}|ur |S|}||<|Sr`raro)cacherrgetsentinelrardrss c s?|}|dur:d}|\}}}}||d<||d<|d}||d<|d<||d<||d<|WdSWdn1sDwY|}v\}}|vrYnT|r|} || d<|| d<| d}d<|d} |d} d|d<|d<| =| |<n8|d}||||g}||d<|d<|<tkrdd<Wd|SWd|SWd|SWd|S1swY|S)NrrT)len) rplinkrootprevnext_argrqlastfulloldrootoldargoldres)rtrrrulockmaxsize root_fullrardrss`          )objectrur^ __wrapped__r])rrr{rsr)rtrrrurrrvrd decoratoros $ zlru_cache..decoratorra)rrrarrdr\ls Br\) OrderedDictc@sleZdZdZddZddZddZdd Zd d Zd d Z ddZ ddZ ddZ ddZ eddZdS)AttrDict@Simple read-only ordered dictionary for storing attribute names.cOst|dks|r t|r|dng}t|trtt|}dd|D|_t||d|_|j}||_ |_ ||_ |_ |_ dS)NrwrcSg|]}|dqSrra).0itemrarard z%AttrDict.__init__..T)ry TypeError isinstancedictlist_keys__init__ _read_only_read_only_errorclearupdatepop setdefaultpopitem)rcargskwitemserrorrarardrs   AttrDict.__init__cC |jr|t|||dSr`)rrr __setitem__rckeyvaluerarardrAttrDict.__setitem__cC|jr|t||dSr`)rrr __delitem__rcrrarardrAttrDict.__delitem__cC t|jSr`)iterrrbrarard__iter__ zAttrDict.__iter__cCrr`)rrrbrarardkeysrz AttrDict.keyscfddDS)Ncsg|]}|qSrararrrbrardrrz#AttrDict.values..rarbrarbrdvalueszAttrDict.valuescr)Ncsg|]}||fqSrararrbrardrz"AttrDict.items..rarbrarbrdrrzAttrDict.itemscCs|Sr`)rrbrararditerkeysszAttrDict.iterkeyscC t|Sr`)rrrbrarard itervalues zAttrDict.itervaluescCrr`)rrrbrarard iteritemsrzAttrDict.iteritemscOtdNzThis object is read-onlyrrrrarardrAttrDict._read_only_errorN)rkrlrm__doc__rrrrrrrrrr staticmethodrrararardrsrc@s4eZdZdZddZddZddZedd Zd S) rrcOsLd|_tj|g|Ri|d|_|j}||_|_||_|_|_dS)NFT) rrrrrrrrr)rcrrrrarardrs  rcCrr`)rrrrrrarardrrrcCrr`)rrrrrrarardrrrcOrrrrrarardrrrN) rkrlrmrrrrrrrararardrs) signature) getargspeccCs t|jSr`)rrfuncrarardget_argsrrcCstt|jSr`)rr parametersrrarardr)timezonec@s2eZdZdZd ddZddZddZd d ZdS) rzSimple timezone implementation.NcCsf||_|s.|jjd|jjd}|dkr!t| d\}}| }nt|d\}}d||f}||_dS)Ni<rz UTC%+03d:%02d)offsetdayssecondsdivmodname)rcrrminuteshoursrarardrs  ztimezone.__init__cC|jSr`)rrcdtrarard utcoffset*ztimezone.utcoffsetcCrr`)rrrarardtzname-rztimezone.tznamecCr_r`rarrararddst0z timezone.dstr`)rkrlrmrrrrrrararardrs    rUTCFTz+0100z+0200z-0500+0000z-1000z-0700) CETEETESTGMTHSTMETMSTUCTrWETcCs6|drt|dkr|dS|ddSt|dS)N)+-00:r) startswithryreplace _timezonesru)tzrarard_timezone_as_offset?s    rcCsNt|}dt|ddt|dd}|ddkr| }tt|d|S)Nrrwrrrr)r)rintrrN)rrrarard _get_timezoneGs $ rcCsd|S)z Build oid key from a table name.zoid(%s)ra)tablerarard_oid_keyOrrc @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) rrrKfloatrrjsonrnumrtextcCs>|jD]\}}|D]}|||<d||d|<q qdS)N%s[]_%s)_typesrsplit)rctyprrrarardras  z_SimpleTypes.__init__cCdS)Nrrarrarard __missing__hrz_SimpleTypes.__missing__N)rkrlrmrrrr rararardrTs rcCs t|trd|vrd|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))r basestring)paramrrarard_quote_if_unqualifiedns rc@seZdZdZdddZdS)_ParameterListz0Helper class for building typed parameter lists.NcCs0|||}t|tr |S||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)adaptrrappendry)rcrr rarardadd~s    z_ParameterList.addr`)rkrlrmrrrararardr{src@eZdZdZdS)r z'Wrapper class for marking Bytea values.Nrkrlrmrrararardr r c@s,eZdZdZedZeddZddZdS)rz(Wrapper class for marking hstore values.z^[Nn][Uu][Ll][Ll]$|[ ,=>]cCs8|durdS|s dS|dd}|j|rd|}|S)NNULL"""z\""%s")r _re_quotesearch)clssrarard_quotes  z Hstore._quotecs"|jdfdd|DS)N,c3s(|]\}}d||fVqdS)z%s=>%sNra)rkvqrard s&z!Hstore.__str__..)r joinrrbrar$rd__str__szHstore.__str__N) rkrlrmrregexr classmethodr r(rararardrs   rc@seZdZdZddZdS)rz&Wrapper class for marking Json values.cCs ||_dSr`)obj)rcr+rarardrrz Json.__init__N)rkrlrmrrrararardrs rc@r)rz-Wrapper class for marking literal SQL values.Nrrararardrrrc@sneZdZdZedZedZedZ 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.Nnullrr\\\1) rr_adapt_text_arrayr'str_re_array_quoter_re_array_escapesubr4rarCrdrGs  zAdapter._adapt_text_arraycsdt|tr|jddfdd|DS|durdSt|tr,|s%dS||jv}|r0dSdS) z Adapt a boolean array parameter.r@r!c3rAr`rarBrCrardr&rDz,Adapter._adapt_bool_array..NrEr0r1)rr_adapt_bool_arrayr'rr2r3r4rarCrdrLs   zAdapter._adapt_bool_arraycsDt|tr|jddfdd|DS|s|dkrdSt|S)z Adapt a numeric array parameter.r@r!c3rAr`rarBrCrardr& rDz+Adapter._adapt_num_array..rrE)rr_adapt_num_arrayr'rHr4rarCrdrMs  zAdapter._adapt_num_arraycsJt|trddfdd|DdS|durdSj|dd S) zAdapt a bytea array parameter.{,c3s|]}|VqdSr`)_adapt_bytea_arrayrBrbrardr&s  z-Adapter._adapt_bytea_array..}Nsnull\s\\)rrr'r.r,rr;rarbrdrPs zAdapter._adapt_bytea_arraycslt|tr|jddfdd|DS|sdSt|ts%|j|}|j|r4d|j d|}|S)zAdapt a json array parameter.r@r!c3rAr`rarBrCrardr&rDz,Adapter._adapt_json_array..rErrF) rr_adapt_json_arrayr'rr.r>rIrrJrKr;rarCrdrSs    zAdapter._adapt_json_arraycCs||}t|t|krtd||j}g}t||D]<\}}|||}|dur/d}n'|s4d}n"t|trCtturB| d}nt|}|j |rVd|j d|}||qdd |S) z)Adapt a record parameter with given type.z"Record parameter %s has wrong sizeNrrasciirrF(%s)r!) get_attnamesrryrrziprbytesrHdecode_re_record_quoter_re_record_escaperKrr')rcr#r rrr0rarard _adapt_record's(      zAdapter._adapt_recordNcCs|durdt|tsd|r||}n ||pd}}t|dd}|r&||}|dkr- |S|dkr>t|tr<|||}|S|drYt|trWt|d|dd}||}|St|d|}||}|S) z'Adapt a value with known database type.Nr __pg_str__recordz[]z_adapt_%s_arrayz _adapt_%s) rrget_simple_nameguess_simple_typegetattrtupler\endswithr)rcrr simplepg_strrrarardr?s,      z Adapter.adaptcCst|}||_|S)z9Create a simple database type with given attribute names.)DbTypere)rr rarard simple_typeWszAdapter.simple_typecCst|tr|jSt|S)z'Get the simple name of a database type.)rrgre _simpletypesr rarardr`^s zAdapter.get_simple_namecCst|tr|jSiS)z5Get the attribute names of a composite database type.)rrgattnamesrjrarardrVes zAdapter.get_attnamesrrrrrrrKcsz|jtWStyYnwttrdSttr dSttr'dStttfr0dStt r7dStt r>dStt t t tfrIdSttrXd|pUdfSttrt|j|jfd d }d }||_|Sd S) z5Try to guess which database type the given value has.rrrrrrrKrcstfddtDS)Nc3s,|]\}}t|d|fVqdS)rwNrHrnr#)guessrhrardr&s zBAdapter.guess_simple_type..get_attnames..)r enumeraterbrorhrrardrVsz/Adapter.guess_simple_type..get_attnamesr^N)_frequent_simple_typestypeKeyErrorrr rrrlongrrPrKrLrMrNrguess_simple_base_typercrhra _get_attnames)rrrVr rarqrdra{s:        zAdapter.guess_simple_typecCs:|D]}t|tr||}n||}|r|SqdS)z,Try to guess the base type of a given array.N)rrrvra)rrr#r rarardrvs   zAdapter.guess_simple_base_typeFcs|durdSt|tr |St|tr"|j|}ttur!|d}n t|tr5|j r.| S|j |}n t|t t t tfrBt|}t|trQ|j|}d|St|tr\|rZdSdSt|trut|rm|dkrkdSd St|rsd S|St|tttfr|St|tr|j|rd nd }|d fdd|DSt|tr|jdd fdd|DSt|dd}|stdt||}t|ttfr||}|S)z>Adapt a value that is put into the SQL and needs to be quoted.NrrT'%s'truefalserz '-Infinity'z 'Infinity'z'NaN'z[%s]z ARRAY[%s]r!c3s |] }t|ddVqdS)T)nestedNrlrBr$rardr&z'Adapter.adapt_inline..rUc3s|] }t|VqdSr`rlrBr$rardr& __pg_repr__z Do not know how to adapt type %s)rrr r.r,rXrHrYrencoder>rMrKrLrNrr-rrrRrQrrurPr adapt_inliner'rcrbrrs)rcrr{rpg_reprrar$rdrsX                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. )rrrcparamsrarardparameter_listszAdapter.parameter_listc ss|gfS|rrtd|}tttfr`|r(|jfddD}n.|jrMtttfr.z!The values and types do not matchcsg|] \}}||qSrara)rrr rrardrscrrararrrardrrrc3s |] \}}||fVqdSr`ra)rrrrCrardr&sz'Adapter.format_query..c3s(|]}|||fVqdSr`)rur)rtypesrrardr& s c3s |] }||fVqdSr`rar)rrrardr&sz0The values must be passed as tuple, list or dict) ValueErrorrrrrcrrryrrWrfromkeysrtrsorted) rccommandrrinlinerliterals used_valuesrra)rrrrrd format_querysd           zAdapter.format_queryr`FNNF)8rkrlrmr frozensetr r3r6r)rIrZrJr[rr*r5r7rr9 _adapt_int _adapt_float _adapt_moneyr<r?rG_adapt_date_arrayrLrM_adapt_int_array_adapt_float_array_adapt_money_arrayrPrSr\rrhr`rVr rHrXrrrurrPrKrLrMrNrrrarvrrrrararardr st                #  - r cCsts|S|ddkS)zCast a boolean value.rr0)r0rrarard cast_bools rcCst}|s|S||S)zCast a JSON value.)r:)rcastrarard cast_jsonsrcCstpt|S)zCast a numeric value.)r3rrrarardcast_num'rcCsPt}|s|S|dkr||d}|dd}ddd|D}tp%t|S)zCast a money value.r (rrcss$|] }|s |dvr|VqdS)z.-N)isdigit)rcrarardr&4s"zcast_money..)r4rr'r3r)rpointrarard cast_money,s  rcCsdd|DS)zCast an int2vector value.cSg|]}t|qSrarrBrarardr:rz#cast_int2vector..)r rrarardcast_int2vector8rcCsh|dkrtjS|dkrtjS|}|ddkrtjS|d}t|dkr(tjS|}t||S)zCast a date value. -infinityinfinityBCr )rKminmaxr ry date_formatrMstrptimer connectionfmtrarard cast_date=s  rcCs$t|dkrdnd}t||S)zCast a time value.r %H:%M:%S.%f%H:%M:%S)ryrMrrL)rrrarard cast_timeQsrz (.*)([+-].*)cCsxt|}|r|\}}nd}t|dkrdnd}tr.|t|7}|d7}t||St||j t |dS)zCast a timetz value.rrrr%zrO) _re_timezonematchgroupsry _has_timezonerrMrtimetzrr)rrrrarard cast_timetzZs  rcCs|dkrtjS|dkrtjS|}|ddkrtjS|}|drRt|dkrR|dd}t|d d kr;tjS|d rBd nd t|ddkrMdnddg}nt|ddkr]tjS|t|ddkrhdndg}td |d |S)zCast a timestamp value.rrrr-%Yrxrwrr%d%d %b%b %drrr%Yrr ) rMrrr rrdryrrr'rrarardcast_timestampjs&  rcCs|dkrtjS|dkrtjS|}|ddkrtjS|}|dr]t|dkr]|dd}t|d d kr;tjS|d rBd nd t|ddkrMdnddg}|dd|d}}n>|drwt |d}|rt| \|d<}nd}n |dd|d}}t|ddkrtjS|t|ddkrdndg}t r| t || dtd|d|Std|d|jt|dS)zCast a timestamptz value.rrrrrrxrwNrrrrrrrrrz%Y-rrrrrr)rMrrr rrdryrrrrrrrrr'rr)rrrrrarardcast_timestamptzs@    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 Cs&t|}|r0dd|D}|ddk}dd|D}|\}}}}}}} |r/| }| } nt|}|rsdd|ddD|d }} |ddk}| rZd d|Dnd d|D}|\}}}}}}} |rr| }| } nt|}|rt|rd d|D}|d dk} dd|D}|\}}}}}}} | r| }| }| }| } nQt|}|rt|rdd|D}|ddk} |d dk} dd|D}|\}}}}}}} | r| }| }| r| }| }| }| } nt d||d|d|7}t ||||| dS)zCast an interval value.cSg|]}|pdqS0rardrarardrrz!cast_interval..rrcSrrarrrarardrrcSrrrarrarardrrNr cSsg|]}t| qSrarrrarardrcSrrarrrarardrrcSrrrarrarardrrrcSrrarrrarardrrcSrrrarrarardrrrcSrrarrrarardrrzCannot parse interval: %sim)rrrr microseconds) _re_interval_iso_8601rrr_re_interval_postgres_verbosegroup_re_interval_postgresany_re_interval_sql_standardrrN) rmsecs_agoyearsmonsrrminssecsusecsago hours_ago years_agorarard cast_intervalsj  &    rc@s eZdZdZidededededededed ed ed ed ed ede de de de de e e eeeeeeeeeed ZdZddZeddZddZd-ddZddZd-dd Z e!d!d"Z"e!d#d$Z#d%d&Z$d'd(Z%d)d*Z&d+d,Z'dS).r aDictionary 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. charbpcharrrvarcharrrint2int4serialint8oidrrjsonbfloat4float8) rrrKintervalrLr timestamp timestamptz int2vectorranyarrayr^Ncst|ts td|j|}|r|}||<|S|dr8|dd}|}|r6||<|S|}|rUfdd| D} |||}||<|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_rwNcsg|]}|jqSra)pgtyperBrbrardr/rz)Typecasts.__missing__..) rrHrdefaultsru_add_connectionrcreate_array_castrVrcreate_record_cast)rcr r base_castrkcastsrarbrdr s&       zTypecasts.__missing__c Cs6zt|}Wn ttfyYdSwd|ddvS)z9Check if a typecast function needs a connection argument.FrrwN)rrr)rrrarard_needs_connection4s  zTypecasts._needs_connectioncCs"|jr||s |St||jdS)z@Add a connection argument to the typecast function if necessary.)r)rrrW)rcrrarardr>szTypecasts._add_connectioncCs ||p|Sz6Get the typecast function for the given database type.ra)rcr defaultrarardruDr=z Typecasts.getcCs~t|tr|g}|dur!|D]}||d|d|dqdSt|s)td|D]}||||<|d|dq+dS);Set a typecast function for the specified database type(s).NrCast parameter must be callable)rrrcallablerr)rcr rr0rarardsetHs  z Typecasts.setcCs>|dur |dSt|tr|g}|D]}||dqdS)zReset the typecasts for the specified type(s) to their defaults. When no type is specified, all typecasts will be reset. N)rrrr)rcr r0rarardresetWs  zTypecasts.resetcCr:)z>Get the default typecast function for the given database type.)rru)rr rarard get_defaultds zTypecasts.get_defaultcCs~t|tr|g}|j}|dur$|D]}||d|d|dqdSt|s,td|D]}|||<|d|dq.dS)z?Set a default typecast function for the given database type(s).Nrr)rrrrrr)rr rrr0rarard set_defaultis  zTypecasts.set_defaultcCsiS)zReturn the fields for the given record type. This method will be replaced with the get_attnames() method of DbTypes. rarcr rarardrVzzTypecasts.get_attnamescCr )zwReturn the current date format. This method will be replaced with the dateformat() method of DbTypes. z%Y-%m-%drarbrarard dateformatrzTypecasts.dateformatcs|dfdd}|S)z1Create an array typecast for the given base cast.rcs |Sr`rar8basecastr(rardrrz)Typecasts.create_array_cast..castra)rcr rrar rdrszTypecasts.create_array_castcs&|dt||fdd}|S)z>Create a named record typecast for the given fields and casts.r^cs|Sr`rar8r*rr^rardrrz*Typecasts.create_record_cast..castrS)rcrfieldsrrrar rdrs zTypecasts.create_record_castr`)(rkrlrmrrHrr.rrur)rrrrrrrrrrrr[r(r*rrr rrrrurrr*rrrVr rrrararardr sl        r cCs t|S)z@Get the global typecast function for the given database type(s).)r rrjrarard get_typecast rcCst||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)r rrarard set_typecastsrc@seZdZdZeddZdS)rgaOClass 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 ||S)6Get names and types of the fields of a composite type.)rwrbrarardrks zDbType.attnamesN)rkrlrmrpropertyrkrararardrgsrgcspeZdZdZedZfddZddZddZ 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 moneycsZtt|t||_d|_t|_|j |j_ |j|j_ |j dkr(d|_ dSd|_ dS)z%Initialize type cache for connection.F:zSELECT oid, typname, typname::text::regtype, typtype, null as typcategory, typdelim, typrelid FROM pg_catalog.pg_type WHERE oid OPERATOR(pg_catalog.=) %s::regtypezSELECT oid, typname, typname::regtype, typtype, typcategory, typdelim, typrelid FROM pg_catalog.pg_type WHERE oid OPERATOR(pg_catalog.=) %s::regtypeN) superrrr,r-_db _regtypesr _typecastsrVrserver_version_query_pg_typer/ __class__rardrs    zDbTypes.__init__c Csn||vr||S|r dnt|}t|jr|n|} || _|| _|| _|| _|| _|| _|| _ || _ |j | _ | S)z3Create a PostgreSQL type name with additional info.r^) rirgrrrerregtypetyptypecategorydelimrelidrVrw) rcrrrrrr r!rer rarardrsz DbTypes.addcCs|z|jtd|f}|j||f}Wn ty d}Ynw|s)td||d}|j|}|||j<||j <|S)z8Get the type info from the database if it is not cached.$1NzType %s could not be foundr) rrrquery getresultrrtrrr)rcrr%rqr rarardr s   zDbTypes.__missing__NcCs"z||WSty|YSw)z&Get the type even if it is not cached.)rt)rcrrrarardrus   z DbTypes.getcCs8t|ts||}|sdS|jsdS|jj|jddS)rNF)with_oid)rrgrur!rrVrrarardrVs  zDbTypes.get_attnamescCr:r)rrurrarardr r=zDbTypes.get_typecastcCs|j||dS)rN)rr)rcr rrarardrrzDbTypes.set_typecastcCs|j|dS)z?Reset the typecast function for the specified database type(s).N)rrrrarardreset_typecastszDbTypes.reset_typecastcCsT|durdSt|ts||}|r|j}|r||nd}|r$|tur&|S||S)z:Cast the given value according to the given database type.N)rrgrurrrH)rcrr rrarardtypecasts   zDbTypes.typecastr`)rkrlrmrrr  _num_typesrrr rurVrrr&r' __classcell__rararrdrs    rz^[A-Za-z][_a-zA-Z0-9]*$ircCs~z$z td|ddjWWSty$ddt|D}td|jYWSwty>ddtt|D}td|jYSw)z>Get a namedtuple factory for row results with the given names.RowT)renamecSs0g|]\}}t|rt|s|nd|fqSz column_%d) _re_fieldnamerrUrmrarardr6s z _row_factory..cSsg|]}d|fqSr,ra)rrnrarardr;r)rT_makerrprrangery)namesrarard _row_factory/s  r1cCst|tjadS)zwChange the size of the namedtuple factory cache. If maxsize is set to None, the cache can grow without bound. N)r\r1rrrarardset_row_factory_size?sr2ccs(|}|D] }tt||VqdS)z0Get query result as an iterator of dictionaries.N) listfieldsrrW)r%r rrarard _dictiterJs r5ccs&t|}|D]}||Vq dS)z0Get query result as an iterator of named tuples.N)r1r3)r%rowr4rarard _namediterQs   r7cCst|t|S)z0Get next row from query result as a named tuple.)r1r3r}r$rarard _namednextXsr8ccs|D]}|dVqdS)z1Get query result as an iterator of scalar values.rNra)r%r4rarard _scalariter]s r9c@s0eZdZdZddZddZddZdd Zd S) _MemoryQueryz)Class that embodies a given query result.cCs||_t||_dS)z4Create query from given result rows and field names.N)resultrcr )rcr;r rarardrfsz_MemoryQuery.__init__cCr)z,Return the stored field names of this query.)r rbrarardr3kz_MemoryQuery.listfieldscCr)z'Return the stored result of this query.)r;rbrarardr$or<z_MemoryQuery.getresultcCrr`)rr;rbrarardrsrz_MemoryQuery.__iter__N)rkrlrmrrr3r$rrararardr:cs  r:cCs||}d|_|S)z3Return DatabaseError with empty sqlstate attribute.N)sqlstate)msgrrrarard _db_errorwsr?cC t|tS)zReturn InternalError.)r?rr>rarard _int_error~rrBcCr@)zReturn ProgrammingError.)r?rrArarard _prg_errorrrCc@sPeZdZdZ  dddZddZddZd d Zd d ZdddZ ddZ dS)r z;A PostgreSQL client-side asynchronous notification handler.NcCsB||_||_|p d||_d|_||_|duri}||_||_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)r.event stop_event listeningcallbackarg_dicttimeout)rcr.rDrGrHrIrErarardrs zNotificationHandler.__init__cCs |dSr`)unlistenrbrarard__del__rzNotificationHandler.__del__cCs&|jr||jd|_dSdS)z(Stop listening and close the connection.N)r.rJcloserbrarardrLs   zNotificationHandler.closecCs8|js|jd|j|jd|jd|_dSdS)z1Start listening for the event and the stop event.z listen "%s"TNrFr.r#rDrErbrarardlisten  zNotificationHandler.listencCs8|jr|jd|j|jd|jd|_dSdS)z0Stop listening for the event and the stop event.z unlisten "%s"FNrMrbrarardrJrOzNotificationHandler.unlistenFcCsB|jr|s|j}d|r|jn|j}|r|d|7}||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)rFr.rErDr#)rcr.stoppayloadr%rarardnotifys   zNotificationHandler.notifycCs||jdk}|s|jg}|jrv|s!t|gg|jdrh|jrc|j}|s,n7|\}}}||j|jfvrH| t d|j|j|f||jkrQ| |j j |||d| |j |js$|rgdSn | | d|jsdSdS)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")pidrDextraN)rNrIr.filenorFselect getnotifyrDrErJr?rHrrG)rcpollrlistnoticerDrSrTrarard__call__s:        zNotificationHandler.__call__)NNNN)NFN) rkrlrmrrrKrLrNrJrRr[rararardr s   r cOstjdtddt|i|S)z8Same as NotificationHandler, under the traditional name.z7pgnotify is deprecated, use NotificationHandler insteadrx) stacklevel)warningswarnDeprecationWarningr rrarardpgnotify sr`c@seZdZdZdZddZddZddZd d Zd d Z d dZ ddZ ddZ e ddZddZe eZddZddZddZddZdd Zd`d!d"ZeZd#d$ZeZd`d%d&ZeZd'd(Zd)d*Zd+d,Zdad.d/Zd0d1Z -dbd2d3Z!d4d5Z"d6d7Z#d`d8d9Z$d`d:d;Z%dcdd?Z'dad@dAZ(dddBdCZ)dedEdFZ*d`dGdHZ+dfdJdKZ,d`dLdMZ-d`dNdOZ.d`dPdQZ/d`dRdSZ0d`dTdUZ1d`dVdWZ2dgdXdYZ3  -dhdZd[Z4  -did\d]Z5 djd^d_Z6dS)kr z*Wrapper class for the _pg connection type.NcOs|st|dkr|d}n|st|dkr|d}nd}|r7t|tr(|j}nz|j}Wn ty6Ynw|rCt|drCt|dsSt|i|}||f|_ d|_ n||_ d|_ ||_|j|_ d|_ i|_ i|_i|_t||_t||_|jdkrd |_nd |_||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. rwr.rNr#TFra=SELECT a.attname, t.oid, t.typname, t.typname::text::regtype, t.typtype, null as typcategory, t.typdelim, t.typrelid FROM pg_catalog.pg_attribute a JOIN pg_catalog.pg_type t ON t.oid OPERATOR(pg_catalog.=) a.atttypid WHERE a.attrelid OPERATOR(pg_catalog.=) %s::regclass AND %s AND NOT a.attisdropped ORDER BY a.attnuma1SELECT a.attname, t.oid, t.typname, t.typname::regtype, t.typtype, t.typcategory, t.typdelim, t.typrelid FROM pg_catalog.pg_attribute a JOIN pg_catalog.pg_type t ON t.oid OPERATOR(pg_catalog.=) a.atttypid WHERE a.attrelid OPERATOR(pg_catalog.=) %s::regclass AND %s AND NOT a.attisdropped ORDER BY a.attnum)ryrurr r._cnxAttributeErrorhasattrr+_db_args _closeabledbnamer _attnames_pkeys _privilegesr adapterrdbtypesr_query_attnames set_cast_hookr'debug)rcrrr.rarardrsD           z DB.__init__cCs|jr t|j|Std)NConnection is not valid)r.rbrBrcrrarard __getattr__Vs zDB.__getattr__cCs0t|jj}||j|t|jt|Sr`)rr__dict__rdirr.r)rcattrsrarard__dir__]s  z DB.__dir__cCs ||S)z9Enter the runtime context. This will start a transaction.)beginrbrarardrefsz DB.__enter__cCs0|dur|dur|dur|dS|dS)z8Exit the runtime context. This will end the transaction.N)commitrollback)rcetevtbrarardrjks  z DB.__exit__cCszz|j}Wn tyd}Ynw|r9z|dWn ty#Ynw|jr;z|WdSty8YdSwdSdSr`)r.rbrmrrerLrr/rarardrKrs&    z DB.__del__cGs|jr>ddd|D}t|jtrt|j|dSt|jdr,|j|ddSt|jr8||dSt|dSdS)zPrint a debug message css|]}t|VqdSr`rl)rrprarardr&rDzDB._do_debug..writeN)rnr'rrprintrcr}r)rcrrrarard _do_debugs    z DB._do_debugcCsd|vr ||}|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_identifierrcrrarard_escape_qualified_names zDB._escape_qualified_namecCstrt|S|r dSdS)z%Get boolean value corresponding to d.r0r1)r0r)rrarard _make_boolsz DB._make_boolcCsdddt|dDS)z'Create a human readable parameter list., css |] \}}d||fVqdS)z$%d=%rNrarmrarardr&r|z"DB._list_params..rw)r'rprrarard _list_paramsszDB._list_paramscCstpt|S)z.Decode a JSON string coming from the database.)r: jsondecoderrarard decode_jsonrzDB.decode_jsoncCst|S)z(Encode a JSON string for use within SQL.) jsonencode)rcrrarardr>rzDB.encode_jsoncCsL|j}|r"z|dWn tyYnw|jr|d|_dStd)zClose the database connection.NConnection already closed)r.rmrrerLrBr/rarardrLs  zDB.closecCs|jr |jdStd)zReset connection with current parameters. All derived queries and large objects derived from this connection will not be usable after this call. rN)r.rrBrbrarardrszDB.resetcCs`|jr*t|jdi|jd}|jr|jd|j||jj||_dS|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. rrwN)rer+rdr.rmrLrkr'r/rarardreopens    z DB.reopencCd}|r |d|7}||S)zBegin a transaction.BEGINrr#)rcmodeqstrrarardrv  zDB.begincCs |dS)zCommit the current transaction.COMMITrrbrarardrwrz DB.commitcCr)z"Roll back the current transaction.ROLLBACKz TO r)rcrrrarardrxrz DB.rollbackcC|d|S)z6Define a new savepoint within the current transaction.z SAVEPOINT rrprarard savepointrz DB.savepointcCr)z'Destroy a previously defined savepoint.zRELEASE rrprarardreleaserz DB.releasecCsVt|tr |g}d}n t|ttfrg}nt|ttfri}n t|tr'|}ntd|s1tdt|tr8ing}|D]>}t|trI| nd}|sQtd|dkrkd}|j | }tdd|D}|St|tru|||<q<| |q<|D]+}d |f}|j | d d }|dur|}q}t|tr| |q}||||<q}|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. N1The parameter must be a string, list, set or dictNo parameter has been specifiedInvalid parameterallzSHOW ALLcss|] }|ddVqdS)Nrxrarrarardr&)r}z#DB.get_parameter..zSHOW %sr)rrrrcrrrrstripr2r.r#r$r)rc parameterrrrrr%rrarard get_parametersR       zDB.get_parameterFcCst|tr ||i}nat|ttfr't|ttfr tt||}nKt||}nDt|ttfrYt|ttttfrEt|}t |dkrE| }|dusRt|tsRt dt||}nt|trg|durft dnt d|sqt di}| D]-\}}t|tr|nd}|st d|dkr|durt d ddi}n|||<qw|rd nd }| D]!\}}|durd ||f}nd |||f}|||j|qdS)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. rwNz8A single value must be specified when parameter is a setz szDB.pkey..)rcss|]}|dVqdS)rNrarr6rarardr&rDzDB.pkey..) rhrrrtrr.r#r$ryrrcr)rcr compositeflushpkeyspkeyr%rarrdrs0          zDB.pkeycCsdd|jdDS)z$Get list of databases in the system.cSrrra)rrrarardrrz$DB.get_databases..z*SELECT datname FROM pg_catalog.pg_database)r.r#r$rbrarard get_databasess zDB.get_databasescCslg}|r|dddd|D|s|d|r#dd|nd}d |}d d |j|DS) 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)r!css|]}d|VqdS)rxNrarr"rarardr&(rDz#DB.get_relations..z?s.nspname NOT SIMILAR TO 'pg/_%|information/_schema' ESCAPE '/'z WHERE %s AND raSELECT pg_catalog.quote_ident(s.nspname) OPERATOR(pg_catalog.||) '.' OPERATOR(pg_catalog.||) pg_catalog.quote_ident(r.relname) FROM pg_catalog.pg_class r JOIN pg_catalog.pg_namespace s ON s.oid OPERATOR(pg_catalog.=) r.relnamespace%s ORDER BY s.nspname, r.relnamecSrrra)rr4rarardr3rz$DB.get_relations..)rr'r.r#r$)rckindssystemwherer%rarard get_relationss  zDB.get_relationscCs |d|S)zReturn list of tables in connected database. Set the system flag if you want to get the system tables as well. r4)r)rcrrarard get_tables5s z DB.get_tablesTcs|j}|r||dz||}W|StyOd}|r$d|}|jtd||f}|j||f}|j fdd|D}t |}|||<Y|Sw)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 OPERATOR(pg_catalog.>) 0z.(%s OR a.attname OPERATOR(pg_catalog.=) 'oid')r"c3s*|]}|dj|ddfVqdS)rrwNr)rrrrardr&Ws(z"DB.get_attnames..) rgrrrtrlrr.r#r$rkr)rcrr%rrkr0r%rarrdrV<s&    zDB.get_attnamescCsD|dur|jjSt|}||jjkr ||j_|j|j|S)z;Use registered type names instead of simplified type names.N)rkrrrgr)rcregtypesrarard use_regtypes\s   zDB.use_regtypesrVcCs|j}|r||d|}z |||f}W|StyIdtd|f}|j|||f}|dd| dk}||||f<Y|Sw)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 pg_catalog.has_table_privilege(%s, $2)r"rT) rirrr2rtrr.r#r$r)rcr privileger privilegesretr%rarardhas_table_privilegehs"  zDB.has_table_privilegec s0|dr |dd}||dvrt|nd}|r&t|tr&|f}|r;ttr;|vr;dvr;|d<|s|z||d}Wntyb|rZttrZdvrZd}nt d|Ynwttr|t | s||rxdvrxd}ntdttstt t fsgt|tkrtd tt||j}|j|j|rd nd}d fd d |D}dvr|rʈd|<d=d||||f}||||j||}|} | s|dd}td||||f| dD]\} } |r| dkr|} | | <qS)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. rNrrTrrz*Missing value in row for specified keynamez,Differing number of items in keyname and rowoid, *rc3.|]}d|||fVqdSz%s OPERATOR(pg_catalog.=) %sNrarrrkcolr6rardr& zDB.get..z"SELECT %s FROM %s WHERE %s LIMIT 1zOPERATOR(pg_catalog.=)=z%No such record in %s where %s with %sr)rdrstriprVrrrrrrtrCrissubsetrcrryrWrjrrrr'rrr.r# dictresultrr?rr) rcrr6keynameqoidrwhatrr%rqrnrrarrdru}st               zDB.getcKsP|dr |dd}|duri}||d|vr|d=||}d|vr,t|nd}|j}|j}|j}gg} } |D]} | |vrY| || | ||| || q@| s`t dd | d | } } |rodnd} d| || | | f} | | ||j| |} | }|r|d D]\} }|r| dkr|} ||| <q|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. rNrrz$No column found that can be insertedrrz,INSERT INTO %s (%s) VALUES (%s) RETURNING %sr)rdrrrVrrjrrrrrCr'rrr.r#rr)rcrr6rrkrrrrr0rrnrr%rqrrarardinsertsD         z DB.insertc s|dr |dd}||dvrt|nd}dur#indvr*d=||r?|vr?dvr?|d<|rHdvrHd}n!z||d}Wn ty]td|wt| sitd|j }|j |j d fd d |D}dvr|rd|<d=g}t|}D]} | vr| |vr|d | | | fq|sSd |}|rdnd} d||||| f} || ||j| |} | } | r| dD]\} } |r| dkr|} | | <qS)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. rNrrrTr$Missing value for primary key in rowrc3rrrarrrardr& rzDB.update..%s = %srrz&UPDATE %s SET %s WHERE %s RETURNING %sr)rdrrVrrrrtrCrrrjrrrr'rrrr.r#rr)rcrr6rrrrrrrnrr%rqrrarrdrsh         $     z DB.updatec s\|dr |dd}|duri}d|vr|d=d|vr!|d=||}d|vr.t|nd}|j}|j}|jggg}} } |D]} | |vr^|| | ||| || qEd |d | }} z| |d} Wn t yt d|wd fdd | D} g}t | } | d|D]$} | | vr|| d}|rt|tsd | }|d | |fq| s|S|rd d |nd }|rdnd}d|||| | ||f}|||z |j||}Wnty|jdkrt dw|}|r&|dD]\} }|r| dkr|} ||| <q|S||||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. rNrrrTrc3rAr`rarrrardr&x rDzDB.upsert..z excluded.%srz update set %snothingrzOINSERT INTO %s AS included (%s) VALUES (%s) ON CONFLICT (%s) DO %s RETURNING %siaz7Upsert operation is not supported by PostgreSQL versionr)rdrrVrrjrrrrr'rrtrCrrurrrrr.r#rrrr)rcrr6rrkrrrr0rupdatesrnrtargetrrdorr%rqrarrdupsert6 s +              z DB.upsertcCsp|duri}||}|D]&\}}|dkrq|j}|tjvr%d||<q|dkr1|d||<qd||<q|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. NrrrFr)rVrrerr(r)rcrr6rkrnr0rarardr s     zDB.clearc  sX|dr |dd}||dvrt|nd}dur#indvr*d=||r?|vr?dvr?|d<|rHdvrHd}n!z||d}Wn ty]td|wt| sitd|j }|j |j d fd d |D}dvr|rd|<d=d |||f}||||j||} 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. rNrrrTrrrc3rrrarrrardr& rzDB.delete..zDELETE FROM %s WHERE %s)rdrrVrrrrtrCrrrjrrrr'rrr.r#r) rcrr6rrrrrr%rqrarrddelete sH           z DB.deletec Cszt|tr ||i}|g}n/t|ttfr*t|ttfr#tt||}nt||}nt|ttfr8t||}nt d|dusKt|t t fsKt d|dusZt|t t fsZt dg}|D]9}| |}|dustt|t t fstt d| dr|rtd|dd}||}|rd |}||q^d d |g}|r|d |r|d d|}|||j|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 optionsrzONLY %sTRUNCATErzRESTART IDENTITYCASCADEr)rrrrcrrWrrrrrrrurdrrrrr'rr.r#) rcrrestartcascadeonlytablesr0ur%rarardtruncate sJ          z DB.truncatec Csl|std|rt|ttfrdtt|}|dur|}nd}d|d|g}|r>t|ttfr7dtt|}|d|g|durkz||d }Wn t t fyjz t| |}Wn t t fygYnwYnw|rt|ttfr|dtt|}|d |g|r| d ||r| d |d |}| ||j|}|} | r|rdd| D} | S)aGet a table as a list. This gets a convenient representation of the table as a list of named tuples in Python. You only need to pass the name of the table (or any other SQL expression returning rows). Note that by default this will return the full content of the table which can be huge and overflow your memory. However, you can control the amount of data returned using the other optional parameters. The parameter 'what' can restrict the query to only return a subset of the table columns. It can be a string, list or a tuple. The parameter 'where' can restrict the query to only return a subset of the table rows. It can be a string, list or a tuple of SQL expressions that all need to be fulfilled. The parameter 'order' specifies the ordering of the rows. It can also be a other string, list or a tuple. If no ordering is specified, the result will be ordered by the primary key(s) or all columns if no primary key exists. You can set 'order' to False if you don't care about the ordering. The parameters 'limit' and 'offset' can be integers specifying the maximum number of rows returned and a number of rows skipped over. If you set the 'scalar' option to True, then instead of the named tuples you will get the first items of these tuples. This is useful if the result has only one column anyway. The table name is missingrNrSELECTFROMrWHERETORDER BYLIMIT %d OFFSET %drcSrrrarrarardr] rz"DB.get_as_list..)rrrrcr'maprHextendrrtrrVrrr.r# namedresult) rcrrrorderlimitrscalarr%rqrarard get_as_list sP    zDB.get_as_listc  s|std|s z||d}Wnttfytd|wt|tr)|g}n t|ttfs4td|rLt|ttfrEd t t |}|durK|}nd}d|d |g} |rlt|ttfred t t |}| d |g|durr|}|rt|ttfrd t t |}| d |g|r| d ||r| d|d | } || |j| } | } |rtnt} | s| St|| } | stdgg} t| D]\}}|vr| n |qt| dk}t| }t || }|rddd}ntdk}|s |rt}n dfdd}d}t || }|s'|rD|r1tt||}|rDfdd| 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. rTrz+The keyname must be a string, list or tuplerNrrrrrrrrrzMissing keyname in rowrwFrcs |fSr`rar)rowindrardr s z DB.get_as_dict..csg|]}|vr|qSrara)rr1)keysetrardr rz"DB.get_as_dict..)rrrtrrCrrrrcr'rrHrrrr.r#r$rrrr3rrpryrVr7r:rW)rcrrrrrrrrr%rqrr keyindir1keytuplegetkeyrrowtuplegetrowrowsra)rrrd get_as_dict` s                  zDB.get_as_dictcCst||||||S)z:Get notification handler that will run the given callback.)r )rcrDrGrHrIrErarardnotification_handler s zDB.notification_handlerr`)NFr)FFr)TF)rVF)FFF)NNNNNF)NNNNNNF)NNN)7rkrlrmrr.rrqrurerjrKrrrrrr.rr>rLrrrvstartrwendrxabortrrrrr#rrrrrrrrrrVrrrurrrrrrrrrrararardr sv>      :G   ,     M . > g  18 B \r __main__zPyGreSQL versionr)rn)r __future__rr_pg ImportErrorossysr version_infoenvironr pathseppathexistsr'add_dll_directoryabspathrIrJ__all__rVr]r,rMrKrLrNrOdecimalrPmathrQrR collectionsrTkeywordrUoperatorrV functoolsrWrerXr)rrYrrZrrr[ru NameErrorrrrHrXr\r]_threadr^rrrinspectrrrrutcrrrrrrrirrrr rrrr rrrrrrrrrrrrrrrrr rrrgrr-r1r2r5r7r8r9r:rr?rBrCr?rGrHrr r`r rkr~rararards<                T:   k % ; m   y  :