
    BCh                         d Z ddlZddlZddlmZmZmZmZ ddlm	Z	m
Z
 ddlmZmZ  ej                  e      Z G d d      Z G d d	e      Z G d
 de      Z G d de      Z G d de      ZdededefdZy)z:
Database-specific connector implementations for SQLGenAI
    N)DictAnyListOptional)textinspect)Engine
Connectionc                       e Zd ZdZdefdZdedefdZdeee	f   deee	f   fdZ
dded	ed
edeee	f   fdZdededee   fdZdedefdZdee   deeee	f      deee	f   fdZdeee	f   fdZy)BaseDBConnectorz+Base class for database-specific connectorsenginec                     || _         y)z#Initialize with a SQLAlchemy engineN)r   )selfr   s     +/var/www/html/app/database/db_connectors.py__init__zBaseDBConnector.__init__   s	        	sql_queryreturnc                     |S )zTransform a query for database-specific compatibility
        
        Args:
            sql_query: The original SQL query
            
        Returns:
            The transformed SQL query
         r   r   s     r   transform_queryzBaseDBConnector.transform_query   s
     r   connection_configc                    	 t        | j                        }|j                  dd      g d}|j                         D ][  }|dg d}|j	                  |      D ]+  }|d   t        |d         dd}|d   j                  |       - |d	   j                  |       ] |S # t        $ r8}t        j                  d
t        |              dt        |      icY d}~S d}~ww xY w)zGet the database schema
        
        Args:
            connection_config: Database connection configuration
            
        Returns:
            Dictionary with database schema information
        databaseName databasetablesnamedescriptioncolumnsr!   typer!   dataTyper"   r#   r   zError getting database schema: errorN)
r   r   getget_table_namesget_columnsstrappend	Exceptionloggerr'   )	r   r   	inspectorschema_data
table_name
table_infocolumncolumn_infoes	            r   
get_schemazBaseDBConnector.get_schema   s    	%,I .11."EK (779 9
&#%!
 (33J? >F &v$'v$7')#K
 y)00=> H%,,Z8!9$  	%LL:3q6(CDSV$$	%s   BB 	C%-CCClimitoffsetc                 r   | j                  |      }	 | j                  j                         5 }|j                  t	        |            }|j
                  rt        |j                               }|dkD  r|j                  |       g }|j                  |      D ]q  }	i }
t        |      D ]N  \  }}|	|   }t        |t        t        t        t        t        d      t        t         f      st        |      }||
|<   P |j#                  |
       s | j%                  ||      }d||t'        |      ||||duxr |t'        |      z   |k  dd	cddd       S dd|j(                  dcddd       S # 1 sw Y   yxY w# t*        $ r9}t,        j/                  dt        |              dt        |      d	cY d}~S d}~ww xY w)
a!  Execute a SQL query and return the results
        
        Args:
            sql_query: The SQL query to execute
            limit: Maximum number of rows to return
            offset: Number of rows to skip
            
        Returns:
            Dictionary with query results
        r   NT)	successr#   rowsrowCount
totalCountr8   r7   hasMoreexecution_timezQuery executed successfully)r:   messagerowcountError executing query: Fr:   r'   )r   r   connectexecuter   returns_rowslistkeys	fetchmany	enumerate
isinstancer+   intfloatboolr$   dictr,   get_total_countlenrA   r-   r.   r'   )r   r   r7   r8   transformed_query
connectionresultr#   r;   rowrow_dicticolvaluetotal_countr5   s                   r   execute_queryzBaseDBConnector.execute_queryI   s    !00;2	7$$& .*#++D1B,CD&&"6;;=1G z((0 D%//6 
.#%&/&8 2FAs$'FE#-ec3tTRVZY]_c5d#e(+E
,1HSM2 H-
. #'"6"6zCT"UK $(#* $$'I&1"(!&#.d#:#aT@RU`@`*.
;. .V $(#@$*OOU. . .^  	7LL23q6(;<$s1v66	7sG   E4 DE(	E4 E(	E4 (E1-E4 1E4 4	F6=.F1+F61F6rS   c                    d}	 |j                         j                         j                  d      rx|j                         }|j                  d      r|dd }d| d}|j	                  t        |            }|j                         }|rd|v r|d   }|S |rt        |      dkD  r|d   }|S # t        $ r,}t        j                  d	t        |              Y d}~|S d}~ww xY w)
zGet the total row count for a query
        
        Args:
            connection: SQLAlchemy connection
            sql_query: The SQL query
            
        Returns:
            Total row count or None if it can't be determined
        NSELECT;%SELECT COUNT(*) AS total_count FROM () AS count_queryrZ   r   zCould not get total row count: )upperstrip
