
    Phd                       d Z ddlmZ ddl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Z% e%        ddZ&ddddZ'ddZ( G d d      Z)y)%SQLAlchemy wrapper around a database.    )annotationsN)AnyDictIterableListLiteralOptionalSequenceUnion)
deprecated)get_from_env)MetaDataTablecreate_engineinspectselecttext)URLEngineResult)ProgrammingErrorSQLAlchemyError)CreateTable)
Executable)NullTypec                     	 ddl } t        | d      rRt        | j                  d      r;| j                  j                  }t        |d      r|j                  dd}||_        yyyy# t
        $ r Y yw xY w)z?Patch DuckDBPyType to be hashable for SQLAlchemy compatibility.r   NtypingDuckDBPyType__hash__c                *    t        t        |             S N)hashstrselfs    d/var/www/html/saasai/venv/lib/python3.12/site-packages/langchain_community/utilities/sql_database.pyr    z%_patch_duckdb_types.<locals>.__hash__&   s    D	?*    )returnint)duckdbhasattrr   r   r    ImportError)r+   duckdb_typer    s      r'   _patch_duckdb_typesr/      sy     68$)O --44K;
3{7K7K7S+ (0$ 8T *P$  s   AA% %	A10A1c           	     <    d| d    d| d    dt        | d          S )NzName: namez
, Unique: uniquez, Columns: column_namesr$   )indexs    r'   _format_indexr6   3   s7    
vz%/): ;~./0	2r(   z...)suffixc                   t        | t              r|dk  r| S t        |       |k  r| S | d|t        |      z
   j                  dd      d   |z   S )z]
    Truncate a string to a certain number of words, based on the max string
    length.
    r   N    )
isinstancer$   lenrsplit)contentlengthr7   s      r'   truncate_wordr@   :   sX     gs#v{
7|v)Vc&k)*11#q9!<vEEr(   c                P    t        j                  d|       st        d|  d      | S )zHSanitize a schema name to only contain letters, digits, and underscores.z^[a-zA-Z0-9_]+$zSchema name 'z_' contains invalid characters. Schema names must contain only letters, digits, and underscores.)rematch
ValueErrorschemas    r'   sanitize_schemarG   I   s8    88&/F8 $O O
 	
 Mr(   c                     e Zd ZdZ	 	 	 	 	 	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZe	 d	 	 	 	 	 	 	 dd       Ze eddd      	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d d	              Ze	 	 	 	 	 d!	 	 	 	 	 	 	 	 	 	 	 d"d
       Z	e
d#d       Zd$dZ eddd      d$d       Ze
d#d       Z	 d%	 	 	 	 	 d&dZd'dZd'dZ	 d(ddd	 	 	 	 	 	 	 	 	 d)dZ	 	 d*ddd	 	 	 	 	 	 	 	 	 	 	 d+dZdd,dZ	 	 d*ddd	 	 	 	 	 	 	 	 	 	 	 d-dZd.dZy)/SQLDatabaser   Nc                    | _         | _        |r|rt        d      t         j                          _        t        t         j                  j                  |            |	r j                  j                  |      ng z          _	        |rt        |      n	t                _
         j                  r* j                   j                  z
  }|rt        d| d      |rt        |      n	t                _         j                  r* j                   j                  z
  }|rt        d| d       j                         }|rt        |      n j                   _        t        |t              st!        d      | _        | _        | _         j&                  rwt         j&                  t(              st!        d      t         j&                        j+                   j                        t)         fd j&                  D               _        |
 _        |	 _        |xs
 t1                _        |sG j2                  j5                  |	 j                   t         j                         j                  	       y
