a
    bgY                     @  s   d 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mZ ddlmZ ddlmZmZmZmZmZmZ ddlmZmZmZ dd	lmZmZ dd
lmZ ddl m!Z! ddl"m#Z# dddddZ$dddddddddZ%G dd dZ&dS )%SQLAlchemy wrapper around a database.    )annotations)AnyDictIterableListLiteralOptionalSequenceUnionN)
deprecated)get_from_env)MetaDataTablecreate_engineinspectselecttext)URLEngineResult)ProgrammingErrorSQLAlchemyError)CreateTable)
Executable)NullTypez+sqlalchemy.engine.interfaces.ReflectedIndexstr)indexreturnc                 C  s&   d| d  d| d  dt | d  S )NzName: namez
, Unique: uniquez, Columns: Zcolumn_namesr   )r    r"   x/var/www/html/cobodadashboardai.evdpl.com/venv/lib/python3.9/site-packages/langchain_community/utilities/sql_database.py_format_index   s    
r$   z...)suffixr   int)contentlengthr%   r   c                C  sJ   t | tr|dkr| S t| |kr&| S | d|t|  ddd | S )z]
    Truncate a string to a certain number of words, based on the max string
    length.
    r   N    )
isinstancer   lenrsplit)r'   r(   r%   r"   r"   r#   truncate_word    s
    r.   c                   @  s  e Zd ZdZdMdddd	d	d
dddd
ddddZedNdddd dddZedOddddddddd d	ddZedPdddddd ddd Ze	dd!d"d#Z
d$d!d%d&Zed'd(d)d*d$d!d+d,Ze	dd!d-d.ZdQd	dd/d0d1Zd2dd3d4d5Zd2dd3d6d7ZdRddd9d:d;d<d<d=d>d?d@ZdSddd9d:d;dd<d<dAdBdCdDZdTd	dd/dEdFZdUddd9ddGdd<d<dAdBdHdIZdJd!dKdLZdS )VSQLDatabaser   N   F,  r   zOptional[str]zOptional[MetaData]zOptional[List[str]]r&   boolzOptional[dict])engineschemametadataignore_tablesinclude_tablessample_rows_in_table_infoindexes_in_table_infocustom_table_infoview_supportmax_string_lengthlazy_table_reflectionc                   s  |_ |_|r|rtdtj _ttjj|d|	rLjj|dng  _	|rbt|nt _
j
rj
j	 }|rtd| d|rt|nt _jrʈjj	 }|rtd| d }|rt|nj	_t|tstd|_|_|_jrVtjts(tdtjj	 t fdd	jD _|
_|	_|plt _|sjj|	j tjjd
 dS )z Create engine from database URI.z4Cannot specify both include_tables and ignore_tables)r4   zinclude_tables  not found in databasezignore_tables z,sample_rows_in_table_info must be an integerz]table_info must be a dictionary with table names as keys and the desired table info as valuesc                 3  s$   | ]}| v r|j | fV  qd S )N)_custom_table_info).0tableintersectionselfr"   r#   	<genexpr>o   s   z'SQLDatabase.__init__.<locals>.<genexpr>Zviewsbindonlyr4   N)_engine_schema
ValueErrorr   
_inspectorsetlistget_table_namesZget_view_names_all_tables_include_tables_ignore_tablesget_usable_table_namesZ_usable_tablesr+   r&   	TypeError_sample_rows_in_table_info_indexes_in_table_infor?   dictrC   _max_string_length_view_supportr   	_metadatareflect)rD   r3   r4   r5   r6   r7   r8   r9   r:   r;   r<   r=   missing_tablesZusable_tablesr"   rB   r#   __init__2   sd    



