U
    e_                     @   s|   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 G d
d deZdS )    N)Decimal)Apps)NotSupportedError)BaseDatabaseSchemaEditor)	Statement)strip_quotes)UniqueConstraint)atomicc                       s   e Zd ZdZdZdZeZdZdZdZ	dZ
dZ fddZ fd	d
Zdd Zdd Zd)ddZd* fdd	Zd+ fdd	Zd,ddZd- fdd	Z fddZ fddZd.dd Zd!d" Z fd#d$Z fd%d&Zd'd( Z  ZS )/DatabaseSchemaEditorzDROP TABLE %(table)sNzEREFERENCES %(to_table)s (%(to_column)s) DEFERRABLE INITIALLY DEFERREDz,ALTER TABLE %(table)s DROP COLUMN %(column)sz7CREATE UNIQUE INDEX %(name)s ON %(table)s (%(columns)s)zDROP INDEX %(name)sc                    s   | j  stdt  S )NzSQLite schema editor cannot be used while foreign key constraint checks are enabled. Make sure to disable them before entering a transaction.atomic() context because SQLite does not support disabling them in the middle of a multi-statement transaction.)
connectiondisable_constraint_checkingr   super	__enter__self	__class__ E/tmp/pip-unpacked-wheel-lctamlir/django/db/backends/sqlite3/schema.pyr      s
    
zDatabaseSchemaEditor.__enter__c                    s(   | j   t ||| | j   d S N)r   Zcheck_constraintsr   __exit__enable_constraint_checking)r   exc_type	exc_value	tracebackr   r   r   r   '   s    
zDatabaseSchemaEditor.__exit__c                 C   s   zdd l }||}W n( tk
r*   Y n |jk
r>   Y nX t|trVtt|S t|tt	tfrnt|S t|trd|
dd S |d krdS t|tttfrd|  S td|t|f d S )Nr   z'%s''z''ZNULLzX'%s'z*Cannot quote parameter value %r of type %s)sqlite3ZadaptImportErrorZProgrammingError
isinstanceboolstrintr   floatreplacebytes	bytearray
memoryviewhex
ValueErrortype)r   valuer   r   r   r   quote_value,   s(    

z DatabaseSchemaEditor.quote_valuec                 C   s
   |  |S r   )r+   )r   r*   r   r   r   prepare_defaultK   s    z$DatabaseSchemaEditor.prepare_defaultFc           	   	   C   s   | j  x}| j j|D ]b}|r.|j|kr.q| j j||j}| D ]2\}}||krH|dksh||krH  W 5 Q R  dS qHqW 5 Q R X dS )a  
        Return whether or not the provided table name is referenced by another
        one. If `column_name` is specified, only references pointing to that
        column are considered. If `ignore_self` is True, self-referential
        constraints are ignored.
        NTF)r   cursorZintrospectionZget_table_listnameZget_relationsvalues)	r   
table_nameZcolumn_nameignore_selfr-   Zother_tableZ	relationsZconstraint_columnZconstraint_tabler   r   r   _is_referenced_by_fk_constraintN   s     	  z4DatabaseSchemaEditor._is_referenced_by_fk_constraintTc                    sf   | j jjsR|rR| |rR| j jr,td| | j   t ||| | j 	  nt ||| d S )NzRenaming the %r table while in a transaction is not supported on SQLite < 3.26 because it would break referential integrity. Try adding `atomic = False` to the Migration class.)
r   features!supports_atomic_references_renamer2   in_atomic_blockr   r   r   alter_db_tabler   )r   modelZold_db_tableZnew_db_tabledisable_constraintsr   r   r   r6   e   s     
z#DatabaseSchemaEditor.alter_db_tablec              
      sb  |  ||sd S |j}|jj}| \}}|j|krJ| jjjsJ| j||ddrJ| jj	rpt
d|jj|f t| jj t j||||d | j |}	|	d d }
|	d d| }| d	 }|| }|| }|	d
||f |	d|
d	   |	d |	d W 5 Q R X W 5 Q R X | j }	|	d W 5 Q R X nt j||||d d S )NT)r1   zRenaming the %r.%r column while in a transaction is not supported on SQLite < 3.26 because it would break referential integrity. Try adding `atomic = False` to the Migration class.)strictzPRAGMA schema_versionr   zPRAGMA writable_schema = 1z REFERENCES "%s" ("%%s")    z3UPDATE sqlite_master SET sql = replace(sql, %s, %s)zPRAGMA schema_version = %dzPRAGMA writable_schema = 0zPRAGMA integrity_checkZVACUUM)Z_field_should_be_alteredr.   _metadb_tableZget_attname_columnr   r3   r4   r2   r5   r   r	   aliasr   alter_fieldr-   executeZfetchone)r   r7   	old_field	new_fieldr9   Zold_field_namer0   _Zold_column_namer-   Zschema_versionZreferences_templateZnew_column_namesearchreplacementr   r   r   r>   |   sT      


