U
    ec~                     @   s   d Z ddlZddl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mZmZ ddlmZmZmZmZ d	ZG d
d dZdS )z,Implements the MySQL Client/Server protocol.    N)DecimalDecimalException   )utils)get_auth_plugin)PARAMETER_COUNT_AVAILABLE
ClientFlag	FieldFlag	FieldType	ServerCmd)DatabaseErrorInterfaceErrorProgrammingErrorget_exception
   c                	   @   s  e Zd ZdZedd Zedd ZdJddZedd ZedKddZ	edLddZ
edMddZdNddZedd Zedd Zedd Zedd ZedOd!d"Zd#d$ ZedPd&d'ZdQd(d)Zed*d+ Zed,d- ZedRd/d0Zed1d2 Zed3d4 ZdSd5d6ZdTd7d8Zed9d: Zed;d< Zed=d> Zed?d@ ZedAdB Z dUdDdEZ!edFdG Z"edHdI Z#dS )VMySQLProtocolzRImplements MySQL client/server protocol

    Create and parses MySQL packets.
    c                 C   s    | t j@ r|r|dd S dS )z.Prepare database string for handshake responseutf8    )r   ZCONNECT_WITH_DBencode)client_flagsdatabase r   </tmp/pip-unpacked-wheel-ix8dg7li/mysql/connector/protocol.py_connect_with_db8   s    zMySQLProtocol._connect_with_dbc              
   C   s   |sdS z"t ||||||d}| }W n6 ttfk
r` }	 ztd|	 |	W 5 d}	~	X Y nX | tj@ rt|}
td|
| }n|d }|S )z#Prepare the authentication responser   )usernamepasswordr   ssl_enabledzFailed authentication: N<B)	r   auth_response	TypeErrorr   r   SECURE_CONNECTIONlenstructpack)r   r   r   r   auth_plugin	auth_datar   authZplugin_auth_responseerrZresplenr   r   r   r   _auth_response?   s$    "
zMySQLProtocol._auth_responseN-   r      @Fc              
   C   s  z|d }|	p|d }	W n8 t tfk
rP } ztd| ddW 5 d}~X Y nX |sZd}z|d}W n tk
r   |}Y nX d}t|}td	| | d
||||}|| |||||	||7 }|| 	||7 }|t
j@ r||	dd 7 }|t
j@ r|
dk	r|| |
7 }|S )z"Make a MySQL Authentication packetr%   r$   &Handshake misses authentication info ()N    r   Zxxxxxxxxxxxxxxxxxxxxxxz<IIHsxr   )r   KeyErrorr   r   AttributeErrorr!   r"   r#   r(   r   r   PLUGIN_AUTHCONNECT_ARGSmake_conn_attrs)self	handshaker   r   r   charsetr   max_allowed_packetr   r$   
conn_attrsr%   r'   username_bytesZfillerusername_lenpacketr   r   r   	make_auth`   sN    



zMySQLProtocol.make_authc                    s    D ]} | dkrd |< qt  fdd D t   t   }td|} D ]P}|tdt|7 }||d7 }|tdt | 7 }| | d7 }q\|S )z Encode the connection attributesN c                 3   s"   | ]}t |t  |  V  qd S )N)r!   ).0xr8   r   r   	<genexpr>   s     z0MySQLProtocol.make_conn_attrs.<locals>.<genexpr>r   r   )sumr!   keysvaluesr"   r#   r   )r8   	attr_nameZconn_attrs_lenZconn_attrs_packetr   r@   r   r3      s     


zMySQLProtocol.make_conn_attrsc                 C   s"   t |t | t |  d S )z Make a SSL authentication packets                         r   	int4store	int2store)r6   r   r7   r   r   r   make_auth_ssl   s    zMySQLProtocol.make_auth_sslc                 C   s   t | }|dk	r||7 }|S )z(Make a MySQL packet containing a commandN)r   	int1store)commandargumentdatar   r   r   make_command   s    
zMySQLProtocol.make_commandr   c                 C   s   t | t | S )z0Make a MySQL packet with Fetch Statement command)r   rG   )statement_idrowsr   r   r   make_stmt_fetch   s    zMySQLProtocol.make_stmt_fetchc
              
   C   s   z|d }
