
    3iE                         d Z ddlZddlZddl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mZmZmZm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	Zd
ZddddddZd	Z dee!   de!fdZ"ededee#e$e%e%f         fd       Z&	 d1dede%deddfdZ'de%fdZ(d2de
e%ge)f   de*de%fdZ+de	dee%ee	   f   fdZ,dedejZ                  fd Z.ded!e%d"e%dejZ                  fd#Z/ded!e%d"e%de)fd$Z0ded!e%d"e%ddfd%Z1	 d1ded!e%d"e%d&ejZ                  d'ee%e%f   ddfd(Z2ded!e%d&ejZ                  dee%e%f   fd)Z3d*e%de%fd+Z4dede%fd,Z5ded!e%d"e%de)fd-Z6	 d3d.eeejZ                  ejn                  ejp                  f      d/e%deejZ                     fd0Z9y)4a.  General utilities for AI features in MySQL Connector/Python.

Includes helpers for:
- defensive dict copying
- temporary table lifecycle management
- SQL execution and result conversions
- DataFrame to/from SQL table utilities
- schema/table/column name validation
- array-like to DataFrame conversion
    N)contextmanager)AnyCallableDictIteratorListOptionalTupleUnion)atomic_transaction)MySQLConnectionAbstract)MySQLCursorAbstract)ParamsSequenceOrDictTypemysql_ai    BIGINTDOUBLELONGTEXTBOOLEANDATETIME)int64float64objectboolzdatetime64[ns]optionsreturnc                 4    | i S t        j                  |       S )z
    Make a defensive copy of a dictionary, or return an empty dict if None.

    Args:
        options: param dict or None

    Returns:
        dict
    )copydeepcopy)r   s    9D:\jyotish\venv\Lib\site-packages\mysql/ai/utils/utils.py	copy_dictr!   I   s     	==!!    db_connectionc           	   #     K   g }	 | t        |       5 }|D ]  \  }}t        |||        	 ddd       y# 1 sw Y   yxY w# t        |       5 }|D ]  \  }}t        |||        	 ddd       w # 1 sw Y   w xY wxY ww)a  
    Context manager to track and automatically clean up temporary SQL tables.

    Args:
        db_connection: Database connection object used to create and delete tables.

    Returns:
        None

    Raises:
        DatabaseError:
            If a database connection issue occurs.
            If an operational error occurs during execution.

    Yields:
        temporary_tables: List of (schema_name, table_name) tuples created during the
            context. All tables in this list are deleted on context exit.
    N)r   delete_sql_table)r#   temporary_tablescursorschema_name
table_names        r    temporary_sql_tablesr*   Y   s{     , /1B.&+;'Z jA ,< /...&+;'Z jA ,< /..sF   B A B 7	B A B A=A1(	A=1A:6A==B r'   queryparamsc                 0    | j                  ||xs d       y)aB  
    Execute an SQL query with optional parameters using the given cursor.

    Args:
        cursor: MySQLCursorAbstract object to execute the query.
        query: SQL query string to execute.
        params: Optional sequence or dict providing parameters for the query.

    Raises:
        DatabaseError:
            If the provided SQL query/params are invalid
            If the query is valid but the sql raises as an exception
            If a database connection issue occurs.
            If an operational error occurs during execution.

    Returns:
        None
     N)execute)r'   r+   r,   s      r    execute_sqlr0   x   s    * NN5&,B'r"   c                  v    t         j                  } dj                  t        j                  | t
                    S )z
    Generate a random uppercase string of fixed length for table names.

    Returns:
        Random string of length RANDOM_TABLE_NAME_LENGTH.
     )k)stringascii_uppercasejoinrandomchoicesRANDOM_TABLE_NAME_LENGTH)char_sets    r    	_get_namer;      s*     %%H776>>(.FGHHr"   	condition	max_callsc                 d    t        |      D ]  } | t               x}      s|c S  t        d      )a  
    Generate a random string name that satisfies a given condition.

    Args:
        condition: Callable that takes a generated name and returns True if it is valid.
        max_calls: Maximum number of attempts before giving up (default 100).

    Returns:
        A random string that fulfills the provided condition.

    Raises:
        RuntimeError: If the maximum number of attempts is reached without success.
    z<Reached max tries without successfully finding a unique name)ranger;   RuntimeError)r<   r=   _names       r    get_random_namerC      s5     9Y[(T)K  U
VVr"   valuec                     t        | t        t        f      r+t        |       dk(  rddgfS dt	        j
                  |       gfS d| gfS )a.  
    Convert a Python value into its SQL-compatible string representation and parameters.

    Args:
        value: The value to format.

    Returns:
        Tuple containing:
            - A string for substitution into a SQL query.
            - A list of parameters to be bound into the query.
    r   z%sNzCAST(%s as JSON))
