U
    f3G                     @   s  d Z ddlZddlZddlZddlmZ ddlmZ ddlm	Z	 ddl
mZ ddl
mZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZ z.zddlZW n ek
r   ddlZY nX W n ek
r   e	dY nX dd Ze dk re	dej  de   kr*dk r>n ne	dej  ddl!m"Z"m#Z# e#rddlm$Z$m%Z% ddl&m'Z' ddl!m(Z(m)Z) e$j*d j+Z,nRddl-Zddl.Zej/0eej/j1 ej23  dZ4ej/5e4fdej/j6Z7ej/8e7 ddl9m:Z: ddl;m<Z< dd l=m>Z> dd!l?m@Z@ dd"lAmBZB dd#lCmDZD d$d% ZEG d&d' d'eZFe#rG d(d) d)ZGG d*d+ d+eGejHZIG d,d- d-eGejJZHG d.d/ d/eZnej/jKZHG d0d/ d/eZdS )1zY
PostgreSQL database backend for Django.

Requires psycopg2 >= 2.8.4 or psycopg >= 3.1.8
    N)contextmanager)settings)ImproperlyConfigured)DatabaseError)connections)BaseDatabaseWrapperCursorDebugWrapper)async_unsafe)cached_property)
SafeString)get_version_tuplez(Error loading psycopg2 or psycopg modulec                  C   s   t jddd } t| S )N    r   )Database__version__splitr   )version r   F/tmp/pip-unpacked-wheel-_jot26k8/django/db/backends/postgresql/base.pypsycopg_version    s    r   )         z6psycopg2 version 2.8.4 or newer is required; you have )   )r   r   r   z5psycopg version 3.1.8 or newer is required; you have r   )IsolationLevelis_psycopg3)adapterssql)Format)get_adapters_templateregister_tzloaderZtimestamptzi  	INETARRAY)DatabaseClient)DatabaseCreation)DatabaseFeatures)DatabaseIntrospection)DatabaseOperations)DatabaseSchemaEditorc                 C   s   | d d krdS d|  S )N
max_lengthZvarcharvarchar(%(max_length)s)r   )datar   r   r   _get_varchar_columnS   s    r,   c                       s\  e Zd ZdZdZddddeddd	d
dddddddddddddddddddZddddZddddZddddddddd d!ddddd"Z	d#Z
d$d%d&d'd(d)d*ZeZeZeZeZeZeZeZd+Zd,d- Zd.d/ Zed0d1 Zd2d3 Zd4d5 Z fd6d7Z edKd9d:Z!d;d< Z"ed=d> Z#d?d@ Z$dLdAdBZ%dCdD Z&e' fdEdFZ(e)dGdH Z*dIdJ Z+  Z,S )MDatabaseWrapper
postgresqlZ
PostgreSQLintegerZbigintZbyteabooleandateztimestamp with time zonez+numeric(%(max_digits)s, %(decimal_places)s)intervalr*   zdouble precisionZinetZjsonbZsmallinttexttimeuuid)	AutoFieldBigAutoFieldZBinaryFieldZBooleanFieldZ	CharFieldZ	DateFieldZDateTimeFieldZDecimalFieldZDurationFieldZ	FileFieldZFilePathFieldZ
FloatFieldZIntegerFieldZBigIntegerFieldZIPAddressFieldZGenericIPAddressFieldZ	JSONFieldZOneToOneFieldPositiveBigIntegerFieldPositiveIntegerFieldPositiveSmallIntegerFieldZ	SlugFieldSmallAutoFieldZSmallIntegerFieldZ	TextFieldZ	TimeFieldZ	UUIDFieldz"%(column)s" >= 0)r8   r9   r:   z GENERATED BY DEFAULT AS IDENTITY)r6   r7   r;   z= %sz= UPPER(%s)zLIKE %szLIKE UPPER(%s)z~ %sz~* %sz> %sz>= %sz< %sz<= %s)exactZiexactcontains	icontainsregexZiregexgtZgteltZlte
startswithendswithistartswith	iendswithzKREPLACE(REPLACE(REPLACE({}, E'\\', E'\\\\'), E'%%', E'\\%%'), E'_', E'\\_')zLIKE '%%' || {} || '%%'zLIKE '%%' || UPPER({}) || '%%'zLIKE {} || '%%'zLIKE UPPER({}) || '%%'zLIKE '%%' || {}zLIKE '%%' || UPPER({}))r=   r>   rB   rD   rC   rE   r   c                 C   s   t | jdS )zo
        Return a tuple of the database's version.
        E.g. for pg_version 120004, return (12, 4).
        i'  )divmod
