o
    ;Dia`                     @   s|  d dl mZmZmZ d dlZd dlmZmZm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mZmZ d dlmZmZ eeZejZejZdd	 ZG d
d deZdd Z dd Z!dd Z"dd Z#dd Z$dd Z%			d1ddZ&e&e_&d2ddZ'dZ(d Z)		d2d!d"Z*		d2d#d$Z+		d2d%d&Z,		d2d'd(Z-		d2d)d*Z.		d2d+d,Z/		d2d-d.Z0d3d/d0Z1e1e_1dS )4    )absolute_importprint_functiondivisionN)next	text_typestring_types)ArgumentError)Table)_is_dbapi_connection_is_dbapi_cursor_is_sqlalchemy_connection_is_sqlalchemy_engine_is_sqlalchemy_session_is_clikchouse_dbapi_connection_quote_placeholders)
drop_tablecreate_tablec                 O   s4   t | trddl}|| } t| |g|R i |S )a	  Provides access to data from any DB-API 2.0 connection via a given query.
    E.g., using :mod:`sqlite3`::

        >>> import petl as etl
        >>> import sqlite3
        >>> connection = sqlite3.connect('example.db')
        >>> table = etl.fromdb(connection, 'SELECT * FROM example')

    E.g., using :mod:`psycopg2` (assuming you've installed it first)::

        >>> import petl as etl
        >>> import psycopg2
        >>> connection = psycopg2.connect('dbname=example user=postgres')
        >>> table = etl.fromdb(connection, 'SELECT * FROM example')

    E.g., using :mod:`pymysql` (assuming you've installed it first)::

        >>> import petl as etl
        >>> import pymysql
        >>> connection = pymysql.connect(password='moonpie', database='thangs')
        >>> table = etl.fromdb(connection, 'SELECT * FROM example')

    The `dbo` argument may also be a function that creates a cursor. N.B., each
    call to the function should return a new cursor. E.g.::

        >>> import petl as etl
        >>> import psycopg2
        >>> connection = psycopg2.connect('dbname=example user=postgres')
        >>> mkcursor = lambda: connection.cursor(cursor_factory=psycopg2.extras.DictCursor)
        >>> table = etl.fromdb(mkcursor, 'SELECT * FROM example')

    The parameter `dbo` may also be an SQLAlchemy engine, session or
    connection object.

    The parameter `dbo` may also be a string, in which case it is interpreted as
    the name of a file containing an :mod:`sqlite3` database.

    Note that the default behaviour of most database servers and clients is for
    the entire result set for each query to be sent from the server to the
    client. If your query returns a large result set this can result in
    significant memory usage at the client. Some databases support server-side
    cursors which provide a means for client libraries to fetch result sets
    incrementally, reducing memory usage at the client.

    To use a server-side cursor with a PostgreSQL database, e.g.::

        >>> import petl as etl
        >>> import psycopg2
        >>> connection = psycopg2.connect('dbname=example user=postgres')
        >>> table = etl.fromdb(lambda: connection.cursor(name='arbitrary'),
        ...                    'SELECT * FROM example')

    For more information on server-side cursors see the following links:

        * http://initd.org/psycopg/docs/usage.html#server-side-cursors
        * http://mysql-python.sourceforge.net/MySQLdb.html#using-and-extending

    r   N)
isinstancer   sqlite3connectDbView)dboqueryargskwargsr    r   C/var/www/Datamplify/venv/lib/python3.10/site-packages/petl/io/db.pyfromdb   s   
=
r   c                   @   s   e Zd Zdd Zdd ZdS )r   c                 O   s   || _ || _|| _|| _d S N)r   r   r   r   )selfr   r   r   r   r   r   r   __init__^   s   
zDbView.__init__c                 C   s   t | jrtd| j t}nOt| jrtd td t}n?t| jr,td| j t}n1t	| jr:td| j t
}n#t| jrHtd| j t}nt| jrVtd| j t}ntd| j || j| jg| jR i | jS )	N-assuming %r is standard DB-API 2.0 connection)assuming %r is standard DB-API 2.0 cursorzxusing a DB-API cursor with fromdb() is not recommended and may lead to unexpected results, a DB-API connection is better5assuming %r instance of sqlalchemy.engine.base.Engine6assuming %r instance of sqlalchemy.orm.session.Session9assuming %r instance of sqlalchemy.engine.base.Connectionz,assuming %r is a function returning a cursor$unsupported database object type: %r)r
   r   debug_iter_dbapi_connectionr   warning_iter_dbapi_cursorr   _iter_sqlalchemy_enginer   _iter_sqlalchemy_sessionr   _iter_sqlalchemy_connectioncallable_iter_dbapi_mkcursr   r   r   r   )r    _iterr   r   r   __iter__d   s6   





 zDbView.__iter__N)__name__
__module____qualname__r!   r2   r   r   r   r   r   \   s    r   c                 o   sF    |  }zt ||g|R i |D ]}|V  qW |  d S |  w r   )r+   close)mkcursr   r   r   cursorrowr   r   r   r0      s   r0   c                 o   sH    |   }zt||g|R i |D ]}|V  qW |  d S |  w r   )r8   r+   r6   )
connectionr   r   r   r8   r9   r   r   r   r)      s   r)   c                 o   s    | j |g|R i | zt| }W n ty"   t|  }Y nw zt|}W n ty4   d }Y nw dd | jD }t|V  |d u rHd S |V  |D ]}|V  qMd S )Nc                 S   s   g | ]}|d  qS )r   r   ).0dr   r   r   
<listcomp>       z&_iter_dbapi_cursor.<locals>.<listcomp>)executeiter	TypeErrorfetchallr   StopIterationdescriptiontuple)r8   r   r   r   it	first_rowhdrr9   r   r   r   r+      s(   
r+   c                 o   s:    |   }t||g|R i |D ]}|V  q|  d S r   )r   r.   r6   )enginer   r   r   r:   r9   r   r   r   r,      s
   r,   c                 o   sJ    t d|  | j|g|R i |}| }t|V  |D ]}|V  qd S )Nconnection: %r)r(   r?   keysrE   )r:   r   r   r   resultsrH   r9   r   r   r   r.      s   

r.   c                 o   s@    | j |g|R i |}| }t|V  |D ]}|V  qd S r   )r?   rK   rE   )sessionr   r   r   rL   rH   r9   r   r   r   r-      s   
r-   TF  c                 C   s   d}t |trddl}||}d}z.|r,|rt||||d t| |||||||	|
d	 t| ||||dd W |r?|  dS dS |rH|  w w )a  
    Load data into an existing database table via a DB-API 2.0
    connection or cursor. Note that the database table will be truncated,
    i.e., all existing rows will be deleted prior to inserting the new data.
    E.g.::

        >>> import petl as etl
        >>> table = [['foo', 'bar'],
        ...          ['a', 1],
        ...          ['b', 2],
        ...          ['c', 2]]
        >>> # using sqlite3
        ... import sqlite3
        >>> connection = sqlite3.connect('example.db')
        >>> # assuming table "foobar" already exists in the database
        ... etl.todb(table, connection, 'foobar')
        >>> # using psycopg2
        >>> import psycopg2
        >>> connection = psycopg2.connect('dbname=example user=postgres')
        >>> # assuming table "foobar" already exists in the database
        ... etl.todb(table, connection, 'foobar')
        >>> # using pymysql
        >>> import pymysql
        >>> connection = pymysql.connect(password='moonpie', database='thangs')
        >>> # tell MySQL to use standard quote character
        ... connection.cursor().execute('SET SQL_MODE=ANSI_QUOTES')
        >>> # load data, assuming table "foobar" already exists in the database
        ... etl.todb(table, connection, 'foobar')

    N.B., for MySQL the statement ``SET SQL_MODE=ANSI_QUOTES`` is required to
    ensure MySQL uses SQL-92 standard quote characters.

    A cursor can also be provided instead of a connection, e.g.::

        >>> import psycopg2
        >>> connection = psycopg2.connect('dbname=example user=postgres')
        >>> cursor = connection.cursor()
        >>> etl.todb(table, cursor, 'foobar')

    The parameter `dbo` may also be an SQLAlchemy engine, session or
    connection object.

    The parameter `dbo` may also be a string, in which case it is interpreted
    as the name of a file containing an :mod:`sqlite3` database.

    If ``create=True`` this function will attempt to automatically create a
    database table before loading the data. This functionality requires
    `SQLAlchemy <http://www.sqlalchemy.org/>`_ to be installed.

    **Keyword arguments:**

    table : table container
        Table data to load
    dbo : database object
        DB-API 2.0 connection, callable returning a DB-API 2.0 cursor, or
        SQLAlchemy connection, engine or session
    tablename : string
        Name of the table in the database
    schema : string
        Name of the database schema to find the table in
    commit : bool
        If True commit the changes
    create : bool
        If True attempt to create the table before loading, inferring types
        from a sample of the data (requires SQLAlchemy)
    drop : bool
        If True attempt to drop the table before recreating (only relevant if
        create=True)
    constraints : bool
        If True use length and nullable constraints (only relevant if
        create=True)
    metadata : sqlalchemy.MetaData
        Custom table metadata (only relevant if create=True)
    dialect : string
        One of {'access', 'sybase', 'sqlite', 'informix', 'firebird', 'mysql',
        'oracle', 'maxdb', 'postgresql', 'mssql'} (only relevant if
        create=True)
    sample : int
        Number of rows to sample when inferring types etc. Set to 0 to use the
        whole table (only relevant if create=True)

    .. note::

        This function is in principle compatible with any DB-API 2.0
        compliant database driver. However, at the time of writing some DB-API
        2.0 implementations, including cx_Oracle and MySQL's
        Connector/Python, are not compatible with this function, because they
        only accept a list argument to the cursor.executemany() function
        called internally by :mod:`petl`. This can be worked around by
        proxying the cursor objects, e.g.::

            >>> import cx_Oracle
            >>> connection = cx_Oracle.Connection(...)
            >>> class CursorProxy(object):
            ...     def __init__(self, cursor):
            ...         self._cursor = cursor
            ...     def executemany(self, statement, parameters, **kwargs):
            ...         # convert parameters to a list
            ...         parameters = list(parameters)
            ...         # pass through to proxied cursor
            ...         return self._cursor.executemany(statement, parameters, **kwargs)
            ...     def __getattr__(self, item):
            ...         return getattr(self._cursor, item)
            ...
            >>> def get_cursor():
            ...     return CursorProxy(connection.cursor())
            ...
            >>> import petl as etl
            >>> etl.todb(tbl, get_cursor, ...)

        Note however that this does imply loading the entire table into
        memory as a list prior to inserting into the database.

    Fr   NT)schemacommit)rO   rP   constraintsmetadatadialectsamplerO   rP   truncate)r   r   r   r   r   r   _todbr6   )tabler   	tablenamerO   rP   createdroprQ   rR   rS   rT   needs_closingr   r   r   r   todb   s*   v