zSQLDatabase.__init__zUnion[str, URL]r   )database_uriengine_argskwargsr   c                 K  s$   |pi }| t |fi |fi |S )z'Construct a SQLAlchemy engine from URI.)r   )clsr^   r_   r`   Z_engine_argsr"   r"   r#   from_uri   s    zSQLDatabase.from_urir   )	catalogr4   host	api_tokenwarehouse_id
cluster_idr_   r`   r   c              
   K  s$  zddl m}	 W n ty*   tdY n0 d}
zddlm} | }
|
j}W n ttfyf   d}Y n0 |du r|tdd|}|
r|
jnd}|du rtdd	|}|du r|du r|
r|
j	}nt
d
|r|rt
d|rd| }n
d| }d| d| d| d| d| 
}| jf ||d|S )a	  
        Class method to create an SQLDatabase instance from a Databricks connection.
        This method requires the 'databricks-sql-connector' package. If not installed,
        it can be added using `pip install databricks-sql-connector`.

        Args:
            catalog (str): The catalog name in the Databricks database.
            schema (str): The schema name in the catalog.
            host (Optional[str]): The Databricks workspace hostname, excluding
                'https://' part. If not provided, it attempts to fetch from the
                environment variable 'DATABRICKS_HOST'. If still unavailable and if
                running in a Databricks notebook, it defaults to the current workspace
                hostname. Defaults to None.
            api_token (Optional[str]): The Databricks personal access token for
                accessing the Databricks SQL warehouse or the cluster. If not provided,
                it attempts to fetch from 'DATABRICKS_TOKEN'. If still unavailable
                and running in a Databricks notebook, a temporary token for the current
                user is generated. Defaults to None.
            warehouse_id (Optional[str]): The warehouse ID in the Databricks SQL. If
                provided, the method configures the connection to use this warehouse.
                Cannot be used with 'cluster_id'. Defaults to None.
            cluster_id (Optional[str]): The cluster ID in the Databricks Runtime. If
                provided, the method configures the connection to use this cluster.
                Cannot be used with 'warehouse_id'. If running in a Databricks notebook
                and both 'warehouse_id' and 'cluster_id' are None, it uses the ID of the
                cluster the notebook is attached to. Defaults to None.
            engine_args (Optional[dict]): The arguments to be used when connecting
                Databricks. Defaults to None.
            **kwargs (Any): Additional keyword arguments for the `from_uri` method.

        Returns:
            SQLDatabase: An instance of SQLDatabase configured with the provided
                Databricks connection details.

        Raises:
            ValueError: If 'databricks-sql-connector' is not found, or if both
                'warehouse_id' and 'cluster_id' are provided, or if neither
                'warehouse_id' nor 'cluster_id' are provided and it's not executing
                inside a Databricks notebook.
        r   )sqlzfdatabricks-sql-connector package not found, please install with `pip install databricks-sql-connector`N)get_contextrd   ZDATABRICKS_HOSTre   ZDATABRICKS_TOKENz6Need to provide either 'warehouse_id' or 'cluster_id'.z/Can't have both 'warehouse_id' or 'cluster_id'.z/sql/1.0/warehouses/z/sql/protocolv1/o/0/zdatabricks://token:@z?http_path=z	&catalog=z&schema=)r^   r_   )Z
databricksrh   ImportErrorZ!dbruntime.databricks_repl_contextri   ZbrowserHostNameAttributeErrorr   ZapiTokenZ	clusterIdrK   rb   )ra   rc   r4   rd   re   rf   rg   r_   r`   rh   contextri   Zdefault_hostZdefault_api_tokenZ	http_pathurir"   r"   r#   from_databricks   sL    4



zSQLDatabase.from_databricks127.0.0.1:8902root cnosdbpublic)urluserpasswordtenantdatabaser   c                 C  sJ   z*ddl m} ||||||}| j|dW S  tyD   tdY n0 dS )a  
        Class method to create an SQLDatabase instance from a CnosDB connection.
        This method requires the 'cnos-connector' package. If not installed, it
        can be added using `pip install cnos-connector`.

        Args:
            url (str): The HTTP connection host name and port number of the CnosDB
                service, excluding "http://" or "https://", with a default value
                of "127.0.0.1:8902".
            user (str): The username used to connect to the CnosDB service, with a
                default value of "root".
            password (str): The password of the user connecting to the CnosDB service,
                with a default value of "".
            tenant (str): The name of the tenant used to connect to the CnosDB service,
                with a default value of "cnosdb".
            database (str): The name of the database in the CnosDB tenant.

        Returns:
            SQLDatabase: An instance of SQLDatabase configured with the provided
            CnosDB connection details.
        r   )make_cnosdb_langchain_uri)r^   zRcnos-connector package not found, please install with `pip install cnos-connector`N)Zcnosdb_connectorrz   rb   rk   )ra   ru   rv   rw   rx   ry   rz   rn   r"   r"   r#   from_cnosdb   s    zSQLDatabase.from_cnosdb)r   c                 C  s
   | j jjS )z/Return string representation of dialect to use.)rI   dialectr   rD   r"   r"   r#   r|     s    zSQLDatabase.dialectzIterable[str]c                 C  s    | j rt| j S t| j| j S zGet names of tables available.)rQ   sortedrP   rR   r}   r"   r"   r#   rS     s    