z DatabaseSchemaEditor.alter_fieldc              	      sr  fddfddj jD }fddj jD }i d}|pFg }t|ddsftd	d
 |D rt| D ]B\}|jrrtfdd
|D srd|_|}|jrr|= ||j= qr|r|||j	< |j
s|jr|||j< |D ]}	|	\}
}||
j	d ||
jd |||j	< |
jrZ|jsZd|
j|d }|||j< n|
j||j< |j	|
j	< q r| j	= | j=  j
r jjj jr jjS t }fddj jD }fddj jD }j j} r fdd|D }tj j}t|}j jj j|||||d}tdd|}||d< j|d< tj jj | t|}j jdt!j j |||||d}tdd|}||d< j|d< tdj j j |}"| #d|j jd$fdd
|D d$|% j jf  jdd j&||j jj jdd j'D ]}#| qJg _'|rnd|_dS )a|  
        Shortcut to transform a model from old_model into new_model

        This follows the correct procedure to perform non-rename or column
        addition operations based on SQLite's documentation

        https://www.sqlite.org/lang_altertable.html#caution

        The essential steps are:
          1. Create a table with the updated definition called "new__app_model"
          2. Copy the data from the existing "app_model" table to the new table
          3. Drop the "app_model" table
          4. Rename the "new__app_model" table to "app_model"
          5. Restore any index of the previous "app_model" table.
        c                    s   | j o| jj kS r   )Zis_relationremote_fieldr7   )f)r7   r   r   is_self_referential   s    z?DatabaseSchemaEditor._remake_table.<locals>.is_self_referentialc                    s$   i | ]}|j  |r| n|qS r   )r.   clone.0rF   )rG   r   r   
<dictcomp>   s    z6DatabaseSchemaEditor._remake_table.<locals>.<dictcomp>c                    s   i | ]}|j  |j qS r   )column
quote_namerI   r   r   r   rK      s    Nprimary_keyFc                 s   s   | ]\}}t |d dV  qdS )rN   FN)getattrrJ   rB   rA   r   r   r   	<genexpr>   s    z5DatabaseSchemaEditor._remake_table.<locals>.<genexpr>c                 3   s   | ]\}} |j kV  qd S r   r.   rP   rR   r   r   rQ      s   zcoalesce(%(col)s, %(default)s))coldefaultc                    s   g | ]} fd d|D qS )c                    s   g | ]}  ||qS r   getrJ   nrename_mappingr   r   
<listcomp>  s     ADatabaseSchemaEditor._remake_table.<locals>.<listcomp>.<listcomp>r   )rJ   uniquerY   r   r   r[     s   z6DatabaseSchemaEditor._remake_table.<locals>.<listcomp>c                    s   g | ]} fd d|D qS )c                    s   g | ]}  ||qS r   rU   rW   rY   r   r   r[     s     r\   r   rJ   indexrY   r   r   r[     s   c                    s   g | ]} j |jkr|qS r   )r.   fieldsr^   delete_fieldr   r   r[     s     )	app_labelr<   unique_togetherindex_togetherindexesconstraintsappsZMetar   
__module__znew__%szNew%s%INSERT INTO %s (%s) SELECT %s FROM %s, c                 3   s   | ]}  |V  qd S r   )rM   )rJ   xr   r   r   rQ   T  s     )handle_autom2m)r8   T)(r;   Zlocal_concrete_fieldsrO   anylistitemsrN   auto_createdrL   r.   many_to_manyZconcreter,   effective_defaultpopnullrM   rE   throughdelete_modelr   rd   re   rf   rg   copydeepcopyrc   r<   r)   ri   Zobject_name	__bases__r   create_modelr?   joinr/   r6   deferred_sql)r   r7   create_fieldrb   alter_fieldsbodymappingZrestore_pk_fieldfieldr>   r@   rA   Zcase_sqlrh   rd   re   rf   rg   Z	body_copyZmeta_contentsmetaZ	new_modelsqlr   )rb   rG   r7   r.   rZ   r   r   _remake_table   s    











	

	


