U
    eG                     @   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-lctamlir/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   s  | j }|d dkr,|di ds,tdt|d p8d| j krjtd|d t|d | j f |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d }|dtr
|dkr
t	nt
 |d r&|d |d< |d r<|d |d< |d rR|d |d< |d rh|d |d< trt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dbnamepostgresUTF8Zclient_encodingassume_roleisolation_levelserver_side_bindingZcursor_factoryTUSERuserZPASSWORDpasswordZHOSThostZPORTportcontextZprepare_threshold)settings_dictgetr   lenopsZmax_name_lengthpop
setdefaultr   ServerBindingCursorCursorr    r   USE_TZtimezone)rI   rY   conn_paramsrR   r   r   r   get_connection_params   sp    

 




  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	st
jj|dd d	 |S )
NrM   FrQ   Tz$Invalid transaction isolation level z9 specified. Use one of the psycopg.IsolationLevel values.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   psycopg2extrasZregister_default_jsonb)rI   rc   optionsZset_isolation_levelZisolation_level_value
connectionr   r   r   get_new_connection   s,    



 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)rp   infoZparameter_statustimezone_namecursorexecuter\   Zset_time_zone_sql)rI   Zconn_timezone_namers   rt   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)rp   rY   rZ   rt   r\   Zcompose_sqlru   )rI   Znew_rolert   r   r   r   r   ensure_role*  s    
zDatabaseWrapper.ensure_rolec                    s8   t    |  }|  }|s"|r4|  s4| j  d S re   )superinit_connection_staterv   rw   Zget_autocommitrp   commit)rI   Z	commit_tzZcommit_role	__class__r   r   ry   4  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)rp   rt   
autocommitr   r   
get_loaderTIMESTAMPTZ_OIDr   ZTEXTrb   r!   r   ra   tzinfo_factory)rI   namert   Ztzloaderr   r   r   create_cursorA  s      
zDatabaseWrapper.create_cursorc                 C   s   | j S re   )rb   )rI   offsetr   r   r   r   V  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_cursorY  s     
zDatabaseWrapper.chunked_cursorc              	   C   s   | j  || j_W 5 Q R X d S re   )Zwrap_database_errorsrp   r}   )rI   r}   r   r   r   _set_autocommitu  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)rt   ru   )rI   Ztable_namesrt   r   r   r   check_constraintsy  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)rp   rt   ru   r   ErrorrI   rt   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   rN   )alias)rx   _nodb_cursorr   r   WrappedDatabaseErrorwarningswarnRuntimeWarningr   allvendorrY   r|   r   closert   )rI   rt   rp   connr{   r   r   r     s:     

zDatabaseWrapper._nodb_cursorc              
   C   s*   |    | jjjW  5 Q R  S Q R X d S re   )Ztemporary_connectionrp   rr   Zserver_versionrH   r   r   r   rG     s    
zDatabaseWrapper.pg_versionc                 C   s
   t || S re   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   rd   r
   rq   rv   rw   ry   r   r   r   r   r   r   r   r   r   rG   r   __classcell__r   r   r{   r   r-   Y   s   	>
"


	
%
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Composedru   )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 )r_   Nr   r   r   r   r   r   r   r_     s   r_   c                   @   s   e Zd ZdS )r`   Nr   r   r   r   r   r`     s   r`   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 re   )	debug_sqlrt   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 re   )r   rt   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   rt   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   ImportErrorrm   r   r   Zpsycopg_anyr   r   r   r   Z
psycopg.pqr   r    r!   typesoidr   Zpsycopg2.extensionsZpsycopg2.extras
extensionsZregister_adapterQuotedStringrn   Zregister_uuidZINETARRAY_OIDZnew_array_typeUNICODEr"   Zregister_typeclientr#   Zcreationr$   featuresr%   Zintrospectionr&   
operationsr'   Zschemar(   r,   r-   r   r`   r_   ZClientCursorrt   r   r   r   r   <module>   s   


  d