r]   c                 C   s0  t |rtd| t| |||||d d S t|r*td| t| |||||d d S t|r>td t| |||||d d S t|rStd| t| |||||d d S t	|rhtd| t
| |||||d d S t|r}td| t| |||||d d S t|rtd| t| |||||d d S td	| )
Nz/assuming %r is clickhosue DB-API 2.0 connectionrU   r"   r#   r$   r%   r&   zFassuming %r is a function returning standard DB-API 2.0 cursor objectsr'   )r   r(   !_todb_clikchouse_dbapi_connectionr
   _todb_dbapi_connectionr   _todb_dbapi_cursorr   _todb_sqlalchemy_enginer   _todb_sqlalchemy_sessionr   _todb_sqlalchemy_connectionr/   _todb_dbapi_mkcursr   )rX   r   rY   rO   rP   rV   r   r   r   rW   a  sL   
















rW   zDELETE FROM %szINSERT INTO %s (%s) VALUES (%s)c                 C   s  t |}|d urt |d | }td| t| }t|}ttt|}dd |D }	td|	 t||	}
td|
 | }|rVt	| }td| |
| |  | }d|	}t|||
f }td	|  ||| td
 |  |rtd |  d S d S )N.tablename: %rc                 S      g | ]}t |qS r   r   r;   nr   r   r   r=     r>   z*_todb_dbapi_connection.<locals>.<listcomp>column names: %rplaceholders: %rtruncate the table via query %r, insert data via query %rclose the cursorcommit transaction)r   r(   r@   r   listmapr   r   r8   SQL_TRUNCATE_QUERYr?   r6   joinSQL_INSERT_QUERYexecutemanyrP   rX   r:   rY   rO   rP   rV   rF   rH   fldscolnamesplaceholdersr8   truncatequeryinsertcolnamesinsertqueryr   r   r   r_     s8   






r_   c                 C   s  t |}|d urt |d | }td| t| }t|}ttt|}dd |D }	td|	 t||	}
td|
 | }|rVd| }td| |	| |
  | }d	|	}d
