o
    /h                    @   sR  U d Z ddlZddlZddlZddlmZmZmZmZ ddl	m
Z
 ddlmZmZ ddlmZ ddlmZ ddlmZmZmZ dd	lmZ dd
lmZmZ ddlmZ ddlmZ edddZee d< e!e"ffddZ#dd Z$G dd dZ%G dd de%Z&G dd de%Z'G dd de%Z(G dd de%Z)e)e)e)e'e(e&dZ*G d d! d!eZ+dS )"ae  
sqldiff.py - Prints the (approximated) difference between models and database

TODO:
 - better support for relations
 - better support for constraints (mainly postgresql?)
 - support for table spaces with postgresql
 - when a table is not managed (meta.managed==False) then only do a one-way
   sqldiff ? show differences from db->table but not the other way around since
   it's not managed.

KNOWN ISSUES:
 - MySQL has by far the most problems with introspection. Please be
   carefull when using MySQL with sqldiff.
   - Booleans are reported back as Integers, so there's no way to know if
     there was a real change.
   - Varchar sizes are reported back without unicode support so their size
     may change in comparison to the real length of the varchar.
   - Some of the 'fixes' to counter these problems might create false
     positives or false negatives.
    N)DictUnionCallableOptional)apps)BaseCommandCommandError)OutputWrapper)no_style)
connectiontransactionmodels)UniqueConstraint)	AutoFieldIntegerField)normalize_together)signalcommand_orderT)nullORDERING_FIELDc                 C   s   t | }t| } d}|t| k r@t| | |r6| | s%| | |d8 }n| | | ||d < t| | |s|d7 }|t| k s|| S )Nr      )typelistlen
isinstancepop)lstltypesltypei r    h/var/www/html/env_mimamsha/lib/python3.10/site-packages/django_extensions/management/commands/sqldiff.pyflatten*   s   
	r"   c                 C   sZ   g }| j r| jD ]
}|t|j q|S | jD ]}|jtd}|d u r%q|| q|S Nr   )	proxyparentsextendall_local_fields_metalocal_fieldsdb_typer   append)meta
all_fieldsparentfcol_typer    r    r!   r(   :   s   

r(   c                   @   s  e Zd Zi ZdgZg dZddddddd	d
ddddddddZdd Zdd Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zd d Zd!Zd!Zd"Zd#d$ Zd%d& Zd'd( Zd)d* Zd+d, Zd-d. Zd/d0 Zd1d2 Zd3d4 Z d5d6 Z!	"	"	"ded7d8Z"dfd9d:Z#d;d< Z$d=d> Z%d?d@ Z&dAdB Z'dCdD Z(dEdF Z)dGdH Z*	"dgdIdJZ+dKdL Z,dMdN Z-dOdP Z.dQdR Z/dSdT Z0dgdUdVZ1	"dgdWdXZ2dYdZ Z3d[d\ Z4d]d^ Z5e6 fd_d`Z7dadb Z8dcdd Z9d"S )hSQLDiffdjango_migrationserrorcommenttable-missing-in-dbtable-missing-in-modelfield-missing-in-dbfield-missing-in-modelfkey-missing-in-dbzfkey-missing-in-modelindex-missing-in-dbindex-missing-in-modelunique-missing-in-dbunique-missing-in-modelfield-type-differfield-parameter-differnotnull-differzerror: %(0)szcomment: %(0)sz!table '%(0)s' missing in databaseztable '%(0)s' missing in modelsz6field '%(1)s' defined in model but missing in databasez6field '%(1)s' defined in database but missing in modelzBfield '%(1)s' FOREIGN KEY defined in model but missing in databasezBfield '%(1)s' FOREIGN KEY defined in database but missing in modelzJfield '%(1)s' INDEX named '%(2)s' defined in model but missing in databasezCfield '%(1)s' INDEX defined in database schema but missing in modelzKfield '%(1)s' UNIQUE named '%(2)s' defined in model but missing in databasezDfield '%(1)s' UNIQUE defined in database schema but missing in modelz9field '%(1)s' not of same type: db='%(3)s', model='%(2)s'z:field '%(1)s' parameters differ: db='%(3)s', model='%(2)s'z?field '%(1)s' null constraint should be '%(2)s' in the databasec                    sZ   d  d ||d   d ||d d fddt|d	d  D f S )
N%s %s
	%s %s %s;ALTER TABLEr   
ADD COLUMNr    c                 3   0    | ]\}}|d kr  |n |V  qdS r   NSQL_COLTYPESQL_KEYWORD.0r   astyler    r!   	<genexpr>w   
    
#SQLDiff.<lambda>.<locals>.<genexpr>   )rK   	SQL_TABLE	SQL_FIELDjoin	enumerateselfrP   qnargsr    rO   r!   <lambda>r   s    zSQLDiff.<lambda>c              	   C   s8   d| d|||d | d|||d f S )Nz%s %s
	%s %s;rD   r   zDROP COLUMNr   rK   rU   rV   rY   r    r    r!   r]   |   s    c                    s   d  d ||d   d ||d d fddt|d	d  D   d
 ||d  ||d tj f	 S )Nz%s %s
	%s %s %s %s %s (%s)%s;rD   r   rE   r   rF   c                 3   rG   rH   rI   rL   rO   r    r!   rQ      rR   rS      
REFERENCESrT      )rK   rU   rV   rW   rX   r   opsdeferrable_sqlrY   r    rO   r!   r]      s    c                    sd   d| d| |d | d| |d |d fdd|d	 D | |d
 f S )Nz%s %s
	%s %s (%s%s);zCREATE INDEXrT   ONr   , c                 3       | ]} |V  qd S Nr    rM   er[   r    r!   rQ          rS   r   ra   rK   rU   rV   rW   rY   r    rj   r!   r]      s     c                 C   s    d| d|||d f S )Nz%s %s;z
