o
    NDi                     @   s  d Z ddlmZ ddlmZmZmZ ddlZddl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Z
ddlmZ dd	lmZ dd
lmZmZ ddlZeeZeZ	 edZedZedZi Z dd Z!dd Z"G dd de#Z$dd Z%dd Z&dd Z'dd Z(e# 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-G d$d% d%e#Z.e.d&de._/e.d'd(e._0e.d)d*e._1G d+d, d,e*Z2e
j3j4Z4	 d-d. Z5G d/d0 d0e6Z7G d1d2 d2e#Z8G d3d4 d4e#Z9G d5d6 d6e#Z:dS )7z
This module holds classes for working with prepared statements and
specifying consistency levels and retry policies for individual
queries.
    )
namedtuple)datetime	timedeltatimezoneN)ConsistencyLevelOperationTimedOut)unix_time_from_uuid1)Encoder)ColDesc)_UNSET_VALUE)OrderedDict_sanitize_identifiersz[^a-zA-Z0-9]z^[^a-zA-Z0-9]*z[^a-zA-Z0-9_]*$c                 C   sF   zt |  W S  ty"   tdtdtd| }|t | < | Y S w )N_ )_clean_name_cacheKeyErrorNON_ALPHA_REGEXsubSTART_BADCHAR_REGEXEND_BADCHAR_REGEX)nameclean r   H/var/www/Datamplify/venv/lib/python3.10/site-packages/cassandra/query.py_clean_column_name;   s   
r   c                 C   s   |S )a  
    Returns each row as a tuple

    Example::

        >>> from cassandra.query import tuple_factory
        >>> session = cluster.connect('mykeyspace')
        >>> session.row_factory = tuple_factory
        >>> rows = session.execute("SELECT name, age FROM users LIMIT 1")
        >>> print(rows[0])
        ('Bob', 42)

    .. versionchanged:: 2.0.0
        moved from ``cassandra.decoder`` to ``cassandra.query``
    r   colnamesrowsr   r   r   tuple_factoryD   s   r   c                   @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )PseudoNamedTupleRowz
    Helper class for pseudo_named_tuple_factory. These objects provide an
    __iter__ interface, as well as index- and attribute-based access to values,
    but otherwise do not attempt to implement the full namedtuple or iterable
    interface.
    c                 C   s   || _ t| | _d S N)_dicttuplevalues_tuple)selfordered_dictr   r   r   __init__]   s   zPseudoNamedTupleRow.__init__c                 C   
   | j | S r    )r!   )r%   r   r   r   r   __getattr__a      
zPseudoNamedTupleRow.__getattr__c                 C   r(   r    )r$   )r%   idxr   r   r   __getitem__d   r*   zPseudoNamedTupleRow.__getitem__c                 C   
   t | jS r    )iterr$   r%   r   r   r   __iter__g   r*   zPseudoNamedTupleRow.__iter__c                 C   s   dj | jj| jdS )Nz	{t}({od}))tod)format	__class____name__r!   r/   r   r   r   __repr__j   s   
zPseudoNamedTupleRow.__repr__N)	r5   
__module____qualname____doc__r'   r)   r,   r0   r6   r   r   r   r   r   V   s    r   c                 C   s   dd t | |D S )z
    Returns each row as a :class:`.PseudoNamedTupleRow`. This is the fallback
    factory for cases where :meth:`.named_tuple_factory` fails to create rows.
    c                 S   s   g | ]}t |qS r   )r   ).0r2   r   r   r   