isinstancedictlistlenjsondumps)rD   s    r    format_value_sqlrL      sL     %$&u:?$<!DJJu$5#666%=r"   c                    dt         t           dt         t           fd}dt        dt        fd}i }t	        | j
                        D ]  \  }}|d   dk(  r|||<   |||<    | j                         }g }|D ]?  }t        |      }	t	        |      D ]  \  }}
 ||   |
      |	|<    |j                  |	       A t        j                  || j                        S )a  
    Convert the results of a cursor's last executed query to a pandas DataFrame.

    Args:
        cursor: MySQLCursorAbstract with a completed query.

    Returns:
        DataFrame with data from the cursor.

    Raises:
        DatabaseError:
            If a database connection issue occurs.
            If an operational error occurs during execution.
            If a compatible SELECT query wasn't the last statement ran
    elemr   c                 4    | t        j                  |       S d S N)rJ   loadsrN   s    r    _json_processorz+sql_response_to_df.<locals>._json_processor   s    #'#3tzz$==r"   c                     | S rP   r.   rR   s    r    _default_processorz.sql_response_to_df.<locals>._default_processor   s    r"         )columns)r	   strrG   r   	enumeratedescriptionfetchallrH   appendpd	DataFramecolumn_names)r'   rS   rU   idx_to_processoridxcolrowsprocessed_rowsrowprocessed_rowrN   s              r    sql_response_to_dfrh      s    ">hsm > >   f001Sq6S=$3S!$6S! 2 ??D NS	"3IC!6!1#!6t!<M# ( 	m,  <<0C0CDDr"   r(   r)   c                 h    t        |       t        |       t        | d| d|        t        |       S )aD  
    Load the entire contents of a SQL table into a pandas DataFrame.

    Args:
        cursor: MySQLCursorAbstract to execute the query.
        schema_name: Name of the schema containing the table.
        table_name: Name of the table to fetch.

    Returns:
        DataFrame containing all rows from the specified table.

    Raises:
        DatabaseError:
            If the table does not exist
            If a database connection issue occurs.
            If an operational error occurs during execution.
        ValueError: If the schema or table name is not valid
    zSELECT * FROM .)validate_namer0   rh   r'   r(   r)   s      r    sql_table_to_dfrm      s6    * +*.QzlCDf%%r"   c                 z    t        |       t        |       | j                  d||f       | j                         duS )a  
    Check whether a table exists in a specific schema.

    Args:
        cursor: MySQLCursorAbstract object to execute the query.
        schema_name: Name of the database schema.
        table_name: Name of the table.

    Returns:
        True if the table exists, False otherwise.

    Raises:
        DatabaseError:
            If a database connection issue occurs.
            If an operational error occurs during execution.
        ValueError: If the schema or table name is not valid
    z
        SELECT 1
        FROM information_schema.tables
        WHERE table_schema = %s AND table_name = %s
        LIMIT 1
        Nrk   r/   fetchonerl   s      r    table_existsrq     sC    ( +*
NN	 
j! ??D((r"   c                 T    t        |       t        |       t        | d| d|        y)a  
    Drop a table from the SQL database if it exists.

    Args:
        cursor: MySQLCursorAbstract to execute the drop command.
        schema_name: Name of the schema.
        table_name: Name of the table to delete.

    Returns:
        None

    Raises:
        DatabaseError:
            If a database connection issue occurs.
            If an operational error occurs during execution.
        ValueError: If the schema or table name is not valid
    zDROP TABLE IF EXISTS rj   N)rk   r0   rl   s      r    r%   r%   6  s,    ( +*/}Aj\JKr"   dfcol_name_to_placeholder_stringc           	         |i }t        |       t        |       |j                  D ]  }t        t        |              | d| }|j                  D ]  }g g }	}t	        ||j                        D ]i  \  }
}t        |
d      r|
j                         n|
}
||v r||   t        |
      g}}nt        |
      \  }}|j                  |       |	j                  |       k dj                  |j                  D cg c]  }t        |       c}      }dj                  |      }d| d| d| d}t        | ||		        yc c}w )
