2

I am trying to write data to a SQL Server 2016 Express database from an Ubuntu 16.04 virtual machine using python. The connection is to be set up via FreeTDS, UnixODBC, pyodbc.

The program gets a string of sensor data over a TCP socket, formats it and writes it to a (new or existing) table. This have to happen every x seconds. Therefor I used this answer.

The code evinces a strange behavior and I tried and searched for hours. It sometimes work and sometimes not. I think the problem is to do with connection = pyodbc.connect(conn_str), because often the code is successfully executed once and then gets stuck at this line. After some minutes an Error appears:

connection = pyodbc.connect(conn_str)
Error: ('08S01', '[08S01] [unixODBC][FreeTDS][SQL Server]Unable to connect: Adaptive Server is unavailable or does not exist (20009) (SQLDriverConnect)')

Maybe the problem correlates with an open connection but it should be closed at the end of the script. Do you have a solution? How can I catch such errors with a try/except funktion? Please ask if I should provide more information.

Thank you in advance for your help!

This is the code:

import sys
import pyodbc
import socket
import re
from threading import Timer
import time

# Timer (see link above)
class InfiniteTimer():

def pi_to_sql():
    dsn = "sqlserverdatasource"
    user = "User"
    password = "Password"
    database = "MSSQL_DB"

    conn_str = "DSN=%s;UID=%s;PWD=%s;DATABASE=%s;" % (dsn, user, password, database)
    connection = pyodbc.connect(conn_str)
    cursor = connection.cursor()

    # Create TCP/IP socket (client)
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # Create connection with socket server (insert IP of server)
    server_address = ('XXX.XXX.XXX.XXX', 10000)
    sock.connect(server_address)

    # Sending order to server
    to_send = "send data"
    sock.sendall(to_send)

    # Receiving data (string, e.g. "DS18B20;28FF97FF841605C0;32.4375")
    data = sock.recv(1024)

    # Filter data using regex
    data_list = re.findall(r"(?P<name>\w{6,});(?P<address>[0-9A-F]{16,});(?P<value>-?\d+\.?\d+)",data,re.M)

    # Closing socket
    sock.close()

    sensor_cnt = len(data_list)

    i = 0

    # Write sensor data to new or existing table using a loop
    while i<=(sensor_cnt-1):
        s_address = data_list[i][1]
        s_value = data_list[i][2]
        act_datetime = time.strftime("%Y%m%d %H:%M:%S")
        table_name = "sensor_" + s_address

        sql_command = """IF (NOT EXISTS (SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'dbo'
AND  TABLE_NAME = '{0:s}'))
BEGIN
CREATE TABLE dbo.{0:s}
(
Timestamp DATETIME2(0),
S_Value FLOAT
)
END
INSERT INTO dbo.{0:s} VALUES
(
'{1:s}','{2:s}'
)""".format(table_name,act_datetime,s_value)

        try:
            cursor.execute(sql_command)
            connection.commit()

        except pyodbc.ProgrammingError:
            print("error")
            connection.close()

        i = i+1

    cursor.close()
    connection.close()

    print("done")

# Calling timer class to execute code every 5s
t = InfiniteTimer(5, pi_to_sql)
t.start()

tsql -C (I used the latest stable .tar.gz from FreeTDS)

Compile-time settings (established with the "configure" script)
                        Version: freetds v1.00.27
         freetds.conf directory: /usr/local/etc
 MS db-lib source compatibility: no
    Sybase binary compatibility: no
                  Thread safety: yes
                  iconv library: yes
                    TDS version: 7.4
                          iODBC: no
                       unixodbc: yes
          SSPI "trusted" logins: no
                       Kerberos: no
                        OpenSSL: no
                         GnuTLS: no
                           MARS: no

/etc/odbc.ini

[sqlserverdatasource]
driver = /usr/local/lib/libtdsodbc.so
server = XXX.XXX.XXX.XXX
port = 61521
database = MSSQL_DB
tds_version = 7.4

isql -v sqlserverdatasource User Password

+---------------------------------------+
| Connected!                            |
|                                       |
| sql-statement                         |
| help [tablename]                      |
| quit                                  |
|                                       |
+---------------------------------------+
SQL> 
4

2 回答 2

0

This thread gave me the idea to test the code on a local server with another version (SQL Server 2014) where I have administrator rights. So I ensured that for each listed IP address, Active and Enabled are both Yes. It is working now. Unfortunately I can´t say excactly what the problem was (if it is up to SQL Server 16 itself or the configs or an incompatibility). I hope that this remark possibly helps somebody.

于 2017-04-13T05:17:20.777 回答
-1

Have you tried it without connection pooling?

conn_str = "DSN=%s;UID=%s;PWD=%s;DATABASE=%s;" % (dsn, user, password, database)
pyodbc.pooling = False
connection = pyodbc.connect(conn_str)
cursor = connection.cursor()

I've seen that clear up connection issues with SQL Server in the past because of this:

https://github.com/mkleehammer/pyodbc/wiki/Features-beyond-the-DB-API#connection-pooling

Good luck!

于 2017-04-05T10:08:53.170 回答