<listcomp>t   s    z-pseudo_namedtuple_factory.<locals>.<listcomp>)ordered_dict_factoryr   r   r   r   pseudo_namedtuple_factoryo   s   r=   c              	      s   t t| }ztd| W n8 ty%   tdjtj| d t| | Y S  t	yD   t
t t| }td| |f  tdt| Y nw  fdd|D S )a  
    Returns each row as a `namedtuple <https://docs.python.org/2/library/collections.html#collections.namedtuple>`_.
    This is the default row factory.

    Example::

        >>> from cassandra.query import named_tuple_factory
        >>> session = cluster.connect('mykeyspace')
        >>> session.row_factory = named_tuple_factory
        >>> rows = session.execute("SELECT name, age FROM users LIMIT 1")
        >>> user = rows[0]

        >>> # you can access field by their name:
        >>> print("name: %s, age: %d" % (user.name, user.age))
        name: Bob, age: 42

        >>> # or you can access fields by their position (like a tuple)
        >>> name, age = user
        >>> print("name: %s, age: %d" % (name, age))
        name: Bob, age: 42
        >>> name = user[0]
        >>> age = user[1]
        >>> print("name: %s, age: %d" % (name, age))
        name: Bob, age: 42

    .. versionchanged:: 2.0.0
        moved from ``cassandra.decoder`` to ``cassandra.query``
    Rowa  Failed creating namedtuple for a result because there were too many columns. This is due to a Python limitation that affects namedtuple in Python 3.0-3.6 (see issue18896). The row will be created with {substitute_factory_name}, which lacks some namedtuple features and is slower. To avoid slower performance accessing values on row objects, Upgrade to Python 3.7, or use a different row factory. (column names: {colnames}))substitute_factory_namer   aA  Failed creating named tuple for results with column names %s (cleaned: %s) (see Python 'namedtuple' documentation for details on name rules). Results will be returned with positional names. Avoid this by choosing different names, using SELECT "<col name>" AS aliases, or specifying a different row_factory on your Sessionc                    s   g | ]} | qS r   r   r:   rowr>   r   r   r;      s    z'named_tuple_factory.<locals>.<listcomp>)mapr   r   SyntaxErrorwarningswarnr3   r=   r5   	Exceptionlistlogwarningr   )r   r   clean_column_namesr   rB   r   named_tuple_factoryx   s(   

rL   c                        fdd|D S )a  
    Returns each row as a dict.

    Example::

        >>> from cassandra.query import dict_factory
        >>> session = cluster.connect('mykeyspace')
        >>> session.row_factory = dict_factory
        >>> rows = session.execute("SELECT name, age FROM users LIMIT 1")
        >>> print(rows[0])
        {u'age': 42, u'name': u'Bob'}

    .. versionchanged:: 2.0.0
        moved from ``cassandra.decoder`` to ``cassandra.query``
    c                       g | ]	}t t |qS r   )dictzipr@   r   r   r   r;          z dict_factory.<locals>.<listcomp>r   r   r   rQ   r   dict_factory   s   rS   c                    rM   )z
    Like :meth:`~cassandra.query.dict_factory`, but returns each row as an OrderedDict,
    so the order of the columns is preserved.

    .. versionchanged:: 2.0.0
        moved from ``cassandra.decoder`` to ``cassandra.query``
    c                    rN   r   )r   rP   r@   rQ   r   r   r;      rR   z(ordered_dict_factory.<locals>.<listcomp>r   r   r   rQ   r   r<      s   r<   c                   @   s   e Zd ZdZdZ	 dZ	 eZ	 dZ	 dZ		 dZ
	 dZdZddddedddfddZdd Zdd	 Zd
d Zdd ZeeeedZdd Zdd Zdd ZeeeedZdS )	Statementz
    An abstract class representing a single query. There are three subclasses:
    :class:`.SimpleStatement`, :class:`.BoundStatement`, and :class:`.BatchStatement`.
    These can be passed to :meth:`.Session.execute()`.
    NFc	           	      C   sz   |rt |dstd|d ur|| _|d ur|| _|| _|d ur#|| _|tur*|| _|d ur1|| _|d ur8|| _	|| _
