Alejandro Alejandro - 1 month ago 19
MySQL Question

pyodbc.Error: ('HY000', 'The driver did not supply an error!')

I have two Mysql connection via pyodbc declared as:

connMy1 = pyodbc.connect('DRIVER={MySQL ODBC 5.3 Unicode Driver};SERVER=***;UID=***;PWD=***')
connMy1.autocommit = True
cursorMy1 = connMy1.cursor()

connMy2 = pyodbc.connect('DRIVER={MySQL ODBC 5.3 Unicode Driver};SERVER=***;UID=***;PWD=***')
connMy2.autocommit = True
cursorMy2 = connMy2.cursor()


I create a CSV with pandas caling the connection like this:

def bajar(sql,tabla,ruta):
print ("bajando datos")
chunk = 10 ** 5
chunks = pandas.read_sql(sql, connMy1, chunksize=chunk)
eliminarArchivo(ruta)
print ("creando CSV")
with open(ruta, 'w') as output:
for n, df in enumerate(chunks):
write_header = n == 0
df.to_csv(output, sep=';', index=False, header=False, na_rep='NULL')
connMy1.commit()


Then I call this function to upload the CSV

def subir(ruta,tabla):
print ("Subiendo datos")
sqlMy2 = "load data local infile '"+ruta+"' into table "+tabla+" fields terminated by ';' lines terminated by '\r\n';"
print (sqlMy2)
cursorMy2.execute(sqlMy2)
connMy2.commit()


If I call the second function first (with a pre created CSV by the first function) it uploads the data perfectly, if I call the function after the first I get:
pyodbc.Error: ('HY000', 'The driver did not supply an error!')

Any hints of what Im doing wrong?
Thank you!

Answer

It might be that the connection created by the first function is still active after you call it. You are not closing that connection so the cursor will still be active.

You don't need two connections. You should ideally open the connection, perform the action, then close the connection.

Try something like this:

def bajar(sql,tabla,ruta):
    connMy1 = pyodbc.connect('DRIVER={MySQL ODBC 5.3 Unicode Driver};SERVER=***;UID=***;PWD=***')
    connMy1.autocommit = True
    cursorMy1 = connMy1.cursor()
    print ("bajando datos")
    chunk = 10 ** 5 
    chunks = pandas.read_sql(sql, connMy1, chunksize=chunk)
    eliminarArchivo(ruta)
    print ("creando CSV")
    with open(ruta, 'w') as output:
        for n, df in enumerate(chunks):
            write_header = n == 0
            df.to_csv(output, sep=';', index=False, header=False, na_rep='NULL')
    connMy1.commit()  
    connMy1.close()

def subir(ruta,tabla):
    connMy1 = pyodbc.connect('DRIVER={MySQL ODBC 5.3 Unicode Driver};SERVER=***;UID=***;PWD=***')
    connMy1.autocommit = True
    cursorMy1 = connMy1.cursor()
    print ("Subiendo datos")
    sqlMy2 = "load data local infile '"+ruta+"' into table "+tabla+" fields terminated by ';' lines terminated by '\r\n';"
    print (sqlMy2)
    cursorMy1.execute(sqlMy2)
    connMy1.commit()
    connMy1.close()

This still isn't ideal and I would recommend creating a class to handle your SQL connections. Something like this would be better:

class MySQL:
    def __init__(self):
        self.conn = None

    def __enter__(self):
        self.conn = pyodbc.connect('DRIVER={MySQL ODBC 5.3 Unicode Driver};SERVER=***;UID=***;PWD=***')
        self.conn.autocommit = True

    def __exit__(self, *args):
        if self.conn:
            self.conn.close()
            self.conn = None

Which you could then call like this:

def bajar(sql,tabla,ruta):
    mysql = MySQL()
    with mysql:
        print ("bajando datos")
        chunk = 10 ** 5 
        chunks = pandas.read_sql(sql, mysql.conn, chunksize=chunk)
        eliminarArchivo(ruta)
        print ("creando CSV")
        with open(ruta, 'w') as output:
            for n, df in enumerate(chunks):
                write_header = n == 0
                df.to_csv(output, sep=';', index=False, header=False, na_rep='NULL')
        mysql.conn.commit()


def subir(ruta,tabla):
    mysql = MySQL()
    with mysql:
        print ("Subiendo datos")
        sqlMy2 = "load data local infile '"+ruta+"' into table "+tabla+" fields terminated by ';' lines terminated by '\r\n';"
        print (sqlMy2)
        mysql.conn.cursor().execute(sqlMy2)
        mysql.conn.commit()

This way, as long as you always use the 'with' statement, you will always connect and disconnect for each action.