||f }td|  ||| td |
  |rtd |  d S d S )Nre   rf   c                 S   rg   r   rh   ri   r   r   r   r=     r>   z5_todb_clikchouse_dbapi_connection.<locals>.<listcomp>rk   rl   zTRUNCATE TABLE IF EXISTS %srm   rn   zINSERT INTO %s (%s) VALUESro   rp   rq   )r   r(   r@   r   rr   rs   r   r   r8   r?   r6   ru   rw   rP   rx   r   r   r   r^     s8   






r^   c                 C   s  t |}|d urt |d | }td| t| }t|}ttt|}dd |D }	td|	 td | }
t|
ds@J d|
j}t	||	}td	| |rdt
| }td
| |
| |
  | }
d|	}t|||f }td|  |
|| |
  |rtd |  d S d S )Nre   rf   c                 S   rg   r   rh   ri   r   r   r   r=     r>   z&_todb_dbapi_mkcurs.<locals>.<listcomp>rk   zobtain cursor and connectionr:   &could not obtain connection via cursorrl   rm   rn   ro   rq   )r   r(   r@   r   rr   rs   r   hasattrr:   r   rt   r?   r6   ru   rv   rw   rP   )rX   r7   rY   rO   rP   rV   rF   rH   ry   rz   r8   r:   r{   r|   r}   r~   r   r   r   rd     s@   