DROP INDEXr   rK   rU   rY   r    r    r!   r]      s    c                    s`   d| d| |d | d| |d | d|d fdd	|d
 D f S )Nz%s %s
	%s %s %s (%s);rD   r   zADD CONSTRAINTrT   UNIQUEre   c                 3   rf   rg   r    rh   rj   r    r!   rQ      rk   rS   r   rl   rY   r    rj   r!   r]      s     c              
   C   s@   d| d|||d | d| d|||d f S )NrC   rD   r   DROP
CONSTRAINTr   rm   rY   r    r    r!   r]      s    c              	   C   D   d| d|||d | d|||d ||d f S NrC   rD   r   MODIFYr   rT   rK   rU   rV   rJ   rY   r    r    r!   r]          c              	   C   rq   rr   rt   rY   r    r    r!   r]      ru   c              	   C   L   d| d|||d | d|||d | |d | df S )N%s %s
	%s %s %s %s;rD   r   rs   r   rT   NOT NULLr^   rY   r    r    r!   r]          c                 C      | d||d  S )Nz-- Error: %sr   )NOTICEERRORrY   r    r    r!   r]          c                 C   rz   )Nz-- Comment: %sr   )r{   rU   rY   r    r    r!   r]      r}   c                 C      | d|d  S )Nz-- Table missing: %sr   r{   rY   r    r    r!   r]          
c                 C   r~   )Nz-- Model missing for table: %sr   r   rY   r    r    r!   r]      r   FNc                 C   s   d | _ || _|| _|d | _|| _|| _tj| _g | _i | _	t
 | _i | _t
 | _| j| j| j| j| j| j| j| j| j| j| j| j| j| j| jd| _d S )Ndense_outputr4   )has_differences
app_modelsoptionsdensestdoutstderrr   introspectiondifferencesunknown_db_fieldssetnew_db_fieldsr   unsigned	SQL_ERRORSQL_COMMENTSQL_TABLE_MISSING_IN_DBSQL_TABLE_MISSING_IN_MODELSQL_FIELD_MISSING_IN_DBSQL_FIELD_MISSING_IN_MODELSQL_FKEY_MISSING_IN_DBSQL_INDEX_MISSING_IN_DBSQL_INDEX_MISSING_IN_MODELSQL_UNIQUE_MISSING_IN_DBSQL_UNIQUE_MISSING_IN_MODELSQL_FIELD_TYPE_DIFFERSQL_FIELD_PARAMETER_DIFFERSQL_NOTNULL_DIFFERDIFF_SQL)rZ   r   r   r   r   r    r    r!   __init__   s8   
zSQLDiff.__init__c                 C   s^   t  | _| jj| jd d| _dd | j| jD | _| jr$| 	  | j
r-|   d S d S )Nonly_existing)r   c                 S      g | ]}|j qS r    name)rM   
table_infor    r    r!   
<listcomp>  s    z SQLDiff.load.<locals>.<listcomp>)r   cursorr   django_table_namesr   django_tablesget_table_list	db_tablescan_detect_notnull_differ	load_nullcan_detect_unsigned_differload_unsignedrZ   r    r    r!   load   s   
zSQLDiff.loadc                 C      t d)Nzcload_null functions must be implemented if diff backend has 'can_detect_notnull_differ' set to TrueNotImplementedErrorr   r    r    r!   r        zSQLDiff.load_nullc                 C   r   )Nzgload_unsigned function must be implemented if diff backend has 'can_detect_unsigned_differ' set to Truer   r   r    r    r!   r     r   zSQLDiff.load_unsignedc                 C   s   | j ||g f d S rg   )r   r,   )rZ   	app_label
model_namer    r    r!   add_app_model_marker  s   zSQLDiff.add_app_model_markerc                 G   s.   || j v s	J d| jd d ||f d S )NzUnknown difference type)
DIFF_TYPESr   r,   )rZ   	diff_typer\   r    r    r!   add_difference  s   zSQLDiff.add_differencec                 C   s   | j S rg   )DATA_TYPES_REVERSE_OVERRIDEr   r    r    r!   get_data_types_reverse_override#  s   z'SQLDiff.get_data_types_reverse_overridec                 C   s   |S rg   r    rZ   field_namesr    r    r!   format_field_names'     zSQLDiff.format_field_namesc           	      C   sp   t  }||| dd |jD }| |}g }| D ]}g }t||D ]}|| q&|t| q|S )z
        Execute query and return a dict

        sql_to_dict(query, param) -> list of dicts

        code from snippet at https://www.djangosnippets.org/snippets/1383/
        c                 S      g | ]}|d  qS r   r    )rM   r   r    r    r!   r   4      z'SQLDiff.sql_to_dict.<locals>.<listcomp>)	r   r   executedescriptionr   fetchallzipr,   dict)	rZ   queryparamr   
fieldnamesresultrowrowsetfieldr    r    r!   sql_to_dict*  s   
zSQLDiff.sql_to_dictc                 C   s   |j tdS r#   )r+   r   )rZ   r   r    r    r!   get_field_model_type>  s   zSQLDiff.get_field_model_typec                 C      i S rg   r    )rZ   current_kwargsr   r   
table_namereverse_typer    r    r!   get_field_db_type_kwargsA  s   z SQLDiff.get_field_db_type_kwargsc              	   C   sV  |d }|   }||v r|| }nBz	| j||}W n8 tyR   | |}|sP| jd d d |d d f}|| jvrMd| j|< | dd|d |f  Y d S Y nw t|rZ| }i }t	|t
rl||d  |d }|d	kr||r|t|d
d dkr|d}t	|tr||d  |d }|dkr|d r|d |d< |dkr|d |d< |d rt|d p|d |d< |d rd|d< |dvrd|d< |rt|ddrd|d< |dkr|d }	| j||	\}}
|
r||
 d| }| |||||}|| | |}|d!i |jtd}|j}|sd}|||jf| jv r)| j|vr)d || jf }|S )"Nr   r   rT   r6   z)Unknown database type for field '%s' (%s)r   kwargsr   i2B  	geom_typePOINTz.django.contrib.gis.db.models.fields.PointField	CharFieldra   
max_lengthDecimalFieldr_   
max_digits   decimal_places   Tblank)	TextFieldr   r   	geographyFGeometryFieldz&django.contrib.gis.db.models.fields.%sr$   public%s %sr    )r   r   get_field_typeKeyErrorget_field_db_type_lookupr   r   r   callabler   r   updategetattrtupleabsget_geometry_typer   get_field_classr+   r   db_tablespacecolumnr   unsigned_suffix)rZ   r   r   r   	type_coder   r   keyr   geo_col
geo_paramsextra_kwargsfield_classfield_db_type
tablespacer    r    r!   get_field_db_typeK  s   










zSQLDiff.get_field_db_typec                 C      d S rg   r    )rZ   r   r    r    r!   r     r   z SQLDiff.get_field_db_type_lookupc                 C   s6   d|v r| dd\}}t|}t||S tt|S )N.r   )rsplit	importlibimport_moduler   r   )rZ   
class_pathmodule_pathpackage_namemoduler    r    r!   r     s
   


zSQLDiff.get_field_classc                 C   s2   |j }|dkr	d}|jp|j}| j|||fdS )N r   fixme)r   	db_columnattnamer   get)rZ   r   r   r   r  r    r    r!   get_field_db_nullable  s
   zSQLDiff.get_field_db_nullablec                 C   s,   |r|dkr| dd  dd  S |S )Nzdouble precisionrF   r   ()splitlower)rZ   
field_typer    r    r!   strip_parameters  s   zSQLDiff.strip_parametersc                 C   sD   g }t |dr|tt|j7 }|jD ]}||j q| ||S )Nindex_together)hasattrr   r   r  indexesr,   fieldsexpand_together)rZ   r-   indexes_normalizedidxr    r    r!   get_index_together  s   

zSQLDiff.get_index_togetherc                 C   s<   t t|j}|jD ]}t|tr||j q
| ||S rg   )	r   r   unique_togetherconstraintsr   r   r,   r  r  )rZ   r-   unique_normalized
constraintr    r    r!   get_unique_together  s   

zSQLDiff.get_unique_togetherc                    s2   g }t |D ]}|t fdd|D  q|S )Nc                 3   s    | ]	}  |jV  qd S rg   )	get_fieldr  rM   r   r-   r    r!   rQ     s    z*SQLDiff.expand_together.<locals>.<genexpr>)r   r,   r   )rZ   togetherr-   new_togetherr  r    r  r!   r    s   zSQLDiff.expand_togetherc                    \  t t }t|D ]q}|r|j|v rq	|jrz|jrz|jp|j | i d}|s9|r9t fdd|	 D } |v r@|r@q	|
| g}	| d| g|	d  |jt d}
|
dri| d| g|	d	 d
 |
drz| d| g|	d	 d q	| |}tdd | D }|D ]}||v rq|r||v rq|
||}	| d|||	d  qd S )Nuniquec                 3   *    | ]\}} g|d  kr|d V  qdS columnsr#  Nr    rM   contraint_namer  r  r    r!   rQ         z4SQLDiff.find_unique_missing_in_db.<locals>.<genexpr>r>   _uniqr$   varcharr<   _like varchar_pattern_opstext text_pattern_opsc                 S   $   g | ]}|d  r|d s|d qS )r#  indexr&  r    rM   vr    r    r!   r         z5SQLDiff.find_unique_missing_in_db.<locals>.<listcomp>r   SchemaEditorClassr(   r  r#  managedr  r	  anyitems_create_index_namer   r+   
startswithr  r   valuesrZ   r-   table_indexestable_constraintsr   	skip_listschema_editorr   db_field_unique
index_namer+   r  db_unique_columnsunique_columnsr    r)  r!   find_unique_missing_in_db  sf   



z!SQLDiff.find_unique_missing_in_dbc                 C   s   t dd t|D }| |}| D ]7\}}|d sq|d r"q|d }	t|	dkr=||	d }
|
d u r8n|
jr<qnt|	|v rDq| d|| qd S )	Nc                 S      g | ]}|j |fqS r    r   r  r    r    r!   r         z8SQLDiff.find_unique_missing_in_model.<locals>.<listcomp>r#  r2  r&  r   r   r?   )	r   r(   r  r:  r   r	  r#  r   r   )rZ   r-   r?  r@  r   r  r  constraint_namer  r&  r   r    r    r!   find_unique_missing_in_model  s&   
z$SQLDiff.find_unique_missing_in_modelc                 C   s*  t t }t|D ]H}|jrQ|jp|j}||vrQ|||g}| d||g|d |jt d}	|		dr@| d||g|d d |		drQ| d||g|d d q	| 
|}
td	d
 | D }|
D ]}||v rkqd|||}| d|||d d qd|jD ]}|j|vr| d||j|jd qd S )Nr<   r  r$   r,  r-  r.  r/  r0  c                 S   r1  )r2  r#  r&  r    r3  r    r    r!   r   U  r5  z4SQLDiff.find_index_missing_in_db.<locals>.<listcomp>_idx)r   r7  r(   db_indexr  r  r;  r   r+   r<  r  r   r=  r  r   r  )rZ   r-   r?  r@  r   rB  r   r  rD  r+   r  db_index_togetherr&  r2  r    r    r!   find_index_missing_in_db5  s^   





z SQLDiff.find_index_missing_in_dbc                 C   sZ  t dd t|D }dd |jD }| |}| D ]\}}	||v r%q|	d r.|	d s.q|	d }
||
d }|	d rA|	d sE|d u rFn]t|
dkr|	d	 rT|jrTq|	d
 rbt|t	j
rb|jrbq|	d rj|jrjq|	d r}|	d dkr}|	dr}|jr}q|	d r|jrq|	d r|jtdrqt|ddrqn|	d rt|
|v rq| d|| qd S )Nc                 S   rH  r    rI  r  r    r    r!   r   l  rJ  z7SQLDiff.find_index_missing_in_model.<locals>.<listcomp>c                 S   r   r    r   rM   r  r    r    r!   r   m      r#  r2  r&  r   r   primary_keyforeign_keyr   r  orderscheckr$   spatial_indexFr=   )r   r(   r  r  r:  r	  r   rS  r   r   
ForeignKeydb_constraintr#  rN  db_checkr   r   r   r   )rZ   r-   r?  r@  r   r  meta_index_namesr  rK  r  r&  r   r    r    r!   find_index_missing_in_modeli  sV   

z#SQLDiff.find_index_missing_in_modelc                 C   s,   |D ]}|d |vr|  d||d  qd S )Nr   r:   )r   )rZ   fieldmaptable_descriptionr   r   r    r    r!   find_field_missing_in_model  s
   z#SQLDiff.find_field_missing_in_modelc           	      C   s   dd |D }|  D ]_\}}||vrjg }|jr/||jjjj|jjj|jjjg d}nd}|	|j
td | jd rO| rO|	d||   |jsW|	d | j|||g|R   | j||f qd S )	Nc                 S   r   r   r    rM   r   r    r    r!   r     r   z4SQLDiff.find_field_missing_in_db.<locals>.<listcomp>r;   r9   r$   include_defaultsz
DEFAULT %srx   )r:  remote_fieldr'   modelr)   db_tabler  
field_namer   r,   r+   r   r   has_defaultget_prep_valueget_defaultr   r   r   add)	rZ   r]  r^  r   	db_fieldsre  r   field_outputopr    r    r!   find_field_missing_in_db  s4   


z SQLDiff.find_field_missing_in_dbc           
      C   s   t dd |D }t|D ]>}|j|vrq||j }| |}| |||}	|r1|||||	\}}	| |	| |ksK|	|fdvrK| d||j||	 qd S )Nc                 S      g | ]}|d  |fqS r   r    r`  r    r    r!   r         z2SQLDiff.find_field_type_differ.<locals>.<listcomp>>   serialinteger	bigserialbigintr@   )r   r(   r   r   r   r  r   )