d S )Non_read_timeoutz<retry_policy should implement cassandra.policies.RetryPolicy)hasattr
ValueErrorretry_policyconsistency_level_routing_keyserial_consistency_levelFETCH_SIZE_UNSET
fetch_sizekeyspacecustom_payloadis_idempotent)	r%   rX   rY   routing_keyr[   r]   r^   r_   r`   r   r   r   r'     s    
zStatement.__init__c                 c   s.    |D ]}t |}td| ||dV  qd S )Nz>H%dsBr   )lenstructpack)r%   partsplr   r   r   _key_parts_packed$  s
   zStatement._key_parts_packedc                 C      | j S r    rZ   r/   r   r   r   _get_routing_key)     zStatement._get_routing_keyc                 C   sH   t |ttfrt|dkr|d | _d S d| || _d S || _d S )N   r       )
isinstancerH   r"   rb   rZ   joinrh   )r%   keyr   r   r   _set_routing_key,  s
   
zStatement._set_routing_keyc                 C   
   d | _ d S r    rj   r/   r   r   r   _del_routing_key5  r*   zStatement._del_routing_keyah  
        The :attr:`~.TableMetadata.partition_key` portion of the primary key,
        which can be used to determine which nodes are replicas for the query.

        If the partition key is a composite, a list or tuple must be passed in.
        Each key component should be in its packed (binary) format, so all
        components should be strings.
        c                 C   ri   r    _serial_consistency_levelr/   r   r   r   _get_serial_consistency_levelE  rl   z'Statement._get_serial_consistency_levelc                 C   s$   |d urt |std|| _d S )Nz`serial_consistency_level must be either ConsistencyLevel.SERIAL or ConsistencyLevel.LOCAL_SERIAL)r   	is_serialrW   rv   )r%   r[   r   r   r   _set_serial_consistency_levelH  s   
z'Statement._set_serial_consistency_levelc                 C   rs   r    ru   r/   r   r   r   _del_serial_consistency_levelP  r*   z'Statement._del_serial_consistency_levela  
        The serial consistency level is only used by conditional updates
        (``INSERT``, ``UPDATE`` and ``DELETE`` with an ``IF`` condition).  For
        those, the ``serial_consistency_level`` defines the consistency level of
        the serial phase (or "paxos" phase) while the normal
        :attr:`~.consistency_level` defines the consistency for the "learn" phase,
        i.e. what type of reads will be guaranteed to see the update right away.
        For example, if a conditional write has a :attr:`~.consistency_level` of
        :attr:`~.ConsistencyLevel.QUORUM` (and is successful), then a
        :attr:`~.ConsistencyLevel.QUORUM` read is guaranteed to see that write.
        But if the regular :attr:`~.consistency_level` of that write is
        :attr:`~.ConsistencyLevel.ANY`, then only a read with a
        :attr:`~.consistency_level` of :attr:`~.ConsistencyLevel.SERIAL` is
        guaranteed to see it (even a read with consistency
        :attr:`~.ConsistencyLevel.ALL` is not guaranteed to be enough).

        The serial consistency can only be one of :attr:`~.ConsistencyLevel.SERIAL`
        or :attr:`~.ConsistencyLevel.LOCAL_SERIAL`. While ``SERIAL`` guarantees full
        linearizability (with other ``SERIAL`` updates), ``LOCAL_SERIAL`` only
        guarantees it in the local data center.

        The serial consistency level is ignored for any query that is not a
        conditional update. Serial reads should use the regular
        :attr:`consistency_level`.

        Serial consistency levels may only be used against Cassandra 2.0+
        and the :attr:`~.Cluster.protocol_version` must be set to 2 or higher.

        See :doc:`/lwt` for a discussion on how to work with results returned from
        conditional statements.

        .. versionadded:: 2.0.0
        )r5   r7   r8   r9   rX   rY   r\   r]   r^   r_   r`   rv   rZ   r'   rh   rk   rr   rt   propertyra   rw   ry   rz   r[   r   r   r   r   rT      sN    


	rT   c                   @   sB   e Zd ZdZddddedddfddZedd Zdd	 ZeZ	dS )
SimpleStatementz&
    A simple, un-prepared query.
    NFc
           
      C   s$   t | ||||||||		 || _dS )a*  
        `query_string` should be a literal CQL statement with the exception
        of parameter placeholders that will be filled through the
        `parameters` argument of :meth:`.Session.execute()`.

        See :class:`Statement` attributes for a description of the other parameters.
        N)rT   r'   _query_string)
r%   query_stringrX   rY   ra   r[   r]   r^   r_   r`   r   r   r   r'     s   


