B
    CVvgQ  ã               @   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dZdZ‡ fdd„Z‡ f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dd„ Z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 DEFERREDz7CREATE UNIQUE INDEX %(name)s ON %(table)s (%(columns)s)zDROP INDEX %(name)sc                s   | j  ¡ stdƒ‚tƒ  ¡ S )NzüSQLite 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-install-o3oxmrkh/Django/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Ú	traceback)r   r   r   r   "   s    
zDatabaseSchemaEditor.__exit__c             C   sÈ   y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ƒrˆd| 
dd¡ S |d kr”dS t|tttfƒr°d| ¡  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_valueFc       
   	   C   sŽ   | j  ¡ �z}xr| j j |¡D ]`}|r0|j|kr0q| j j ||j¡}x8| ¡ D ],}|d \}}	||krL|dkst|	|krLdS qLW qW W d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.
        Zforeign_keyNTF)r   ÚcursorZintrospectionZget_table_listÚnameZ_get_foreign_key_constraintsÚvalues)
r   Ú
table_nameZcolumn_nameÚignore_selfr)   Zother_tableÚconstraintsÚ
constraintZconstraint_tableZconstraint_columnr   r   r   Ú_is_referenced_by_fk_constraintC   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 )Nz°Renaming 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_renamer0   Úin_atomic_blockr   r   r   Úalter_db_tabler   )r   ÚmodelZold_db_tableZnew_db_tableÚdisable_constraints)r   r   r   r4   V   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 d Q R X W d Q R X | j ¡ �}	|	 d¡ W d Q R X ntƒ j||||d� d S )NT)r-   z´Renaming 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   r1   r2   r0   r3   r   r	   Úaliasr   Úalter_fieldr)   ÚexecuteZfetchone)r   r5   Ú	old_fieldÚ	new_fieldr7   Zold_field_namer,   Ú_Zold_column_namer)   Zschema_versionZreferences_templateZnew_column_nameÚsearchÚreplacement)r   r   r   r<   e   s8    

z DatabaseSchemaEditor.alter_fieldc          	      sZ  ‡fdd„‰‡fdd„ˆj jD ƒ}‡fdd„ˆj jD ƒ}i ‰d}t|ddƒs`|ržt|d	 ddƒržx<t| ¡ ƒD ],\}}	|	jrnd|	_|	}|	jrn||= ||	j= qnW |rÎ|||j< |j	sÎ|j
rÎˆ ˆ |¡¡||j< |�r^|\}
}| |
jd¡ | |
jd¡ |||j< |
j�r@|j�s@d
ˆ |
j¡ˆ ˆ |¡¡dœ }|||j< nˆ |
j¡||j< |jˆ|
j< ˆ �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� xˆj&D ]}ˆ "|¡ �q0W g ˆ_&|�rVd|_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 )N)Zis_relationÚremote_fieldr5   )Úf)r5   r   r   Úis_self_referential¡   s    z?DatabaseSchemaEditor._remake_table.<locals>.is_self_referentialc                s$   i | ]}ˆ |ƒr|  ¡ n||j“qS r   )Úcloner*   )Ú.0rD   )rE   r   r   ú
<dictcomp>¤   s   z6DatabaseSchemaEditor._remake_table.<locals>.<dictcomp>c                s   i | ]}ˆ   |j¡|j“qS r   )Ú
quote_nameÚcolumn)rG   rD   )r   r   r   rH   ª   s    NÚprimary_keyFr8   zcoalesce(%(col)s, %(default)s))ÚcolÚdefaultc                s   g | ]}‡ fd d„|D ƒ‘qS )c                s   g | ]}ˆ   ||¡‘qS r   )Úget)rG   Ún)Úrename_mappingr   r   ú
<listcomp>Ý   s    zADatabaseSchemaEditor._remake_table.<locals>.<listcomp>.<listcomp>r   )rG   Úunique)rP   r   r   rQ   Ý   s   z6DatabaseSchemaEditor._remake_table.<locals>.<listcomp>c                s   g | ]}‡ fd d„|D ƒ‘qS )c                s   g | ]}ˆ   ||¡‘qS r   )rN   )rG   rO   )rP   r   r   rQ   ä   s    zADatabaseSchemaEditor._remake_table.<locals>.<listcomp>.<listcomp>r   )rG   Úindex)rP   r   r   rQ   ä   s   c                s   g | ]}ˆ j |jkr|‘qS r   )r*   Úfields)rG   rS   )Údelete_fieldr   r   rQ   ë   s    )Ú	app_labelr:   Úunique_togetherÚindex_togetherÚindexesr.   ÚappsZMetar   Ú
__module__znew__%szNew%sz%INSERT INTO %s (%s) SELECT %s FROM %sz, c             3   s   | ]}ˆ   |¡V  qd S )N)rI   )rG   Úx)r   r   r   ú	<genexpr>  s    z5DatabaseSchemaEditor._remake_table.<locals>.<genexpr>)Úhandle_autom2m)r6   T)'r9   Zlocal_concrete_fieldsÚgetattrÚlistÚitemsrK   Úauto_createdrJ   r*   Úmany_to_manyZconcreter(   Zeffective_defaultÚpopÚnullrI   rC   ÚthroughÚdelete_modelr   rW   rX   rY   r.   ÚcopyÚdeepcopyrV   r:   r&   r[   Zobject_nameÚ	__bases__r   Úcreate_modelr=   Újoinr+   r4   Údeferred_sql)r   r5   Úcreate_fieldrU   r<   ÚbodyÚmappingZrestore_pk_fieldr*   Úfieldr>   r?   Zcase_sqlrZ   rW   rX   rY   r.   Z	body_copyZmeta_contentsÚmetaZ	new_modelÚsqlr   )rU   rE   r5   rP   r   r   Ú_remake_tableŽ   sª    