rZ   r-   r^  r   funcrj  r   r   
model_typer+   r    r    r!   find_field_type_differ  s$   


zSQLDiff.find_field_type_differc                 C   s   t dd |D }t|D ]b}|j|vrq||j }| |}| |||}	| || |	ks1q|r<|||||	\}}	|jtdd }
d|	v r[|	dd\}	}|	 
dd}nd }||	kre|
|kso| d	||j||	 qd S )
Nc                 S   rn  r   r    r`  r    r    r!   r     ro  z7SQLDiff.find_field_parameter_differ.<locals>.<listcomp>r$   rV  z CHECKr   r  )rA   )r   r(   r   r   r   r  db_parametersr   r  striplstriprstripr   )rZ   r-   r^  r   rv  rj  r   r   rw  r+   model_checkrZ  r    r    r!   find_field_parameter_differ  s4   


z#SQLDiff.find_field_parameter_differc                 C   sl   | j sd S t|D ]*}|jp|j}||f| jv rq	| ||}|j|kr3|jr)dp*d}| d||| q	d S )Nro   SETrB   )r   r(   r  r  r   r
  r   r   )rZ   r-   r^  r   r   r  r   actionr    r    r!   find_field_notnull_differ  s   
z!SQLDiff.find_field_notnull_differc                 C   r   rg   r    )rZ   r   r   r   r    r    r!   get_constraints  r   zSQLDiff.get_constraintsc                 C   s@  | j d r!| d d  | jD ]}|| jvr || jvr | d| qd }| jD ]}|j}|j}|j	}| j d s:|j
r:q&||krE| ||j || jvrQ| d| q&t| jdr`| j| j|}n	| | j|| j}tdd t|D }|jr{t|d< z
| j| j|}	W n" ty }
 z| d	d