startswithendswithrE   r   fetchonerQ   r-   r.   warningr+   	r   rS   r   rZ   clean_querycount_querycount_result	count_rowr5   s	            r   rP   zBaseDBConnector.get_total_count   s     	G &&(33H='oo/'',"-cr"2K !Fk]Rbc)11${2CD(113	)!;"+M":K  3y>A#5"+A,K
 	  	GNN<SVHEFF 		Gs   BB+ B+ +	C 4!CC c                     d| S )zGet the appropriate EXPLAIN query for this database type
        
        Args:
            sql_query: The SQL query to explain
            
        Returns:
            The EXPLAIN query
        zEXPLAIN r   r   s     r   get_explain_queryz!BaseDBConnector.get_explain_query   s     )%%r   r#   r;   c                     d|dS )zParse the EXPLAIN result into a standardized format
        
        Args:
            columns: Column names from the EXPLAIN result
            rows: Rows from the EXPLAIN result
            
        Returns:
            Parsed EXPLAIN data
        genericformatdatar   r   r#   r;   s      r   parse_explain_resultz$BaseDBConnector.parse_explain_result   s      
 	
r   c                     g i dddS )zGet database configuration settings
        
        Returns:
            Dictionary with database configuration settings
        r   flagssettingssql_modeversionr   )r   s    r   get_db_configzBaseDBConnector.get_db_config   s     	
 	
