3
(hs                 @   s   d Z ddlZddlZddlmZ ddlmZmZmZm	Z	 ddl
mZmZ ddlmZ ddlmZmZ dd	lmZmZ d
ZG dd deZdS )z,Implements the MySQL Client/Server protocol
    N)Decimal   )	FieldFlag	ServerCmd	FieldType
ClientFlag)errorsutils)get_auth_plugin)PY2struct_unpack)DatabaseErrorget_exception
   c            	   @   s  e Zd ZdZdd Zdd ZdEddZdd ZdFddZdGddZ	dHddZ
dIddZdd Zdd Zdd ZdJdd Zd!d" ZdKd$d%ZdLd&d'Zd(d) Zd*d+ Zd,d- Zd.d/ ZdMd0d1ZdNd2d3Zd4d5 Zd6d7 Zd8d9 Zd:d; Zd<d= Zf f ddd>fd?d@ZdAdB ZdCdD Z dS )OMySQLProtocolzRImplements MySQL client/server protocol

    Create and parses MySQL packets.
    c             C   s    |t j@ r|r|jdd S dS )z.Prepare database string for handshake responseutf8    )r   ZCONNECT_WITH_DBencode)selfclient_flagsdatabase r   L/tmp/pip-install-q3hcpn_q/mysql-connector-python/mysql/connector/protocol.py_connect_with_db4   s    zMySQLProtocol._connect_with_dbc             C   s   |sdS y"t ||||||d}|j }	W n< ttjfk
rf }
 ztjdjt|
W Y dd}
~
X nX |tj@ rt	|	}t
jd||	 }n|	d }|S )z#Prepare the authentication responser   )usernamepasswordr   ssl_enabledzFailed authentication: {0}Nz<B)r
   auth_response	TypeErrorr   InterfaceErrorformatstrr   SECURE_CONNECTIONlenstructpack)r   r   r   r   r   auth_plugin	auth_datar   authZplugin_auth_responseexcZresplenr   r   r   r   _auth_response:   s     "
zMySQLProtocol._auth_responseN-   r      @Fc             C   s  y|d }|	p|d }	W n6 t tfk
rN } ztjdj|W Y dd}~X nX |sXd}y|jd}W n tk
r~   |}Y nX tjdjdd	 t	|d
||||}|| j
|||||	||7 }|| j||7 }|tj@ r||	jdd 7 }|tj@ o|
dk	r|| j|
7 }|S )z"Make a MySQL Authentication packetr'   r&   z*Handshake misses authentication info ({0})N    r   z<IIH{filler}{usrlen}sxx   )Zfillerusrlenr   )r   KeyErrorr   ProgrammingErrorr    r   AttributeErrorr$   r%   r#   r*   r   r   PLUGIN_AUTHZCONNECT_ARGSmake_conn_attrs)r   	handshaker   r   r   charsetr   max_allowed_packetr   r&   
conn_attrsr'   r)   username_bytespacketr   r   r   	make_authQ   s4    


zMySQLProtocol.make_authc                s   x  D ]} | dkrd |< qW t  fdd D t j  t j  }tjd|}xX D ]P}|tjdt|7 }||jd7 }|tjdt | 7 }| | jd7 }qbW |S )z Encode the connection attributesN c                s    g | ]}t |t  |  qS r   )r#   ).0r.   )r9   r   r   
<listcomp>   s    z1MySQLProtocol.make_conn_attrs.<locals>.<listcomp>z<Br   )sumr#   keysvaluesr$   r%   r   )r   r9   	attr_nameZconn_attrs_lenZconn_attrs_packetr   )r9   r   r5   y   s    
.
zMySQLProtocol.make_conn_attrsc             C   s&   t j|t j| t j| dd  S )z Make a SSL authentication packetr   r/   )r	   	int4store	int2store)r   r7   r   r8   r   r   r   make_auth_ssl   s    zMySQLProtocol.make_auth_sslc             C   s   t j|}|dk	r||7 }|S )z(Make a MySQL packet containing a commandN)r	   	int1store)r   commandargumentdatar   r   r   make_command   s    
zMySQLProtocol.make_commandr   c             C   s   t j|t j| S )z0Make a MySQL packet with Fetch Statement command)r	   rD   )r   statement_idrowsr   r   r   make_stmt_fetch   s    zMySQLProtocol.make_stmt_fetchc	             C   s   y|d }	|p|d }W n6 t tfk
rN }
 ztjdj|