z"DatabaseSchemaEditor._remake_tablec                    sh   |rt  | nR| | jd| |jji  t| jD ](}t	|t
r:||jjr:| j| q:d S )Ntable)r   rw   r?   sql_delete_tablerM   r;   r<   ro   r}   r   r   Zreferences_tableremove)r   r7   rm   r   r   r   r   rw   m  s     z!DatabaseSchemaEditor.delete_modelc                    sd   |j r"|jjjjr"| |jj n>|jsB|jsB|jrB| 	|dk	rR| j
||d nt || dS )zCreate a field on a model.N)r~   )rr   rE   rv   r;   rq   r{   rN   r]   ru   rs   r   r   	add_fieldr   r7   r   r   r   r   r     s    	
zDatabaseSchemaEditor.add_fieldc                    s   |j r"|jjjjr| |jj n`| jjjrZ|j	sZ|j
sZ|jsZ|jrJ|jsZt || n(|j| jdd dkrtdS | j||d dS )z
        Remove a field from a model. Usually involves deleting a column,
        but for M2Ms may involve deleting a table.
        )r   r)   Nra   )rr   rE   rv   r;   rq   rw   r   r3   Zcan_alter_table_drop_columnrN   r]   Zdb_indexdb_constraintr   remove_fieldZdb_parametersr   r   r   r   r   r     s&    	z!DatabaseSchemaEditor.remove_fieldc	                 C   s`  | j jjr`|j|jkr`| ||| ||kr`|jr:|js`|jrF|js`| | |j	j
|||S | j|||fgd |d}	|d}
|jr\||ks|	|
kr\t }|jj	}|jD ]L}|j|krq|js|j|jkr||j q|jr|jj	jr||j q|jrF|jD ]2}|j|kr&q|jjj	jr||jj q|D ]}| | qJdS )z3Perform a "physical" (non-ManyToMany) field update.r   	collationN)r   r3   Zcan_alter_table_rename_columnrL   Z
column_sqlrE   r   r?   Z_rename_field_sqlr;   r<   r   rV   r]   setr7   Zrelated_objectsrelated_modelrr   
field_namer.   addrN   rv   rq   )r   r7   r@   rA   Zold_typenew_typeZold_db_paramsZnew_db_paramsr9   Zold_collationZnew_collationZrelated_modelsoptsrE   rr   r   r   r   r   _alter_field  s`    
   




z!DatabaseSchemaEditor._alter_fieldc                 C   s   |j jjj|j jjjkrz| j|j j|j jj| |j jj| f|j jj| |j jj| fgd dS | |j j | 	d| 
|j jjjdd| | gdd| | g| 
|j jjjf  | |j j dS )z*Alter M2Ms to repoint their to= endpoints.r   Nrj   rk   id)rE   rv   r;   r<   r   	get_fieldZm2m_reverse_field_nameZm2m_field_namer{   r?   rM   r|   Zm2m_column_nameZm2m_reverse_namerw   )r   r7   r@   rA   r9   r   r   r   _alter_many_to_many  sX    





z(DatabaseSchemaEditor._alter_many_to_manyc                    s@   t |tr2|js"|js"|js"|jr2t || n
| | d S r   )	r   r   	conditioncontains_expressionsinclude
deferrabler   add_constraintr   r   r7   
constraintr   r   r   r   +  s    
z#DatabaseSchemaEditor.add_constraintc                    s@   t |tr2|js"|js"|js"|jr2t || n
| | d S r   )	r   r   r   r   r   r   r   remove_constraintr   r   r   r   r   r   6  s    
z&DatabaseSchemaEditor.remove_constraintc                 C   s   d| S )NzCOLLATE r   )r   r   r   r   r   _collate_sqlA  s    z!DatabaseSchemaEditor._collate_sql)NF)T)F)NNN)T)F)__name__ri   __qualname__r   Zsql_create_fkZsql_create_inline_fkZsql_create_column_inline_fkZsql_delete_columnZsql_create_uniqueZsql_delete_uniqueZsql_alter_table_commentZsql_alter_column_commentr   r   r+   r,   r2   r6   r>   r   rw   r   r   r   r   r   r   r   __classcell__r   r   r   r   r
      sD      
 6     
 =% 
;@r
   )rx   decimalr   Zdjango.apps.registryr   Z	django.dbr   Zdjango.db.backends.base.schemar   Z!django.db.backends.ddl_referencesr   Zdjango.db.backends.utilsr   Zdjango.db.modelsr   Zdjango.db.transactionr	   r
   r   r   r   r   <module>   s   