r   Ni  r   )__name__
__module____qualname____doc__r	   r   r+   r   r   r   r6   rL   r[   r
   r   rP   rn   r   ru   r|   r   r   r   r   r      s    5v 
 
 
(%DcN (%tCH~ (%T?7s ?73 ?7s ?7SWX[]`X`Sa ?7B*  RU B
&3 
&3 
&
DI 
T$sCx.=Q 
VZ[^`c[cVd 
 
tCH~ 
r   r   c                       e Zd ZdZdedefdZdeeef   deeef   fdZde	dede
e   fdZdedefd	Zd
ee   deeeef      deeef   fdZdeeef   fdZy)MySQLConnectorz!MySQL-specific database connectorr   r   c                     |S )zTransform a query for MySQL compatibility
        
        Note: The AI model now handles GROUP BY compatibility with ONLY_FULL_GROUP_BY mode,
        so this method primarily exists for backward compatibility or manual queries.
        r   r   s     r   r   zMySQLConnector.transform_query   s
     r   r   c                 4   	 t        | j                        }|j                  dd      }|g d}|j                         D ]  }|dg d}|j	                  |      D ]+  }|d   t        |d         dd}|d   j                  |       - |j                  |      j                  d	g       }	|d   D ]  }|d   |	v sd
|d<    |d   j                  |        |S # t        $ r8}
t        j                  dt        |
              dt        |
      icY d}
~
S d}
~
ww xY w)zGet the MySQL database schema
        
        Args:
            connection_config: Database connection configuration
            
        Returns:
            Dictionary with database schema information
        r   r   r   r    r!   r$   r%   r#   constrained_columnsTisPrimaryKeyr   zError getting MySQL schema: r'   Nr   r   r(   r)   r*   r+   r,   get_pk_constraintr-   r.   r'   )r   r   r/   database_namer0   r1   r2   r3   r4   
pk_columnsr5   s              r   r6   zMySQLConnector.get_schema   sN   &	%,I-11."EM *K (779 9
&#%!
 (33J? >F &v$'v$7')#K
 y)00=> '88DHHI^`bc
#-i#8 ;K"6*j86:N3; H%,,Z8-90  	%LL7Ax@ASV$$	%s$   B4C 7C 	D-DDDrS   c                 Z   d}	 |j                         j                         j                  d      r|j                         }|j                  d      r|dd }	 d| d}|j	                  t        |            }|j                         }|rt        |d      r|j                  }n|rt        |      dkD  r|d   }|S 	 |S # t        $ r,}t        j                  d	t        |              Y d}~|S d}~ww xY w# t        $ r,}t        j                  d
t        |              Y d}~|S d}~ww xY w)z,Get the total row count for a query in MySQLNr]   r^   r_   r`   ra   rZ   r   zCould not get count for query: zError getting total count: )rb   rc   rd   re   rE   r   rf   hasattrrZ   rQ   r-   r.   rg   r+   rh   s	            r   rP   zMySQLConnector.get_total_count  s5   	C &&(33H='oo/'',"-cr"2KO$I+Vf"gK#-#5#5d;6G#HL , 5 5 7I WY%F&/&;&;"s9~'9&/l - >,  ! ONN%DSVH#MNN O 	CNN8QABB	Cs=   AC5 A B= =	C2!C-'C5 -C22C5 5	D*>!D%%D*c                     d| S )z+Get the appropriate EXPLAIN query for MySQLzEXPLAIN FORMAT=JSON r   r   s     r   rn   z MySQLConnector.get_explain_query0  s    %i[11r   r#   r;   c                     d|dS )zParse the MySQL EXPLAIN resultmysqlrq   r   rt   s      r   ru   z#MySQLConnector.parse_explain_result4  s     
 	
r   c           	      <   g i ddd}	 | j                   j                         5 }|j                  t        d            }|j	                         }|r-t        |      dkD  r|d   |d<   |d   j                  d      |d<   |j                  t        d            }|j	                         }|rt        |      dkD  r|d   |d	<   g d
}|D ]O  }	 |j                  t        |            }|j	                         }|r |j                         D ]  }||   |d   |<    Q 	 ddd       |S # t        $ r+}t        j                  dt        |              Y d}~d}~ww xY w# 1 sw Y   |S xY w# t        $ r,}t        j                  dt        |              Y d}~|S d}~ww xY w)z|Get MySQL configuration settings
        
        Returns:
            Dictionary with MySQL configuration settings
        r   rw   zSELECT @@SESSION.sql_moder   rz   ,rx   zSELECT VERSION()r{   )z1SELECT @@innodb_strict_mode AS innodb_strict_modez.SELECT @@character_set_server AS character_setz&SELECT @@collation_server AS collationz1SELECT @@max_allowed_packet AS max_allowed_packetry   zError fetching MySQL setting: Nz$Error fetching MySQL configuration: )r   rD   rE   r   rf   rQ   splitrH   r-   r.   rg   r+   )	r   configrS   rT   rU   settings_queriesquerykeyr5   s	            r   r|   zMySQLConnector.get_db_config;  s    	
!	L$$& R*#++D1L,MNoo'3s8a<),QF:&&)!fll3&7F7O $++D1C,DEoo'3s8a<(+AF9%$  . RER!+!3!3DK!@$oo/'*xxz C:=c(z 23 7CR-RD  % R)GAx'PQQR;RD   	LNNA#a&JKK	Ls`   E& B%E	AD"EE& "	E+!EEEEE#E& #E& &	F/!FFN)r~   r   r   r   r+   r   r   r   r6   r
   r   rL   rP   rn   r   ru   r|   r   r   r   r   r      s    +  /%DcN /%tCH~ /%b*  RU :23 23 2
DI 
T$sCx.=Q 
VZ[^`c[cVd 
0tCH~ 0r   r   c                       e Zd ZdZdedefdZdee   deeeef      deeef   fdZ	deeef   deeef   fd	Z
deeef   fd
Zy)PostgreSQLConnectorz&PostgreSQL-specific database connectorr   r   c                     d| S )z0Get the appropriate EXPLAIN query for PostgreSQLzEXPLAIN (FORMAT JSON) r   r   s     r   rn   z%PostgreSQLConnector.get_explain_queryp  s    '	{33r   r#   r;   c                     d|dS )z#Parse the PostgreSQL EXPLAIN result
postgresqlrq   r   rt   s      r   ru   z(PostgreSQLConnector.parse_explain_resultt  s     #
 	
r   r   c                 n   	 t        | j                        }|j                  dd      }|j                  d      xs d}|g d}|j                  |      D ]  }|dg d}|j	                  ||      D ]+  }|d   t        |d	         dd
}	|d   j                  |	       - |j                  ||      }
|
j                  dg       }|d   D ]  }	|	d   |v sd|	d<    |d   j                  |        |S # t        $ r8}t        j                  dt        |              dt        |      icY d}~S d}~ww xY w)zGet the PostgreSQL database schema
        
        Args:
            connection_config: Database connection configuration
            
        Returns:
            Dictionary with database schema information
        r   r   schema_namepublicr   schemar    r!   r$   r%   r#   r   Tr   r   z!Error getting PostgreSQL schema: r'   Nr   )r   r   r/   r   r   r0   r1   r2   r3   r4   pk_constraintr   r5   s                r   r6   zPostgreSQLConnector.get_schema{  sv   )	%,I-11."EM+//>J(K *K (77{7K 9
&#%!
 (33J{3S >F &v$'v$7')#K
 y)00=> !* ; ;J{ ; [*../DbI
#-i#8 ;K"6*j86:N3; H%,,Z8/92  	%LL<SVHEFSV$$	%s$   CC3 C3 3	D4<-D/)D4/D4c           	      V   g i ddd}	 | j                   j                         5 }g d}|D ]w  }	 |j                  t        |            }|j	                         }|rHt        |      dkD  r:|j                  dd      j                  dd      }|d   |d   |<   |dk(  r|d   |d	<   y 	 ddd       |S # t        $ r+}t        j                  d
t        |              Y d}~d}~ww xY w# 1 sw Y   |S xY w# t        $ r,}t        j                  dt        |              Y d}~|S d}~ww xY w)zGet PostgreSQL configuration settings
        
        Returns:
            Dictionary with PostgreSQL configuration settings
        r   rw   )zSHOW server_version;z!SHOW standard_conforming_strings;zSHOW search_path;zSHOW DateStyle;r   zSHOW r^   ry   server_versionr{   z#Error fetching PostgreSQL setting: Nz)Error fetching PostgreSQL configuration: )r   rD   rE   r   rf   rQ   replacer-   r.   rg   r+   )	r   r   rS   r   r   rT   rU   setting_namer5   s	            r   r|   z!PostgreSQLConnector.get_db_config  sL    	
	Q$$& W*$  . WEW!+!3!3DK!@$oo/3s8a<+0=="+E+M+McSU+VL?B1vF:.|<  ,/??47Fy 1WW2  % W)LSQRVH'UVVW)W2   	QNNFs1vhOPP	Qs^   C3 
C&A4B/"C&%C3 /	C#8!CC&C##C&&C0+C3 0C3 3	D(<!D##D(Nr~   r   r   r   r+   rn   r   r   r   ru   r6   r|   r   r   r   r   r   m  s    043 43 4
DI 
T$sCx.=Q 
VZ[^`c[cVd 
2%DcN 2%tCH~ 2%h'tCH~ 'r   r   c                       e Zd ZdZdedefdZdee   deeeef      deeef   fdZ	deeef   deeef   fd	Z
deeef   fd
Zy)SQLServerConnectorz&SQL Server-specific database connectorr   r   c                     d| dS )z0Get the appropriate EXPLAIN query for SQL ServerzSET SHOWPLAN_XML ON; z; SET SHOWPLAN_XML OFF;r   r   s     r   rn   z$SQLServerConnector.get_explain_query  s    &yk1HIIr   r#   r;   c                     d|dS )z#Parse the SQL Server EXPLAIN result	sqlserverrq   r   rt   s      r   ru   z'SQLServerConnector.parse_explain_result  s     "
 	
r   r   c                 H   	 t        | j                        }|j                  dd      }|g d}d}|j                  |      D ]  }|dg d}|j	                  ||      D ]+  }|d   t        |d         dd	}	|d
   j                  |	       - |j                  ||      }