|p|d }W n8 t tfk
rP } ztd| ddW 5 d}~X Y nX |sZd}z|d}W n tk
r   |}Y nX t|}td| d	tj	|}|| 
||||||
|7 }|| ||7 }|td
|7 }|tj@ r||dd 7 }|tj@ r|	dk	r|| |	7 }|S )z0Make a MySQL packet with the Change User commandr%   r$   r+   r,   Nr-   r   r   r.   <Hr   )r   r/   r   r   r0   r!   r"   r#   r   ZCHANGE_USERr(   r   r   r1   r2   r3   )r4   r5   r   r   r   r6   r   r   r$   r8   r%   r'   r9   r:   r;   r   r   r   make_change_user   sJ    




zMySQLProtocol.make_change_userc           	   	   C   s  i }t d| dd d |d< |d tkrDtd|d  dt tj| dd dd	\} |d
< t d| dd \|d< }}|d< |d< }}|d
  |d
< | dd } t|| }d}|tj	@ r|rt
d|d nd}| d| }| |d } |d dkr|dd }|tj@ rrd| krH|d
 drHd|  } |d< ntj| dd	\} |d< |d d|d< nd|d< || |d< ||d< |S )zParse a MySQL Handshake-packet<xxxxBr      protocolz$Protocol mismatch; server version = z, client version = Nr   endZserver_version_originalz<I8sx2sBH2sBxxxxxxxxxx   Zserver_threadidr6   Zserver_statusr-         z5.5.8r$   utf-8Zmysql_native_passwordr%   capabilities)r"   unpackPROTOCOL_VERSIONr   r   read_stringdecodeZintreadr   r    minr1   
startswith)	r;   resZ
auth_data1Zcapabilities1Zcapabilities2Zauth_data_lengthr^   Z
auth_data2sizer   r   r   parse_handshake  sP    
 zMySQLProtocol.parse_handshakec                 C   s@   t | d\} }|dks tdt j| dd\} }| |dfS )z$Parse a MySQL AuthNextFactor packet.r      z.Failed parsing AuthNextFactor packet (invalid)r   rW   r]   )r   read_intr   ra   rb   )r;   statusr$   r   r   r   parse_auth_next_factor8  s
    z$MySQLProtocol.parse_auth_next_factorc              
   C   s   | d dkst di }ztd| dd d |d< t| dd \} |d< t| \} |d	< td
| dd \|d< |d< | dd } | rt| \} |d< |d d|d< W n, tk
r } zt d|W 5 d}~X Y nX |S )zParse a MySQL OK-packet   r   z#Failed parsing OK packet (invalid).rT   rU   Zfield_countNZaffected_rowsZ	insert_idz<HHstatus_flagwarning_countZinfo_msgr]   zFailed parsing OK packet.)r   r"   r_   r   read_lc_intread_lc_stringrb   
ValueError)r;   Z	ok_packetr'   r   r   r   parse_okA  s$    zMySQLProtocol.parse_okc              
   C   sT   zt | dd d }|W S  tjtfk
rN } ztd|W 5 d}~X Y nX dS )z=Parse a MySQL packet with the number of columns in result setrl   Nr   zFailed parsing column count)r   ro   r"   errorrq   r   )r;   countr'   r   r   r   parse_column_countX  s
    z MySQLProtocol.parse_column_countr]   c              	   C   s   t | dd \} }t | \} }t | \} }t | \} }t | \} }t | \} }ztd| \}}}}}W n  tjk
r   tddY nX |||dddd| tj@ ||f	S )zParse a MySQL column-packetrl   Nz	<xHIBHBxxz!Failed parsing column information)	r   rp   r"   r_   rs   r   rb   r	   ZNOT_NULL)r;   encoding_namer6   Zcolumn_typeflagsr   r   r   parse_columna  s6    

zMySQLProtocol.parse_columnc              
   C   s   |d dkr|  |S d}i }ztd|}W n. tjk
