3
(hM                 @   s  d 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mZ yddlZddlmZmZ W n0 ek
r Z zedjeW Y ddZ[X nX yddlmZmZ W n ek
r   dZY nX d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+ ej,j-Z-ej,j.Z.ej,j/Z/ej,j0Z0ej,j1Z1dd Z2G dd dZ3G dd deZ4G dd deZ5G d d! d!eZ6dS )"a  Django database Backend using MySQL Connector/Python.

This Django database backend is heavily based on the MySQL backend from Django.

Changes include:
* Support for microseconds (MySQL 5.6.3 and later)
* Using INFORMATION_SCHEMA where possible
* Using new defaults for, for example SQL_AUTO_IS_NULL

Requires and comes with MySQL Connector/Python v8.0.22 and later:
    http://dev.mysql.com/downloads/connector/python/
    N)datetime)settings)ImproperlyConfigured)IntegrityError)BaseDatabaseWrapper)utils)cached_property)	dateparsetimezone)MySQLConverterMySQLConverterBasez)Error loading mysql.connector module: {0})datetime_to_mysqltime_to_mysqlFT   )DatabaseClient)DatabaseCreation)DatabaseIntrospection)DatabaseValidation)DatabaseFeatures)DatabaseOperations)DatabaseSchemaEditorc             C   sb   t jrHtj| r4tjd|  t tj }tj| |} | j	tj
jd d} trTt| S | jdS d S )NzGMySQL received a naive datetime (%s) while time zone support is active.)tzinfoz%Y-%m-%d %H:%M:%S.%f)r   USE_TZr
   is_naivewarningswarnRuntimeWarningZget_default_timezoneZ
make_aware
astimezoneutcreplace	HAVE_CEXTr   strftime)valueZdefault_timezone r#   O/tmp/pip-install-q3hcpn_q/mysql-connector-python/mysql/connector/django/base.py$adapt_datetime_with_timezone_supportU   s    
r%   c               @   sN   e Zd ZdZdZdd Zdd	 Zd
d ZdddZdd Z	dd Z
dd ZdS )CursorWrapperzWrapper around MySQL Connector/Python's cursor class.

    The cursor class is defined by the options passed to MySQL
    Connector/Python. If buffered option is True in those options,
    MySQLCursorBuffered will be used.
            c             C   s
   || _ d S )N)cursor)selfr+   r#   r#   r$   __init__s   s    zCursorWrapper.__init__c             C   s@   |s|S t |}x*|j D ]\}}t|trt|||< qW |S )N)dictitems
isinstancer   r%   )r,   argsnew_argskeyr"   r#   r#   r$   _adapt_execute_args_dictv   s    
z&CursorWrapper._adapt_execute_args_dictc             C   sD   |s|S t |}x*t|D ]\}}t|trt|||< qW t|S )N)list	enumerater0   r   r%   tuple)r,   r1   r2   iargr#   r#   r$   _adapt_execute_args   s    
z!CursorWrapper._adapt_execute_argsNc             C   sz   t |tr| j|}n
| j|}y| jj||S  tjjk
rt } z&|j	d | j
krbtt|j	  W Y dd}~X nX dS )zExecutes the given operation

        This wrapper method around the execute()-method of the cursor is
        mainly needed to re-raise using different exceptions.
        r   N)r0   r.   r4   r:   r+   executemysql	connectorOperationalErrorr1   codes_for_integrityerrorr   r7   )r,   queryr1   r2   er#   r#   r$   r;      s    

zCursorWrapper.executec             C   sZ   y| j j||S  tjjk
rT } z&|jd | jkrBtt|j  W Y dd}~X nX dS )zExecutes the given operation

        This wrapper method around the executemany()-method of the cursor is
        mainly needed to re-raise using different exceptions.
        r   N)	r+   executemanyr<   r=   r>   r1   r?   r   r7   )r,   r@   r1   rA   r#   r#   r$   rB      s    zCursorWrapper.executemanyc             C   s   t | j|S )z"Return attribute of wrapped cursor)getattrr+   )r,   attrr#   r#   r$   __getattr__   s    zCursorWrapper.__getattr__c             C   s
   t | jS )z$Returns iterator over wrapped cursor)iterr+   )r,   r#   r#   r$   __iter__   s    zCursorWrapper.__iter__)r'   r(   r)   r*   )N)__name__