|
j                  dg       }|d
   D ]  }	|	d   |v sd|	d<    |d   j                  |        |S # t        $ r8}t        j                  dt        |              dt        |      icY d}~S d}~ww xY w)zGet the SQL Server database schema
        
        Args:
            connection_config: Database connection configuration
            
        Returns:
            Dictionary with database schema information
        r   r   r   dbor   r    r!   r$   r%   r#   r   Tr   r   z!Error getting SQL Server schema: r'   Nr   )r   r   r/   r   r0   r   r1   r2   r3   r4   r   r   r5   s                r   r6   zSQLServerConnector.get_schema  sf   )	%,I-11."EM *K  K'77{7K 9
&#%!
 (33J{3S >F &v$'v$7')#K
 y)00=> !* ; ;J{ ; [*../DbI
#-i#8 ;K"6*j86:N3; H%,,Z8/92  	%LL<SVHEFSV$$	%s$   B>C  C   	D!)-DD!D!c                    g i ddd}	 | j                   j                         5 }	 |j                  t        d            }|j	                         }|r|d   |d<   |j                  t        d            }|j	                         }|r=|j                         D ]*  }||   |d   |<   ||   dk(  s|d   j                  |       , d
d
d
       |S # t        $ r+}t        j                  d	t        |              Y d
}~9d
}~ww xY w# 1 sw Y   |S xY w# t        $ r,}t        j                  dt        |              Y d
}~|S d
}~ww xY w)zGet SQL Server configuration settings
        
        Returns:
            Dictionary with SQL Server configuration settings
        r   rw   zSELECT @@VERSION AS versionr{   aR  
                        SELECT 
                            CASE WHEN (16384 & @@OPTIONS) = 16384 THEN 1 ELSE 0 END AS ANSI_NULLS,
                            CASE WHEN (8 & @@OPTIONS) = 8 THEN 1 ELSE 0 END AS ANSI_PADDING,
                            CASE WHEN (4 & @@OPTIONS) = 4 THEN 1 ELSE 0 END AS ANSI_WARNINGS
                    ry      rx   z$Error fetching SQL Server settings: Nz)Error fetching SQL Server configuration: )r   rD   rE   r   rf   rH   r,   r-   r.   rg   r+   )r   r   rS   rT   rU   ansi_settingsr   r5   s           r   r|   z SQLServerConnector.get_db_config  sa    	
	Q$$& T*T'//5R0STF //+C,/	Ny) %/$6$6t = 8 %M (002C#&88: <C69#hF:.s3"3x1} &w 6 6s ;<#T4  ! TNN%I#a&#RSST+T4   	QNNFs1vhOPP	Qs^   D DBC,CD 	D !C;6D;D  DDD D 	E!E  ENr   r   r   r   r   r     s    0J3 J3 J