a  
    Insert all rows from a pandas DataFrame into an existing SQL table.

    Args:
        cursor: MySQLCursorAbstract for execution.
        schema_name: Name of the database schema.
        table_name: Table to insert new rows into.
        df: DataFrame containing the rows to insert.
        col_name_to_placeholder_string:
            Optional mapping of column names to custom SQL value/placeholder
            strings.

    Returns:
        None

    Raises:
        DatabaseError:
            If the rows could not be inserted into the table, e.g., a type or shape issue
            If a database connection issue occurs.
            If an operational error occurs during execution.
        ValueError: If the schema or table name is not valid
    Nrj   item, zINSERT INTO  (z
) VALUES ())r,   )rk   rX   rY   valuesziphasattrrv   rL   r]   extendr6   r0   )r'   r(   r)   rs   rt   rc   qualified_table_namerf   placeholdersr,   rN   elem_placeholderelem_paramscols_sqlplaceholders_sql
insert_sqls                   r    extend_sql_tabler   P  sV   : &-)+&+*zzc#h  *]!J<8 yy!2fS"**-ID#")$"7499;TD440Ns0SIV+  1A0F- + 01MM+& . 99"**=*3c#h*=>99\2/0 1z$4#5Q8 	 	FJv6+  >s   5D<
c                 p    t         fd      } d| }t               t        |       |j                  D ]  }t        t        |              g }|j                  j                         D ]N  \  }}t        j                  t        |      d      }t        t        |             |j                  | d|        P dj                  |      }	t        d |j                  D              }
|
r|	dz  }	d| d	|	 d
}t         |       	 t         ||       ||fS # t        $ r t         |        w xY w)a  
    Create a new SQL table with a random name, and populate it with data from a DataFrame.

    If an 'id' column is defined in the dataframe, it will be used as the primary key.

    Args:
        cursor: MySQLCursorAbstract for executing SQL.
        schema_name: Schema in which to create the table.
        df: DataFrame containing the data to be inserted.

    Returns:
        Tuple (qualified_table_name, table_name): The schema-qualified and
        unqualified table names.

    Raises:
        RuntimeError: If a random available table name could not be found.
        ValueError: If any schema, table, or a column name is invalid.
        DatabaseError:
            If a database connection issue occurs.
            If an operational error occurs during execution.
    c                      t        |        S rP   )rq   )r)   r'   r(   s    r    <lambda>z#sql_table_from_df.<locals>.<lambda>  s    |FKLLr"   rj   r    rw   c              3   B   K   | ]  }|j                         d k(    yw)idN)lower).0rc   s     r    	<genexpr>z$sql_table_from_df.<locals>.<genexpr>  s     ?JSSYY[D(Js   z, PRIMARY KEY (id)zCREATE TABLE rx   ry   )rC   rk   rX   rY   dtypesitemsPD_TO_SQL_DTYPE_MAPPINGgetr]   r6   anyr0   r   	Exceptionr%   )r'   r(   rs   r)   r~   rc   columns_sqldtypesql_typecolumns_str
has_id_colcreate_table_sqls   ``          r    sql_table_from_dfr     s@   0 !LJ *]!J<8+*zzc#h  Kiioo'
U*..s5z:Fc#hcU!H:./	 ( ))K(K?BJJ??J++ '';&<B{m1M()j"=
  ++	  j9s   D D5rB   c                 n    t        | t              rt        j                  d|       st	        d|        | S )a  
    Validate that the string is a legal SQL identifier (letters, digits, underscores).

    Args:
        name: Name (schema, table, or column) to validate.

    Returns:
        The validated name.

    Raises:
        ValueError: If the name does not meet format requirements.
    z^[A-Za-z0-9_]+$zUnsupported name format )rF   rY   rematch