W Y dd}
~
X nX |sXd}y|jd}W n tk
r~   |}Y nX tjdjt	|dt
j|}|| j||||||	|7 }|| j||7 }|tjd	|7 }|tj@ r||jdd
 7 }|S )z0Make a MySQL packet with the Change User commandr'   r&   z*Handshake misses authentication info ({0})Nr-   r   z<B{usrlen}sx)r0   z<Hr   )r   r1   r   r2   r    r   r3   r$   r%   r#   r   ZCHANGE_USERr*   r   r   r4   )r   r6   r   r   r   r7   r   r   r&   r'   r)   r:   r;   r   r   r   make_change_user   s.    



zMySQLProtocol.make_change_userc       
   	   C   s  i }t d|dd d |d< |d tkr>tdj|d ttj|dd dd\}|d	< t d
|dd \|d< }}|d< |d< }}|d	 j |d	< |dd }tj|| }d}|tj	@ r
|rt
d|d nd}	|d|	 }||	d }|d dkr
|dd }|tj@ rjd|kr@|d	 jdr@d| }|d< ntj|dd\}|d< |d jd|d< nd|d< || |d< ||d< |S )zParse a MySQL Handshake-packetz<xxxxBr      protocolz;Protocol mismatch; server version = {}, client version = {}Nr   )endZserver_version_originalz<I8sx2sBH2sBxxxxxxxxxx   Zserver_threadidr7   Zserver_statusr-         r   z5.5.8r&   zutf-8Zmysql_native_passwordr'   capabilitiesrW   )r   PROTOCOL_VERSIONr   r    r	   read_stringdecodeZintreadr   r"   minr4   
startswith)
r   r;   resZ
auth_data1Zcapabilities1Zcapabilities2Zauth_data_lengthrV   Z
auth_data2sizer   r   r   parse_handshake   s<    	,
zMySQLProtocol.parse_handshakec             C   s   |d dkst jdi }ytd|dd d |d< tj|dd \}|d< tj|\}|d	< td
|dd \|d< |d< |dd }|rtj|\}|d< |d jd|d< W n tk
r   t jdY nX |S )zParse a MySQL OK-packet   r   z#Failed parsing OK packet (invalid).z<xxxxBrP   Zfield_countNZaffected_rowsZ	insert_idz<HHstatus_flagwarning_countZinfo_msgzutf-8zFailed parsing OK packet.)r   r   r   r	   read_lc_intread_lc_stringrZ   
ValueError)r   r;   Z	ok_packetr   r   r   parse_ok   s    
zMySQLProtocol.parse_okc             C   sD   yt j|dd d }|S  tjtfk
r>   tjdY nX dS )z=Parse a MySQL packet with the number of columns in result setr`   Nr   zFailed parsing column count)r	   rc   r$   errorre   r   r   )r   r;   countr   r   r   parse_column_count  s
    z MySQLProtocol.parse_column_countutf-8c             C   s   t j|dd \}}t j|\}}t j|\}}t j|\}}t j|\}}t j|\}}ytd|\}}}}}W n  tjk
r   tjdY nX |j||dddd| tj	@ |fS )zParse a MySQL column-packetr`   Nz	<xHIBHBxxz!Failed parsing column information)
r	   rd   r   r$   rg   r   r   rZ   r   ZNOT_NULL)r   r;   r7   _name
field_typeflagsr   r   r   parse_column  s$    
zMySQLProtocol.parse_columnc             C   s   |d dkr| j |S d}i }ytd|}W n  tjk
rL   tj|Y nX |d dkodt|dksptj||d |d	< |d
 |d< |S )zParse a MySQL EOF-packetr`   r   zFailed parsing EOF packet.z<xxxBBHHr      	      rb      ra   )rf   r   r$   rg   r   r   r#   )r   r;   err_msgr]   unpackedr   r   r   	parse_eof'  s    

zMySQLProtocol.parse_eofTc       	      C   s   d}i }|r |dd j d}n
|j d}x|D ]}ydd |j ddD \}}W n   tj|Y nX |jd	}yt|||< W q0   yt|jd	||< W n    tjd
j|||Y nX Y q0X q0W |S )zParse the statistics packetz)Failed getting COM_STATISTICS informationr`   Ns     c             S   s   g | ]}|j  qS r   )strip)r>   vr   r   r   r?   F  s    z2MySQLProtocol.parse_statistics.<locals>.<listcomp>   :rr   zutf-8z{0} ({1}:{2}).)splitr   r   rZ   intr   r    )	r   r;   Zwith_headererrmsgr]   pairspairZlblvalr   r   r   parse_statistics;  s(    


 zMySQLProtocol.parse_statisticsc       
      C   s&  g }d}d}d}x