r\ } zt||W 5 d}~X Y nX |d dkrvt|dks~t||d	 |d
< |d |d< |S )zParse a MySQL EOF-packetrl   r   zFailed parsing EOF packet.z<xxxBBHHNr      	   rh   rn      rm   )rr   r"   r_   rs   r   r!   )r4   r;   err_msgre   unpackedr'   r   r   r   	parse_eof  s    
zMySQLProtocol.parse_eofTc           	      C   s  d}i }|r | dd  d}n
|  d}|D ]}zdd | ddD \}}W n, tk
r| } zt||W 5 d}~X Y nX |d	}zt|||< W q. ttfk
r
   zt|d	||< W n@ tk
r } z t| d
| d| d|W 5 d}~X Y nX Y q.X q.|S )zParse the statistics packetz)Failed getting COM_STATISTICS informationrl   Ns     c                 S   s   g | ]}|  qS r   )strip)r>   vr   r   r   
<listcomp>  s     z2MySQLProtocol.parse_statistics.<locals>.<listcomp>   :rh   r]   z (:r,   )splitrq   r   rb   intr/   r   r   )	r;   Zwith_headererrmsgre   pairspairZlblvalr'   r   r   r   parse_statistics  s&    

6zMySQLProtocol.parse_statisticsc                 C   s"  |}g }d}d}d}|s ||kr$q|  }	|	dr|	dd g}
|  }	|	drr|
|	dd  |  }	qL|
|	dd  ttd|
}n>|	d dkr|	d dk r| |	}d}nd}t|	dd }|dkr|dk	r|| n|dkr|dkrt|	|d7 }q||fS )	zRead MySQL text result

        Reads all or given number of rows from the socket.

        Returns a tuple with 2 elements: a list with all rows and
        the EOF packet.
        Nr   s   rl   r-   r{      r   )	recvrd   appendr   Zread_lc_string_list	bytearrayjoinr   r   )r4   sockversionrt   rw   rP   eofZrowdatair;   Zdatasr   r   r   read_text_result  s6    	




zMySQLProtocol.read_text_resultc                 C   s   |d t jkrd}d}nL|d t jkr0d}d}n4|d t jt jfkrNd}d}n|d t jkrdd}d}|d	 tj@ rz| }| |d
 t	
|| d| d fS )z%Parse an integer from a binary packetr   <b<hrh   <irl   <qr[   r   Nr   )r
   TINYSHORTINT24LONGLONGLONGr	   ZUNSIGNEDupperr"   r_   )r;   fieldformat_lengthr   r   r   _parse_binary_integer  s    z#MySQLProtocol._parse_binary_integerc                 C   sD   |d t jkrd}d}nd}d}| |d t|| d| d fS )z)Parse a float/double from a binary packetr   r[   <drl   z<fNr   )r
   DOUBLEr"   r_   )r;   r   r   r   r   r   r   _parse_binary_float  s    z!MySQLProtocol._parse_binary_floatr   c                 C   s    t | \} }| t||fS )z(Parse a New Decimal from a binary packet)r   rp   r   rb   )r;   r6   valuer   r   r   _parse_binary_new_decimal  s    z'MySQLProtocol._parse_binary_new_decimalc              	   C   s   | d }d}|dkrBt jtd| dd d | d | d d}np|dkrd}|d	krrtd
| d|d  d }t j td| dd d | d | d | d | d | d |d}| |d d |fS )z&Parse a timestamp from a binary packetr   Nrl   rR   r   r}   )yearmonthdayr      <Ir[   rU      )r   r   r   hourminutesecondmicrosecond)datetimedater"   r_   )r;   r   r   mcsr   r   r   _parse_binary_timestamp  s,    
z%MySQLProtocol._parse_binary_timestampc                 C   s   | d }|s | dd t  fS | d|d  }d}|dkrTtd|dd d }td|dd d }|d dkr|d9 }t j||d ||d	 |d d
}| |d d |fS )z'Parse a time value from a binary packetr   r   Nr[   r   rU   r\   r   r   )dayssecondsmicrosecondsminuteshours)r   	timedeltar"   r_   )r;   r   rM   r   r   tmpr   r   r   _parse_binary_time  s$    z MySQLProtocol._parse_binary_timec           
      C   s  t |d d d }dd |d| D }||d }g }t|D ]R\}}|t|d d  d|d d > @ r||d qB|d tjtjtjtjtj	fkr| 