ValueError)rB   s    r    rk   rk     s4     tS!bhh/A4&H3D6:;;Kr"   c                     | j                   }|+t        }t        |       5 }d| }t        ||       ddd       t	        |       |S # 1 sw Y   xY w)a  
    Retrieve the name of the currently selected schema, or set and ensure the default schema.

    Args:
        db_connection: MySQL connector database connection object.

    Returns:
        Name of the schema (database in use).

    Raises:
        ValueError: If the schema name is not valid
        DatabaseError:
            If a database connection issue occurs.
            If an operational error occurs during execution.
    NzCREATE DATABASE IF NOT EXISTS )databaseDEFAULT_SCHEMAr   r0   rk   )r#   schemar'   create_database_stmts       r    source_schemar     sX      ##F~.&%CF8#L  45 / &M /.s   AAc                     t        |       t        |       | j                  d| d| d       | j                         du S )a+  
    Determine if a given SQL table is empty.

    Args:
        cursor: MySQLCursorAbstract with access to the database.
        schema_name: Name of the schema containing the table.
        table_name: Name of the table to check.

    Returns:
        True if the table has no rows, False otherwise.

    Raises:
        DatabaseError:
            If the table does not exist
            If a database connection issue occurs.
            If an operational error occurs during execution.
        ValueError: If the schema or table name is not valid
    zSELECT 1 FROM rj   z LIMIT 1Nro   rl   s      r    is_table_emptyr     sA    * +*
NN^K=*XFG??$$r"   arr
col_prefixc                    | yt        | t        j                        rt        j                  |       S t        | t        j                        r| j	                         S | j
                  dk(  r| j                  dd      } t        | j                  d         D cg c]	  }| d|  }}t        j                  | |d      S c c}w )a$  
    Convert input data to a pandas DataFrame if necessary.

    Args:
        arr: Input data as a pandas DataFrame, NumPy ndarray, pandas Series, or None.

    Returns:
        If the input is None, returns None.
        Otherwise, returns a DataFrame backed by the same underlying data whenever
        possible (except in cases where pandas or NumPy must copy, such as for
        certain views or non-contiguous arrays).

    Notes:
        - If an ndarray is passed, column names will be integer indices (0, 1, ...).
        - If a DataFrame is passed, column names and indices are preserved.
        - The returned DataFrame is a shallow copy and shares data with the original
          input when possible; however, copies may still occur for certain input
          types or memory layouts.
    NrV   rA   F)rX   r   )	rF   r^   r_   Seriesto_framendimreshaper?   shape)r   r   rb   	col_namess       r    convert_to_dfr     s    . {#r||$||C  #ryy!||~
xx1}kk"a 27		!2EF2E3J<q&2EIF<<YU;; Gs   C rP   )d   )feature):__doc__r   rJ   r7   r   r4   
contextlibr   typingr   r   r   r   r   r	   r
   r   numpynppandasr^   mysql.ai.utils.atomic_cursorr   mysql.connector.abstractsr   mysql.connector.cursorr   mysql.connector.typesr   VAR_NAME_SPACEr9   r   r   rG   r!   rH   tuplerY   r*   r0   r;   r   intrC   rL   r_   rh   rm   rq   r%   r   r   rk   r   r   r   ndarrayr   r.   r"   r    <module>r      s  8	    	  % N N N   ; = 6 :     
"x~ "$ "  B*Bd5c?#$B B> QU(((+(5M(	(0I3 IWxt4 W Ws W0C E#tCy.$9 &+E2 +Er|| +E\&&.1&?B&\\&> ) ).1 )?B )	 )FLL.1L?BL	L> 6:=7=7=7 =7 		=7
 %)cN=7 
=7@:,:,.1:,79||:,
38_:,z  (!8 S :%%.1%?B%	%<  #<	%bii;<	=#<#< bll#<r"   