rd   c                 C   s   t |}|d urt |d | }td| t| }t|}ttt|}dd |D }	td|	 td t|ds=J d|j}
t	|
|	}td	| |rZt
| }td
| || d|	}t|||f }td|  ||| |r~td |
  d S d S )Nre   rf   c                 S   rg   r   rh   ri   r   r   r   r=   3  r>   z&_todb_dbapi_cursor.<locals>.<listcomp>rk   zobtain connection via cursorr:   r   rl   rm   rn   ro   rq   )r   r(   r@   r   rr   rs   r   r   r:   r   rt   r?   ru   rv   rw   rP   )rX   r8   rY   rO   rP   rV   rF   rH   ry   rz   r:   r{   r|   r}   r~   r   r   r   r`   &  s8   






r`   c                 C      t | | ||||d d S NrU   )rc   r   )rX   rI   rY   rO   rP   rV   r   r   r   ra   S  s   
ra   c                 C   s  t d| t|}|d urt|d | }t d| t| }t|}ttt|}dd |D }	t d|	 |j}
|
j}t||	}t d| |rOt d |	 }|r_t
| }t d	| || d
|	}t|||f }t d|  |D ]}||| qs|rt d |  d S d S )NrJ   re   rf   c                 S   rg   r   rh   ri   r   r   r   r=   i  r>   z/_todb_sqlalchemy_connection.<locals>.<listcomp>rk   rl   zbegin transactionrm   rn   ro   rq   )r(   r   r@   r   rr   rs   r   r:   r   beginrt   r?   ru   rv   rP   )rX   r:   rY   rO   rP   rV   rF   rH   ry   rz   proxied_raw_connectionactual_raw_connectionr{   transr|   r}   r~   r9   r   r   r   rc   Z  s<   







rc   c                 C   r   r   )rc   r:   )rX   rM   rY   rO   rP   rV   r   r   r   rb     s   
rb   c                 C   s`   d}t |trddl}||}d}zt| ||||dd W |r&|  dS dS |r/|  w w )a
  
    Load data into an existing database table via a DB-API 2.0
    connection or cursor. As :func:`petl.io.db.todb` except that the database
    table will be appended, i.e., the new data will be inserted into the
    table, and any existing rows will remain.

    Fr   NTrU   )r   r   r   r   rW   r6   )rX   r   rY   rO   rP   r\   r   r   r   r   appenddb  s   	


r   )NTFFTNNrN   )NTF)NT)2
__future__r   r   r   loggingpetl.compatr   r   r   petl.errorsr   petl.util.baser	   petl.io.db_utilsr
   r   r   r   r   r   r   r   petl.io.db_creater   r   	getLoggerr3   loggerr(   r*   r   r   r0   r)   r+   r,   r.   r-   r]   rW   rt   rv   r_   r^   rd   r`   ra   rc   rb   r   r   r   r   r   <module>   sd   (
D4			
 
3
/
/
0
-

5