zSimpleStatement.__init__c                 C   ri   r    )r}   r/   r   r   r   r~     s   zSimpleStatement.query_stringc                 C      t j| jd}d| j|f S )NNot Setz,<SimpleStatement query="%s", consistency=%s>r   value_to_namegetrY   r~   r%   consistencyr   r   r   __str__     zSimpleStatement.__str__)
r5   r7   r8   r9   r\   r'   r{   r~   r   r6   r   r   r   r   r|   z  s    

r|   c                   @   s   e Zd ZdZdZdZdZdZeZ	dZ
dZdZdZdZdZdZdZdZdZ	dddZe	dddZdd Zd	d
 Zdd ZeZdS )PreparedStatementa  
    A statement that has been prepared against at least one Cassandra node.
    Instances of this class should not be created directly, but through
    :meth:`.Session.prepare()`.

    A :class:`.PreparedStatement` should be prepared only once. Re-preparing a statement
    may affect performance (as the operation requires a network roundtrip).

    |prepared_stmt_head|: Do not use ``*`` in prepared statements if you might
    change the schema of the table being queried. The driver and server each
    maintain a map between metadata for a schema and statements that were
    prepared against that schema. When a user changes a schema, e.g. by adding
    or removing a column, the server invalidates its mappings involving that
    schema. However, there is currently no way to propagate that invalidation
    to drivers. Thus, after a schema change, the driver will incorrectly
    interpret the results of ``SELECT *`` queries prepared before the schema
    change. This is currently being addressed in `CASSANDRA-10786
    <https://issues.apache.org/jira/browse/CASSANDRA-10786>`_.

    .. |prepared_stmt_head| raw:: html

       <b>A note about <code>*</code> in prepared statements</b>
    Nc
           
      C   s@   || _ || _|| _|| _|| _|| _|| _|| _|	| _d| _	d S )NF)
column_metadataquery_idrouting_key_indexesr~   r^   protocol_versionresult_metadataresult_metadata_idcolumn_encryption_policyr`   )
r%   r   r   r   queryr^   r   r   r   r   r   r   r   r'     s   
zPreparedStatement.__init__c              
      s   |st ||d |||||	|
	S |r|}n;d }|d }|j|j}|rN|j|j}|rN|j}tdd t|D  z fdd|D }W n	 t	yM   Y nw t ||||||||	|
	S )Nr   c                 s   s    | ]
\}}|j |fV  qd S r    r   )r:   icr   r   r   	<genexpr>  s    z1PreparedStatement.from_message.<locals>.<genexpr>c                    s   g | ]} |j  qS r   r   )r:   r   statement_indexesr   r   r;     s    z2PreparedStatement.from_message.<locals>.<listcomp>)
r   	keyspacesr   keyspace_nametables
table_namepartition_keyrO   	enumerater   )clsr   r   
pk_indexescluster_metadatar   prepared_keyspacer   r   r   r   r   	first_colks_meta
table_metapartition_key_columnsr   r   r   from_message  s4   

zPreparedStatement.from_messagec                 C   s   t | |S )z
        Creates and returns a :class:`BoundStatement` instance using `values`.

        See :meth:`BoundStatement.bind` for rules on input ``values``.
        )BoundStatementbind)r%   r#   r   r   r   r     s   zPreparedStatement.bindc                 C   s,   | j d u r| jrt| jnt | _ || j v S r    )_routing_key_index_setr   set)r%   r   r   r   r   is_routing_key_index  s   

z&PreparedStatement.is_routing_key_indexc                 C   r   )Nr   z.<PreparedStatement query="%s", consistency=%s>r   r   r   r   r   r     r   zPreparedStatement.__str__r    )r5   r7   r8   r9   r   rX   rY   r_   r\   r]   r^   r   r   r~   r   r   r   r   r   r[   r'   classmethodr   r   r   r   r6   r   r   r   r   r     s4    
"r   c                   @   s\   e Zd ZdZdZ	 dZ	 ddddeddfddZdd Zdd Z	e
d	d
 Zdd ZeZdS )r   z
    A prepared statement that has been bound to a particular set of values.
    These may be created directly or through :meth:`.PreparedStatement.bind()`.
    Nc	           
      C   sr   || _ |j| _|j| _|j| _|j| _|j| _|j| _g | _|j}	|	r)|	d j	| _
t| ||||||||j	 dS )z
        `prepared_statement` should be an instance of :class:`PreparedStatement`.

        See :class:`Statement` attributes for a description of the other parameters.
        r   N)prepared_statementrX   rY   r[   r]   r_   r`   r#   r   r   r^   rT   r'   )