__module____qualname____doc__r?   r-   r4   r:   r;   rB   rE   rG   r#   r#   r#   r$   r&   e   s      


r&   c                   sl  e Zd ZdZdddddddd	d
ddddd
dddddddddddddddZdZZdd d!d d"d#d$d%d&d'd!d!d d d(Zd)Zd*d+d,d-d.d/d0Zd1d2d3d4hZ	e
jZeZeZeZeZeZeZeZ fd5d6Zd7d8 Zd9d: Zd;d< Zd=d> Zd[d@dAZ dBdC Z!dDdE Z"dFdG Z#dHdI Z$d\dJdKZ%dLdM Z&e'dNdO Z(e'dPdQ Z)e'dRdS Z*e'dTdU Z+e'dVdW Z,e-dXdY Z.  Z/S )]DatabaseWrapperr<   zinteger AUTO_INCREMENTzbigint AUTO_INCREMENTlongblobboolzvarchar(%(max_length)s)datezdatetime(6)z+numeric(%(max_digits)s, %(decimal_places)s)Zbigintzdouble precisionintegerzchar(15)zchar(39)jsonzbigint UNSIGNEDzinteger UNSIGNEDzsmallint UNSIGNEDzsmallint AUTO_INCREMENTZsmallintlongtextztime(6)zchar(32))Z	AutoFieldZBigAutoFieldZBinaryFieldZBooleanFieldZ	CharFieldZ	DateFieldZDateTimeFieldZDecimalFieldZDurationFieldZ	FileFieldZFilePathFieldZ
FloatFieldZIntegerFieldZBigIntegerFieldZIPAddressFieldZGenericIPAddressFieldZ	JSONFieldZNullBooleanFieldZOneToOneFieldPositiveBigIntegerFieldPositiveIntegerFieldPositiveSmallIntegerFieldZ	SlugFieldZSmallAutoFieldZSmallIntegerFieldZ	TextFieldZ	TimeFieldZ	UUIDFieldtinyblobblob
mediumblobtinytexttext
mediumtextz= %szLIKE %szLIKE BINARY %szREGEXP BINARY %sz	REGEXP %sz> %sz>= %sz< %sz<= %s)exactZiexactcontains	icontainsregexZiregexgtZgteltZlte
startswithendswithistartswith	iendswithzCREPLACE(REPLACE(REPLACE({}, '\\', '\\\\'), '%%', '\%%'), '_', '\_')z"LIKE BINARY CONCAT('%%', {}, '%%')zLIKE CONCAT('%%', {}, '%%')zLIKE BINARY CONCAT({}, '%%')zLIKE CONCAT({}, '%%')zLIKE BINARY CONCAT('%%', {})zLIKE CONCAT('%%', {}))r]   r^   rb   rd   rc   re   zread uncommittedzread committedzrepeatable readZserializablec                s\   t t| j|| y| jd d | _W n tk
rB   t | _Y nX | jrPt nt	 | _
d S )NOPTIONSuse_pure)superrL   r-   settings_dict	_use_pureKeyErrorr    rg   DjangoMySQLConverterDjangoCMySQLConverter	converter)r,   r1   kwargs)	__class__r#   r$   r-     s    zDatabaseWrapper.__init__c             C   s   |j drdS td S )NZmysql_isF)rb   AttributeError)r,   rD   r#   r#   r$   rE     s    
zDatabaseWrapper.__getattr__c             C   s   ddddd}| j }|d r(|d |d< |d r<|d |d< |d	 rP|d	 |d
< |d jdrl|d |d< n|d r|d |d< |d rt|d |d< tj|d< tjjjj	g|d< y|j
|d  W n tk
r   Y nX |S )Nutf8TF)charsetZuse_unicodeZbufferedZconsume_resultsUSERuserNAMEZdatabaseZPASSWORDpasswdZHOST/Zunix_sockethostZPORTportZraise_on_warningsZclient_flagsrf   )ri   rb   intr   DEBUGr<   r=   	constantsZ
ClientFlagZ
FOUND_ROWSupdaterk   )r,   ro   ri   r#   r#   r$   get_connection_params$  s0    
z%DatabaseWrapper.get_connection_paramsc             C   s*   | j st|d< nt|d< tjjf |}|S )NZconverter_class)rg   rm   rl   r<   r=   connect)r,   Zconn_paramsZcnxr#   r#   r$   get_new_connectionJ  s
    