z"SQLDatabase.get_usable_table_namesz0.0.1rS   z1.0)alternativeZremovalc                 C  s   |   S r~   )rS   r}   r"   r"   r#   rO   "  s    zSQLDatabase.get_table_namesc                 C  s   |   S )z-Information about all tables in the database.)get_table_infor}   r"   r"   r#   
table_info'  s    zSQLDatabase.table_info)table_namesr   c                   s     |dur6t| }|r2td| d| dd jjD }t t| }|rzjjjjt	|j
d  fddjjD }g }|D ]}jr|jjv r|j|j  q|j D ]"\}}	t|	jtu r|j|	 qtt|j}
|
  }jpj}|r,|d7 }jrJ|d	| d	7 }jrh|d	| d	7 }|rv|d
7 }|| q|  d|}|S )f  Get information about specified tables.

        Follows best practices as specified in: Rajkumar et al, 2022
        (https://arxiv.org/abs/2204.00498)

        If `sample_rows_in_table_info`, the specified number of sample rows will be
        appended to each table description. This can increase performance as
        demonstrated in the paper.
        Nztable_names r>   c                 S  s   g | ]
}|j qS r"   r   r@   tblr"   r"   r#   
<listcomp>=      z.SQLDatabase.get_table_info.<locals>.<listcomp>rF   c                   s4   g | ],}|j t v rjd kr,|j ds|qS )ZsqliteZsqlite_)r   rM   r|   
startswithr   Zall_table_namesrD   r"   r#   r   G  s   z

/*
z*/z

)rS   rM   
differencerK   rZ   Zsorted_tablesr[   rY   rI   rN   rJ   r?   r   appendcolumnsitemstyper   Z_columnsremover   r   compilerstriprV   rU   _get_table_indexes_get_sample_rowssortjoin)rD   r   r\   Zmetadata_table_namesZ
to_reflectZmeta_tablesZtablesrA   kvZcreate_tabler   Zhas_extra_infoZ	final_strr"   r   r#   r   ,  sT    


zSQLDatabase.get_table_infor   )rA   r   c                 C  s(   | j |j}dtt|}d| S )Nr   zTable Indexes:
)rL   Zget_indexesr   r   mapr$   )rD   rA   ZindexesZindexes_formattedr"   r"   r#   r   l  s    zSQLDatabase._get_table_indexesc                 C  s   t || j}ddd |jD }z^| j ,}||}tt	dd |}W d    n1 sd0    Y  ddd |D }W n t
y   d}Y n0 | j d	|j d
| d| S )N	c                 S  s   g | ]
}|j qS r"   r   )r@   colr"   r"   r#   r   v  r   z0SQLDatabase._get_sample_rows.<locals>.<listcomp>c                 S  s   dd | D S )Nc                 S  s   g | ]}t |d d qS )Nd   r!   )r@   ir"   r"   r#   r   ~  r   zBSQLDatabase._get_sample_rows.<locals>.<lambda>.<locals>.<listcomp>r"   )Zlsr"   r"   r#   <lambda>~  r   z.SQLDatabase._get_sample_rows.<locals>.<lambda>r   c                 S  s   g | ]}d  |qS )r   )r   r@   rowr"   r"   r#   r     r   rr   z rows from z table:
)r   limitrU   r   r   rI   connectexecuterN   r   r   r   )rD   rA   commandZcolumns_str
connectionZsample_rows_resultZsample_rowsZsample_rows_strr"   r"   r#   r   q  s"    
"
zSQLDatabase._get_sample_rowsall
parametersexecution_optionszUnion[str, Executable]zLiteral['all', 'one', 'cursor']zOptional[Dict[str, Any]]z'Union[Sequence[Dict[str, Any]], Result])r   fetchr   r   r   c          	      C  s  |pi }|pi }| j  }| jdur| jdkrJ|jd| jf|d n| jdkrj|jd| jf|d n| jdkrvn| jdkr|jd	| jf|d np| jd
kr|jd| j |d nN| jdkr|jd| j |d n,| jdkrn | jdkr|jd| jf|d t|trt|}n t|tr*nt	dt
| |j|||d}|jr|dkrrdd | D }nP|dkr| }|du rg n| g}n$|dkr|W  d   S td|W  d   S W d   n1 s0    Y  g S )z
        Executes SQL command through underlying engine.

        If the statement returns no rows, an empty list is returned.
        N	snowflakez"ALTER SESSION SET search_path = %s)r   ZbigqueryzSET @@dataset_id=?ZmssqlZtrinozUSE ?ZduckdbzSET search_path TO oraclez#ALTER SESSION SET CURRENT_SCHEMA = Zsqlany