r%   r   rX   rY   ra   r[   r]   r^   r_   metar   r   r   r'     s   zBoundStatement.__init__c                 C   s(  |du rd}| j j}| j j}| j j}t|trD|}g }|D ]&}z
|||j  W q tyC   |dkr:|t	 ntd|j Y qw t
|}t
|}||kr\tdt
|t
|f |dk rx| j jrx|t
| j jk rxtd|t
| j jf || _g | _t||D ]s\}	}
|	du r| jd q|	t	u r|dkr|   qtd| z0t|
j|
j|
j}|o||}|r||n|
j}||	|}|r|||}| j| W q ttjfy } zt|	}d|
j|
j||f }t|d}~ww |dkr|t
| j }|rt|D ]}|   q
| S )	a  
        Binds a sequence of values for the prepared statement parameters
        and returns this instance.  Note that `values` *must* be:

        * a sequence, even if you are only binding one value, or
        * a dict that relates 1-to-1 between dict keys and columns

        .. versionchanged:: 2.6.0

            :data:`~.UNSET_VALUE` was introduced. These can be bound as positional parameters
            in a sequence, or by name in a dict. Additionally, when using protocol v4+:

            * short sequences will be extended to match bind parameters with UNSET_VALUE
            * names may be omitted from a dict with UNSET_VALUE implied.

        .. versionchanged:: 3.0.0

            method will not throw if extra keys are present in bound dict (PYTHON-178)
        Nr      z)Column name `%s` not found in bound dict.z;Too many arguments provided to bind() (got %d, expected %d)zJToo few arguments provided to bind() (got %d, required %d for routing key)zLAttempt to bind UNSET_VALUE while using unsuitable protocol version (%d < 4)zQReceived an argument of invalid type for column "%s". Expected: %s, Got: %s; (%s))r   r   r   r   ro   rO   appendr   r   UNSET_VALUErb   rW   r   
raw_valuesr#   rP   _append_unset_valuer
   r   r   contains_columncolumn_typetype	serializeencrypt	TypeErrorrc   errorrange)r%   r#   proto_versioncol_meta	ce_policyvalues_dictcol	value_lencol_meta_lenvaluecol_speccol_descuses_cecol_type	col_bytesexcactual_typemessagediffr   r   r   r   r   0  s   


zBoundStatement.bindc                 C   s@   t | j}| j|r| jj| }td|j | jt d S )Nz9Cannot bind UNSET_VALUE as a part of the routing key '%s')	rb   r#   r   r   r   rW   r   r   r   )r%   
next_indexr   r   r   r   r     s
   