t|
   t  W Y d }
~
q&d }
~
ww i }| D ] \}}|d }t|dkr|d |d |d|d||d < q| |||| | |||| | ||	| |  ||	| | !|||| | "|||| | #||	| | $||	| | %||	| q&t&dd | j'D | _(d S )Nall_applicationsr8   include_proxy_modelsr7   r  c                 S   s   g | ]}|j p
| |fqS r    )r  get_attnamer  r    r    r!   r   0  s    z,SQLDiff.find_differences.<locals>.<listcomp>r   r5   zunable to introspect table: %sr&  r   rS  r#  r   )rS  r#  r   r(  r   c                 S   s   g | ]	\}}}t |qS r    )r   )rM   
_app_label_model_namediffsr    r    r!   r   q  s    ))r   r   r   r   IGNORE_MISSING_TABLESr   r   r)   rd  r   r%   __name__r  r   r  r   r   r(   order_with_respect_tor   get_table_description	Exceptionstrr{  r   rollbackr:  r   r	  rL  r\  r_  rm  rG  rP  rx  r  r  maxr   r   )rZ   tablecur_app_label	app_modelr-   r   r   r@  r]  r^  ri   r?  r(  dctr&  r    r    r!   find_differences
  s   






	
zSQLDiff.find_differencesc                 C   s&   | j d r| | dS | | dS )zPrint differences to stdoutsqlN)r   print_diff_sqlprint_diff_text)rZ   rP   r    r    r!   
print_difft  s   
zSQLDiff.print_diffc           
         s  | j s| j d | jd | js$| j d | jd d }| jD ]\}}}|s1q)| jsL|rL||krL| jd d |f  |}| jsa|ra| jd d |f  |D ]\}|\}}| j| t	 fddt