DI 
T$sCx.=Q 
VZ[^`c[cVd 
2%DcN 2%tCH~ 2%h(tCH~ (r   r   c                       e Zd ZdZdedefdZdee   deeeef      deeef   fdZ	deeef   deeef   fd	Z
dded
ededeeef   fdZdededefdZdeeef   fdZy)OracleConnectorz"Oracle-specific database connectorr   r   c           
         | j                   j                  j                         }|j                  dd      j	                         }| j                   j                         5 }	 t        d| d       t        d      }|j                  |      }|j                         D cg c]  }|d   	 }}t        d| d       ddl
}	d	}
|	j                  |
||	j                        }|D cg c]  }|d   xs |d
    }}g }|D ]=  }d|v r&|j                  d      \  }}|j                  |       -|j                  |       ? t        d| d       g }|D ]u  }|D ]n  }t        d      }|j                  |||j	                         d      }|j                         }|dkD  sG||vsL|j                  |       t        d| d| d       p w |r2|d   }t        d| d       |j                  t        d|              nt        d       	 t        d       t        d       d	}
|	j                  |
||	j                        }|D cg c]  }|d   xs |d
    }}g }|D ]=  }d|v r&|j                  d      \  }}|j                  |       -|j                  |       ? |r6dj!                  |      }d|j#                  dd       d| d| dcddd       S 	 ddd       y c c}w c c}w c c}w # t$        $ r*}t        dt'        |       d       Y d}~ddd       yd}~ww xY w# t$        $ r"}t        dt'        |       d       Y d}~td}~ww xY w# 1 sw Y   y xY w)!a4  Get the appropriate EXPLAIN query for Oracle
        
        For Oracle, we'll use a simpler approach that doesn't depend on PLAN_TABLE.
        Instead, we'll use the DBMS_XPLAN.DISPLAY_CURSOR function which works with
        recently executed SQL statements without requiring special privileges.
        usernamer   z#
[ORACLE] Current connection user: 
z0SELECT USERNAME FROM ALL_USERS ORDER BY USERNAMEr   z
[ORACLE] Available schemas: N%\bFROM\s+([\w\.]+)|\bJOIN\s+([\w\.]+)r   .z
[ORACLE] Tables in query: zxSELECT COUNT(*) FROM ALL_TABLES 
                                          WHERE OWNER = :schema AND TABLE_NAME = :table)r   tablez
[ORACLE] Found table z in schema z$
[ORACLE] Setting current schema to #ALTER SESSION SET CURRENT_SCHEMA = zE
[ORACLE] Could not find a schema containing the tables in the query
zB
[ORACLE] Using table statistics approach instead of EXPLAIN PLAN
z%
[ORACLE] Gathering table statistics
z', 'zR
                        WITH query_info AS (
                            SELECT ''z''a  ' AS sql_text FROM DUAL
                        ),
                        table_stats AS (
                            SELECT 
                                t.TABLE_NAME,
                                t.NUM_ROWS,
                                t.BLOCKS,
                                t.AVG_ROW_LEN,
                                t.LAST_ANALYZED
                            FROM ALL_TABLES t
                            WHERE t.TABLE_NAME IN ('a	  ')
                        ),
                        index_stats AS (
                            SELECT 
                                i.TABLE_NAME,
                                i.INDEX_NAME,
                                i.UNIQUENESS,
                                i.INDEX_TYPE,
                                ic.COLUMN_NAME
                            FROM ALL_INDEXES i
                            JOIN ALL_IND_COLUMNS ic ON i.INDEX_NAME = ic.INDEX_NAME
                            WHERE i.TABLE_NAME IN ('a  ')
                        )
                        SELECT 'QUERY ANALYSIS' AS SECTION, 'Original Query' AS INFO_TYPE, sql_text AS DETAILS FROM query_info
                        UNION ALL
                        SELECT 'TABLE STATISTICS', table_name, 'Rows: ' || NUM_ROWS || ', Blocks: ' || BLOCKS || ', Avg Row Len: ' || AVG_ROW_LEN || ', Last Analyzed: ' || LAST_ANALYZED FROM table_stats
                        UNION ALL
                        SELECT 'INDEX INFORMATION', table_name || '.' || index_name, 'Type: ' || INDEX_TYPE || ', Uniqueness: ' || UNIQUENESS || ', Column: ' || COLUMN_NAME FROM index_stats
                        UNION ALL
                        SELECT 'RECOMMENDATIONS', 'Join Columns', 'Consider indexes on join columns like DEPARTMENT_ID if not already indexed' FROM DUAL
                        UNION ALL
                        SELECT 'RECOMMENDATIONS', 'Group By Columns', 'Consider composite indexes on GROUP BY columns (EMPLOYEE_ID, FIRST_NAME, LAST_NAME)' FROM DUAL
                        UNION ALL
                        SELECT 'RECOMMENDATIONS', 'Execution Plan', 'For detailed execution plan, try running this query in Oracle SQL Developer' FROM DUAL
                        z%
[ORACLE] Error with all approaches: a	  
                    SELECT 
                        'ORACLE EXECUTION PLAN' as section,
                        'The execution plan could not be generated automatically.' as details
                    FROM DUAL
                    UNION ALL
                    SELECT 
                        'QUERY ANALYSIS',
                        'Your query joins EMPLOYEES and PROJECTS tables on DEPARTMENT_ID, groups by employee attributes, and filters with HAVING COUNT(p.PROJECT_ID) > 2.'
                    FROM DUAL
                    UNION ALL
                    SELECT 
                        'RECOMMENDATIONS',
                        'Consider indexes on join columns (DEPARTMENT_ID) and GROUP BY columns (EMPLOYEE_ID, FIRST_NAME, LAST_NAME).'
                    FROM DUAL
                    UNION ALL
                    SELECT 
                        'RECOMMENDATIONS',
                        'For detailed execution plan, try running this query in Oracle SQL Developer.'
                    FROM DUAL
                    z+
[ORACLE] Error setting up schema context: a-  
        SELECT 
            'Oracle Execution Plan' as plan_section,
            'The execution plan could not be generated automatically.' as plan_info
        FROM DUAL
        UNION ALL
        SELECT 
            'Query Analysis',
            'Consider checking table statistics and indexes for the tables in your query.'
        FROM DUAL
        UNION ALL
        SELECT 
            'Recommendation',
            'You may need to run this query through Oracle SQL Developer or another tool with explain plan capabilities.'
        FROM DUAL
        )r   urltranslate_connect_argsr(   rb   rD   printr   rE   fetchallrefindall
IGNORECASEr   r,   scalarjoinr   r-   r+   )r   r   connection_infor   rS   schemas_queryschemas_resultrU   available_schemasr   table_patterntable_matchesmatchtable_namesclean_table_namesr   r   r1   potential_schemascheck_queryrT   counttarget_schematables_listr5   s                            r   rn   z!OracleConnector.get_explain_queryG  s    ++//@@B"&&z26<<> [[  " M	QjLQ<XJbIJ !%%W X!+!3!3M!B7E7N7N7P$QSV$Q!$Q67H6ILM  H "

=)R]] SANOuQx3583OO %'!( 8Ee|-2[[-=*
)00<)0078 45F4GrJK %'!/ ZF!2 Z&* 0X '\!+!3!3KF]b]h]h]jAk!l & 197H)H-44V<!$;E7+fXUW"XYZZ %$5a$8MA-PRST&&t.QR_Q`,a'bccdW `a CD %MM$&JJ}i$WMER"SE58#7uQx#7"SK"S )+%!, <%<16S1A.FJ-44Z@-44U;< )&,kk2C&D$%%.%6%6sD%A$B 
C5 6AM B5 6AM B/$ YM	Q M	QT )UM	QbS %R P\ #Th ! B3q6("MNmM	Q M	Qd4  QDSVHBOPPQYM	Qbs   M!=LK*8L"K5B$LLA&L9K)?K$A4K)M
L$K))	L2L
LLL	M
(M MM

MMr#   r;   c                     |rdd|d   v r]d|d   v rVi }|D ]G  }|j                  d      }|j                  d      }|s(|s+||vrg ||<   ||   j                  |       I d|d|ddS d|dd	S )
zParse the Oracle EXPLAIN result
        
        This method handles both actual execution plans from DBMS_XPLAN.DISPLAY_CURSOR
        and our fallback format with plan_section and plan_info columns.
        plan_sectionr   	plan_infooracleTzOracle execution plan could not be generated automatically. Please check your database permissions or use Oracle SQL Developer.)rr   rs   is_fallbacksectionsr@   F)rr   rs   r   )r(   r,   )r   r#   r;   r   rU   sectioninfos          r   ru   z$OracleConnector.parse_explain_result  s     Nd1g-+a2HH 3''.1ww{+th.,.)W%,,T23 ##$ ]   
 	