|s ||kr"P |j  }|jdr|dd g}	|j  }x(|jdrr|	j|dd  |j  }qLW |	j|dd  tjtdj|	}n>|d dkr|d dk r| j|}d}nd}tj|dd }|dkr|dk	r|j| n|dkr|dkrt||d7 }qW ||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   r`   r-   rp      r   )	recvr\   appendr	   Zread_lc_string_list	bytearrayjoinrv   r   )
r   sockversionrh   rM   eofZrowdatair;   Zdatasr   r   r   read_text_resultV  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|j }||d
 t	||d| d fS )z%Parse an integer from a binary packetr   z<bz<hrr   z<ir`   z<qrU   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   sB   |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   rU   z<dr`   z<fNr   )r   DOUBLEr   )r   r;   r   r   r   r   r   r   _parse_binary_float  s    z!MySQLProtocol._parse_binary_floatc          	   C   s   |d }d}|dkr@t jtd|dd d |d |d d}nl|dkrd}|d	krnt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   Nr`   z<Hr   rs   )yearmonthdayr      z<IrU   rP      )r   r   r   hourminutesecondmicrosecond)datetimedater   )r   r;   r   r   valuemcsr   r   r   _parse_binary_timestamp  s(    z%MySQLProtocol._parse_binary_timestampc             C   s   |d }|d|d  }d}|dkr:t d|dd d }t d|dd d }|d dkrd|d
9 }tj||d ||d |d d	}||d d |fS )z'Parse a time value from a binary packetr   r   rU   z<INrP   r   r   )dayssecondsmicrosecondsminuteshoursrW   )r   r   	timedelta)r   r;   r   r   rJ   r   r   tmpr   r   r   _parse_binary_time  s    z MySQLProtocol._parse_binary_timec       
      C   sz  t |d d d }dd |d| D }||d }g }x4t|D ]&\}}|t|d d  d|d d > @ r|jd qFqF|d tjtjtjtjtj	fkr| j
||\}}	|j|	 qF|d tjtjfkr| j||\}}	|j|	 qF|d tjtjtjfkr$| j||\}}	|j|	 qF|d tjkrP| j||\}}	|j|	 qFtj|\}}	|j|	j| qFW t|S )	z(Parse values from a binary result packetr   rr   rU   c             S   s   g | ]}t |qS r   )r{   )r>   r   r   r   r   r?     s    z6MySQLProtocol._parse_binary_values.<locals>.<listcomp>r   Nr   )r#   	enumerater{   r   r   r   r   r   r   r   r   r   FLOATr   DATETIMEDATEZ	TIMESTAMPr   TIMEr   r	   rd   rZ   tuple)
r   fieldsr;   r7   Znull_bitmap_lengthnull_bitmaprB   posr   r   r   r   r   _parse_binary_values  s4    $
z"MySQLProtocol._parse_binary_valuesc       
      C   s   g }d}d}d}x|dk	rP ||kr&P |j  }	|	d dkrJ| j|	}d}n&|	d dkrpd}| j||	dd |}|dkr|dk	r|j| n|dkr|dkrt|	|d7 }qW ||fS )zwRead MySQL binary protocol result

        Reads all or given number of binary resultset rows from the socket.
        Nr   r`   rp   rP   r   )r   rv   r   r   r   )