|D  }	d	 fd
dt
|	d	D }	| js| jd d|	f  qc|r| jd d | d ||	f  qc| j|	 qcq)d S )NzE# Detecting notnull changes not implemented for this database backendr  zF# Detecting unsigned changes not implemented for this database backendr   z+ Application:z|-+ Differences for model:c                 3   s>    | ]\}}t | t|ttfrd |n|fV  qdS )re   N)r  rU   r   r   r   rW   rM   r   ri   rO   r    r!   rQ     s    
z*SQLDiff.print_diff_text.<locals>.<genexpr>'c                 3   s.    | ]\}}|d  dkr  |p|V  qdS )rT   r   N)r|   r  rO   r    r!   rQ     s
    
z|--+z%s %s %s %s %sAppModel)r   r   writer{   r   r   r   rU   
DIFF_TEXTSr   rX   rW   r  )
rZ   rP   r  r   r   r  diffr   	diff_argsr/  r    rO   r!   r  {  sr   

	zSQLDiff.print_diff_textc              	   C   s,  | j s| j|d | jd d }tjj}| js+| js)| j|	d d S d S | j|	d | j
D ]S\}}}|s?q7| jsV||krV| j|d||  |}| jsi|ri| j|d||  |D ]}|\}}	| j| |||	}
| jr|
dd}
| j|
 qkq7| j|	d	 d S )
NzF-- Detecting notnull changes not implemented for this database backendr  z-- No differenceszBEGIN;z-- Application: %sz-- Model: %sz
	rF   zCOMMIT;)r   r   r  r{   r   rb   
quote_namer   r   rK   r   rU   r   replace)rZ   rP   r  r[   r   r   r  r  r   r  r/  r    r    r!   r    sD   
zSQLDiff.print_diff_sql)NNNNNrg   ):r  
__module____qualname__r   r  r   r  r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r
  r  r  r  r  rG  rL  rP  r\  r_  rm  rx  r  r  r  r  r
   r  r  r  r    r    r    r!   r2   H   s    
	"


\		
@45

#jEr2   c                   @   s$   e Zd ZdZdZdd Zdd ZdS )GenericSQLDiffFc                 C   r   rg   r    r   r    r    r!   r     r   zGenericSQLDiff.load_nullc                 C   r   rg   r    r   r    r    r!   r     r   zGenericSQLDiff.load_unsignedN)r  r  r  r   r   r   r   r    r    r    r!   r    s
    r  c                       sj   e Zd ZdZdZdZ fddZdd Zdd Zd	d
 Z	dd Z
d fdd	Zdd Z	dddZ  ZS )	MySQLDiffTUNSIGNEDc                    s   t    t | _|   d S rg   )superr   r   auto_incrementload_auto_incrementr   	__class__r    r!   r     s   
zMySQLDiff.loadc                 C   s   dd |D S )Nc                 S   s   g | ]}|  qS r    )r  )rM   r0   r    r    r!   r     r   z0MySQLDiff.format_field_names.<locals>.<listcomp>r    r   r    r    r!   r     s   zMySQLDiff.format_field_namesc                 C   sL   d}| j D ]}| d|g}|D ]}|||d f}|d dk| j|< qqd S )Nr   z
                SELECT column_name, is_nullable
                FROM information_schema.columns
                WHERE table_schema = DATABASE()
                    AND table_name = %scolumn_nameis_nullableYESr   r   r   rZ   r   r   r   r   r   r    r    r!   r     s   
zMySQLDiff.load_nullc                 C   sF   d}| j D ]}| d|g}|D ]}|||d f}| j| qqd S )Nr   z
                SELECT column_name
                FROM information_schema.columns
                WHERE table_schema = DATABASE()
                    AND table_name = %s
                    AND column_type LIKE '%%unsigned'r  )r   r   r   ri  r  r    r    r!   r     s   
	zMySQLDiff.load_unsignedc                 C   s@   | j D ]}| d|g}|D ]}||d f}| j| qqd S )Nz
                SELECT column_name
                FROM information_schema.columns
                WHERE table_schema = DATABASE()
                   AND table_name = %s
                   AND extra = 'auto_increment'r  )r   r   r  ri  )rZ   r   r   r   r   r    r    r!   r    s   
	zMySQLDiff.load_auto_incrementNc                    s   t  |||}|sd S |rC| |}| |dkr&| |dkr&|d}| |dkr3|dkr3d}||jf| jv rCd|vrC|d7 }|S )Ncharr,  varboolrr  AUTO_INCREMENTz AUTO_INCREMENT)r  r   r   r  r|  r   r  rZ   r   r   r   r+   r  r  r    r!   r   /  s&   