r   r   c                 2   t        d       	 |j                  dd      j                         }|j                  dd      }|j                  dd      }t        d|        t        d|        t        d|r|nd	        |g d
}|r|n|}t        d|        | j                  j	                         5 }t        d      }|j                  |d|j                         i      }	|	j                         D 
cg c]  }
|
d   	 }}
t        dt        |       d|        |D ]  }|dg d}t        d      }|j                  ||j                         |d      }|j                         D ]<  }|d   |d   r|d    d|d    dn|d   d|d   dk(  d}|d   j                  |       > |d   j                  |        	 ddd       |S c c}
w # 1 sw Y   |S xY w# t        $ r8}t        j                  dt        |              dt        |      icY d}~S d}~ww xY w) zGet the Oracle database schema
        
        Args:
            connection_config: Database connection configuration
            
        Returns:
            Dictionary with database schema information
        z-

**** ORACLE GET_SCHEMA METHOD CALLED ****

r   r   r   serviceNamez([DEBUG] Getting Oracle schema for user: z[DEBUG] Database/SID: z[DEBUG] Service Name: zNot providedr   z#[DEBUG] Querying schema for owner: zSELECT DISTINCT TABLE_NAME 
                       FROM ALL_TABLES 
                       WHERE OWNER = :owner 
                       ORDER BY TABLE_NAMEownerr   z[DEBUG] Found z tables for owner r    a  SELECT 
                              COLUMN_NAME, 
                              DATA_TYPE, 
                              DATA_LENGTH, 
                              NULLABLE, 
                              COLUMN_ID 
                           FROM ALL_TAB_COLS 
                           WHERE OWNER = :owner 
                           AND TABLE_NAME = :table_name 
                           ORDER BY COLUMN_ID)r   r1      r   ()   Y)r!   r&   r"   nullabler#   r   NzError getting Oracle schema: r'   )r   r(   rb   r   rD   r   rE   r   rQ   r,   r-   r.   r'   r+   )r   r   r   r   service_namer0   target_ownerrS   table_querytable_resultrU   r   r1   r2   column_querycolumn_resultr3   r4   r5   s                      r   r6   zOracleConnector.get_schema  sr    	ABM	%+//
