File: migrate_1_x_to_2_x.rst

package info (click to toggle)
pymssql 2.3.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 972 kB
  • sloc: python: 3,801; sh: 152; makefile: 151; ansic: 1
file content (167 lines) | stat: -rw-r--r-- 5,513 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
==========================
Migrating from 1.x to 2.x
==========================

Because of the DB-API standard and because effort was made to make the
interface of pymssql 2.x similar to that of pymssql 1.x, there are only a few
differences and usually upgrading is pretty easy.

There are a few differences though...

``str`` vs. ``unicode``
=======================

Note that we are talking about Python 2, because pymssql 1.x doesn't work on
Python 3.

pymssql 1.x will return ``str`` instances::

    >>> pymssql.__version__
    '1.0.3'
    >>> conn.as_dict = True
    >>> cursor = conn.cursor()
    >>> cursor.execute("SELECT 'hello' AS str FROM foo")
    >>> cursor.fetchall()
    [{0: 'hello', 'str': 'hello'}]

whereas pymssql 2.x will return ``unicode`` instances::

    >>> pymssql.__version__
    u'2.0.1.2'
    >>> conn.as_dict = True
    >>> cursor = conn.cursor()
    >>> cursor.execute("SELECT 'hello' AS str FROM foo")
    >>> cursor.fetchall()
    [{u'str': u'hello'}]

If your application has code that deals with ``str`` and ``unicode``
differently, then you may run into issues.

You can always convert a ``unicode`` to a ``str`` by encoding::

    >>> cursor.execute("SELECT 'hello' AS str FROM foo")
    >>> s = cursor.fetchone()['str']
    >>> s
    u'hello'
    >>> s.encode('utf-8')
    'hello'

Handling of ``uniqueidentifier`` columns
========================================

SQL Server has a data type called `uniqueidentifier
<http://technet.microsoft.com/en-us/library/ms187942.aspx>`_.

In pymssql 1.x, ``uniqueidentifier`` columns are returned in results as
byte strings with 16 bytes; if you want a :class:`python:uuid.UUID` instance,
then you have to construct it yourself from the byte string::

    >>> cursor.execute("SELECT * FROM foo")
    >>> id_value = cursor.fetchone()['uniqueidentifier']
    >>> id_value
    'j!\xcf\x14D\xce\xe6B\xab\xe0\xd9\xbey\x0cMK'
    >>> type(id_value)
    <type 'str'>
    >>> len(id_value)
    16
    >>> import uuid
    >>> id_uuid = uuid.UUID(bytes_le=id_value)
    >>> id_uuid
    UUID('14cf216a-ce44-42e6-abe0-d9be790c4d4b')

In pymssql 2.x, ``uniqueidentifier`` columns are returned in results as
instances of :class:`python:uuid.UUID` and if you want the bytes, like in
pymssql 1.x, you have to use :attr:`python:uuid.UUID.bytes_le` to get them::

    >>> cursor.execute("SELECT * FROM foo")
    >>> id_value = cursor.fetchone()['uniqueidentifier']
    >>> id_value
    UUID('14cf216a-ce44-42e6-abe0-d9be790c4d4b')
    >>> type(id_value)
    <class 'uuid.UUID'>
    >>> id_value.bytes_le
    'j!\xcf\x14D\xce\xe6B\xab\xe0\xd9\xbey\x0cMK'

Arguments to ``pymssql.connect``
================================

The arguments are a little bit different. Some notable differences:

In pymssql 1.x, the parameter to specify the host is called ``host`` and it can contain a host and port -- e.g.:

::

    conn = pymssql.connect(host='SQLHOST:1433')  # specified TCP port at a host

There are some other syntaxes for the ``host`` parameter that allow using a
comma instead of a colon to delimit host and port, to specify Windows hosts, to
specify a specific SQL Server instance, etc.

::

    conn = pymssql.connect(host=r'SQLHOST,5000')  # specified TCP port at a host
    conn = pymssql.connect(host=r'(local)\SQLEXPRESS')  # named instance on local machine [Win]

In pymssql 2.x, the ``host`` parameter is supported (I am unsure if it has all
of the functionality of pymssql 1.x). There is also a parameter to specify the
host that is called ``server``. There is a separate parameter called ``port``.

::

    conn = pymssql.connect(server='SQLHOST', port=1500)

Parameter substitution
======================

For parameter substitution, pymssql 2.x supports the ``format`` and
``pyformat`` `PEP 249 paramstyles
<http://www.python.org/dev/peps/pep-0249/#paramstyle>`_.

Note that for ``pyformat``, PEP 249 only shows the example of a string substitution -- e.g.::

    %(name)s

It is not clear from PEP 249 whether other types should be supported, like::

    %(name)d
    %(name)f

However, in this `mailing list thread
<http://python.6.x6.nabble.com/Some-obscurity-with-paramstyle-td2163302.html>`_,
the general consensus is that the string format should be the only one
required.

Note that pymssql 2.x does not support ``%(name)d``, whereas pymssql 1.x did.
So you may have to change code that uses this notation::

    >>> pymssql.__version__
    u'2.0.1.2'
    >>> pymssql.paramstyle
    'pyformat'

    >>> cursor.execute("select 'hello' where 1 = %(name)d", dict(name=1))
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "pymssql.pyx", line 430, in pymssql.Cursor.execute (pymssql.c:5900)
        if not self._source._conn.nextresult():
    pymssql.ProgrammingError: (102, "Incorrect syntax near '('.
    DB-Lib error message 20018, severity 15:\n
    General SQL Server error: Check messages from the SQL Server\n")

to::

    >>> cursor.execute("select 'hello' where '1' = %(name)s", dict(name='1'))
    >>> cursor.fetchall()
    [(u'hello',)]

or::

    >>> cursor.execute("select 'hello' where 1 = %d", 1)
    >>> cursor.fetchall()
    [(u'hello',)]

Examples of this problem:

* `Google Group post: paramstyle changed? <https://groups.google.com/forum/?fromgroups=#!searchin/pymssql/param/pymssql/sSriPxHfZNk/VoOrl-84MQwJ>`_
* `GitHub issue #155: pymssql 2.x does not support "%(foo)d" parameter substitution style; pymssql 1.x did <https://github.com/pymssql/pymssql/issues/155>`_