z"BoundStatement._append_unset_valuec                    sl    j jsd S  jd ur jS  j j}t|dkr# j|d   _ jS d  fdd|D  _ jS )Nrm   r   rn   c                 3   s    | ]} j | V  qd S r    )r#   )r:   r   r/   r   r   r         z-BoundStatement.routing_key.<locals>.<genexpr>)r   r   rZ   rb   r#   rp   rh   )r%   routing_indexesr   r/   r   ra     s   
 zBoundStatement.routing_keyc                 C   s$   t j| jd}d| jj| j|f S )Nr   z6<BoundStatement query="%s", values=%s, consistency=%s>)r   r   r   rY   r   r~   r   r   r   r   r   r        zBoundStatement.__str__)r5   r7   r8   r9   r   r#   r\   r'   r   r   r{   ra   r   r6   r   r   r   r   r     s     
\
r   c                   @   s:   e Zd ZdZdZ	 dZ	 dZ	 dd Zdd Zdd Z	dS )		BatchTypez
    A BatchType is used with :class:`.BatchStatement` instances to control
    the atomicity of the batch operation.

    .. versionadded:: 2.0.0
    Nc                 C      || _ || _d S r    )r   r   )r%   r   r   r   r   r   r'        
zBatchType.__init__c                 C   ri   r    r   r/   r   r   r   r     rl   zBatchType.__str__c                 C   s   d| j f S )NzBatchType.%sr   r/   r   r   r   r6     s   zBatchType.__repr__)
r5   r7   r8   r9   LOGGEDUNLOGGEDCOUNTERr'   r   r6   r   r   r   r   r     s    r   r   r   rm   r      c                   @   s   e Zd ZdZdZ	 dZ	 dZdZej	dddddfddZ
dd Z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eZdS )BatchStatementzx
    A protocol-level batch of operations which are applied atomically
    by default.

    .. versionadded:: 2.0.0
    Nc                 C   s*   || _ g | _|| _tj| ||||d dS )aF  
        `batch_type` specifies The :class:`.BatchType` for the batch operation.
        Defaults to :attr:`.BatchType.LOGGED`.

        `retry_policy` should be a :class:`~.RetryPolicy` instance for
        controlling retries on the operation.

        `consistency_level` should be a :class:`~.ConsistencyLevel` value
        to be used for all operations in the batch.

        `custom_payload` is a :ref:`custom_payload` passed to the server.
        Note: as Statement objects are added to the batch, this map is
        updated with any values found in their custom payloads. These are
        only allowed when using protocol version 4 or higher.

        Example usage:

        .. code-block:: python

            insert_user = session.prepare("INSERT INTO users (name, age) VALUES (?, ?)")
            batch = BatchStatement(consistency_level=ConsistencyLevel.QUORUM)

            for (name, age) in users_to_insert:
                batch.add(insert_user, (name, age))

            session.execute(batch)

        You can also mix different types of operations within a batch:

        .. code-block:: python

            batch = BatchStatement()
            batch.add(SimpleStatement("INSERT INTO users (name, age) VALUES (%s, %s)"), (name, age))
            batch.add(SimpleStatement("DELETE FROM pending_users WHERE name=%s"), (name,))
            session.execute(batch)

        .. versionadded:: 2.0.0

        .. versionchanged:: 2.1.0
            Added `serial_consistency_level` as a parameter

        .. versionchanged:: 2.6.0
            Added `custom_payload` as a parameter
        )rX   rY   r[   r_   N)
batch_type_statements_and_parameters_sessionrT   r'   )r%   r   rX   rY   r[   sessionr_   r   r   r   r'     s   /

zBatchStatement.__init__c                 C   s0   | j dd= d| _d| _| jr| j  dS dS )z
        This is a convenience method to clear a batch statement for reuse.

        *Note:* it should not be used concurrently with uncompleted execution futures executing the same
        ``BatchStatement``.
        N)r   r^   ra   r_   clearr/   r   r   r   r     s   zBatchStatement.clearc                 C   s
  t |tr"|r| jdu rt n| jj}t|||}| d|d | S t |trD|j}|	|du r2dn|}| 