B?EEGK-11."EM,00CL<[MJK*=/:;*<<^*\]^ *K -:={L7~FG $$& 3=*".  *11+I[I[I]?^_,8,A,A,CDS#a&DDs6{m3El^TU #) $=J *')#%"J $(	1$L %/$6$6$"."4"4"6jQ%M
 #0"8"8": B$*1IGMay6!9+Qvayk(CV\]^V_+-(.q	S(8	' #9-44[AB  )00<I$=3=j W E3=j  	%LL8QABSV$$	%sP   B%G 2A G2G>B:G9	G GGG G 	H-HHHr7   r8   c                    | j                  |      }	 | j                  j                         5 }| j                  j                  j	                         }|j                  dd      j                         }ddl}d}	|j                  |	||j                        }
|
D cg c]  }|d   xs |d    }}|g}t               }|D ]:  }d|v s|j                  d      \  }}|j                  |j                                < |j                  t        |             |sV|D ]Q  }d|vs	 t        d|j                          d	      }|j!                  |      }|D ]  }|j#                  |d           S g }|D ]  }||vs|j#                  |        t'        d| d       d}|D ]e  }	 t'        d| d       |j!                  t        d|              |j!                  t        |            }|j*                  rt        |j-                               }|dkD  r|j/                  |       g }|j/                  |      D ]q  }i }t1        |      D ]N  \  }}||   }t3        |t(        t4        t6        t8        t;        d      t        t<        f      st)        |      }|||<   P |j#                  |       s d}	 | j?                  ||      }d||tE        |      ||dc cddd       S d|jF                  d|jF                   |dc cddd       S  |r|t%        d      c c}w # t$        $ r%}t'        d
| dt)        |              Y d}~,d}~ww xY w# t$        $ r+}t@        jC                  dt)        |              Y d}~d}~ww xY w# t$        $ r(}t'        d| dt)        |       d       |}Y d}~d}~ww xY w# 1 sw Y   yxY w# t$        $ r9}t@        jI                  dt)        |              dt)        |      dcY d}~S d}~ww xY w)a  Execute a SQL query and return the results
        
        For Oracle, we need to set the schema context before executing queries
        to ensure the database can find the tables referenced in the query.
        
        Args:
            sql_query: The SQL query to execute
            limit: Maximum number of rows to return
            offset: Number of rows to skip
            
        Returns:
            Dictionary with query results
        r   r   r   Nr   r   r   z1SELECT OWNER FROM ALL_TABLES WHERE TABLE_NAME = 'r   zError finding schema for table z: z*