z"DatabaseSchemaEditor._remake_tablec                sl   |rt ƒ  |¡ nV|  | jd|  |jj¡i ¡ x6t| jƒD ](}t	|t
ƒr<| |jj¡r<| j |¡ q<W d S )NÚtable)r   rg   r=   Úsql_delete_tablerI   r9   r:   r`   rm   r   r   Zreferences_tableÚremove)r   r5   r^   rs   )r   r   r   rg   5  s    z!DatabaseSchemaEditor.delete_modelc             C   s2   |j r |jjjjr |  |jj¡S | j||d� dS )z�
        Create a field on a model. Usually involves adding a column, but may
        involve adding a table instead (for M2M fields).
        )rn   N)rc   rC   rf   r9   rb   rk   rt   )r   r5   rq   r   r   r   Ú	add_fieldB  s    zDatabaseSchemaEditor.add_fieldc             C   sN   |j r"|jjjjrJ|  |jj¡ n(|j| jd�d dkr<d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&   N)rU   )	rc   rC   rf   r9   rb   rg   Zdb_parametersr   rt   )r   r5   rq   r   r   r   Úremove_fieldL  s    z!DatabaseSchemaEditor.remove_fieldc	             C   sH  | j jjr`|j|jkr`|  ||¡|  ||¡kr`|jr:|js`|jrF|js`|  |  |j	j
|||¡¡S | j|||fd� |j�rD||k�rDtƒ }	|jj	}
xV|
jD ]L}|j|krªqš|jsÊ|j|jkræ|	 |j¡ qš|jrš|jj	jrš|	 |j¡ qšW |j�r*x6|
jD ],}|j|k�rqú|jjj	jrú|	 |jj¡ qúW x|	D ]}|  |¡ �q0W dS )z3Perform a "physical" (non-ManyToMany) field update.)r<   N)r   r1   Zcan_alter_table_rename_columnrJ   Z
column_sqlrC   Zdb_constraintr=   Z_rename_field_sqlr9   r:   rt   rR   Úsetr5   Zrelated_objectsÚrelated_modelrc   Ú
field_namer*   ÚaddrK   rf   rb   )r   r5   r>   r?   Zold_typeZnew_typeZold_db_paramsZnew_db_paramsr7   Zrelated_modelsÚoptsrC   rc   r{   r   r   r   Ú_alter_field^  s4    


z!DatabaseSchemaEditor._alter_fieldc             C   sÌ   |j jjj|j jjjkrR| j|j j|j jj | ¡ ¡|j jj | ¡ ¡f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<   Nz%INSERT INTO %s (%s) SELECT %s FROM %sz, Úid)rC   rf   r9   r:   rt   Ú	get_fieldZm2m_reverse_field_namerk   r=   rI   rl   Zm2m_column_nameZm2m_reverse_namerg   )r   r5   r>   r?   r7   r   r   r   Ú_alter_many_to_many‚  s&    

z(DatabaseSchemaEditor._alter_many_to_manyc                s.   t |tƒr |jr tƒ  ||¡ n
|  |¡ d S )N)r   r   Ú	conditionr   Úadd_constraintrt   )r   r5   r/   )r   r   r   r„   ¥  s    z#DatabaseSchemaEditor.add_constraintc                s.   t |tƒr |jr tƒ  ||¡ n
|  |¡ d S )N)r   r   rƒ   r   Úremove_constraintrt   )r   r5   r/   )r   r   r   r…   «  s    z&DatabaseSchemaEditor.remove_constraintc             C   s   d| S )Nz	 COLLATE r   )r   Z	collationr   r   r   Ú_collate_sql±  s    z!DatabaseSchemaEditor._collate_sql)NF)T)F)NNN)T)F)Ú__name__r[   Ú__qualname__rv   Zsql_create_fkZsql_create_inline_fkZsql_create_uniqueZsql_delete_uniquer   r   r(   r0   r4   r<   rt   rg   rx   ry   r   r‚   r„   r…   r†   Ú__classcell__r   r   )r   r   r
      s*   
)
 (

##r
   )rh   Ú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   