z"DatabaseWrapper.get_new_connectionc             C   s   g }| j jr|jd |r>| j }|jdj| W d Q R X d| jkry| j| jd  W n$ tk
r   | j	| jd  Y nX d S )NzSET SQL_AUTO_IS_NULL = 0z; Z
AUTOCOMMIT)
featuresZis_sql_auto_is_null_enabledappendr+   r;   joinri   Zset_autocommitrq   _set_autocommit)r,   Zassignmentsr+   r#   r#   r$   init_connection_stateS  s    


z%DatabaseWrapper.init_connection_stateNc             C   s   | j j }t|S )N)
connectionr+   r&   )r,   namer+   r#   r#   r$   create_cursorf  s    
zDatabaseWrapper.create_cursorc             C   s(   yt j|  W n tk
r"   Y nX d S )N)r   	_rollbackNotSupportedError)r,   r#   r#   r$   r   j  s    zDatabaseWrapper._rollbackc          	   C   s   | j  || j_W d Q R X d S )N)Zwrap_database_errorsr   
autocommit)r,   r   r#   r#   r$   r   p  s    zDatabaseWrapper._set_autocommitc          	   C   s"   | j  }|jd W dQ R X dS )z
        Disable foreign key checks, primarily for use in adding rows with
        forward references. Always return True to indicate constraint checks
        need to be re-enabled.
        zSET foreign_key_checks=0NT)r+   r;   )r,   r+   r#   r#   r$   disable_constraint_checkingt  s    
z+DatabaseWrapper.disable_constraint_checkingc             C   s>   d| j  | _ }z"| j }|jd W dQ R X W d|| _ X dS )zM
        Re-enable foreign key checks after they have been disabled.
        FzSET foreign_key_checks=1N)needs_rollbackr+   r;   )r,   r   r+   r#   r#   r$   enable_constraint_checking~  s
    
z*DatabaseWrapper.enable_constraint_checkingc       
      C   s   | j  }|dkr| jj|}x|D ]}| jj||}|s<q$| jj||}xd|D ]\\}}}|jd||||||||f  x2|j D ]&}	td||	d |||	d ||f qW qPW q$W W dQ R X dS )a]  
        Check each table name in `table_names` for rows with invalid foreign
        key references. This method is intended to be used in conjunction with
        `disable_constraint_checking()` and `enable_constraint_checking()`, to
        determine if rows with invalid references were entered while constraint
        checks were off.
        Na0  
                        SELECT REFERRING.`%s`, REFERRING.`%s` FROM `%s` as REFERRING
                        LEFT JOIN `%s` as REFERRED
                        ON (REFERRING.`%s` = REFERRED.`%s`)
                        WHERE REFERRING.`%s` IS NOT NULL AND REFERRED.`%s` IS NULL
                        zThe row in table '%s' with primary key '%s' has an invalid foreign key: %s.%s contains a value '%s' that does not have a corresponding value in %s.%s.r   r   )r+   introspectiontable_namesZget_primary_key_columnZget_key_columnsr;   Zfetchallr   )
r,   r   r+   Z
table_nameZprimary_key_column_nameZkey_columnsZcolumn_nameZreferenced_table_nameZreferenced_column_nameZbad_rowr#   r#   r$   check_constraints  s&    

z!DatabaseWrapper.check_constraintsc             C   s,   y| j j  W n tk
r"   dS X dS d S )NFT)r   ZpingError)r,   r#   r#   r$   	is_usable  s
    zDatabaseWrapper.is_usablec             C   s   dS )NZMySQLr#   )r,   r#   r#   r$   display_name  s    zDatabaseWrapper.display_namec             C   s   | j jrdddd}|S i S )Nz`%(column)s` >= 0)rS   rT   rU   )r   Z!supports_column_check_constraints)r,   r   r#   r#   r$   data_type_check_constraints  s    z+DatabaseWrapper.data_type_check_constraintsc          	   C   s*   | j  }|jd |j d S Q R X d S )NzSELECT VERSION()r   )Ztemporary_connectionr;   fetchone)r,   r+   r#   r#   r$   mysql_server_info  s    

z!DatabaseWrapper.mysql_server_infoc          	   C   s.   | j  }tjjf |}|j }W d Q R X |S )N)r   r<   r=   r   Zget_server_version)r,   configconnZserver_versionr#   r#   r$   mysql_version  s    zDatabaseWrapper.mysql_versionc          
   C   s@   | j  }|jd |j }W d Q R X t|r:|d jdnf S )NzSELECT @@sql_moder   ,)r+   r;   r   setsplit)r,   r+   sql_moder#   r#   r$   r     s    