||\}}	||	 qB|d tjtjfkr| ||\}}	||	 qB|d tjtjfkr| ||\}}	||	 qB|d tjtjtjfkrN| |\}}	||	 qB|d tjkrx| |\}}	||	 qBt|\}}	||	| qBt|S )	z(Parse values from a binary result packetr   rh   r[   c                 S   s   g | ]}t |qS r   )r   )r>   r   r   r   r   r   4  s     z6MySQLProtocol._parse_binary_values.<locals>.<listcomp>r   Nr   )r!   	enumerater   r   r
   r   r   r   r   r   r   r   FLOATr   DECIMALZ
NEWDECIMALr   DATETIMEDATE	TIMESTAMPr   TIMEr   r   rp   rb   tuple)
r4   fieldsr;   r6   Znull_bitmap_lengthnull_bitmaprD   posr   r   r   r   r   _parse_binary_values1  sH    $
z"MySQLProtocol._parse_binary_valuesc           
      C   s   g }d}d}d}|dk	rq||kr$q|  }	|	d dkrH| |	}d}n&|	d dkrnd}| ||	dd |}|dkr|dk	r|| n|dkr|dkrt|	|d7 }q||fS )zwRead MySQL binary protocol result

        Reads all or given number of binary resultset rows from the socket.
        Nr   rl   r{   rU   r   )r   r   r   r   r   )
r4   r   columnsrt   r6   rP   r   rD   r   r;   r   r   r   read_binary_result[  s*    

z MySQLProtocol.read_binary_resultc              
   C   s   | d dkst di }zht| dd d\} |d< t| d\} |d< t| d\} |d	< | d
d } t| d\} |d< W n, tk
r } zt d|W 5 d}~X Y nX |S )z'Parse a MySQL Binary Protocol OK packetrl   r   zFailed parsing Binary OK packetrU   NrO   rh   Znum_columnsZ
num_paramsr   rn   )r   r   ri   rq   )r;   Zok_pktr'   r   r   r   parse_binary_prepare_okw  s    z%MySQLProtocol.parse_binary_prepare_okc                 C   s   d}d}| dk rX| dkr$d}t j}q| dkr8d}t j}q| dkrLd}t j}qd	}t j}nJd
}| dkrpd}t j}n2| dkrd}t j}n| dkrd}t j}n
t j}d}t|| ||fS )z0Prepare an integer for the MySQL binary protocolNr   ir   i r   i   r   r         r   i  rR   l    r   z<Q)r
   r   r   r   r   r"   r#   )r   
field_typery   r   r   r   r   prepare_binary_integer  s6    z$MySQLProtocol.prepare_binary_integerc                 C   s   t | tjrtj}nt | tjr(tj}ntdt| j	t
| j t
| j }t | tjr|t
| j t
| j t
| j }| jdkr|t| j7 }t
t|| }||fS )a  Prepare a timestamp object for the MySQL binary protocol

        This method prepares a timestamp of type datetime.datetime or
        datetime.date for sending over the MySQL binary protocol.
        A tuple is returned with the prepared value and field type
        as elements.

        Raises ValueError when the argument value is of invalid type.

        Returns a tuple.
        z2Argument must a datetime.datetime or datetime.dater   )
isinstancer   r
   r   r   r   rq   r   rH   r   rJ   r   r   r   r   r   r   rG   r!   )r   r   packedr   r   r   prepare_binary_timestamp  s0    






z&MySQLProtocol.prepare_binary_timestampc           	      C   s  t | tjtjfstdtj}d}d}d}t | tjr| jdk rFd}t| j	d\}}t|d\}}|t
t| jt
| t
| t
| 7 }| j}n8|t
dt
| j t
| j t
| j 7 }| j}|r|t
|7 }t
|| }t
t|| }||fS )a  Prepare a time object for the MySQL binary protocol

        This method prepares a time object of type datetime.timedelta or
        datetime.time for sending over the MySQL binary protocol.
        A tuple is returned with the prepared value and field type
        as elements.

        Raises ValueError when the argument value is of invalid type.

        Returns a tuple.
        z3Argument must a datetime.timedelta or datetime.timer   Nr-   r   i  <   )r   r   r   timerq   r
   r   r   divmodr   r   rG   absrJ   r   r   r   r   r   r!   )	r   r   negativer   r   r   	remainderZminsZsecsr   r   r   prepare_binary_time  sH    



