Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge with master #6

Merged
merged 4 commits into from
Aug 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/errors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,9 +289,9 @@ PyObject* GetErrorFromHandle(Connection *conn, const char* szFunction, HDBC hdbc
// Not always NULL terminated (MS Access)
sqlstateT[5] = 0;

// For now, default to UTF-16LE if this is not in the context of a connection.
// For now, default to UTF-16 if this is not in the context of a connection.
// Note that this will not work if the DM is using a different wide encoding (e.g. UTF-32).
const char *unicode_enc = conn ? conn->metadata_enc.name : "utf-16-le";
const char *unicode_enc = conn ? conn->metadata_enc.name : ENCSTR_UTF16NE;
Object msgStr(PyUnicode_Decode((char*)szMsg, cchMsg * sizeof(ODBCCHAR), unicode_enc, "strict"));

if (cchMsg != 0 && msgStr.Get())
Expand Down
7 changes: 6 additions & 1 deletion src/params.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,12 @@ static int PyToCType(Cursor *cur, unsigned char **outbuf, PyObject *cell, ParamI
pts->hour = PyDateTime_DATE_GET_HOUR(cell);
pts->minute = PyDateTime_DATE_GET_MINUTE(cell);
pts->second = PyDateTime_DATE_GET_SECOND(cell);
pts->fraction = PyDateTime_DATE_GET_MICROSECOND(cell) * 1000;

// Truncate the fraction according to precision
long fast_pow10[] = {1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
SQLUINTEGER milliseconds = PyDateTime_DATE_GET_MICROSECOND(cell) * 1000;
pts->fraction = milliseconds - (milliseconds % fast_pow10[9 - pi->DecimalDigits]);

*outbuf += sizeof(SQL_TIMESTAMP_STRUCT);
ind = sizeof(SQL_TIMESTAMP_STRUCT);
}
Expand Down
18 changes: 11 additions & 7 deletions tests2/mysqltests.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
usage = """\
usage: %prog [options] connection_string

Unit tests for MySQL. To use, pass a connection string as the parameter. The tests will create and drop tables t1 and
t2 as necessary. The default installation of mysql allows you to connect locally with no password and already contains
a 'test' database, so you can probably use the following. (Update the driver name as appropriate.)

./mysqltests DRIVER={MySQL};DATABASE=test
Unit tests for MySQL. To use, pass a connection string as the parameter.
The tests will create and drop tables t1 and t2 as necessary.

These tests use the pyodbc library from the build directory, not the version installed in your
Python directories. You must run `python setup.py build` before running these tests.

You can also put the connection string into a tmp/setup.cfg file like so:

[mysqltests]
connection-string=DRIVER=MySQL ODBC 8.0 Unicode Driver;charset=utf8mb4;SERVER=localhost;DATABASE=pyodbc;UID=root;PWD=rootpw

Note: Include charset=utf8mb4 in the connection string so the high-Unicode tests won't fail.
"""

import sys, os, re
Expand Down Expand Up @@ -689,9 +693,9 @@ def test_emoticons(self):
#
# http://www.fileformat.info/info/unicode/char/1f31c/index.htm

v = "x \U0001F31C z"
v = u"x \U0001F31C z"

self.cursor.execute("create table t1(s varchar(100))")
self.cursor.execute("CREATE TABLE t1(s varchar(100)) DEFAULT CHARSET=utf8mb4")
self.cursor.execute("insert into t1 values (?)", v)

result = self.cursor.execute("select s from t1").fetchone()[0]
Expand Down
12 changes: 12 additions & 0 deletions tests2/sqlservertests.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,18 @@ def test_fast_executemany_to_local_temp_table(self):
self.cursor.executemany(sql, params)
self.assertEqual(self.cursor.execute("SELECT txt FROM #issue295").fetchval(), v)

def test_fast_executemany_to_datetime2(self):
if self.handle_known_issues_for('freetds', print_reminder=True):
warn('FREETDS_KNOWN_ISSUE - test_fast_executemany_to_datetime2: test cancelled.')
return
v = datetime(2019, 3, 12, 10, 0, 0, 123456)
self.cursor.execute("CREATE TABLE ##issue540 (dt2 DATETIME2(2))")
sql = "INSERT INTO ##issue540 (dt2) VALUES (?)"
params = [(v,)]
self.cursor.fast_executemany = True
self.cursor.executemany(sql, params)
self.assertEqual(self.cursor.execute("SELECT CAST(dt2 AS VARCHAR) FROM ##issue540").fetchval(), '2019-03-12 10:00:00.12')

#
# binary
#
Expand Down
10 changes: 7 additions & 3 deletions tests2/testutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,13 @@ def print_library_info(cnxn):
cursor = cnxn.cursor()
for typename in ['VARCHAR', 'WVARCHAR', 'BINARY']:
t = getattr(pyodbc, 'SQL_' + typename)
cursor.getTypeInfo(t)
row = cursor.fetchone()
print('Max %s = %s' % (typename, row and row[2] or '(not supported)'))
try:
cursor.getTypeInfo(t)
except pyodbc.Error as e:
print('Max %s = (not supported)' % (typename, ))
else:
row = cursor.fetchone()
print('Max %s = %s' % (typename, row and row[2] or '(not supported)'))

if platform.system() == 'Windows':
print(' %s' % ' '.join([s for s in platform.win32_ver() if s]))
Expand Down
13 changes: 6 additions & 7 deletions tests3/mysqltests.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,18 @@
usage = """\
usage: %prog [options] connection_string

Unit tests for MySQL. To use, pass a connection string as the parameter. The tests will create and drop tables t1 and
t2 as necessary. The default installation of mysql allows you to connect locally with no password and already contains
a 'test' database, so you can probably use the following. (Update the driver name as appropriate.)

./mysqltests DRIVER={MySQL};DATABASE=test
Unit tests for MySQL. To use, pass a connection string as the parameter.
The tests will create and drop tables t1 and t2 as necessary.

These tests use the pyodbc library from the build directory, not the version installed in your
Python directories. You must run `python setup.py build` before running these tests.

You can also put the connection string into a tmp/setup.cfg file like so:

[mysqltests]
connection-string=DRIVER={MySQL};SERVER=localhost;UID=uid;PWD=pwd;DATABASE=db
connection-string=DRIVER=MySQL ODBC 8.0 Unicode Driver;charset=utf8mb4;SERVER=localhost;DATABASE=pyodbc;UID=root;PWD=rootpw

Note: Include charset=utf8mb4 in the connection string so the high-Unicode tests won't fail.
"""

import sys, os, re
Expand Down Expand Up @@ -722,7 +721,7 @@ def test_emoticons(self):

v = "x \U0001F31C z"

self.cursor.execute("create table t1(s varchar(100))")
self.cursor.execute("CREATE TABLE t1(s varchar(100)) DEFAULT CHARSET=utf8mb4")
self.cursor.execute("insert into t1 values (?)", v)

result = self.cursor.execute("select s from t1").fetchone()[0]
Expand Down
12 changes: 12 additions & 0 deletions tests3/sqlservertests.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,18 @@ def test_fast_executemany_to_local_temp_table(self):
self.cursor.executemany(sql, params)
self.assertEqual(self.cursor.execute("SELECT txt FROM #issue295").fetchval(), v)

def test_fast_executemany_to_datetime2(self):
if self.handle_known_issues_for('freetds', print_reminder=True):
warn('FREETDS_KNOWN_ISSUE - test_fast_executemany_to_datetime2: test cancelled.')
return
v = datetime(2019, 3, 12, 10, 0, 0, 123456)
self.cursor.execute("CREATE TABLE ##issue540 (dt2 DATETIME2(2))")
sql = "INSERT INTO ##issue540 (dt2) VALUES (?)"
params = [(v,)]
self.cursor.fast_executemany = True
self.cursor.executemany(sql, params)
self.assertEqual(self.cursor.execute("SELECT CAST(dt2 AS VARCHAR) FROM ##issue540").fetchval(), '2019-03-12 10:00:00.12')

#
# binary
#
Expand Down