| | d||j | S t |tr`|rOtd| 
| | d|jj|j | S |j}|rw| jdu rmt n| jj}t|||}| 
| | d|d | S )z
        Adds a :class:`.Statement` and optional sequence of parameters
        to be used with the statement to the batch.

        Like with other statements, parameters must be a sequence, even
        if there is only one item.
        NFr   TzIParameters cannot be passed with a BoundStatement to BatchStatement.add())ro   strr   r	   encoderbind_params_add_statement_and_paramsr   r   r   _update_stater#   r   rW   r   r~   )r%   	statement
parametersr   r   bound_statementr~   r   r   r   add*  s6   




	
zBatchStatement.addc                 C   s$   t ||D ]
\}}| || qdS )a  
        Adds a sequence of :class:`.Statement` objects and a matching sequence
        of parameters to the batch. Statement and parameter sequences must be of equal length or
        one will be truncated. :const:`None` can be used in the parameters position where are needed.
        N)rP   r   )r%   
statementsr   r   r   r   r   r   add_allM  s   zBatchStatement.add_allc                 C   s0   t | jdkrtdd | j|||f d S )Ni  z7Batch statement cannot contain more than %d statements.)rb   r   rW   r   )r%   is_preparedr   r   r   r   r   r   V  s   z(BatchStatement._add_statement_and_paramsc                 C   s6   | j d u r|jr|j r|j | _ |j| _d S d S d S d S r    )ra   r^   r%   r   r   r   r   _maybe_set_routing_attributes[  s   
z,BatchStatement._maybe_set_routing_attributesc                 C   s,   |j r| j d u ri | _ | j |j  d S d S r    )r_   updater   r   r   r   _update_custom_payloada  s
   
z%BatchStatement._update_custom_payloadc                 C   s   |  | | | d S r    )r   r   r   r   r   r   r   g  s   
zBatchStatement._update_statec                 C   r-   r    )rb   r   r/   r   r   r   __len__k  r*   zBatchStatement.__len__c                 C   s$   t j| jd}d| jt| |f S )Nr   z7<BatchStatement type=%s, statements=%d, consistency=%s>)r   r   r   rY   r   rb   r   r   r   r   r   n  r   zBatchStatement.__str__r    )r5   r7   r8   r9   r   r[   r   r   r   r   r'   r   r   r   r   r   r   r   r   r   r6   r   r   r   r   r     s,    
5
#	r   c                    sB   t |tr| t fdd| D  S | t fdd|D  S )Nc                 3   s"    | ]\}}|  |fV  qd S r    cql_encode_all_types)r:   kvr   r   r   r     s     zbind_params.<locals>.<genexpr>c                 3   s    | ]}  |V  qd S r    r   )r:   r   r   r   r   r     r   )ro   rO   itemsr"   )r   paramsr   r   r   r   r     s   
r   c                   @   s   e Zd ZdZdS )TraceUnavailablezN
    Raised when complete trace details cannot be fetched from Cassandra.
    N)r5   r7   r8   r9   r   r   r   r   r     s    r   c                   @   sr   e Zd ZdZdZ	 dZ	 dZ	 dZ	 dZ	 dZ		 dZ
	 dZ	 dZdZdZdZdd Zdd
dZdd Zdd ZdS )
QueryTracez[
    A trace of the duration and events that occurred when executing
    an operation.
    Nz:SELECT * FROM system_traces.sessions WHERE session_id = %sz8SELECT * FROM system_traces.events WHERE session_id = %sg~jth?c                 C   r   r    )trace_idr   )r%   r   r   r   r   r   r'     r   zQueryTrace.__init__       @Tc                 C   s~  d}t   }	 t   | }|dur||krtd|f td| j | t| j|d| jf||}|r8| nd}|duoG|j	duoG|j
du}	|rN|r]|	s]t | jd|   |d7 }q|	rgtd	| j ntd
| j |j| _|	rzt|j	dnd| _	|j
| _
|j| _|j| _t|dd| _td| j t   | }| t| j|d| jf||}
td| j tdd |
D | _dS )a  
        Retrieves the actual tracing details from Cassandra and populates the
        attributes of this instance.  Because tracing details are stored
        asynchronously by Cassandra, this may need to retry the session
        detail fetch.  If the trace is still not available after `max_wait`
        seconds, :exc:`.TraceUnavailable` will be raised; if `max_wait` is
        :const:`None`, this will retry forever.

        `wait_for_complete=False` bypasses the wait for duration to be populated.
        This can be used to query events from partial sessions.

        `query_cl` specifies a consistency level to use for polling the trace tables,
        if it should be different than the session default.
        r   TNz_Trace information was not available within %f seconds. Consider raising Session.max_trace_wait.z/Attempting to fetch trace info for trace ID: %s)rY   r   rm   z#Fetched trace info for trace ID: %sz,Fetching parital trace info for trace ID: %smicrosecondsclientz1Attempting to fetch trace events for trace ID: %sz%Fetched trace events for trace ID: %sc                 s   s*    | ]}t |j|j|j|j|jV  qd S r    )
TraceEventactivityevent_idsourcesource_elapsedthread)r:   rr   r   r   r     s    "z&QueryTrace.populate.<locals>.<genexpr>)timer   rI   debugr   _executer|   _SELECT_SESSIONS_FORMAToneduration
started_atsleep_BASE_RETRY_SLEEPrequestrequest_typer   coordinatorr   getattrr   _SELECT_EVENTS_FORMATr"   events)r%   max_waitwait_for_completequery_clattemptstart
time_spentsession_resultssession_rowis_completeevent_resultsr   r   r   populate  sJ   
zQueryTrace.populatec                 C   s`   |d ur|| nd }| j j||dd |d}t|_|  z| W S  ty/   td|f w )NF)tracer_   timeoutz5Trace information was not available within %f seconds)r   _create_response_futurerL   row_factorysend_requestresultr   r   )r%   r   r   r  r  r  futurer   r   r   r    s   
zQueryTrace._executec                 C   s    d| j | j| j| j| j| jf S )NzE%s [%s] coordinator: %s, started at: %s, duration: %s, parameters: %s)r  r   r  r	  r  r   r/   r   r   r   r     s
   zQueryTrace.__str__)r   TN)r5   r7   r8   r9   r   r  r  r   r  r   r	  r  r   r  r  r  r'   r  r  r   r   r   r   r   r     s4    