y
)z Create engine from database URI.z4Cannot specify both include_tables and ignore_tablesrE   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  H   K   | ]  }|v r|j                   |   f  y wr"   )_custom_table_info).0tableintersectionr&   s     r'   	<genexpr>z'SQLDatabase.__init__.<locals>.<genexpr>   s1      +4EL( //674s   "viewsbindonlyrF   N)_engine_schemarD   r   
_inspectorsetlistget_table_namesget_view_names_all_tables_include_tables_ignore_tablesget_usable_table_names_usable_tablesr;   r*   	TypeError_sample_rows_in_table_info_indexes_in_table_inforM   dictrP   _max_string_length_view_supportr   	_metadatareflect)r&   enginerF   metadataignore_tablesinclude_tablessample_rows_in_table_infoindexes_in_table_infocustom_table_infoview_supportmax_string_lengthlazy_table_reflectionmissing_tablesusable_tablesrP   s   `             @r'   __init__zSQLDatabase.__init__V   sE    mSTT!$,,/ 000?@@Lt--V-<RTV

 7Es>2#%!11D4D4DDN %n%55KL  5Bc-0su!0043C3CCN $^$44JK  3354Ac-0tGWGW3S9JKK*C'&;#"3""d55t<3 
 t667DDTEUEUVL&* +!44+ 'D# #4)!/XZ$NN"""\\$--.||	 #  %r(   c                4    |xs i } | t        |fi |fi |S )z'Construct a SQLAlchemy engine from URI.)r   )clsdatabase_uriengine_argskwargs_engine_argss        r'   from_urizSQLDatabase.from_uri   s(     #(b=>>I&IIr(   z0.3.18zFor performing structured retrieval using Databricks SQL, see the latest best practices and recommended APIs at https://docs.unitycatalog.io/ai/integrations/langchain/ insteadz1.0)messageremovalc           
        	 ddl m}	 d}
	 ddlm}  |       }
|
j
                  }|t        dd|      }|
r|
j                  nd}|t        dd	|      }|||
r|
j                  }nt        d
      |r|rt        d      |rd| }nd| }d| d| d| d| d| 
} | j                  d||d|S # t        $ r t        d      w xY w# t        t        f$ r d}Y w xY w)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_contexthostDATABRICKS_HOST	api_token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=)ry   rz    )
databricksr   r-   !dbruntime.databricks_repl_contextr   browserHostNameAttributeErrorr   apiToken	clusterIdrD   r}   )rx   catalogrF   r   r   warehouse_id
cluster_idrz   r{   r   contextr   default_hostdefault_api_token	http_pathuris                   r'   from_databrickszSQLDatabase.from_databricks   sJ   x	& 	 E!mG"22L <(9<HD07G,,T$[2DFWXIJ$6$..
 L  JNOO.|n=I.zl;I ")AdV 4"9WIXfXG 	 s||P+PPPS  	: 	 ^, 	 L	 s   B2 C
 2C
CCc                |    	 ddl m}  ||||||      }| j                  |      S # t        $ r t        d      w xY w)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)ry   zRcnos-connector package not found, please install with `pip install cnos-connector`)cnosdb_connectorr   r}   r-   )rx   urluserpasswordtenantdatabaser   r   s           r'   from_cnosdbzSQLDatabase.from_cnosdb  sN    <		B+CxRC<<S<11 	0 	s   #& ;c                B    | j                   j                  j                  S )z/Return string representation of dialect to use.)rV   dialectr1   r%   s    r'   r   zSQLDatabase.dialectC  s     ||##(((r(   c                    | j                   rt        | j                         S t        | j                  | j                  z
        S zGet names of tables available.)r^   sortedr]   r_   r%   s    r'   r`   z"SQLDatabase.get_usable_table_namesH  s8    $..//d&&)<)<<==r(   z0.0.1r`   )alternativer   c                "    | j                         S r   )r`   r%   s    r'   r[   zSQLDatabase.get_table_namesN  s     **,,r(   c                "    | j                         S )z-Information about all tables in the database.)get_table_infor%   s    r'   
table_infozSQLDatabase.table_infoS  s     ""$$r(   c                @   | j                         }|-t        |      j                  |      }|rt        d| d      |}| j                  j
                  D cg c]  }|j                   }}t        |      t        |      z
  }|rF| j                  j                  | j                  | j                  t        |      | j                         | j                  j
                  D cg c]E  }|j                  t        |      v r,| j                  dk(  r|j                  j                  d      s|G }}g }	|D ]  }
| j                  rA|
j                  | j                  v r)|	j                  | j                  |
j                            Q	 |
j                   j#                         D ]<  \  }}t%        |j$                        t&        u s"|
j(                  j+                  |       > 	 t1        t3        |
      j5                  | j                              }|j7                          }|rE	 i }|
j                   D ](  }|j8                  s|j8                  ||j                  <   * |r	|d| dz  }| j<                  xs | j>                  }|r|d	z  }| j<                  r|d
| jA                  |
       d
z  }| j>                  r|d
| jC                  |
       d
z  }|r|dz  }|	j                  |        |	jE                          djG                  |	      }|S c c}w c c}w # t,        $ rf t/        |
j                         j#                         D ]<  \  }}t%        |j$                        t&        u s"|
j(                  j+                  |       > Y w xY w# t:        $ r t        d      w xY w)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.
        ztable_names rK   rR   sqlitesqlite_z

/*
Column Comments: z
*/z:Column comments are available on PostgreSQL, MySQL, Oraclez

/*
z*/z

)$r`   rY   
differencerD   rh   sorted_tablesr1   ri   rg   rV   rZ   rW   r   
startswithrM   appendcolumnsitemstyper   _columnsremover   re   r$   r   compilerstripcomment	Exceptionrd   rc   _get_table_indexes_get_sample_rowssortjoin)r&   table_namesget_col_commentsall_table_namesrt   tblmetadata_table_names
to_reflectmeta_tablestablesrO   kvcreate_tabler   column_comments_dictcolumnhas_extra_info	final_strs                      r'   r   zSQLDatabase.get_table_infoX  s\    557" -88IN </??U!VWW)O48NN4P4PQ4PS4PQ)C0D,EE
NN""((\\*%||	 #  ~~33
3xx3//\\X-#((2E2Ei2P 3 	 
  E&&5::9P9P+Pd55ejjAB	1!MM//1DAqAFF|x/--a0 2 {5199$,,GHL(//12J  +-("'--!>>@F0= #0 ,"78L7MTR
 ++Nt/N/N  h&
**4#:#:5#A"B"EE
..4#8#8#?"@CC
d"
MM*%c !d 	KK'	M  R
& " 1 /557DAqAFF|x/--a0 81, ! $T s>   L$A
L;LL!N?&NAN$NNNc                    | j                   j                  |j                        }dj                  t	        t
        |            }d| S )Nr   zTable Indexes:
)rX   get_indexesr1   r   mapr6   )r&   rO   indexesindexes_formatteds       r'   r   zSQLDatabase._get_table_indexes  s?    //--ejj9 IIc-&AB!"3!455r(   c                2   t        |      j                  | j                        }dj                  |j                  D cg c]  }|j
                   c}      }	 | j                  j                         5 }|j                  |      }t        t        d |            }d d d        dj                  D cg c]  }dj                  |       c}      }	| j                   d|j
                   d| d|	 S c c}w # 1 sw Y   ]xY wc c}w # t        $ r d}	Y Dw xY w)N	c                D    | D cg c]  }t        |      d d  c}S c c}w )Nd   r4   )lsis     r'   <lambda>z.SQLDatabase._get_sample_rows.<locals>.<lambda>  s     "#="QCF4CL"#=#=s   r    z rows from z table:
)r   limitrc   r   r   r1   rV   connectexecuterZ   r   r   )
r&   rO   commandcolcolumns_str
connectionsample_rows_resultsample_rowsrowsample_rows_strs
             r'   r   zSQLDatabase._get_sample_rows  s   -%%d&E&EF iiU]] C]c] CD	!%%':%/%7%7%@""=?QR ( #ii;(O;C3;(OPO ../{5::,im2!	
' !D (' )P   	! O	!s;   C2D 3(C7D 2D
D 7D <D DD
parametersexecution_optionsc               ^   |xs i }|xs i }| j                   j                         5 }| j                  w| j                  dk(  r!|j	                  d| j                  f|       nG| j                  dk(  r!|j	                  d| j                  f|       n| j                  dk(  rn| j                  dk(  r |j	                  d	| j                  f|       n| j                  d
k(  r!|j	                  d| j                   |       n| j                  dk(  r!|j	                  d| j                   |       nw| j                  dk(  rng| j                  dk(  r |j	                  d| j                  f|       n8| j                  dk(  r)|j	                  dt        | j                         |       t        |t              rt        |      }n(t        |t              rnt        dt        |             |j                  |||      }|j                  r|dk(  r,|j                         D cg c]  }|j                          }}nF|dk(  r&|j!                         }	|	g n|	j                         g}n|dk(  r|cddd       S t#        d      |cddd       S 	 ddd       g S c c}w # 1 sw Y   g S xY w)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   bigqueryzSET @@dataset_id=?mssqltrinozUSE ?r+   zSET search_path TO oraclez#ALTER SESSION SET CURRENT_SCHEMA = sqlany
postgresqlzSET search_path TO %shanazSET SCHEMA z#Query expression has unknown type: allonecursorz8Fetch parameter must be either 'one', 'all', or 'cursor')rV   beginrW   r   exec_driver_sqlrG   r;   r$   r   r   rb   r   r   returns_rowsfetchall_asdictfetchonerD   )
r&   r   fetchr   r   r   r   xresultfirst_results
             r'   _executezSQLDatabase._execute  s     %2
-3\\!Z||'<<;...<*; / 
 \\Z/..,*; / 
 \\W,\\W,..*; / 
 \\X-
 ..-dll^<*; /  \\X-..=dll^L*; /  \\X- \\\1../*; / 
 \\V+..%odll&C%DE*; / 
 '3'w-GZ0"Ed7m_ UVV''"3 ( F ""E>39??3DE3Daaiik3DFEe^#)??#4L#/#7Rl>R>R>T=UFh&!O "!R %R  Y "!@ #A "Z 	 FE "Z 	s$   H J"'J>4J"<J"J""J,c               ^   | j                  ||||      }|dk(  r|S |D 	cg c];  }|j                         D 	ci c]  \  }}	|t        |	| j                         c}	}= }
}}}	|s&|
D cg c]  }t	        |j                                }
}|
syt        |
      S c c}	}w c c}	}}w c c}w )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   )r?   r   )r  r   r@   rf   tuplevaluesr$   )r&   r   r   include_columnsr   r   r   rr   valueresr   s               r'   runzSQLDatabase.run4  s     UzEV  
 HM 

  &'WWY%.MFE eD4K4KLL%.  	 
 256#35&#C6s8O
 7s   B#"BB#- B*B#c                ^    	 | j                  |      S # t        $ r}	 d| cY d}~S d}~ww xY w)r   Error: N)r   rD   )r&   r   es      r'   get_table_info_no_throwz#SQLDatabase.get_table_info_no_throwY  s7    	!&&{33 	!*QC= 	!s    	,',,c               h    	 | j                  |||||      S # t        $ r}	 d| cY d}~S d}~ww xY w)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   )r&   r   r   r  r   r   r  s          r'   run_no_throwzSQLDatabase.run_no_throwi  sM     
	!88%"3 /     	!*QC= 	!s    	1,11c                |    t        | j                               }| j                         }|dj                  |      dS )z4Return db context that you may want in agent prompt.z, )r   r   )rZ   r`   r  r   )r&   r   r   s      r'   r   zSQLDatabase.get_context  s7    46689113
(;9OPPr(   )
NNNN   FNFi,  F)rj   r   rF   Optional[str]rk   zOptional[MetaData]rl   Optional[List[str]]rm   r  rn   r*   ro   boolrp   Optional[dict]rq   r  rr   r*   rs   r  r"   )ry   zUnion[str, URL]rz   r  r{   r   r)   rI   )NNNNN)r   r$   rF   r$   r   r  r   r  r   r  r   r  rz   r  r{   r   r)   rI   )z127.0.0.1:8902rootr   cnosdbpublic)r   r$   r   r$   r   r$   r   r$   r   r$   r)   rI   )r)   r$   )r)   zIterable[str])NF)r   r  r   r  r)   r$   )rO   r   r)   r$   )r   )
r   Union[str, Executable]r   Literal['all', 'one', 'cursor']r   Optional[Dict[str, Any]]r   r  r)   z'Union[Sequence[Dict[str, Any]], Result])r   F)r   r  r   r  r  r  r   r  r   r  r)   1Union[str, Sequence[Dict[str, Any]], Result[Any]])r   r  r)   r$   )r   r$   r   zLiteral['all', 'one']r  r  r   r  r   r  r)   r  )r)   zDict[str, Any])__name__
__module____qualname____doc__rv   classmethodr}   r   r   r   propertyr   r`   r[   r   r   r   r   r  r	  r  r  r   r   r(   r'   rI   rI   S   sy   /
 !%'+-1.2)*&+,0"!$&+NN N %	N
 +N ,N $'N  $N *N N N  $N`  '+J%J $J 	J
 
J J   ##'&*$(&*^Q^Q ^Q 	^Q
 !^Q $^Q "^Q $^Q ^Q 
^Q ^Q@  $ && & 	&
 & & 
& &P ) )> %=uM- N- % %
 QVY.YIMY	Yv6

B 27\
 046:\'\ /\
 -\ 4\ 
1\B 27 %	# 046:#'# /# 	# -# 4# 
;#J!& (- %	! 046:!! %! 	! -! 4! 
;!8Qr(   rI   )r)   None)r5   z+sqlalchemy.engine.interfaces.ReflectedIndexr)   r$   )r>   r   r?   r*   r7   r$   r)   r$   )rF   r$   r)   r$   )*r   
__future__r   rB   r   r   r   r   r   r	   r
   r   r   
sqlalchemylangchain_core._apir   langchain_core.utilsr   r   r   r   r   r   r   sqlalchemy.enginer   r   r   sqlalchemy.excr   r   sqlalchemy.schemar   sqlalchemy.sql.expressionr   sqlalchemy.typesr   r/   r6   r@   rG   rI   r   r(   r'   <module>r-     so    + " 	 P P P  * -  2 1 < ) 0 %
(   ?D FvQ vQr(   