z!MySQLProtocol.prepare_binary_timec                 C   s   t | t | | }|S )zMPrepare long data for prepared statements

        Returns a string.
        rF   )Z	statementparamrM   r;   r   r   r   prepare_stmt_send_long_data  s    z)MySQLProtocol.prepare_stmt_send_long_datar   c	              	   C   s  d}	dgt |d d  }
g }g }d}t |}g }|s:|n|t }|dkrNd}|dkrZi }|rt|}|D ]\}}|| qjdgt |d d  }
|s|r*|t |krtd	t|D ]l\}}d}|dkr|
|d   d|d > O  < |ttj	t|  q||kr6|| d r,tj
}ntj}nt|tr`| |\}}}|| npt|tr||}|tt ||  tj}n8t|tr|tt ||  tj
}n
t|tr|tt t||t||  tj}nt|tr,|td
| tj}nt|tjtjfrZ| |\}}|| nvt|tjtjfr| |\}}|| nH|rt||}|tt ||  tj}nt d|j!j" d|t|t|  |r|d |kr|||  d |}|tt ||  qt#|t| t#|	 }|dk	r`|t | }n|}|r
|dk	r|t|7 }|d$dd |
D td 7 }d}|D ]H}||7 }|dk	r|d |kr||||  7 }n|d7 }|d7 }q|D ]}||7 }q|S )z6Make a MySQL packet with the Statement Execute commandr   r   r   r[   r-   Zutf8mb4r   NzTFailed executing prepared statement: data values does not match number of parametersr   z&MySQL binary protocol can not handle 'z	' objectsc                 S   s   g | ]}t d |qS )B)r"   r#   )r>   bitr   r   r   r   z  s     z3MySQLProtocol.make_stmt_execute.<locals>.<listcomp>r   )%r!   r   listr   r   r   r   rJ   r
   NULLZBLOBSTRINGr   r   r   strr   Zlc_intZVARCHARbytesr   r   floatr"   r#   r   r   r   r   r   r   r   r   	__class____name__rG   r   )r4   rO   rM   
parametersry   Zlong_data_usedr6   Zquery_attrsZconverter_str_fallbackZiteration_countr   rD   typesr   data_lenZquery_attr_namesrw   Zattr_valr   r   _flagsr   rx   r;   Zparameter_countrt   Za_typeZa_valuer   r   r   make_stmt_execute  s    









zMySQLProtocol.make_stmt_executec                 C   sX   | d dkst dtj| dd dd\} }| rJ| d d	krJ| dd } |d
| fS )z&Parse a MySQL AuthSwitchRequest-packetrl   r{   z'Failed parsing AuthSwitchRequest packetrU   Nr   rW   r\   r   r   )r   r   ra   rb   )r;   Zplugin_namer   r   r   parse_auth_switch_request  s    z'MySQLProtocol.parse_auth_switch_requestc                 C   s    | d dkst d| dd S )z!Parse a MySQL AuthMoreData-packetrl   r   z"Failed parsing AuthMoreData packetrU   N)r   )r;   r   r   r   parse_auth_more_data  s    z"MySQLProtocol.parse_auth_more_data)	NNNr)   r   r*   FNN)r)   r   r*   )N)r   )NNNr)   r   FNN)r]   )T)r   )r   )r]   )r   r]   )r   r   r   Nr   NF)$r   
__module____qualname____doc__staticmethodr   r(   r<   r3   rI   rN   rQ   rS   rg   rk   rr   ru   rz   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   2   s   

#         
>
	        
;
3


 
'




*


!
&
0
       
 
r   )r   r   r"   decimalr   r   r=   r   Zauthenticationr   	constantsr   r   r	   r
   r   errorsr   r   r   r   r`   r   r   r   r   r   <module>   s   