pg_versionselfr   r   r   get_database_version   s    z$DatabaseWrapper.get_database_versionc                 C   st  | j }|d dkr,|di ds,tdt|d p8d| j krjtd|d t|d | j f ddi}|d rd	|d i|d }n<|d d kr|di dd  d	d
i|d }n
|d }|dd  |dd  |dd  |d r|d |d< |d r|d |d< |d r2|d |d< |d rH|d |d< trptt	j
| j|d< |dd |d< |S )NNAME OPTIONSZservicez`settings.DATABASES is improperly configured. Please supply the NAME or OPTIONS['service'] value.zThe database name '%s' (%d characters) is longer than PostgreSQL's limit of %d characters. Supply a shorter NAME in settings.DATABASES.Zclient_encodingUTF8Zdbnamepostgresassume_roleisolation_levelserver_side_bindingUSERuserZPASSWORDpasswordZHOSThostZPORTportcontextZprepare_threshold)settings_dictgetr   lenopsZmax_name_lengthpopr   r    r   USE_TZtimezone)rI   rY   conn_paramsr   r   r   get_connection_params   s`    

 




  z%DatabaseWrapper.get_connection_paramsc                 C   s   | j d }d}z|d }W n tk
r6   tj| _Y n:X zt|| _d}W n$ tk
rn   td| dY nX | jjf |}|r| j|_t	r|
ddkrtnt|_ntjj|dd	 d
 t|_|S )NrM   FrQ   Tz$Invalid transaction isolation level z9 specified. Use one of the psycopg.IsolationLevel values.rR   c                 S   s   | S Nr   )xr   r   r   <lambda>      z4DatabaseWrapper.get_new_connection.<locals>.<lambda>)Zconn_or_cursloads)rY   KeyErrorr   ZREAD_COMMITTEDrQ   
ValueErrorr   r   connectr   rZ   ServerBindingCursorCursorZcursor_factorypsycopg2extrasZregister_default_jsonb)rI   r`   optionsZset_isolation_levelZisolation_level_value
connectionr   r   r   get_new_connection   s6    



	 z"DatabaseWrapper.get_new_connectionc              	   C   s`   | j d krdS | j jd}| j}|r\||kr\| j  }|| j |g W 5 Q R X dS dS )NFZTimeZoneT)ro   infoZparameter_statustimezone_namecursorexecuter\   Zset_time_zone_sql)rI   Zconn_timezone_namerr   rs   r   r   r   ensure_timezone   s    
zDatabaseWrapper.ensure_timezonec              	   C   s^   | j d krdS | jdi d }rZ| j   }| jd|g}|| W 5 Q R X dS dS )NFrM   rP   zSET ROLE %sT)ro   rY   rZ   rs   r\   Zcompose_sqlrt   )rI   Znew_rolers   r   r   r   r   ensure_role+  s    
zDatabaseWrapper.ensure_rolec                    s8   t    |  }|  }|s"|r4|  s4| j  d S rb   )superinit_connection_stateru   rv   Zget_autocommitro   commit)rI   Z	commit_tzZcommit_role	__class__r   r   rx   5  s
    
z%DatabaseWrapper.init_connection_stateNc                 C   sl   |r| j j|d| j jd}n
| j  }trV| j jttj}| j	|j	krht
| j	| ntjrb| jnd |_|S )NF)Z
scrollableZwithhold)ro   rs   
autocommitr   r   
get_loaderTIMESTAMPTZ_OIDr   ZTEXTr_   r!   r   r^   tzinfo_factory)rI   namers   Ztzloaderr   r   r   create_cursorB  s      
zDatabaseWrapper.create_cursorc                 C   s   | j S rb   )r_   )rI   offsetr   r   r   r   W  s    zDatabaseWrapper.tzinfo_factoryc                 C   sh   |  j d7  _ zt }W n tk
r2   d }Y nX |rFtt|}nd}| jdt j	|| j f dS )Nr   syncz_django_curs_%d_%s_%d)r   )
_named_cursor_idxasynciocurrent_taskRuntimeErrorstridZ_cursor	threadingcurrent_threadident)rI   r   Z
task_identr   r   r   chunked_cursorZ  s     
zDatabaseWrapper.chunked_cursorc              	   C   s   | j  || j_W 5 Q R X d S rb   )Zwrap_database_errorsro   r|   )rI   r|   r   r   r   _set_autocommitv  s    zDatabaseWrapper._set_autocommitc              	   C   s,   |   }|d |d W 5 Q R X dS )zl
        Check constraints by setting them to immediate. Return them to deferred
        afterward.
        zSET CONSTRAINTS ALL IMMEDIATEzSET CONSTRAINTS ALL DEFERREDN)rs   rt   )rI   Ztable_namesrs   r   r   r   check_constraintsz  s    