zDatabaseWrapper.sql_modec             C   s   | j S )N)rj   )r,   r#   r#   r$   rg     s    zDatabaseWrapper.use_pure)	rV   rW   rX   rM   rY   rZ   r[   rR   rQ   )N)N)0rH   rI   rJ   vendorZ
data_typesZ_limited_data_types	operatorsZpattern_escZpattern_opsZisolation_levelsr<   r=   ZDatabaser   ZSchemaEditorClassr   Zclient_classr   Zcreation_classr   Zfeatures_classr   Zintrospection_classr   Z	ops_classr   Zvalidation_classr-   rE   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   propertyrg   __classcell__r#   r#   )rp   r$   rL      s   	 &	


(rL   c               @   s<   e Zd ZdZdddZdddZdd Zd	d
 Zdd ZdS )rl   z/Custom converter for Django for MySQLConnectionNc             C   s   t j|jdS )zXReturn MySQL TIME data type as datetime.time()

        Returns datetime.time()
        zutf-8)r	   
parse_timedecode)r,   r"   dscr#   r#   r$   _TIME_to_python  s    z$DjangoMySQLConverter._TIME_to_pythonc             C   sB   |sdS t j| |}|dkr dS tjr>tj|r>|jtjd}|S )a  Connector/Python always returns naive datetime.datetime

        Connector/Python always returns naive timestamps since MySQL has
        no time zone support. Since Django needs non-naive, we need to add
        the UTC time zone.

        Returns datetime.datetime()
        N)r   )r   Z_DATETIME_to_pythonr   r   r
   r   r   r   )r,   r"   r   dtr#   r#   r$   __DATETIME_to_python  s    	z)DjangoMySQLConverter.__DATETIME_to_pythonc             C   s
   | j |S )N)_str_to_mysql)r,   r"   r#   r#   r$   _safestring_to_mysql  s    z)DjangoMySQLConverter._safestring_to_mysqlc             C   s
   | j |S )N)r   )r,   r"   r#   r#   r$   _safetext_to_mysql  s    z'DjangoMySQLConverter._safetext_to_mysqlc             C   s
   | j |S )N)Z_bytes_to_mysql)r,   r"   r#   r#   r$   _safebytes_to_mysql  s    z(DjangoMySQLConverter._safebytes_to_mysql)N)N)	rH   rI   rJ   rK   r   Z)_DjangoMySQLConverter__DATETIME_to_pythonr   r   r   r#   r#   r#   r$   rl     s   

rl   c               @   s$   e Zd ZdZdddZdddZdS )	rm   z0Custom converter for Django for CMySQLConnectionNc             C   s   t jt|S )zXReturn MySQL TIME data type as datetime.time()

        Returns datetime.time()
        )r	   r   str)r,   r"   r   r#   r#   r$   r     s    z%DjangoCMySQLConverter._TIME_to_pythonc             C   s*   |sdS t jr&tj|r&|jtjd}|S )a  Connector/Python always returns naive datetime.datetime

        Connector/Python always returns naive timestamps since MySQL has
        no time zone support. Since Django needs non-naive, we need to add
        the UTC time zone.

        Returns datetime.datetime()
        N)r   )r   r   r
   r   r   r   )r,   r"   r   r#   r#   r$   r     s
    	z*DjangoCMySQLConverter.__DATETIME_to_python)N)N)rH   rI   rJ   rK   r   Z*_DjangoCMySQLConverter__DATETIME_to_pythonr#   r#   r#   r$   rm   	  s   
rm   )7rK   r   sysr   Zdjango.confr   Zdjango.core.exceptionsr   Z	django.dbr   Zdjango.db.backends.base.baser   r   Zdjango.utils.functionalr   Zdjango.utilsr	   r
   Zmysql.connectorr<   Zmysql.connector.conversionr   r   ImportErrorerrformatZ_mysql_connectorr   r   r    clientr   Zcreationr   r   r   Z
validationr   r   r   
operationsr   Zschemar   r=   r   ZDatabaseErrorr   r>   ZProgrammingErrorr%   r&   rL   rl   rm   r#   r#   r#   r$   <module>(   sP   
L  5%