
    Pi                    &   d Z ddlmZ ddlZ ej        dej        ej        z            Z ej        d          Z ej        d          Z	 e
h d          Z e
h d          ZddZddZddZddZddZ e
             e
            dddZdS )zsSQL statement classification for Dippy.

Provides dialect-agnostic detection of read-only vs write SQL statements.
    )annotationsNa  
    '(?:[^']*'')*[^']*'           # Single-quoted string ('' for escape)
    | "(?:[^"]*"")*[^"]*"         # Double-quoted string ("" for escape)
    | `[^`]*`                     # Backtick identifier (MySQL)
    | \[[^\]]*\]                  # Bracket identifier (SQL Server)
    | --[^\n]*                    # Single-line comment
    | /\*.*?\*/                   # Block comment
    z\s+z[A-Za-z_]\w*>   SHOWSELECTEXPLAINDESCRIBE>   DROPALTERGRANTMERGECREATEDELETEINSERTREVOKEUPDATEREPLACETRUNCATEsqlstrreturnc                8    t                               d|           S )zBRemove string literals, quoted identifiers, and comments from SQL. )_QUOTED_PATTERNsub)r   s    //root/projects/gits/Dippy/src/dippy/core/sql.py_strip_quotedr   -   s    sC(((    boolc                h   t          |           }|                    d          }|dk    rdS ||dz   d         }|                                }|sdS t          d |D                       rGt	          |          D ]5\  }}|                                rd||dz   d         v r dS ,|dk    r dS 6dS dS )z@Check if SQL contains multiple statements (semicolon-separated).;F   Nc              3  "   K   | ]
}|d k    V  dS )r   N ).0cs     r   	<genexpr>z+_has_multiple_statements.<locals>.<genexpr>A   s&      
,
,18
,
,
,
,
,
,r   T)r   findstripall	enumerateisspace)r   stripped
first_semiafterafter_strippedir%   s          r   _has_multiple_statementsr1   2   s    S!!Hs##JRuZ!^%%&E[[]]N u 
,
,^
,
,
,,,  e$$ 	 	DAqyy{{ %A.((44 )ctt  u4r   posintc                h    t                               | |          }|r|                                n|S )zSkip whitespace at position.)_WHITESPACE_PATTERNmatchend)r   r2   ms      r   _skip_whitespacer9   R   s.    !!#s++A 155777S r   c                $   t          |           }d}||k     rt          | |          }||k    rn| |         dk    rJd}|dz  }||k     r:|dk    r4| |         dk    r|dz  }n| |         dk    r|dz  }|dz  }||k     r|dk    4d}s| |         dk    r|dz  }d}t                              | |          }|rO|                                                                }|r%|                                }|dk    rd}n|d	k    r	 |S |dz  }||k     |S )
zFSkip over CTE definitions (name AS (...), ...) to find main statement.T(r!   r   )F,AS	RECURSIVElenr9   _KEYWORD_PATTERNr6   groupupperr7   )r   r2   length	expect_asdepthr8   kws          r   	_skip_cterI   X   s`   XXFI
,,sC((&==s8s??E1HC,,5199s8s??QJEEX__QJEq ,,5199 Is8s??1HCI""3,, 
	""B eegg:: %II;&&JqE ,,F Jr   c                D   t          |           }||k     rt          | |          }||k    rnst                              | |          }|rK|                                                                }|dk    rdS |dk    rdS |                                }|dz  }||k     dS )zFCheck if SELECT statement contains INTO (making it a write operation).INTOTFROMFr!   r@   )r   r2   rE   r8   rH   s        r   _check_select_intorM      s     XXF
,,sC((&==""3,, 	""BV||tV||u%%''Cq ,, 5r   )extra_readonlyextra_writerN   frozenset[str]rO   bool | Nonec               0   t          |           rdS t          |           }t          |z  }t          |z  }d}|t	          |          k     rt          ||          }|t	          |          k    rnt                              ||          }|sdS |                                	                                }|dk    r#t          ||                                          }|dk    r&t          ||                                          rdS dS ||v rdS ||v rdS dS dS )a  
    Determine if a SQL statement is read-only.

    Args:
        sql: The SQL statement to analyze.
        extra_readonly: Additional keywords to treat as read-only (dialect-specific).
        extra_write: Additional keywords to treat as write operations (dialect-specific).

    Returns:
        True: Statement is definitely read-only (safe to auto-approve).
        False: Statement is definitely a write operation.
        None: Unknown or ambiguous (caller should prompt user).

    Notes:
        - Multiple statements (semicolon-separated) return None.
        - CTEs (WITH ... AS) are handled by analyzing the main statement.
        - Side-effect functions (e.g., SQLite's writefile) are NOT detected.
    Nr   WITHr   FT)r1   r   _READONLY_KEYWORDS_WRITE_KEYWORDSrA   r9   rB   r6   rC   rD   rI   r7   rM   )	r   rN   rO   r,   readonly_keywordswrite_keywordsr2   r8   rH   s	            r   is_readonly_sqlrX      s*   0  $$ t S!!H*^;${2N
C
H

x--#h--""8S11 	4WWYY__<<Haeegg..C>>!(AEEGG44 u4"""45t4r   )r   r   r   r   )r   r   r   r   )r   r   r2   r3   r   r3   )r   r   r2   r3   r   r   )r   r   rN   rP   rO   rP   r   rQ   )__doc__
__future__r   recompileVERBOSEDOTALLr   r5   rB   	frozensetrT   rU   r   r1   r9   rI   rM   rX   r#   r   r   <module>r`      sS   
 # " " " " " 				 "* J
 
 !bj(( 2:o.. YHHHII )   ") ) ) )
   @! ! ! !' ' ' 'T   2 &/Y[["+)++	7 7 7 7 7 7 7 7r   