z!DatabaseWrapper.check_constraintsc              	   C   sF   z$| j  }|d W 5 Q R X W n tjk
r<   Y dS X dS d S )NzSELECT 1FT)ro   rs   rt   r   ErrorrI   rs   r   r   r   	is_usable  s    zDatabaseWrapper.is_usablec                 #   s   d }z t   }|V  W 5 Q R X W n tjtfk
r   |d k	rD tdt t	 D ]j}|j
dkrX|jd dkrX| j| jd|jd i| jd}z| }|V  W 5 Q R X W 5 |  X  qqX Y nX d S )Na8  Normally Django will use a connection to the 'postgres' database to avoid running initialization queries against the production database when it's not needed (for example, when running tests). Django was unable to create a connection to the 'postgres' database and will use the first PostgreSQL database instead.r.   rK   rO   )alias)rw   _nodb_cursorr   r   WrappedDatabaseErrorwarningswarnRuntimeWarningr   allvendorrY   r{   r   closers   )rI   rs   ro   connrz   r   r   r     s:     

zDatabaseWrapper._nodb_cursorc              
   C   s*   |    | jjjW  5 Q R  S Q R X d S rb   )Ztemporary_connectionro   rq   Zserver_versionrH   r   r   r   rG     s    
zDatabaseWrapper.pg_versionc                 C   s
   t || S rb   r   r   r   r   r   make_debug_cursor  s    z!DatabaseWrapper.make_debug_cursor)N)N)-__name__
__module____qualname__r   Zdisplay_namer,   
data_typesZdata_type_check_constraintsZdata_types_suffix	operatorsZpattern_escZpattern_opsr   r(   ZSchemaEditorClassr#   Zclient_classr$   Zcreation_classr%   Zfeatures_classr&   Zintrospection_classr'   Z	ops_classr   rJ   ra   r
   rp   ru   rv   rx   r   r   r   r   r   r   r   r   r   rG   r   __classcell__r   r   rz   r   r-   Y   s   	8
)


	
%
r-   c                   @   s   e Zd ZdZdddZdS )CursorMixinzE
        A subclass of psycopg cursor implementing callproc.
        Nc                 C   s   t |tjst|}td|tdg}|r`|D ]$}|t| |td q4|d= |td t|}| | |S )NzSELECT * FROM (,))
isinstancer   Z
IdentifierZSQLappendLiteralZComposedrt   )rI   r   argsZqpartsitemZstmtr   r   r   callproc  s    


zCursorMixin.callproc)N)r   r   r   __doc__r   r   r   r   r   r     s   r   c                   @   s   e Zd ZdS )rj   Nr   r   r   r   r   r   r   rj     s   rj   c                   @   s   e Zd ZdS )rk   Nr   r   r   r   r   rk     s   rk   c                   @   s   e Zd Zdd ZdS )r	   c              
   C   s.   |  | | j|W  5 Q R  S Q R X d S rb   )	debug_sqlrs   copy)rI   Z	statementr   r   r   r     s    zCursorDebugWrapper.copyN)r   r   r   r   r   r   r   r   r	     s   r	   c                   @   s   e Zd Zdd Zdd ZdS )r	   c              
   G   s6   |  |" | jj||f| W  5 Q R  S Q R X d S rb   )r   rs   copy_expert)rI   r   filer   r   r   r   r     s    zCursorDebugWrapper.copy_expertc              
   O   s>   | j d| d$ | jj||f||W  5 Q R  S Q R X d S )NzCOPY %s TO STDOUT)r   )r   rs   copy_to)rI   r   tabler   kwargsr   r   r   r     s    zCursorDebugWrapper.copy_toN)r   r   r   r   r   r   r   r   r   r	     s   )Lr   r   r   r   
contextlibr   Zdjango.confr   Zdjango.core.exceptionsr   Z	django.dbr   r   r   Zdjango.db.backends.base.baser   Zdjango.db.backends.utilsr	   ZBaseCursorDebugWrapperZdjango.utils.asyncior
   Zdjango.utils.functionalr   Zdjango.utils.safestringr   Zdjango.utils.versionr   Zpsycopgr   ImportErrorrl   r   r   Zpsycopg_anyr   r   r   r   Z
psycopg.pqr   r    r!   typesoidr~   Zpsycopg2.extensionsZpsycopg2.extras
extensionsZregister_adapterQuotedStringrm   Zregister_uuidZINETARRAY_OIDZnew_array_typeUNICODEr"   Zregister_typeclientr#   Zcreationr$   featuresr%   Zintrospectionr&   
operationsr'   Zschemar(   r,   r-   r   rk   rj   ZClientCursorrs   r   r   r   r   <module>   s   


  e