8r   c                   @   s>   e Zd ZdZdZ	 dZ	 dZ	 dZ	 dZ	 dd Z	dd Z
dS )r   z@
    Representation of a single event within a query trace.
    Nc                 C   sH   || _ tjt|tjd| _|| _|d urt|d| _nd | _|| _	d S )N)tzr   )
descriptionr   fromtimestampr   r   utcr   r   r   thread_name)r%   r%  timeuuidr   r   r(  r   r   r   r'   >  s   
zTraceEvent.__init__c                 C   s   d| j | j| j| jf S )Nz%s on %s[%s] at %s)r%  r   r(  r   r/   r   r   r   r   H  s   zTraceEvent.__str__)r5   r7   r8   r9   r%  r   r   r   r(  r'   r   r   r   r   r   r     s    
r   c                   @   s   e Zd ZdZdd ZdS )HostTargetingStatementz
    Wraps any query statement and attaches a target host, making
    it usable in a targeted LBP without modifying the user's statement.
    c                 C   s,   t |jj| j|jfi | _|j| _|| _d S r    )r   r4   r5   __dict__target_host)r%   inner_statementr,  r   r   r   r'   R  s   

zHostTargetingStatement.__init__N)r5   r7   r8   r9   r'   r   r   r   r   r*  M  s    r*  );r9   collectionsr   r   r   r   rerc   r  rE   	cassandrar   r   cassandra.utilr   cassandra.encoderr	   cassandra.policiesr
   cassandra.protocolr   r   r   logging	getLoggerr5   rI   r   compiler   r   r   r   r   r   objectr   r=   rL   rS   r<   r\   rT   r|   r   r   r   r   r   r   r   r   ValueSequencer   rG   r   r   r   r*  r   r   r   r   <module>   sd   



		; 'n %" % /