zMySQLDiff.get_field_db_typec                 C   s|  t dd t|D }dd |jD }| |}| |}| D ]\}	}
|	|v r*q!|
d r3|
d s3q!|
d }||d }t|dkr|sN| d	||	 q!|
d
 rV|j	rVq!|
d rdt
|tjrd|jrdq!|
d rl|jrlq!|
d r|
d dkr|
dr|jrq!|
d r|jrq!|
d r|jtdrq!t|ddrq!n|
d rt||v rq!|
d r|
d rt||v rq!| d	||	 q!d S )Nc                 S   rH  r    rI  r  r    r    r!   r   N  rJ  z9MySQLDiff.find_index_missing_in_model.<locals>.<listcomp>c                 S   r   r    r   rQ  r    r    r!   r   O  rR  r#  r2  r&  r   r   r=   rS  rT  r   r  rU  rV  r$   rW  F)r   r(   r  r  r  r:  r	  r   r   rS  r   r   rX  rY  r#  rN  rZ  r   r   r   )rZ   r-   r?  r@  r   r  r[  r  r  rK  r  r&  r   r    r    r!   r\  K  sj   


z%MySQLDiff.find_index_missing_in_modelc                    r"  )Nr#  c                 3   r$  r%  r    r'  r)  r    r!   rQ     r*  z6MySQLDiff.find_unique_missing_in_db.<locals>.<genexpr>r>   r+  r$   r,  r<   r-  r.  r/  r0  c                 S      g | ]
}|d  r|d qS r#  r&  r    r3  r    r    r!   r         z7MySQLDiff.find_unique_missing_in_db.<locals>.<listcomp>r6  r>  r    r)  r!   rG    sb   



z#MySQLDiff.find_unique_missing_in_dbr  rg   )r  r  r  r   r   r   r   r   r   r   r  r   r\  rG  __classcell__r    r    r  r!   r    s    Br  c                       sV   e Zd ZdZdZdd Zdd Z	d fdd		Zd
d Zdd Z	d fdd	Z
  ZS )SqliteSQLDiffTFc                 C   sH   | j D ]}d}| d| g D ]}|||d f}|d  | j|< qqd S )Nr   zPRAGMA table_info('%s');r   notnullr  )rZ   r   r   r   r   r    r    r!   r     s   
zSqliteSQLDiff.load_nullc                 C   r   rg   r    r   r    r    r!   r     r   zSqliteSQLDiff.load_unsignedNc                    s   |d u rg }dd t |D }| D ]!}|d }t|dkr4|d }	|	|v r4|d s/|d r4||	 q| |}
tdd | D }|
D ]}||v rR|| qGt j|||||d	 d S )
Nc                 S   s   g | ]}|j r|jp|jqS r    )r#  r  r  r  r    r    r!   r     s    
z;SqliteSQLDiff.find_unique_missing_in_db.<locals>.<listcomp>r&  r   r   r#  rS  c                 S   r  r  r    r3  r    r    r!   r     r  )rA  )r(   r=  r   r,   r  r   r  rG  )rZ   r-   r?  r@  r   rA  rF  r  r&  r   r  rE  r  r    r!   rG    s6   




z'SqliteSQLDiff.find_unique_missing_in_dbc                 C   r   rg   r    rZ   r-   r?  r@  r   r    r    r!   rP       z&SqliteSQLDiff.find_index_missing_in_dbc                 C   r   rg   r    r  r    r    r!   r\  	  r  z)SqliteSQLDiff.find_index_missing_in_modelc                    sP   t  |||}|sd S |r&| |}| |dkr&| |dkr&|d}|S )Nr  r,  r  )r  r   r   r  r|  r  r  r    r!   r     s   

zSqliteSQLDiff.get_field_db_typerg   r  )r  r  r  r   r   r   r   rG  rP  r\  r   r  r    r    r  r!   r    s    $r  c                       s   e Zd ZdZdZdddZdZdZdd Zd	d Z	d
d Z
 fddZdd Zdd Zdd Zdd Zdd Zdd Zd fdd	Zdd Z  ZS )PostgresqlSQLDiffTz*django.contrib.postgres.fields.HStoreField(django.contrib.postgres.fields.JSONField)hstorejsonba  
        SELECT nspname, relname, conname, attname, pg_get_constraintdef(pg_constraint.oid)
        FROM pg_constraint
        INNER JOIN pg_attribute ON pg_constraint.conrelid = pg_attribute.attrelid AND pg_attribute.attnum = any(pg_constraint.conkey)
        INNER JOIN pg_class ON conrelid=pg_class.oid
        INNER JOIN pg_namespace ON pg_namespace.oid=pg_class.relnamespace
        ORDER BY CASE WHEN contype='f' THEN 0 ELSE 1 END,contype,nspname,relname,conname;
    z
        SELECT nspname, relname, attname, attnotnull
        FROM pg_attribute
        INNER JOIN pg_class ON attrelid=pg_class.oid
        INNER JOIN pg_namespace ON pg_namespace.oid=pg_class.relnamespace;
    c              
   C   L   d| d|||d | d|||d | d||d f S Nrw   rD   r   ALTERr   TYPErT   rt   rY   r    r    r!   r]   7  s    zPostgresqlSQLDiff.<lambda>c              
   C   r  r  rt   rY   r    r    r!   r]   @  s    c              	   C   rv   )Nrw   rD   r   zALTER COLUMNr   rT   rx   r^   rY   r    r    r!   r]   J  ry   c                    s   t    i | _|   d S rg   )r  r   check_constraintsload_constraintsr   r  r    r!   r   S  s   
