Skip to content
This repository
Browse code

Added FreeTDS unit tests

  • Loading branch information...
commit 83db883c6c82f5f8676231b7b21a93b42f0edde9 1 parent c278e74
Michael Kleehammer authored

Showing 1 changed file with 1,263 additions and 0 deletions. Show diff stats Hide diff stats

  1. +1,263 0 tests2/freetdstests.py
1,263 tests2/freetdstests.py
... ... @@ -0,0 +1,1263 @@
  1 +#!/usr/bin/python
  2 +# -*- coding: latin-1 -*-
  3 +
  4 +usage = """\
  5 +usage: %prog [options] connection_string
  6 +
  7 +Unit tests for FreeTDS / SQL Server. To use, pass a connection string as the parameter.
  8 +The tests will create and drop tables t1 and t2 as necessary.
  9 +
  10 +These run using the version from the 'build' directory, not the version
  11 +installed into the Python directories. You must run python setup.py build
  12 +before running the tests.
  13 +
  14 +You can also put the connection string into tmp/setup.cfg like so:
  15 +
  16 + [freetdstests]
  17 + connection-string=DSN=xyz;UID=test;PWD=test
  18 +"""
  19 +
  20 +import sys, os, re
  21 +import unittest
  22 +from decimal import Decimal
  23 +from datetime import datetime, date, time
  24 +from os.path import join, getsize, dirname, abspath
  25 +from testutils import *
  26 +
  27 +_TESTSTR = '0123456789-abcdefghijklmnopqrstuvwxyz-'
  28 +
  29 +def _generate_test_string(length):
  30 + """
  31 + Returns a string of `length` characters, constructed by repeating _TESTSTR as necessary.
  32 +
  33 + To enhance performance, there are 3 ways data is read, based on the length of the value, so most data types are
  34 + tested with 3 lengths. This function helps us generate the test data.
  35 +
  36 + We use a recognizable data set instead of a single character to make it less likely that "overlap" errors will
  37 + be hidden and to help us manually identify where a break occurs.
  38 + """
  39 + if length <= len(_TESTSTR):
  40 + return _TESTSTR[:length]
  41 +
  42 + c = (length + len(_TESTSTR)-1) / len(_TESTSTR)
  43 + v = _TESTSTR * c
  44 + return v[:length]
  45 +
  46 +class FreeTDSTestCase(unittest.TestCase):
  47 +
  48 + SMALL_FENCEPOST_SIZES = [ 0, 1, 255, 256, 510, 511, 512, 1023, 1024, 2047, 2048, 4000 ]
  49 + LARGE_FENCEPOST_SIZES = [ 4095, 4096, 4097, 10 * 1024, 20 * 1024 ]
  50 +
  51 + ANSI_FENCEPOSTS = [ _generate_test_string(size) for size in SMALL_FENCEPOST_SIZES ]
  52 + UNICODE_FENCEPOSTS = [ unicode(s) for s in ANSI_FENCEPOSTS ]
  53 + IMAGE_FENCEPOSTS = ANSI_FENCEPOSTS + [ _generate_test_string(size) for size in LARGE_FENCEPOST_SIZES ]
  54 +
  55 + def __init__(self, method_name, connection_string):
  56 + unittest.TestCase.__init__(self, method_name)
  57 + self.connection_string = connection_string
  58 +
  59 + def get_sqlserver_version(self):
  60 + """
  61 + Returns the major version: 8-->2000, 9-->2005, 10-->2008
  62 + """
  63 + self.cursor.execute("exec master..xp_msver 'ProductVersion'")
  64 + row = self.cursor.fetchone()
  65 + return int(row.Character_Value.split('.', 1)[0])
  66 +
  67 + def setUp(self):
  68 + self.cnxn = pyodbc.connect(self.connection_string)
  69 + self.cursor = self.cnxn.cursor()
  70 +
  71 + for i in range(3):
  72 + try:
  73 + self.cursor.execute("drop table t%d" % i)
  74 + self.cnxn.commit()
  75 + except:
  76 + pass
  77 +
  78 + for i in range(3):
  79 + try:
  80 + self.cursor.execute("drop procedure proc%d" % i)
  81 + self.cnxn.commit()
  82 + except:
  83 + pass
  84 +
  85 + try:
  86 + self.cursor.execute('drop function func1')
  87 + self.cnxn.commit()
  88 + except:
  89 + pass
  90 +
  91 + self.cnxn.rollback()
  92 +
  93 + def tearDown(self):
  94 + try:
  95 + self.cursor.close()
  96 + self.cnxn.close()
  97 + except:
  98 + # If we've already closed the cursor or connection, exceptions are thrown.
  99 + pass
  100 +
  101 + def test_binary_type(self):
  102 + if sys.hexversion >= 0x02060000:
  103 + self.assertIs(pyodbc.BINARY, bytearray)
  104 + else:
  105 + self.assertIs(pyodbc.BINARY, buffer)
  106 +
  107 + def test_multiple_bindings(self):
  108 + "More than one bind and select on a cursor"
  109 + self.cursor.execute("create table t1(n int)")
  110 + self.cursor.execute("insert into t1 values (?)", 1)
  111 + self.cursor.execute("insert into t1 values (?)", 2)
  112 + self.cursor.execute("insert into t1 values (?)", 3)
  113 + for i in range(3):
  114 + self.cursor.execute("select n from t1 where n < ?", 10)
  115 + self.cursor.execute("select n from t1 where n < 3")
  116 +
  117 +
  118 + def test_different_bindings(self):
  119 + self.cursor.execute("create table t1(n int)")
  120 + self.cursor.execute("create table t2(d datetime)")
  121 + self.cursor.execute("insert into t1 values (?)", 1)
  122 + self.cursor.execute("insert into t2 values (?)", datetime.now())
  123 +
  124 + def test_datasources(self):
  125 + p = pyodbc.dataSources()
  126 + self.assert_(isinstance(p, dict))
  127 +
  128 + def test_getinfo_string(self):
  129 + value = self.cnxn.getinfo(pyodbc.SQL_CATALOG_NAME_SEPARATOR)
  130 + self.assert_(isinstance(value, str))
  131 +
  132 + def test_getinfo_bool(self):
  133 + value = self.cnxn.getinfo(pyodbc.SQL_ACCESSIBLE_TABLES)
  134 + self.assert_(isinstance(value, bool))
  135 +
  136 + def test_getinfo_int(self):
  137 + value = self.cnxn.getinfo(pyodbc.SQL_DEFAULT_TXN_ISOLATION)
  138 + self.assert_(isinstance(value, (int, long)))
  139 +
  140 + def test_getinfo_smallint(self):
  141 + value = self.cnxn.getinfo(pyodbc.SQL_CONCAT_NULL_BEHAVIOR)
  142 + self.assert_(isinstance(value, int))
  143 +
  144 + def test_noscan(self):
  145 + self.assertEqual(self.cursor.noscan, False)
  146 + self.cursor.noscan = True
  147 + self.assertEqual(self.cursor.noscan, True)
  148 +
  149 + def test_guid(self):
  150 + self.cursor.execute("create table t1(g1 uniqueidentifier)")
  151 + self.cursor.execute("insert into t1 values (newid())")
  152 + v = self.cursor.execute("select * from t1").fetchone()[0]
  153 + self.assertEqual(type(v), str)
  154 + self.assertEqual(len(v), 36)
  155 +
  156 + def test_nextset(self):
  157 + self.cursor.execute("create table t1(i int)")
  158 + for i in range(4):
  159 + self.cursor.execute("insert into t1(i) values(?)", i)
  160 +
  161 + self.cursor.execute("select i from t1 where i < 2 order by i; select i from t1 where i >= 2 order by i")
  162 +
  163 + for i, row in enumerate(self.cursor):
  164 + self.assertEqual(i, row.i)
  165 +
  166 + self.assertEqual(self.cursor.nextset(), True)
  167 +
  168 + for i, row in enumerate(self.cursor):
  169 + self.assertEqual(i + 2, row.i)
  170 +
  171 + def test_fixed_unicode(self):
  172 + value = u"t\xebsting"
  173 + self.cursor.execute("create table t1(s nchar(7))")
  174 + self.cursor.execute("insert into t1 values(?)", u"t\xebsting")
  175 + v = self.cursor.execute("select * from t1").fetchone()[0]
  176 + self.assertEqual(type(v), unicode)
  177 + self.assertEqual(len(v), len(value)) # If we alloc'd wrong, the test below might work because of an embedded NULL
  178 + self.assertEqual(v, value)
  179 +
  180 +
  181 + def _test_strtype(self, sqltype, value, resulttype=None, colsize=None):
  182 + """
  183 + The implementation for string, Unicode, and binary tests.
  184 + """
  185 + assert colsize is None or isinstance(colsize, int), colsize
  186 + assert colsize is None or (value is None or colsize >= len(value))
  187 +
  188 + if colsize:
  189 + sql = "create table t1(s %s(%s))" % (sqltype, colsize)
  190 + else:
  191 + sql = "create table t1(s %s)" % sqltype
  192 +
  193 + if resulttype is None:
  194 + resulttype = type(value)
  195 +
  196 + self.cursor.execute(sql)
  197 + self.cursor.execute("insert into t1 values(?)", value)
  198 + v = self.cursor.execute("select * from t1").fetchone()[0]
  199 + self.assertEqual(type(v), resulttype)
  200 +
  201 + if value is not None:
  202 + self.assertEqual(len(v), len(value))
  203 +
  204 + # To allow buffer --> db --> bytearray tests, always convert the input to the expected result type before
  205 + # comparing.
  206 + if type(value) is not resulttype:
  207 + value = resulttype(value)
  208 +
  209 + self.assertEqual(v, value)
  210 +
  211 +
  212 + def _test_strliketype(self, sqltype, value, resulttype=None, colsize=None):
  213 + """
  214 + The implementation for text, image, ntext, and binary.
  215 +
  216 + These types do not support comparison operators.
  217 + """
  218 + assert colsize is None or isinstance(colsize, int), colsize
  219 + assert colsize is None or (value is None or colsize >= len(value))
  220 +
  221 + if colsize:
  222 + sql = "create table t1(s %s(%s))" % (sqltype, colsize)
  223 + else:
  224 + sql = "create table t1(s %s)" % sqltype
  225 +
  226 + if resulttype is None:
  227 + resulttype = type(value)
  228 +
  229 + self.cursor.execute(sql)
  230 + self.cursor.execute("insert into t1 values(?)", value)
  231 + v = self.cursor.execute("select * from t1").fetchone()[0]
  232 + self.assertEqual(type(v), resulttype)
  233 +
  234 + if value is not None:
  235 + self.assertEqual(len(v), len(value))
  236 +
  237 + # To allow buffer --> db --> bytearray tests, always convert the input to the expected result type before
  238 + # comparing.
  239 + if type(value) is not resulttype:
  240 + value = resulttype(value)
  241 +
  242 + self.assertEqual(v, value)
  243 +
  244 +
  245 + #
  246 + # varchar
  247 + #
  248 +
  249 + def test_varchar_null(self):
  250 + self._test_strtype('varchar', None, colsize=100)
  251 +
  252 + # Generate a test for each fencepost size: test_varchar_0, etc.
  253 + def _maketest(value):
  254 + def t(self):
  255 + self._test_strtype('varchar', value, colsize=len(value))
  256 + return t
  257 + for value in ANSI_FENCEPOSTS:
  258 + locals()['test_varchar_%s' % len(value)] = _maketest(value)
  259 +
  260 + def test_varchar_many(self):
  261 + self.cursor.execute("create table t1(c1 varchar(300), c2 varchar(300), c3 varchar(300))")
  262 +
  263 + v1 = 'ABCDEFGHIJ' * 30
  264 + v2 = '0123456789' * 30
  265 + v3 = '9876543210' * 30
  266 +
  267 + self.cursor.execute("insert into t1(c1, c2, c3) values (?,?,?)", v1, v2, v3);
  268 + row = self.cursor.execute("select c1, c2, c3, len(c1) as l1, len(c2) as l2, len(c3) as l3 from t1").fetchone()
  269 +
  270 + self.assertEqual(v1, row.c1)
  271 + self.assertEqual(v2, row.c2)
  272 + self.assertEqual(v3, row.c3)
  273 +
  274 + def test_varchar_upperlatin(self):
  275 + self._test_strtype('varchar', '�')
  276 +
  277 + #
  278 + # unicode
  279 + #
  280 +
  281 + def test_unicode_null(self):
  282 + self._test_strtype('nvarchar', None, colsize=100)
  283 +
  284 + # Generate a test for each fencepost size: test_unicode_0, etc.
  285 + def _maketest(value):
  286 + def t(self):
  287 + self._test_strtype('nvarchar', value, colsize=len(value))
  288 + return t
  289 + for value in UNICODE_FENCEPOSTS:
  290 + locals()['test_unicode_%s' % len(value)] = _maketest(value)
  291 +
  292 + def test_unicode_upperlatin(self):
  293 + self._test_strtype('nvarchar', u'�')
  294 +
  295 + def test_unicode_longmax(self):
  296 + # Issue 188: Segfault when fetching NVARCHAR(MAX) data over 511 bytes
  297 +
  298 + ver = self.get_sqlserver_version()
  299 + if ver < 9: # 2005+
  300 + return # so pass / ignore
  301 + self.cursor.execute("select cast(replicate(N'x', 512) as nvarchar(max))")
  302 +
  303 + #
  304 + # binary
  305 + #
  306 +
  307 + def test_binary_null(self):
  308 + self._test_strtype('varbinary', None, colsize=100)
  309 +
  310 + def test_large_binary_null(self):
  311 + # Bug 1575064
  312 + self._test_strtype('varbinary', None, colsize=4000)
  313 +
  314 + # buffer
  315 +
  316 + def _maketest(value):
  317 + def t(self):
  318 + self._test_strtype('varbinary', buffer(value), resulttype=pyodbc.BINARY, colsize=len(value))
  319 + return t
  320 + for value in ANSI_FENCEPOSTS:
  321 + locals()['test_binary_buffer_%s' % len(value)] = _maketest(value)
  322 +
  323 + # bytearray
  324 +
  325 + if sys.hexversion >= 0x02060000:
  326 + def _maketest(value):
  327 + def t(self):
  328 + self._test_strtype('varbinary', bytearray(value), colsize=len(value))
  329 + return t
  330 + for value in ANSI_FENCEPOSTS:
  331 + locals()['test_binary_bytearray_%s' % len(value)] = _maketest(value)
  332 +
  333 + #
  334 + # image
  335 + #
  336 +
  337 + def test_image_null(self):
  338 + self._test_strliketype('image', None, type(None))
  339 +
  340 + # Generate a test for each fencepost size: test_unicode_0, etc.
  341 + def _maketest(value):
  342 + def t(self):
  343 + self._test_strliketype('image', buffer(value), pyodbc.BINARY)
  344 + return t
  345 + for value in IMAGE_FENCEPOSTS:
  346 + locals()['test_image_buffer_%s' % len(value)] = _maketest(value)
  347 +
  348 + if sys.hexversion >= 0x02060000:
  349 + # Python 2.6+ supports bytearray, which pyodbc considers varbinary.
  350 +
  351 + # Generate a test for each fencepost size: test_unicode_0, etc.
  352 + def _maketest(value):
  353 + def t(self):
  354 + self._test_strtype('image', bytearray(value))
  355 + return t
  356 + for value in IMAGE_FENCEPOSTS:
  357 + locals()['test_image_bytearray_%s' % len(value)] = _maketest(value)
  358 +
  359 + def test_image_upperlatin(self):
  360 + self._test_strliketype('image', buffer('�'), pyodbc.BINARY)
  361 +
  362 + #
  363 + # text
  364 + #
  365 +
  366 + # def test_empty_text(self):
  367 + # self._test_strliketype('text', bytearray(''))
  368 +
  369 + def test_null_text(self):
  370 + self._test_strliketype('text', None, type(None))
  371 +
  372 + # Generate a test for each fencepost size: test_unicode_0, etc.
  373 + def _maketest(value):
  374 + def t(self):
  375 + self._test_strliketype('text', value)
  376 + return t
  377 + for value in ANSI_FENCEPOSTS:
  378 + locals()['test_text_buffer_%s' % len(value)] = _maketest(value)
  379 +
  380 + def test_text_upperlatin(self):
  381 + self._test_strliketype('text', '�')
  382 +
  383 + #
  384 + # bit
  385 + #
  386 +
  387 + def test_bit(self):
  388 + value = True
  389 + self.cursor.execute("create table t1(b bit)")
  390 + self.cursor.execute("insert into t1 values (?)", value)
  391 + v = self.cursor.execute("select b from t1").fetchone()[0]
  392 + self.assertEqual(type(v), bool)
  393 + self.assertEqual(v, value)
  394 +
  395 + #
  396 + # decimal
  397 + #
  398 +
  399 + def _decimal(self, precision, scale, negative):
  400 + # From test provided by planders (thanks!) in Issue 91
  401 +
  402 + self.cursor.execute("create table t1(d decimal(%s, %s))" % (precision, scale))
  403 +
  404 + # Construct a decimal that uses the maximum precision and scale.
  405 + decStr = '9' * (precision - scale)
  406 + if scale:
  407 + decStr = decStr + "." + '9' * scale
  408 + if negative:
  409 + decStr = "-" + decStr
  410 + value = Decimal(decStr)
  411 +
  412 + self.cursor.execute("insert into t1 values(?)", value)
  413 +
  414 + v = self.cursor.execute("select d from t1").fetchone()[0]
  415 + self.assertEqual(v, value)
  416 +
  417 + def _maketest(p, s, n):
  418 + def t(self):
  419 + self._decimal(p, s, n)
  420 + return t
  421 + for (p, s, n) in [ (1, 0, False),
  422 + (1, 0, True),
  423 + (6, 0, False),
  424 + (6, 2, False),
  425 + (6, 4, True),
  426 + (6, 6, True),
  427 + (38, 0, False),
  428 + (38, 10, False),
  429 + (38, 38, False),
  430 + (38, 0, True),
  431 + (38, 10, True),
  432 + (38, 38, True) ]:
  433 + locals()['test_decimal_%s_%s_%s' % (p, s, n and 'n' or 'p')] = _maketest(p, s, n)
  434 +
  435 +
  436 + def test_decimal_e(self):
  437 + """Ensure exponential notation decimals are properly handled"""
  438 + value = Decimal((0, (1, 2, 3), 5)) # prints as 1.23E+7
  439 + self.cursor.execute("create table t1(d decimal(10, 2))")
  440 + self.cursor.execute("insert into t1 values (?)", value)
  441 + result = self.cursor.execute("select * from t1").fetchone()[0]
  442 + self.assertEqual(result, value)
  443 +
  444 + def test_subquery_params(self):
  445 + """Ensure parameter markers work in a subquery"""
  446 + self.cursor.execute("create table t1(id integer, s varchar(20))")
  447 + self.cursor.execute("insert into t1 values (?,?)", 1, 'test')
  448 + row = self.cursor.execute("""
  449 + select x.id
  450 + from (
  451 + select id
  452 + from t1
  453 + where s = ?
  454 + and id between ? and ?
  455 + ) x
  456 + """, 'test', 1, 10).fetchone()
  457 + self.assertNotEqual(row, None)
  458 + self.assertEqual(row[0], 1)
  459 +
  460 + def _exec(self):
  461 + self.cursor.execute(self.sql)
  462 +
  463 + def test_close_cnxn(self):
  464 + """Make sure using a Cursor after closing its connection doesn't crash."""
  465 +
  466 + self.cursor.execute("create table t1(id integer, s varchar(20))")
  467 + self.cursor.execute("insert into t1 values (?,?)", 1, 'test')
  468 + self.cursor.execute("select * from t1")
  469 +
  470 + self.cnxn.close()
  471 +
  472 + # Now that the connection is closed, we expect an exception. (If the code attempts to use
  473 + # the HSTMT, we'll get an access violation instead.)
  474 + self.sql = "select * from t1"
  475 + self.assertRaises(pyodbc.ProgrammingError, self._exec)
  476 +
  477 + def test_empty_string(self):
  478 + self.cursor.execute("create table t1(s varchar(20))")
  479 + self.cursor.execute("insert into t1 values(?)", "")
  480 +
  481 + def test_fixed_str(self):
  482 + value = "testing"
  483 + self.cursor.execute("create table t1(s char(7))")
  484 + self.cursor.execute("insert into t1 values(?)", "testing")
  485 + v = self.cursor.execute("select * from t1").fetchone()[0]
  486 + self.assertEqual(type(v), str)
  487 + self.assertEqual(len(v), len(value)) # If we alloc'd wrong, the test below might work because of an embedded NULL
  488 + self.assertEqual(v, value)
  489 +
  490 + def test_empty_unicode(self):
  491 + self.cursor.execute("create table t1(s nvarchar(20))")
  492 + self.cursor.execute("insert into t1 values(?)", u"")
  493 +
  494 + def test_unicode_query(self):
  495 + self.cursor.execute(u"select 1")
  496 +
  497 + def test_negative_row_index(self):
  498 + self.cursor.execute("create table t1(s varchar(20))")
  499 + self.cursor.execute("insert into t1 values(?)", "1")
  500 + row = self.cursor.execute("select * from t1").fetchone()
  501 + self.assertEquals(row[0], "1")
  502 + self.assertEquals(row[-1], "1")
  503 +
  504 + def test_version(self):
  505 + self.assertEquals(3, len(pyodbc.version.split('.'))) # 1.3.1 etc.
  506 +
  507 + #
  508 + # date, time, datetime
  509 + #
  510 +
  511 + def test_datetime(self):
  512 + value = datetime(2007, 1, 15, 3, 4, 5)
  513 +
  514 + self.cursor.execute("create table t1(dt datetime)")
  515 + self.cursor.execute("insert into t1 values (?)", value)
  516 +
  517 + result = self.cursor.execute("select dt from t1").fetchone()[0]
  518 + self.assertEquals(type(value), datetime)
  519 + self.assertEquals(value, result)
  520 +
  521 + def test_datetime_fraction(self):
  522 + # SQL Server supports milliseconds, but Python's datetime supports nanoseconds, so the most granular datetime
  523 + # supported is xxx000.
  524 +
  525 + value = datetime(2007, 1, 15, 3, 4, 5, 123000)
  526 +
  527 + self.cursor.execute("create table t1(dt datetime)")
  528 + self.cursor.execute("insert into t1 values (?)", value)
  529 +
  530 + result = self.cursor.execute("select dt from t1").fetchone()[0]
  531 + self.assertEquals(type(value), datetime)
  532 + self.assertEquals(result, value)
  533 +
  534 + def test_datetime_fraction_rounded(self):
  535 + # SQL Server supports milliseconds, but Python's datetime supports nanoseconds. pyodbc rounds down to what the
  536 + # database supports.
  537 +
  538 + full = datetime(2007, 1, 15, 3, 4, 5, 123456)
  539 + rounded = datetime(2007, 1, 15, 3, 4, 5, 123000)
  540 +
  541 + self.cursor.execute("create table t1(dt datetime)")
  542 + self.cursor.execute("insert into t1 values (?)", full)
  543 +
  544 + result = self.cursor.execute("select dt from t1").fetchone()[0]
  545 + self.assertEquals(type(result), datetime)
  546 + self.assertEquals(result, rounded)
  547 +
  548 + #
  549 + # ints and floats
  550 + #
  551 +
  552 + def test_int(self):
  553 + value = 1234
  554 + self.cursor.execute("create table t1(n int)")
  555 + self.cursor.execute("insert into t1 values (?)", value)
  556 + result = self.cursor.execute("select n from t1").fetchone()[0]
  557 + self.assertEquals(result, value)
  558 +
  559 + def test_negative_int(self):
  560 + value = -1
  561 + self.cursor.execute("create table t1(n int)")
  562 + self.cursor.execute("insert into t1 values (?)", value)
  563 + result = self.cursor.execute("select n from t1").fetchone()[0]
  564 + self.assertEquals(result, value)
  565 +
  566 + def test_bigint(self):
  567 + input = 3000000000
  568 + self.cursor.execute("create table t1(d bigint)")
  569 + self.cursor.execute("insert into t1 values (?)", input)
  570 + result = self.cursor.execute("select d from t1").fetchone()[0]
  571 + self.assertEqual(result, input)
  572 +
  573 + def test_float(self):
  574 + value = 1234.567
  575 + self.cursor.execute("create table t1(n float)")
  576 + self.cursor.execute("insert into t1 values (?)", value)
  577 + result = self.cursor.execute("select n from t1").fetchone()[0]
  578 + self.assertEquals(result, value)
  579 +
  580 + def test_negative_float(self):
  581 + value = -200
  582 + self.cursor.execute("create table t1(n float)")
  583 + self.cursor.execute("insert into t1 values (?)", value)
  584 + result = self.cursor.execute("select n from t1").fetchone()[0]
  585 + self.assertEqual(value, result)
  586 +
  587 +
  588 + #
  589 + # stored procedures
  590 + #
  591 +
  592 + # def test_callproc(self):
  593 + # "callproc with a simple input-only stored procedure"
  594 + # pass
  595 +
  596 + def test_sp_results(self):
  597 + self.cursor.execute(
  598 + """
  599 + Create procedure proc1
  600 + AS
  601 + select top 10 name, id, xtype, refdate
  602 + from sysobjects
  603 + """)
  604 + rows = self.cursor.execute("exec proc1").fetchall()
  605 + self.assertEquals(type(rows), list)
  606 + self.assertEquals(len(rows), 10) # there has to be at least 10 items in sysobjects
  607 + self.assertEquals(type(rows[0].refdate), datetime)
  608 +
  609 +
  610 + def test_sp_results_from_temp(self):
  611 +
  612 + # Note: I've used "set nocount on" so that we don't get the number of rows deleted from #tmptable.
  613 + # If you don't do this, you'd need to call nextset() once to skip it.
  614 +
  615 + self.cursor.execute(
  616 + """
  617 + Create procedure proc1
  618 + AS
  619 + set nocount on
  620 + select top 10 name, id, xtype, refdate
  621 + into #tmptable
  622 + from sysobjects
  623 +
  624 + select * from #tmptable
  625 + """)
  626 + self.cursor.execute("exec proc1")
  627 + self.assert_(self.cursor.description is not None)
  628 + self.assert_(len(self.cursor.description) == 4)
  629 +
  630 + rows = self.cursor.fetchall()
  631 + self.assertEquals(type(rows), list)
  632 + self.assertEquals(len(rows), 10) # there has to be at least 10 items in sysobjects
  633 + self.assertEquals(type(rows[0].refdate), datetime)
  634 +
  635 +
  636 + def test_sp_results_from_vartbl(self):
  637 + self.cursor.execute(
  638 + """
  639 + Create procedure proc1
  640 + AS
  641 + set nocount on
  642 + declare @tmptbl table(name varchar(100), id int, xtype varchar(4), refdate datetime)
  643 +
  644 + insert into @tmptbl
  645 + select top 10 name, id, xtype, refdate
  646 + from sysobjects
  647 +
  648 + select * from @tmptbl
  649 + """)
  650 + self.cursor.execute("exec proc1")
  651 + rows = self.cursor.fetchall()
  652 + self.assertEquals(type(rows), list)
  653 + self.assertEquals(len(rows), 10) # there has to be at least 10 items in sysobjects
  654 + self.assertEquals(type(rows[0].refdate), datetime)
  655 +
  656 + def test_sp_with_dates(self):
  657 + # Reported in the forums that passing two datetimes to a stored procedure doesn't work.
  658 + self.cursor.execute(
  659 + """
  660 + if exists (select * from dbo.sysobjects where id = object_id(N'[test_sp]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
  661 + drop procedure [dbo].[test_sp]
  662 + """)
  663 + self.cursor.execute(
  664 + """
  665 + create procedure test_sp(@d1 datetime, @d2 datetime)
  666 + AS
  667 + declare @d as int
  668 + set @d = datediff(year, @d1, @d2)
  669 + select @d
  670 + """)
  671 + self.cursor.execute("exec test_sp ?, ?", datetime.now(), datetime.now())
  672 + rows = self.cursor.fetchall()
  673 + self.assert_(rows is not None)
  674 + self.assert_(rows[0][0] == 0) # 0 years apart
  675 +
  676 + def test_sp_with_none(self):
  677 + # Reported in the forums that passing None caused an error.
  678 + self.cursor.execute(
  679 + """
  680 + if exists (select * from dbo.sysobjects where id = object_id(N'[test_sp]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
  681 + drop procedure [dbo].[test_sp]
  682 + """)
  683 + self.cursor.execute(
  684 + """
  685 + create procedure test_sp(@x varchar(20))
  686 + AS
  687 + declare @y varchar(20)
  688 + set @y = @x
  689 + select @y
  690 + """)
  691 + self.cursor.execute("exec test_sp ?", None)
  692 + rows = self.cursor.fetchall()
  693 + self.assert_(rows is not None)
  694 + self.assert_(rows[0][0] == None) # 0 years apart
  695 +
  696 +
  697 + #
  698 + # rowcount
  699 + #
  700 +
  701 + def test_rowcount_delete(self):
  702 + self.assertEquals(self.cursor.rowcount, -1)
  703 + self.cursor.execute("create table t1(i int)")
  704 + count = 4
  705 + for i in range(count):
  706 + self.cursor.execute("insert into t1 values (?)", i)
  707 + self.cursor.execute("delete from t1")
  708 + self.assertEquals(self.cursor.rowcount, count)
  709 +
  710 + def test_rowcount_nodata(self):
  711 + """
  712 + This represents a different code path than a delete that deleted something.
  713 +
  714 + The return value is SQL_NO_DATA and code after it was causing an error. We could use SQL_NO_DATA to step over
  715 + the code that errors out and drop down to the same SQLRowCount code. On the other hand, we could hardcode a
  716 + zero return value.
  717 + """
  718 + self.cursor.execute("create table t1(i int)")
  719 + # This is a different code path internally.
  720 + self.cursor.execute("delete from t1")
  721 + self.assertEquals(self.cursor.rowcount, 0)
  722 +
  723 + def test_rowcount_select(self):
  724 + """
  725 + Ensure Cursor.rowcount is set properly after a select statement.
  726 +
  727 + pyodbc calls SQLRowCount after each execute and sets Cursor.rowcount, but SQL Server 2005 returns -1 after a
  728 + select statement, so we'll test for that behavior. This is valid behavior according to the DB API
  729 + specification, but people don't seem to like it.
  730 + """
  731 + self.cursor.execute("create table t1(i int)")
  732 + count = 4
  733 + for i in range(count):
  734 + self.cursor.execute("insert into t1 values (?)", i)
  735 + self.cursor.execute("select * from t1")
  736 + self.assertEquals(self.cursor.rowcount, -1)
  737 +
  738 + rows = self.cursor.fetchall()
  739 + self.assertEquals(len(rows), count)
  740 + self.assertEquals(self.cursor.rowcount, -1)
  741 +
  742 + #
  743 + # always return Cursor
  744 + #
  745 +
  746 + # In the 2.0.x branch, Cursor.execute sometimes returned the cursor and sometimes the rowcount. This proved very
  747 + # confusing when things went wrong and added very little value even when things went right since users could always
  748 + # use: cursor.execute("...").rowcount
  749 +
  750 + def test_retcursor_delete(self):
  751 + self.cursor.execute("create table t1(i int)")
  752 + self.cursor.execute("insert into t1 values (1)")
  753 + v = self.cursor.execute("delete from t1")
  754 + self.assertEquals(v, self.cursor)
  755 +
  756 + def test_retcursor_nodata(self):
  757 + """
  758 + This represents a different code path than a delete that deleted something.
  759 +
  760 + The return value is SQL_NO_DATA and code after it was causing an error. We could use SQL_NO_DATA to step over
  761 + the code that errors out and drop down to the same SQLRowCount code.
  762 + """
  763 + self.cursor.execute("create table t1(i int)")
  764 + # This is a different code path internally.
  765 + v = self.cursor.execute("delete from t1")
  766 + self.assertEquals(v, self.cursor)
  767 +
  768 + def test_retcursor_select(self):
  769 + self.cursor.execute("create table t1(i int)")
  770 + self.cursor.execute("insert into t1 values (1)")
  771 + v = self.cursor.execute("select * from t1")
  772 + self.assertEquals(v, self.cursor)
  773 +
  774 + #
  775 + # misc
  776 + #
  777 +
  778 + def test_lower_case(self):
  779 + "Ensure pyodbc.lowercase forces returned column names to lowercase."
  780 +
  781 + # Has to be set before creating the cursor, so we must recreate self.cursor.
  782 +
  783 + pyodbc.lowercase = True
  784 + self.cursor = self.cnxn.cursor()
  785 +
  786 + self.cursor.execute("create table t1(Abc int, dEf int)")
  787 + self.cursor.execute("select * from t1")
  788 +
  789 + names = [ t[0] for t in self.cursor.description ]
  790 + names.sort()
  791 +
  792 + self.assertEquals(names, [ "abc", "def" ])
  793 +
  794 + # Put it back so other tests don't fail.
  795 + pyodbc.lowercase = False
  796 +
  797 + def test_row_description(self):
  798 + """
  799 + Ensure Cursor.description is accessible as Row.cursor_description.
  800 + """
  801 + self.cursor = self.cnxn.cursor()
  802 + self.cursor.execute("create table t1(a int, b char(3))")
  803 + self.cnxn.commit()
  804 + self.cursor.execute("insert into t1 values(1, 'abc')")
  805 +
  806 + row = self.cursor.execute("select * from t1").fetchone()
  807 +
  808 + self.assertEquals(self.cursor.description, row.cursor_description)
  809 +
  810 +
  811 + def test_temp_select(self):
  812 + # A project was failing to create temporary tables via select into.
  813 + self.cursor.execute("create table t1(s char(7))")
  814 + self.cursor.execute("insert into t1 values(?)", "testing")
  815 + v = self.cursor.execute("select * from t1").fetchone()[0]
  816 + self.assertEqual(type(v), str)
  817 + self.assertEqual(v, "testing")
  818 +
  819 + self.cursor.execute("select s into t2 from t1")
  820 + v = self.cursor.execute("select * from t1").fetchone()[0]
  821 + self.assertEqual(type(v), str)
  822 + self.assertEqual(v, "testing")
  823 +
  824 +
  825 + def test_money(self):
  826 + d = Decimal('123456.78')
  827 + self.cursor.execute("create table t1(i int identity(1,1), m money)")
  828 + self.cursor.execute("insert into t1(m) values (?)", d)
  829 + v = self.cursor.execute("select m from t1").fetchone()[0]
  830 + self.assertEqual(v, d)
  831 +
  832 +
  833 + def test_executemany(self):
  834 + self.cursor.execute("create table t1(a int, b varchar(10))")
  835 +
  836 + params = [ (i, str(i)) for i in range(1, 6) ]
  837 +
  838 + self.cursor.executemany("insert into t1(a, b) values (?,?)", params)
  839 +
  840 + count = self.cursor.execute("select count(*) from t1").fetchone()[0]
  841 + self.assertEqual(count, len(params))
  842 +
  843 + self.cursor.execute("select a, b from t1 order by a")
  844 + rows = self.cursor.fetchall()
  845 + self.assertEqual(count, len(rows))
  846 +
  847 + for param, row in zip(params, rows):
  848 + self.assertEqual(param[0], row[0])
  849 + self.assertEqual(param[1], row[1])
  850 +
  851 +
  852 + def test_executemany_one(self):
  853 + "Pass executemany a single sequence"
  854 + self.cursor.execute("create table t1(a int, b varchar(10))")
  855 +
  856 + params = [ (1, "test") ]
  857 +
  858 + self.cursor.executemany("insert into t1(a, b) values (?,?)", params)
  859 +
  860 + count = self.cursor.execute("select count(*) from t1").fetchone()[0]
  861 + self.assertEqual(count, len(params))
  862 +
  863 + self.cursor.execute("select a, b from t1 order by a")
  864 + rows = self.cursor.fetchall()
  865 + self.assertEqual(count, len(rows))
  866 +
  867 + for param, row in zip(params, rows):
  868 + self.assertEqual(param[0], row[0])
  869 + self.assertEqual(param[1], row[1])
  870 +
  871 +
  872 + def test_executemany_failure(self):
  873 + """
  874 + Ensure that an exception is raised if one query in an executemany fails.
  875 + """
  876 + self.cursor.execute("create table t1(a int, b varchar(10))")
  877 +
  878 + params = [ (1, 'good'),
  879 + ('error', 'not an int'),
  880 + (3, 'good') ]
  881 +
  882 + self.failUnlessRaises(pyodbc.Error, self.cursor.executemany, "insert into t1(a, b) value (?, ?)", params)
  883 +
  884 +
  885 + def test_row_slicing(self):
  886 + self.cursor.execute("create table t1(a int, b int, c int, d int)");
  887 + self.cursor.execute("insert into t1 values(1,2,3,4)")
  888 +
  889 + row = self.cursor.execute("select * from t1").fetchone()
  890 +
  891 + result = row[:]
  892 + self.failUnless(result is row)
  893 +
  894 + result = row[:-1]
  895 + self.assertEqual(result, (1,2,3))
  896 +
  897 + result = row[0:4]
  898 + self.failUnless(result is row)
  899 +
  900 +
  901 + def test_row_repr(self):
  902 + self.cursor.execute("create table t1(a int, b int, c int, d int)");
  903 + self.cursor.execute("insert into t1 values(1,2,3,4)")
  904 +
  905 + row = self.cursor.execute("select * from t1").fetchone()
  906 +
  907 + result = str(row)
  908 + self.assertEqual(result, "(1, 2, 3, 4)")
  909 +
  910 + result = str(row[:-1])
  911 + self.assertEqual(result, "(1, 2, 3)")
  912 +
  913 + result = str(row[:1])
  914 + self.assertEqual(result, "(1,)")
  915 +
  916 +
  917 + def test_concatenation(self):
  918 + v2 = '0123456789' * 30
  919 + v3 = '9876543210' * 30
  920 +
  921 + self.cursor.execute("create table t1(c1 int identity(1, 1), c2 varchar(300), c3 varchar(300))")
  922 + self.cursor.execute("insert into t1(c2, c3) values (?,?)", v2, v3)
  923 +
  924 + row = self.cursor.execute("select c2, c3, c2 + c3 as both from t1").fetchone()
  925 +
  926 + self.assertEqual(row.both, v2 + v3)
  927 +
  928 + def test_view_select(self):
  929 + # Reported in forum: Can't select from a view? I think I do this a lot, but another test never hurts.
  930 +
  931 + # Create a table (t1) with 3 rows and a view (t2) into it.
  932 + self.cursor.execute("create table t1(c1 int identity(1, 1), c2 varchar(50))")
  933 + for i in range(3):
  934 + self.cursor.execute("insert into t1(c2) values (?)", "string%s" % i)
  935 + self.cursor.execute("create view t2 as select * from t1")
  936 +
  937 + # Select from the view
  938 + self.cursor.execute("select * from t2")
  939 + rows = self.cursor.fetchall()
  940 + self.assert_(rows is not None)
  941 + self.assert_(len(rows) == 3)
  942 +
  943 + def test_autocommit(self):
  944 + self.assertEqual(self.cnxn.autocommit, False)
  945 +
  946 + othercnxn = pyodbc.connect(self.connection_string, autocommit=True)
  947 + self.assertEqual(othercnxn.autocommit, True)
  948 +
  949 + othercnxn.autocommit = False
  950 + self.assertEqual(othercnxn.autocommit, False)
  951 +
  952 + def test_unicode_results(self):
  953 + "Ensure unicode_results forces Unicode"
  954 + othercnxn = pyodbc.connect(self.connection_string, unicode_results=True)
  955 + othercursor = othercnxn.cursor()
  956 +
  957 + # ANSI data in an ANSI column ...
  958 + othercursor.execute("create table t1(s varchar(20))")
  959 + othercursor.execute("insert into t1 values(?)", 'test')
  960 +
  961 + # ... should be returned as Unicode
  962 + value = othercursor.execute("select s from t1").fetchone()[0]
  963 + self.assertEqual(value, u'test')
  964 +
  965 +
  966 + def test_sqlserver_callproc(self):
  967 + try:
  968 + self.cursor.execute("drop procedure pyodbctest")
  969 + self.cnxn.commit()
  970 + except:
  971 + pass
  972 +
  973 + self.cursor.execute("create table t1(s varchar(10))")
  974 + self.cursor.execute("insert into t1 values(?)", "testing")
  975 +
  976 + self.cursor.execute("""
  977 + create procedure pyodbctest @var1 varchar(32)
  978 + as
  979 + begin
  980 + select s
  981 + from t1
  982 + return
  983 + end
  984 + """)
  985 + self.cnxn.commit()
  986 +
  987 + # for row in self.cursor.procedureColumns('pyodbctest'):
  988 + # print row.procedure_name, row.column_name, row.column_type, row.type_name
  989 +
  990 + self.cursor.execute("exec pyodbctest 'hi'")
  991 +
  992 + # print self.cursor.description
  993 + # for row in self.cursor:
  994 + # print row.s
  995 +
  996 + def test_skip(self):
  997 + # Insert 1, 2, and 3. Fetch 1, skip 2, fetch 3.
  998 +
  999 + self.cursor.execute("create table t1(id int)");
  1000 + for i in range(1, 5):
  1001 + self.cursor.execute("insert into t1 values(?)", i)
  1002 + self.cursor.execute("select id from t1 order by id")
  1003 + self.assertEqual(self.cursor.fetchone()[0], 1)
  1004 + self.cursor.skip(2)
  1005 + self.assertEqual(self.cursor.fetchone()[0], 4)
  1006 +
  1007 + def test_timeout(self):
  1008 + self.assertEqual(self.cnxn.timeout, 0) # defaults to zero (off)
  1009 +
  1010 + self.cnxn.timeout = 30
  1011 + self.assertEqual(self.cnxn.timeout, 30)
  1012 +
  1013 + self.cnxn.timeout = 0
  1014 + self.assertEqual(self.cnxn.timeout, 0)
  1015 +
  1016 + def test_sets_execute(self):
  1017 + # Only lists and tuples are allowed.
  1018 + def f():
  1019 + self.cursor.execute("create table t1 (word varchar (100))")
  1020 + words = set (['a'])
  1021 + self.cursor.execute("insert into t1 (word) VALUES (?)", [words])
  1022 +
  1023 + self.assertRaises(pyodbc.ProgrammingError, f)
  1024 +
  1025 + def test_sets_executemany(self):
  1026 + # Only lists and tuples are allowed.
  1027 + def f():
  1028 + self.cursor.execute("create table t1 (word varchar (100))")
  1029 + words = set (['a'])
  1030 + self.cursor.executemany("insert into t1 (word) values (?)", [words])
  1031 +
  1032 + self.assertRaises(TypeError, f)
  1033 +
  1034 + def test_row_execute(self):
  1035 + "Ensure we can use a Row object as a parameter to execute"
  1036 + self.cursor.execute("create table t1(n int, s varchar(10))")
  1037 + self.cursor.execute("insert into t1 values (1, 'a')")
  1038 + row = self.cursor.execute("select n, s from t1").fetchone()
  1039 + self.assertNotEqual(row, None)
  1040 +
  1041 + self.cursor.execute("create table t2(n int, s varchar(10))")
  1042 + self.cursor.execute("insert into t2 values (?, ?)", row)
  1043 +
  1044 + def test_row_executemany(self):
  1045 + "Ensure we can use a Row object as a parameter to executemany"
  1046 + self.cursor.execute("create table t1(n int, s varchar(10))")
  1047 +
  1048 + for i in range(3):
  1049 + self.cursor.execute("insert into t1 values (?, ?)", i, chr(ord('a')+i))
  1050 +
  1051 + rows = self.cursor.execute("select n, s from t1").fetchall()
  1052 + self.assertNotEqual(len(rows), 0)
  1053 +
  1054 + self.cursor.execute("create table t2(n int, s varchar(10))")
  1055 + self.cursor.executemany("insert into t2 values (?, ?)", rows)
  1056 +
  1057 + def test_description(self):
  1058 + "Ensure cursor.description is correct"
  1059 +
  1060 + self.cursor.execute("create table t1(n int, s varchar(8), d decimal(5,2))")
  1061 + self.cursor.execute("insert into t1 values (1, 'abc', '1.23')")
  1062 + self.cursor.execute("select * from t1")
  1063 +
  1064 + # (I'm not sure the precision of an int is constant across different versions, bits, so I'm hand checking the
  1065 + # items I do know.
  1066 +
  1067 + # int
  1068 + t = self.cursor.description[0]
  1069 + self.assertEqual(t[0], 'n')
  1070 + self.assertEqual(t[1], int)
  1071 + self.assertEqual(t[5], 0) # scale
  1072 + self.assertEqual(t[6], True) # nullable
  1073 +
  1074 + # varchar(8)
  1075 + t = self.cursor.description[1]
  1076 + self.assertEqual(t[0], 's')
  1077 + self.assertEqual(t[1], str)
  1078 + self.assertEqual(t[4], 8) # precision
  1079 + self.assertEqual(t[5], 0) # scale
  1080 + self.assertEqual(t[6], True) # nullable
  1081 +
  1082 + # decimal(5, 2)
  1083 + t = self.cursor.description[2]
  1084 + self.assertEqual(t[0], 'd')
  1085 + self.assertEqual(t[1], Decimal)
  1086 + self.assertEqual(t[4], 5) # precision
  1087 + self.assertEqual(t[5], 2) # scale
  1088 + self.assertEqual(t[6], True) # nullable
  1089 +
  1090 +
  1091 + def test_none_param(self):
  1092 + "Ensure None can be used for params other than the first"
  1093 + # Some driver/db versions would fail if NULL was not the first parameter because SQLDescribeParam (only used
  1094 + # with NULL) could not be used after the first call to SQLBindParameter. This means None always worked for the
  1095 + # first column, but did not work for later columns.
  1096 + #
  1097 + # If SQLDescribeParam doesn't work, pyodbc would use VARCHAR which almost always worked. However,
  1098 + # binary/varbinary won't allow an implicit conversion.
  1099 +
  1100 + self.cursor.execute("create table t1(n int, s varchar(20))")
  1101 + self.cursor.execute("insert into t1 values (1, 'xyzzy')")
  1102 + row = self.cursor.execute("select * from t1").fetchone()
  1103 + self.assertEqual(row.n, 1)
  1104 + self.assertEqual(type(row.s), str)
  1105 +
  1106 + self.cursor.execute("update t1 set n=?, s=?", 2, None)
  1107 + row = self.cursor.execute("select * from t1").fetchone()
  1108 + self.assertEqual(row.n, 2)
  1109 + self.assertEqual(row.s, None)
  1110 +
  1111 +
  1112 + def test_output_conversion(self):
  1113 + def convert(value):
  1114 + # `value` will be a string. We'll simply add an X at the beginning at the end.
  1115 + return 'X' + value + 'X'
  1116 + self.cnxn.add_output_converter(pyodbc.SQL_VARCHAR, convert)
  1117 + self.cursor.execute("create table t1(n int, v varchar(10))")
  1118 + self.cursor.execute("insert into t1 values (1, '123.45')")
  1119 + value = self.cursor.execute("select v from t1").fetchone()[0]
  1120 + self.assertEqual(value, 'X123.45X')
  1121 +
  1122 + # Now clear the conversions and try again. There should be no Xs this time.
  1123 + self.cnxn.clear_output_converters()
  1124 + value = self.cursor.execute("select v from t1").fetchone()[0]
  1125 + self.assertEqual(value, '123.45')
  1126 +
  1127 +
  1128 + def test_too_large(self):
  1129 + """Ensure error raised if insert fails due to truncation"""
  1130 + value = 'x' * 1000
  1131 + self.cursor.execute("create table t1(s varchar(800))")
  1132 + def test():
  1133 + self.cursor.execute("insert into t1 values (?)", value)
  1134 + self.assertRaises(pyodbc.DataError, test)
  1135 +
  1136 + def test_geometry_null_insert(self):
  1137 + def convert(value):
  1138 + return value
  1139 +
  1140 + self.cnxn.add_output_converter(-151, convert) # -151 is SQL Server's geometry
  1141 + self.cursor.execute("create table t1(n int, v geometry)")
  1142 + self.cursor.execute("insert into t1 values (?, ?)", 1, None)
  1143 + value = self.cursor.execute("select v from t1").fetchone()[0]
  1144 + self.assertEqual(value, None)
  1145 + self.cnxn.clear_output_converters()
  1146 +
  1147 + def test_login_timeout(self):
  1148 + # This can only test setting since there isn't a way to cause it to block on the server side.
  1149 + cnxns = pyodbc.connect(self.connection_string, timeout=2)
  1150 +
  1151 + def test_row_equal(self):
  1152 + self.cursor.execute("create table t1(n int, s varchar(20))")
  1153 + self.cursor.execute("insert into t1 values (1, 'test')")
  1154 + row1 = self.cursor.execute("select n, s from t1").fetchone()
  1155 + row2 = self.cursor.execute("select n, s from t1").fetchone()
  1156 + b = (row1 == row2)
  1157 + self.assertEqual(b, True)
  1158 +
  1159 + def test_row_gtlt(self):
  1160 + self.cursor.execute("create table t1(n int, s varchar(20))")
  1161 + self.cursor.execute("insert into t1 values (1, 'test1')")
  1162 + self.cursor.execute("insert into t1 values (1, 'test2')")
  1163 + rows = self.cursor.execute("select n, s from t1 order by s").fetchall()
  1164 + self.assert_(rows[0] < rows[1])
  1165 + self.assert_(rows[0] <= rows[1])
  1166 + self.assert_(rows[1] > rows[0])
  1167 + self.assert_(rows[1] >= rows[0])
  1168 + self.assert_(rows[0] != rows[1])
  1169 +
  1170 + rows = list(rows)
  1171 + rows.sort() # uses <
  1172 +
  1173 + def test_context_manager_success(self):
  1174 +
  1175 + self.cursor.execute("create table t1(n int)")
  1176 + self.cnxn.commit()
  1177 +
  1178 + try:
  1179 + with pyodbc.connect(self.connection_string) as cnxn:
  1180 + cursor = cnxn.cursor()
  1181 + cursor.execute("insert into t1 values (1)")
  1182 + except Exception:
  1183 + pass
  1184 +
  1185 + cnxn = None
  1186 + cursor = None
  1187 +
  1188 + rows = self.cursor.execute("select n from t1").fetchall()
  1189 + self.assertEquals(len(rows), 1)
  1190 + self.assertEquals(rows[0][0], 1)
  1191 +
  1192 +
  1193 + def test_untyped_none(self):
  1194 + # From issue 129
  1195 + value = self.cursor.execute("select ?", None).fetchone()[0]
  1196 + self.assertEqual(value, None)
  1197 +
  1198 + def test_large_update_nodata(self):
  1199 + self.cursor.execute('create table t1(a varbinary(max))')
  1200 + hundredkb = bytearray('x'*100*1024)
  1201 + self.cursor.execute('update t1 set a=? where 1=0', (hundredkb,))
  1202 +
  1203 + def test_func_param(self):
  1204 + self.cursor.execute('''
  1205 + create function func1 (@testparam varchar(4))