[ORACLE] Will try schemas in this order: r   z$
[ORACLE] Setting schema context to r   zCould not get total count: T)r:   r#   r;   r<   r=   schema_usedz,Query executed successfully. Rows affected: )r:   r<   r@   r   z,
[ORACLE] Error executing query with schema z9Could not find a valid schema for the tables in the queryrB   FrC   )%r   r   rD   r   r   r(   rb   r   r   r   setr   addextendrG   r   rE   r,   r-   r   r+   rF   rH   rI   rJ   rK   rL   rM   rN   r$   rO   rP   r.   rg   rQ   rA   r'   ) r   r   r7   r8   rR   rS   r   r   r   r   r   r   r   schemas_to_tryexplicit_schemasr   r   _schema_queryschema_resultrU   r5   unique_schemas
last_errorrT   r#   r;   rV   rW   rX   rY   rZ   s                                    r   r[   zOracleConnector.execute_queryq  ss    !00;u	7$$& pa*"&++//"H"H"J*..z2>DDF  H "

=)R]] SANOuQx3583OO #+#&5 ( =Ee|$)KK$4	(,,V\\^<= %%d+;&<= (!, 	[e+[/36ghmhshshugvvw4x/y0:0B0B<0P+8 !BC$2$9$9#a&$A!B	[ "$, 6F^3&--f56 CNCSSUVW "
, ;!F:! EfXRPQ"**42UV\U]0^+_` ",!3!3D9J4K!L!..&*6;;=&9G  &z & 0 0 8 $&D'-'7'7'> 
6+-.7.@ !:FAs,/FE+5ec3tUYZ^U_aegk=l+m03E
49HSM!: !%H 5
6 +/KW.2.B.B:y.Y
 ,0+2(,,/I.9/5$ opa paD ,0,2OO-YZ`ZiZiYj+k/5	$ Cpa pa^;!| $$#$_``O P2 $- [ %(GwbQTUVQWPX&Y Z Z[d $- W &1LSQRVH/U V VW& % ! MfXUWX[\]X^W__abc%&
 !Opa pad  	7LL23q6(;<$s1v66	7s   O A,N7L,N7AN7!A	L*N78*N7#D
N.M NN7	O N:N7<	O N7	M	$M>N7M		N7	N !M;6N;N  N	N4N/)N7/N44N77O <O  O 	P.P :P PrS   c                    ddl }|j                  d|j                  |j                  z        }|j	                  |      }|r|j                  d      }|j                  d|j                  |j                  z        }|j	                  |      }|r|j                  d      nd}	d| d|	 }
|j                  t        |
            }|j                         }|r|d   S dS y)z-Get the total row count for a query in Oracler   NzC\bFROM\s+.*?(?=\bWHERE\b|\bGROUP\s+BY\b|\bORDER\s+BY\b|\bLIMIT\b|$)z:\bWHERE\s+.*?(?=\bGROUP\s+BY\b|\bORDER\s+BY\b|\bLIMIT\b|$)r   zSELECT COUNT(*) AS total_count  )	r   compiler   DOTALLsearchgrouprE   r   rf   )r   rS   r   r   from_pattern
from_matchfrom_clausewhere_patternwhere_matchwhere_clauserj   rT   rU   s                r   rP   zOracleConnector.get_total_count  s     	zz"hjljwjwz|  {D  {D  kD  E!((3
$**1-KJJ'dfhfsfsvxvvf  AM'..y9K3>;,,Q/BL;K=,XK''[(9:F//#C 3q6'a'r   c                 :   g i ddd}	 | j                   j                         5 }	 |j                  t        d            }|j	                         }|rt        |      dkD  r|d   |d<   |j                  t        d            }|D ]  }|d   |d   |d   <    	 d
d
d
       |S # t        $ r+}t        j                  d	t        |              Y d
}~9d
}~ww xY w# 1 sw Y   |S xY w# t        $ r,}t        j                  dt        |              Y d
}~|S d
}~ww xY w)z~Get Oracle configuration settings
        
        Returns:
            Dictionary with Oracle configuration settings
        r   rw   z-SELECT BANNER FROM V$VERSION WHERE ROWNUM = 1r   r{   z
                        SELECT PARAMETER, VALUE FROM NLS_SESSION_PARAMETERS 
                        WHERE PARAMETER IN ('NLS_DATE_FORMAT', 'NLS_TIMESTAMP_FORMAT', 'NLS_NUMERIC_CHARACTERS')
                    r   ry   z Error fetching Oracle settings: Nz%Error fetching Oracle configuration: )
r   rD   rE   r   rf   rQ   r-   r.   rg   r+   )r   r   rS   rT   rU   
nls_paramsr5   s          r   r|   zOracleConnector.get_db_config  s;    	
	M$$& P*P'//5d0efF //+Cs3x!|,/Fy) ",!3!3D : 5 "J  * <58Vz*3q62<P(  ! PNN%Ec!fX#NOOPP(   	MNNB3q6(KLL	Ms^   C% CA1B!CC% !	C*!CCCCC"C% "C% %	D.!DDNr}   )r~   r   r   r   r+   rn   r   r   r   ru   r6   rL   r[   r
   rP   r|   r   r   r   r   r   D  s    ,l3 l3 l\ 
DI  
T$sCx.=Q  
VZ[^`c[cVd  
DX%DcN X%tCH~ X%tE7s E73 E7s E7SWX[]`X`Sa E7N*   ("tCH~ "r   r   db_typer   r   c                     | j                         } | dv rt        |      S | dv rt        |      S | dv rt        |      S | dv rt	        |      S t
        j                  d|  d       t        |      S )zGet the appropriate connector for a database type
    
    Args:
        db_type: Database type (mysql, postgresql, sqlserver, oracle)
        engine: SQLAlchemy engine
        
    Returns:
        Database-specific connector instance
    )r   mariadb)r   postgres)r   mssql)r   zUnknown database type: z, using base connector)lowerr   r   r   r   r.   rg   r   )r  r   s     r   get_connectorr
  1  s     mmoG&&f%%	.	."6**	*	*!&))	J	v&& 	0	9OPQv&&r   )r   loggingtimetypingr   r   r   r   
sqlalchemyr   r   sqlalchemy.enginer	   r
   	getLoggerr~   r.   r   r   r   r   r   r+   r
  r   r   r   <module>r     s      , , $ 0			8	$G
 G
RV_ Vpi/ iVj jXjo jZ'3 ' '? 'r   