zPostgresqlSQLDiff.loadc                 C   s>   |  | jg D ]}|d |d |d f}|d  | j|< qd S )Nnspnamerelnamer  
attnotnull)r   SQL_LOAD_NULLr   rZ   r  r   r    r    r!   r   X  s   zPostgresqlSQLDiff.load_nullc                 C   r   rg   r    r   r    r    r!   r   ]  r  zPostgresqlSQLDiff.load_unsignedc                 C   sD   |  | jg D ]}|d |d |d f}d|d v r|| j|< qd S )Nr  r  r  CHECKpg_get_constraintdef)r   SQL_LOAD_CONSTRAINTSr  r  r    r    r!   r  b  s   
z"PostgresqlSQLDiff.load_constraintsc                 C   s   dd|  | idS )Nz)django.contrib.postgres.fields.ArrayField
base_field)r   r   )r   )rZ   r  r    r    r!   get_data_type_arrayfieldh  s   z*PostgresqlSQLDiff.get_data_type_arrayfieldc                    s   i ddd fddd fddd fd	dd
 fddd fddd fddd fddd fddd fddd fddd fddd fddd fddd fddd  fd!dd" fd#d fd$dd%d&d'S )(Ni  r   i  c                          j ddS )NBooleanFieldr  r  r    r   r    r!   r]   s      zCPostgresqlSQLDiff.get_data_types_reverse_override.<locals>.<lambda>i  c                      r  )NBinaryFieldr  r  r    r   r    r!   r]   t  r  i  c                      r  Nr   r  r  r    r   r    r!   r]   u  r  i  c                      r  Nr   r  r  r    r   r    r!   r]   v  r  i  c                      r  r  r  r    r   r    r!   r]   w  r  i  c                      r  r  r  r    r   r    r!   r]   x  r  i  c                      r  r  r  r    r   r    r!   r]   y  r  i  c                      r  r  r  r    r   r    r!   r]   z  r  i  c                      r  r  r  r    r   r    r!   r]   {  r  i  c                      r  )NBigIntegerFieldr  r  r    r   r    r!   r]   |  r  i  c                      r  N
FloatFieldr  r  r    r   r    r!   r]   }  r  i  c                      r  r  r  r    r   r    r!   r]   ~  r  i  c                      r  r  r  r    r   r    r!   r]     r  i[  c                      r  NDateTimeFieldr  r  r    r   r    r!   r]     r  i  c                      r  r  r  r    r   r    r!   r]     r  i  c                      r  )Nr   r  r  r    r   r    r!   r]     r  c                      r  )NDurationFieldr  r  r    r   r    r!   r]     r  z0django.contrib.postgres.search.SearchVectorFieldr  )i  i  i  r    r   r    r   r!   r   p  sN   	

z1PostgresqlSQLDiff.get_data_types_reverse_overridec              	   C   s&  i }| dd|g | D ]6\}}}}||vr;g | dk| dv | dkr3t|d ddnd	d
d
d||< || d | q| dd|g | D ]\}}||vrdg d
d
d	dd
d||< || d | qQ| d|g | D ]\}	}
}}|	|vrt|
||d	d
dd||	< qy|S )zm
        Find constraints for table

        Backport of django's introspection.get_constraints(...)
        a  
            SELECT
                kc.constraint_name,
                kc.column_name,
                c.constraint_type,
                array(SELECT table_name::text || '.' || column_name::text FROM information_schema.constraint_column_usage WHERE constraint_name = kc.constraint_name)
            FROM information_schema.key_column_usage AS kc
            JOIN information_schema.table_constraints AS c ON
                kc.table_schema = c.table_schema AND
                kc.table_name = c.table_name AND
                kc.constraint_name = c.constraint_name
            WHERE
                kc.table_schema = %s AND
                kc.table_name = %s
        r   primary key)r  r#  zforeign keyr   r   r   NF)r&  rS  r#  rT  rV  r2  r&  a  
            SELECT kc.constraint_name, kc.column_name
            FROM information_schema.constraint_column_usage AS kc
            JOIN information_schema.table_constraints AS c ON
                kc.table_schema = c.table_schema AND
                kc.table_name = c.table_name AND
                kc.constraint_name = c.constraint_name
            WHERE
                c.constraint_type = 'CHECK' AND
                kc.table_schema = %s AND
                kc.table_name = %s
        Ta  
            SELECT
                c2.relname,
                ARRAY(
                    SELECT (SELECT attname FROM pg_catalog.pg_attribute WHERE attnum = i AND attrelid = c.oid)
                    FROM unnest(idx.indkey) i
                ),
                idx.indisunique,
                idx.indisprimary
            FROM pg_catalog.pg_class c, pg_catalog.pg_class c2,
                pg_catalog.pg_index idx
            WHERE c.oid = idx.indrelid
                AND idx.indexrelid = c2.oid
                AND c.relname = %s
        )r   r   r  r   r  r,   r   )rZ   r   r   r   r  r  r   kind	used_colsr2  r&  r#  primaryr    r    r!   r    s\   



	