r   r   columnsrh   r7   rM   r   rB   r   r;   r   r   r   read_binary_result  s,    
z MySQLProtocol.read_binary_resultc             C   s   |d dkst jdi }yhtj|dd d\}|d< tj|d\}|d< tj|d\}|d	< |d
d }tj|d\}|d< W n tk
r   t jdY nX |S )z'Parse a MySQL Binary Protocol OK packetr`   r   zFailed parsing Binary OK packetrP   NrL   rr   Znum_columnsZ
num_paramsr   rb   )r   r   r	   Zread_intre   )r   r;   Zok_pktr   r   r   parse_binary_prepare_ok   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j||||fS )z0Prepare an integer for the MySQL binary protocolNr      z<bi   z<hl        z<iz<q   z<Bi  z<Hl    z<Iz<Qii i   )r   r   r   r   r   r$   r%   )r   r   rm   rn   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|j	tj
|j tj
|j }t |tjr|tj
|j tj
|j tj
|j }|jdkr|tj|j7 }tj
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   re   r	   rE   r   rG   r   r   r   r   r   r   rD   r#   )r   r   rm   packedr   r   r   _prepare_binary_timestamp2  s    
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
jt|jt
j| t
j| t
j|	 7 }|j}n8|t
jdt
j|j t
j|j t
j|j 7 }|j}|r|t
j|7 }t
j|| }t
j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   timere   r   r   r   divmodr   r	   rD   absrG   r   r   r   r   r   r#   )
r   r   rm   negativer   r   r   	remainderZminsZsecsr   r   r   _prepare_binary_timeT  s2    
" z"MySQLProtocol._prepare_binary_timec             C   s   t j|t j| | }|S )zMPrepare long data for prepared statements

        Returns a string.
        )r	   rD   rE   )r   Z	statementparamrJ   r;   r   r   r   _prepare_stmt_send_long_data  s    z*MySQLProtocol._prepare_stmt_send_long_datar   c             C   sB  d}dgt |d d  }g }	g }
d}|dkr2d}|dkr>i }|oD|rt |t |krbtjd	xlt|D ]^\}}|| }d}|dkr||d   d|d > O  < |
jtjtjtj|  qnn||kr|| d rtj	}ntj
}nt|tr| j|\}}}|	j| nt|trrtrF|	jtjt ||  n"|j|}|	jtjt ||  tj}nBt|tr|	jtjt ||  tj	}ntrt|tr|j|}|	jtjt ||  tj}nt|tr|	jtjt t|j|t|j|  tj}nt|trB|	jtjd
| tj}nrt|tjtjfrp| j|\}}|	j| nDt|tjtjfr| j |\}}|	j| ntj!dj"|j#j$d|
jtj|tj|  qnW tj%|tj| tj%| dj&dd |D  tjd }x|
D ]}||7 }qW x|	D ]}||7 }q,W |S )z6Make a MySQL packet with the Statement Execute commandr   r   r   rU   r-   Zutf8mb4r   NzTFailed executing prepared statement: data values does not match number of parametersz<dz:MySQL binary protocol can not handle '{classname}' objects)	classnamec             S   s   g | ]}t jd |qS )B)r$   r%   )r>   bitr   r   r   r?     s    z3MySQLProtocol.make_stmt_execute.<locals>.<listcomp>)'r#   r   r   r   r   r	   rG   r   ZNULLZBLOBSTRINGr   r{   r   r!   r   Zlc_intr   ZVARCHARbytesunicoder   ZDECIMALfloatr$   r%   r   r   r   r   r   r   r   r2   r    	__class____name__rD   r   )r   rL   rJ   
parametersrn   Zlong_data_usedr7   Ziteration_countr   rB   typesr   r   rk   r   rm   r;   Za_typeZa_valuer   r   r   make_stmt_execute  s    







0

zMySQLProtocol.make_stmt_executec             C   sZ   |d dkst jdtj|dd dd\}}|rL|d d	krL|dd }|jd
|fS )z&Parse a MySQL AuthSwitchRequest-packetr`   rp   z'Failed parsing AuthSwitchRequest packetrP   Nr   )rR   r   r   r   rW   rW   )r   r   r	   rY   rZ   )r   r;   Zplugin_namer   r   r   parse_auth_switch_request  s    z'MySQLProtocol.parse_auth_switch_requestc             C   s"   |d dkst jd|dd S )z!Parse a MySQL AuthMoreData-packetr`   r   z"Failed parsing AuthMoreData packetrP   N)r   r   )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   FN)rj   )T)r   )rj   )r   rj   )!r   
__module____qualname____doc__r   r*   r<   r5   rF   rK   rN   rO   r_   rf   ri   ro   rv   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   .   sJ      
% 


  
"0


%
 
!"-[r   )r   r$   r   decimalr   	constantsr   r   r   r   r=   r   r	   Zauthenticationr
   Zcatch23r   r   r   r   rX   objectr   r   r   r   r   <module>   s   