mirror of
https://github.com/hanzoai/pymssql.git
synced 2026-10-30 14:54:29 +00:00
281 lines
12 KiB
ReStructuredText
281 lines
12 KiB
ReStructuredText
==========================
|
|
Frequently asked questions
|
|
==========================
|
|
|
|
Cannot connect to SQL Server
|
|
============================
|
|
|
|
If your Python program/script can't connect to a *SQL Server* instance, try the
|
|
following:
|
|
|
|
* By default *SQL Server* 2005 and newer don't accept remote connections, you
|
|
have to use *SQL Server Surface Area Configuration* and/or *SQL Server
|
|
Configuration Manager* to enable specific protocols and network adapters;
|
|
don't forget to restart *SQL Server* after making these changes,
|
|
|
|
* If *SQL Server* is on a remote machine, check whether connections are not
|
|
blocked by any intermediate firewall device, firewall software, antivirus
|
|
software, or other security facility,
|
|
|
|
* Check that you can connect with another tool.
|
|
|
|
If you are using `FreeTDS <http://www.freetds.org/>`_, then you can use the
|
|
included ``tsql`` command to try to connect -- it looks like this::
|
|
|
|
$ tsql -H sqlserverhost -p 1433 -U user -P password -D tempdb
|
|
locale is "en_US.UTF-8"
|
|
locale charset is "UTF-8"
|
|
using default charset "UTF-8"
|
|
Setting tempdb as default database in login packet
|
|
1> SELECT @@VERSION
|
|
2> GO
|
|
|
|
Microsoft SQL Server 2012 - 11.0.2100.60 (X64)
|
|
Feb 10 2012 19:39:15
|
|
Copyright (c) Microsoft Corporation
|
|
Developer Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1)
|
|
|
|
(1 row affected)
|
|
|
|
.. note::
|
|
Note that I use the ``-H`` option rather than the ``-S`` option to
|
|
``tsql``. This is because with ``-H``, it will bypass reading settings
|
|
from the ``freetds.conf`` file like ``port`` and ``tds version``, and
|
|
so this is more similar to what happens with pymssql.
|
|
|
|
If you **can't** connect with ``tsql`` or other tools, then the problem is
|
|
probably not pymssql; you probably have a problem with your server
|
|
configuration (see below), :doc:`FreeTDS Configuration </freetds>`,
|
|
network, etc.
|
|
|
|
If you **can** connect with ``tsql``, then you should be able to connect
|
|
with pymssql with something like this::
|
|
|
|
>>> import pymssql
|
|
>>> conn = pymssql.connect(
|
|
... server="sqlserverhost",
|
|
... port=1433,
|
|
... user="user",
|
|
... password="password",
|
|
... database="tempdb")
|
|
>>> conn
|
|
<pymssql.Connection object at 0x10107a3f8>
|
|
>>> cursor = conn.cursor()
|
|
>>> cursor.execute("SELECT @@VERSION")
|
|
>>> print(cursor.fetchone()[0])
|
|
Microsoft SQL Server 2012 - 11.0.2100.60 (X64)
|
|
Feb 10 2012 19:39:15
|
|
Copyright (c) Microsoft Corporation
|
|
Developer Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1)
|
|
|
|
If something like the above doesn't work, then you can try to diagnose by
|
|
setting one or both of the following `FreeTDS environment variables that control logging <http://www.freetds.org/userguide/logging.htm>`_:
|
|
|
|
* ``TDSDUMP``
|
|
* ``TDSDUMPCONFIG``
|
|
|
|
Either or both of these can be set. They can be set to a filename or to
|
|
``stdout`` or ``stderr``.
|
|
|
|
These will cause FreeTDS to output a ton of information about what it's doing
|
|
and you may very well spot that it's not using the port that you expected or
|
|
something similar. For example::
|
|
|
|
>>> import os
|
|
>>> os.environ['TDSDUMP'] = 'stdout'
|
|
>>>
|
|
>>> import pymssql
|
|
>>> conn = pymssql.connect(server="sqlserverhost")
|
|
log.c:194:Starting log file for FreeTDS 0.92.dev.20140102
|
|
on 2014-01-09 14:05:32 with debug flags 0x4fff.
|
|
config.c:731:Setting 'dump_file' to 'stdout' from $TDSDUMP.
|
|
...
|
|
dblib.c:7934:20013: "Unknown host machine name"
|
|
dblib.c:7955:"Unknown host machine name", client returns 2 (INT_CANCEL)
|
|
util.c:347:tdserror: client library returned TDS_INT_CANCEL(2)
|
|
util.c:370:tdserror: returning TDS_INT_CANCEL(2)
|
|
login.c:418:IP address pointer is empty
|
|
login.c:420:Server sqlserverhost:1433 not found!
|
|
...
|
|
|
|
.. note::
|
|
Note that pymssql will use a default port of 1433, despite any ports
|
|
you may have specified in your ``freetds.conf`` file. So if you have
|
|
SQL Server running on a port other than 1433, you must explicitly
|
|
specify the ``port`` in your call to ``pymssql.connect``. You cannot
|
|
rely on it to pick up the port in your ``freetds.conf``, even though
|
|
``tsql -S`` might do this. This is why I recommend using ``tsql -H``
|
|
instead for diagnosing connection problems.
|
|
|
|
It is also useful to know that ``tsql -C`` will output a lot of information
|
|
about FreeTDS, that can be useful for diagnosing problems::
|
|
|
|
$ tsql -C
|
|
Compile-time settings (established with the "configure" script)
|
|
Version: freetds v0.92.dev.20140102
|
|
freetds.conf directory: /usr/local/etc
|
|
MS db-lib source compatibility: no
|
|
Sybase binary compatibility: no
|
|
Thread safety: yes
|
|
iconv library: yes
|
|
TDS version: 5.0
|
|
iODBC: yes
|
|
unixodbc: no
|
|
SSPI "trusted" logins: no
|
|
Kerberos: no
|
|
OpenSSL: no
|
|
GnuTLS: no
|
|
|
|
* If you use pymssql on Linux/Unix with FreeTDS, check that FreeTDS's
|
|
configuration is ok and that it can be found by pymssql. The easiest way is to
|
|
test connection using ``tsql`` utility which can be found in FreeTDS package.
|
|
See :doc:`FreeTDS Configuration </freetds>` for more info,
|
|
|
|
Returned dates are not correct
|
|
==============================
|
|
|
|
If you use pymssql on Linux/\*nix and you suspect that returned dates are not
|
|
correct, please read the :doc:`FreeTDS and dates <freetds_and_dates>` page.
|
|
|
|
pymssql does not unserialize ``DATE`` and ``TIME`` columns to ``datetime.date`` and ``datetime.time`` instances
|
|
===============================================================================================================
|
|
|
|
You may notice that pymssql will unserialize a ``DATETIME`` column to a
|
|
:class:`python:datetime.datetime` instance, but it will unserialize ``DATE``
|
|
and ``TIME`` columns as simple strings. For example::
|
|
|
|
>>> cursor.execute("""
|
|
... CREATE TABLE dates_and_times (
|
|
... datetime DATETIME,
|
|
... date DATE,
|
|
... time TIME,
|
|
... )
|
|
... """)
|
|
>>> cursor.execute("INSERT INTO dates_and_times VALUES (GETDATE(), '20140109', '6:17')")
|
|
>>> cursor.execute("SELECT * FROM dates_and_times")
|
|
>>> cursor.fetchall()
|
|
[{u'date': u'2014-01-09', u'time': u'06:17:00.0000000',
|
|
u'datetime': datetime.datetime(2014, 1, 9, 12, 41, 59, 403000)}]
|
|
>>> cursor.execute("DROP TABLE dates_and_times")
|
|
|
|
Yep, so the problem here is that ``DATETIME`` has been supported by `FreeTDS
|
|
<http://www.freetds.org/>`_ for a long time, but ``DATE`` and ``TIME`` are
|
|
newer types in SQL Server, Microsoft never added support for them to db-lib
|
|
and FreeTDS added support for them in version 0.95.
|
|
|
|
If you need support for these data types (i.e. they get returned from the
|
|
database as their native corresponding Python data types instead of as strings)
|
|
as well as for the ``DATETIME2`` one, then make sure the following conditions
|
|
are met:
|
|
|
|
* You are connecting to SQL Server 2008 or newer.
|
|
* You are using FreeTDS 0.95 or newer.
|
|
* You are using TDS protocol version 7.3 or newer.
|
|
|
|
Shared object "libsybdb.so.3" not found
|
|
=======================================
|
|
|
|
On Linux/\*nix you may encounter the following behaviour::
|
|
|
|
>>> from pymssql import _mssql
|
|
Traceback (most recent call last):
|
|
File "<stdin>", line 1, in ?
|
|
ImportError: Shared object "libsybdb.so.3" not found
|
|
|
|
It may mean that the FreeTDS library is unavailable, or that the dynamic linker is
|
|
unable to find it. Check that it is installed and that the path to ``libsybdb.so``
|
|
is in ``/etc/ld.so.conf`` file. Then do ``ldconfig`` as root to refresh linker
|
|
database. On Solaris, I just set the ``LD_LIBRARY_PATH`` environment variable to
|
|
the directory with the library just before launching Python.
|
|
|
|
pymssql 2.x bundles the FreeTDS ``sybdb`` library for supported platforms. This
|
|
error may show up in 2.x versions if you are trying to build with your own
|
|
FreeTDS.
|
|
|
|
"DB-Lib error message 20004, severity 9: Read from SQL server failed" error appears
|
|
===================================================================================
|
|
|
|
On Linux/\*nix you may encounter the following behaviour::
|
|
|
|
>>> from pymssql import _mssql
|
|
>>> c=_mssql.connect('hostname:portnumber','user','pass')
|
|
Traceback (most recent call last):
|
|
File "<stdin>", line 1, in <module>
|
|
_mssql.DatabaseException: DB-Lib error message 20004, severity 9:
|
|
Read from SQL server failed.
|
|
DB-Lib error message 20014, severity 9:
|
|
Login incorrect.
|
|
|
|
It may happen when one of the following is true:
|
|
|
|
* ``freetds.conf`` file cannot be found,
|
|
* ``tds version`` in ``freetds.conf`` file is not ``7.0`` or ``4.2``,
|
|
* any character set is specified in ``freetds.conf``,
|
|
* an unrecognized character set is passed to :func:`_mssql.connect()` or
|
|
:func:`pymssql.connect()` method.
|
|
|
|
``"Login incorrect"`` following this error is spurious, real ``"Login
|
|
incorrect"`` messages has code=18456 and severity=14.
|
|
|
|
Unable to use long username and password
|
|
========================================
|
|
|
|
This is a solved FreeTDS problem but you need to be using FreeTDS 0.95 or newer,
|
|
if you are stuck with 0.91 then keep in mind this limitation, even when you can
|
|
get usernames, passwords longer than 30 to work on tsql.
|
|
|
|
Error in stored procedure does not throw Python exception
|
|
=========================================================
|
|
|
|
Consider the stored procedure::
|
|
|
|
CREATE PROCEDURE my_sp
|
|
AS
|
|
BEGIN
|
|
SET NOCOUNT ON;
|
|
SELECT 1;
|
|
SELECT 1/0;
|
|
END
|
|
|
|
If we run that in SSMS with ``EXEC my_sp`` we see the following in the Messages tab::
|
|
|
|
Msg 8134, Level 16, State 1, Procedure my_sp, Line 6 [Batch Start Line 0]
|
|
Divide by zero error encountered.
|
|
|
|
However, if we do the same thing in Python we don't get an exception::
|
|
|
|
>>> import pymssql
|
|
>>> cnxn = pymssql.connect("192.168.0.199", "scott", "tiger^5HHH", "test")
|
|
>>> crsr = cnxn.cursor()
|
|
>>> crsr.execute("EXEC my_sp")
|
|
>>>
|
|
|
|
That's because when a stored procedure (or anonymous code block) returns multiple result sets, the first result set (from SELECT 1) is automatically made available for us to process, e.g., by using ``crsr.fetchall()``::
|
|
|
|
>>> crsr.fetchall()
|
|
[(1,)]
|
|
>>>
|
|
|
|
but the second result set is queued until we call ``crsr.nextset()``. If that result contains an error code then a pymssql exception is thrown::
|
|
|
|
>>> crsr.nextset()
|
|
Traceback (most recent call last):
|
|
File "src\\pymssql\\_pymssql.pyx", line 494, in pymssql._pymssql.Cursor.nextset
|
|
File "src\\pymssql\\_mssql.pyx", line 1461, in pymssql._mssql.MSSQLConnection.nextresult
|
|
File "src\\pymssql\\_mssql.pyx", line 1343, in pymssql._mssql.MSSQLConnection.get_result
|
|
File "src\\pymssql\\_mssql.pyx", line 1817, in pymssql._mssql.check_cancel_and_raise
|
|
File "src\\pymssql\\_mssql.pyx", line 1844, in pymssql._mssql.maybe_raise_MSSQLDatabaseException
|
|
File "src\\pymssql\\_mssql.pyx", line 1861, in pymssql._mssql.raise_MSSQLDatabaseException
|
|
pymssql._mssql.MSSQLDatabaseException: (8134, b'Divide by zero error encountered.DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')
|
|
|
|
So, if your stored procedure is going to return multiple result sets you need to make sure that you call ``.nextset()`` enough times to process them all.
|
|
|
|
More troubleshooting
|
|
====================
|
|
|
|
If the above hasn't covered the problem you can send a message describing it to
|
|
the pymssql mailing list. You can also consult FreeTDS troubleshooting `page for
|
|
issues related to the TDS protocol`_.
|
|
|
|
.. _page for issues related to the TDS protocol: https://www.freetds.org/userguide/troubleshooting.html
|