z!PostgresqlSQLDiff.get_constraintsNc           	         s  t  |||}|sd S |r|dr2|jp|j}| d||fd d }|dr0|dd}|S |jrGt	|t
rG|dkrAd}n|d	krGd
}|r|j}|dkrRd}|jpW|j}| j|||fi dd }|r|dd}|dd}ddd |dD }|d| 7 }|S )Nz[]a`  SELECT attname, format_type(atttypid, atttypmod) AS type
                        FROM   pg_attribute
                        WHERE  attrelid = %s::regclass
                        AND    attname = %s
                        AND    attnum > 0
                        AND    NOT attisdropped
                        ORDER  BY attnum;
                    r   r   zcharacter varyingr,  rr  rq  ru  rt  r  r   r  z((r  z))ry  z("c              	   S   s4   g | ]}d |v rd dd |ddD p|qS )ry  z" c                 s   s    | ]}| d V  qdS )"N)r{  )rM   pr    r    r!   rQ   C  s    zAPostgresqlSQLDiff.get_field_db_type.<locals>.<listcomp>.<genexpr>rF   r   )rW   r  rh   r    r    r!   r   A  s    z7PostgresqlSQLDiff.get_field_db_type.<locals>.<listcomp>rF   )r  r   endswithr  r  r   r<  r  rS  r   r   r   r  r	  rW   r  )	rZ   r   r   r   r+   r  introspect_db_typer   check_constraintr  r    r!   r     sX   
	



	z#PostgresqlSQLDiff.get_field_db_typec              	   C   sD   z|  d|gd d }| j|dW S  ttfy!   Y d S w )Nz-SELECT typname FROM pg_type WHERE typelem=%s;r   typname_)r   DATA_TYPES_REVERSE_NAMEr	  r{  
IndexErrorr   )rZ   r   r   r    r    r!   r   L  s   z*PostgresqlSQLDiff.get_field_db_type_lookupr  )r  r  r  r   r   r  r  r  r   r   r   r   r   r   r  r  r   r  r   r   r  r    r    r  r!   r    s.    		 ?	r  )postgispostgresql_psycopg2
postgresqlmysqlsqlite3oraclec                       sT   e Zd ZdZdZ fddZ fddZedd Z fd	d
Z	 fddZ
  ZS )Commanda  Prints the (approximated) difference between models and fields in the database for the given app name(s).

It indicates how columns in the database are different from the sql that would
be generated by Django. This command is not a database migration tool. (Though
it can certainly help) It's purpose is to show the current differences as a way
to check/debug ur models compared to the real database tables and columns.Fc                    s   t  | |jddd |jdddddd	d
 |jddddddd
 |jddddddd |jddddddd |jdddddd |jdddddd |jd dd!dtjd d S )"Nr   *)nargsz--all-applicationsz-a
store_trueFr  z8Automaticly include all application from INSTALLED_APPS.)r  defaultdesthelpz--not-only-existingz-estore_falseTr   z_Check all tables that exist in the database, not only tables that should exist based on models.z--dense-outputz-dr   zRShows the output in dense format, normally output is spreaded over multiple lines.)r  r  r  r  z--output_textz-tr  z:Outputs the differences as descriptive text instead of SQLz--include-proxy-modelsr  z!Include proxy models in the graphz--include-defaultsra  z3Include default values in SQL output (beta feature)z--migrate-for-testsmigrate_for_tests)r  add_argumentsadd_argumentargparseSUPPRESS)rZ   parserr  r    r!   r   s  sn   
zCommand.add_argumentsc                    s   t  j|i | d| _d S )Nr   )r  r   	exit_code)rZ   r\   r   r  r    r!   r     s   
zCommand.__init__c                 O   s\  ddl m} |d }d }t|dr|jd d }n|j}|dkr$td|d	 r/tjd
d}n&|s5tdt|t	t
tfs@|g}g }|D ]}t|}||jd
d qD|s[td|d }	|	rsddlm}
 |
dg|R d
d
d |s}tjdd }d|v r|dd }t|t}|||| j| jd}|  |  |jsd| _|| j d S )Nr   )settingsr   	DATABASESr  ENGINEdummyzDjango doesn't know which syntax to use for your SQL statements, because you haven't specified the DATABASE_ENGINE setting. Edit your settings file and change DATABASE_ENGINE to something like 'postgresql' or 'mysql'.r  T)include_auto_createdzEnter at least one appname.z+Unable to execute sqldiff no models founds.r  )call_commandmigrate)no_input
run_syncdbr   r   )r   r   )django.confr  r  r  DATABASE_ENGINEr   r   
get_modelsr   r   r   r   get_app_configr'   django.core.managementr  r   r  r  DATABASE_SQLDIFF_CLASSESr	  r  r   r   r   r  r   r  r  rP   )rZ   r\   r   r  
app_labelsenginer   r   
app_configr  r  clssqldiff_instancer    r    r!   handle  sN   

zCommand.handlec              
      s   zt  j|i | W d S  tyD } z,|d r t| dd }|s)ttj| jj}|	d|j
j|f  td W Y d }~d S d }~ww )N	tracebackr   z%s: %srT   )r  r   r   r   r	   sysr   rP   r|   r  r  r  exit)rZ   r\   r   ri   r   r  r    r!   r     s   zCommand.executec                    s   t  | t| j d S rg   )r  run_from_argvr  r  r  )rZ   argvr  r    r!   r     s   zCommand.run_from_argv)r  r  r  r  output_transactionr   r   r   r  r   r  r  r    r    r  r!   r  i  s    ?
;r  ),__doc__r   r  r  typingr   r   r   r   django.appsr   r  r   r   django.core.management.baser	   django.core.management.colorr
   	django.dbr   r   r   django.db.modelsr   django.db.models.fieldsr   r   django.db.models.optionsr   "django_extensions.management.utilsr   r   __annotations__r   r   r"   r(   r2   r  r  r  r  r  r  r    r    r    r!   <module>   sP          % ZS  E