postgresqlzSET search_path TO %sz#Query expression has unknown type: r   c                 S  s   g | ]}|  qS r"   )_asdict)r@   xr"   r"   r#   r     r   z(SQLDatabase._execute.<locals>.<listcomp>onecursorz8Fetch parameter must be either 'one', 'all', or 'cursor')rI   beginrJ   r|   Zexec_driver_sqlr+   r   r   r   rT   r   r   Zreturns_rowsZfetchallZfetchoner   rK   )	rD   r   r   r   r   r   r   resultZfirst_resultr"   r"   r#   _execute  s    












2zSQLDatabase._executez1Union[str, Sequence[Dict[str, Any]], Result[Any]])r   r   include_columnsr   r   r   c                  sV    j ||||d}|dkr|S  fdd|D }|sBdd |D }|sJdS t|S dS )zExecute a SQL command and return a string representing the results.

        If the statement returns rows, a string of the results is returned.
        If the statement returns no rows, an empty string is returned.
        r   r   c                   s"   g | ]} fd d|  D qS )c                   s    i | ]\}}|t | jd qS ))r(   )r.   rX   )r@   columnvaluer}   r"   r#   
<dictcomp>  s   z.SQLDatabase.run.<locals>.<listcomp>.<dictcomp>)r   )r@   rr}   r"   r#   r     s   
z#SQLDatabase.run.<locals>.<listcomp>c                 S  s   g | ]}t | qS r"   )tuplevaluesr   r"   r"   r#   r     r   rr   N)r   r   )rD   r   r   r   r   r   r   resr"   r}   r#   run  s    
zSQLDatabase.runc              
   C  s@   z|  |W S  ty: } zd| W  Y d}~S d}~0 0 dS )r   Error: N)r   rK   )rD   r   er"   r"   r#   get_table_info_no_throw  s    
z#SQLDatabase.get_table_info_no_throwzLiteral['all', 'one']c             
   C  sJ   z| j |||||dW S  tyD } zd| W  Y d}~S d}~0 0 dS )a*  Execute a SQL command and return a string representing the results.

        If the statement returns rows, a string of the results is returned.
        If the statement returns no rows, an empty string is returned.

        If the statement throws an error, the error message is returned.
        )r   r   r   r   N)r   r   )rD   r   r   r   r   r   r   r"   r"   r#   run_no_throw  s    zSQLDatabase.run_no_throwzDict[str, Any]c                 C  s$   t |  }|  }|d|dS )z4Return db context that you may want in agent prompt.z, )r   r   )rN   rS   r   r   )rD   r   r   r"   r"   r#   ri   9  s    zSQLDatabase.get_context)
NNNNr0   FNFr1   F)N)NNNNN)rp   rq   rr   rs   rt   )N)r   )r   F)N)r   F)__name__
__module____qualname____doc__r]   classmethodrb   ro   r{   propertyr|   rS   r   rO   r   r   r   r   r   r   r   r   ri   r"   r"   r"   r#   r/   /   st             $P 
     "`     (@! \  %  r/   )'r   
__future__r   typingr   r   r   r   r   r	   r
   r   Z
sqlalchemyZlangchain_core._apir   Zlangchain_core.utilsr   r   r   r   r   r   r   Zsqlalchemy.enginer   r   r   Zsqlalchemy.excr   r   Zsqlalchemy.schemar   Zsqlalchemy.sql.expressionr   Zsqlalchemy.typesr   r$   r.   r/   r"   r"   r"   r#   <module>   s   ( 