Skip to content

Commit

Permalink
implement a bunch more db -> python converters (getting so close to c…
Browse files Browse the repository at this point in the history
…ompletion)
  • Loading branch information
damoxc committed Mar 3, 2010
1 parent f8fc77c commit 9cead17
Show file tree
Hide file tree
Showing 4 changed files with 210 additions and 27 deletions.
150 changes: 141 additions & 9 deletions _mssql.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ This is an effort to convert the pymssql low-level C module to Cython.

DEF PYMSSQL_DEBUG = 0

import sys
import decimal
import datetime
from sqlfront cimport *
from stdio cimport fprintf, sprintf, FILE
from stdlib cimport strlen

cdef extern int rmv_lcl(char *, char *, size_t)

cdef extern from "stdio.h" nogil:
cdef FILE *stderr
Expand All @@ -21,6 +24,8 @@ cdef int _mssql_last_msg_severity = 0
cdef int _mssql_last_msg_state = 0
cdef char *_mssql_last_msg_str = ""

cdef _decimal_context

# List to store the connection objects in
cdef list connection_object_list = list()

Expand Down Expand Up @@ -96,7 +101,7 @@ login_timeout = 60
min_error_severity = 6

# Buffer size for large numbers
cdef int NUMERIC_BUF_SZ = 45
DEF NUMERIC_BUF_SZ = 45

###################
## Error Handler ##
Expand Down Expand Up @@ -377,19 +382,75 @@ cdef class MSSQLConnection:
self._connected = 0

cdef convert_db_value(self, BYTE *data, int type, int length):
#cdef char buf[NUMERIC_BUF_SZ] # buffer in which we store text rep of bug nums
cdef char buf[NUMERIC_BUF_SZ] # buffer in which we store text rep of bug nums
cdef double ddata
cdef int len
cdef long intdata
cdef long prevPrecision
cdef BYTE precision
cdef DBDATEREC di
cdef DBDATETIME dt
cdef DBCOL dbcol

if type == SQLBIT:
intdata = <int><DBBIT *>data
return bool(intdata)
return bool(<int>(<DBBIT *>data)[0])

elif type == SQLINT1:
return int(<int>(<DBTINYINT *>data)[0])

elif type == SQLINT2:
return int(<int>(<DBSMALLINT *>data)[0])

elif type == SQLINT4:
return int(<int>(<DBINT *>data)[0])

elif type == SQLINT8:
return long(<long>(<long *>data)[0])

elif type == SQLFLT4:
return float(<float>(<DBREAL *>data)[0])

elif type == SQLFLT8:
return float(<float>(<DBFLT8 *>data)[0])

elif type in (SQLMONEY, SQLMONEY4, SQLNUMERIC, SQLDECIMAL):
dbcol.SizeOfStruct = sizeof(dbcol)

if type in (SQLMONEY, SQLMONEY4):
precision = 4
else:
precision = dbcol.Scale

prevPrecision = _decimal_context.prec
_decimal_context.prec = precision

length = dbconvert(self.dbproc, type, data, -1, SQLCHAR,
<BYTE *>buf, NUMERIC_BUF_SZ)

len = rmv_lcl(buf, buf, NUMERIC_BUF_SZ)

if not len:
raise MSSQLDriverException('Could not remove locale formatting')
return decimal.Decimal(str(buf))

elif type == SQLDATETIM4:
dbconvert(self.dbproc, type, data, -1, SQLDATETIME,
<BYTE *>&dt, -1)
dbdatecrack(self.dbproc, &di, <DBDATETIME *><BYTE *>&dt)
return datetime.datetime(di.year, di.month, di.day,
di.hour, di.minute, di.second, di.millisecond * 1000)

elif type == SQLDATETIME:
dbdatecrack(self.dbproc, &di, <DBDATETIME *>data)
return datetime.datetime(di.year, di.month, di.day,
di.hour, di.minute, di.second, di.millisecond * 1000)

elif type in (SQLVARCHAR, SQLCHAR, SQLTEXT):
if self.charset:
return str(<char *>data).decode(self.charset)
else:
return str(<char *>data)
else:
return str(<char *>data)

def execute_non_query(self, query_string, params=None):
"""
Expand Down Expand Up @@ -765,9 +826,74 @@ cdef int get_type(DBPROCESS *dbproc, int row_info, int col) nogil:
cdef int get_length(DBPROCESS *dbproc, int row_info, int col) nogil:
return dbdatlen(dbproc, col) if row_info == REG_ROW else dbadlen(dbproc, row_info, col)

####################################
## Quoting Functions ##
####################################

######################
## Helper Functions ##
######################
"""cdef int remove_locale(char *s, char *buf, size_t buflen):
cdef char c, lastsep
cdef size_t i, length, n
for i in xrange(buflen + 1):
c = s[i]
if c in ('.', ','):
lastsep = c
n = 0
for i in xrange(buflen + 1):
if (c >= '0' and c <= '9') or c in ('-', '+'):
buf[n] = s[i]
n += 1
elif (s[i] == lastsep):
buf[n] = s[i]
n += 1
print str(buf)
return 0
cdef size_t l, pi, bi
if b == <char *>NULL:
return 0
if s == <char *>NULL:
b[0] = 0
return 0
pi = 0
# Find the last separator and length of s
c = p[pi]
while c:
if c == '.' or c == ',':
lastsep = p
pi += 1
c = p[pi]
l = p - s
if buflen < l:
return 0
pi = 0
bi = 0
# Copy the number, skipping all but the last separator and all other
# chars.
p = s
c = p[pi]
while c:
bi += 1
if (c >= '0' and c <= '9') or (c == '-' or c == '+'):
b[bi] = c
elif p == lastsep:
b[bi] = '.'
pi += 1
c = p[pi]
b[0] = 0
return <int>(b - buf)"""

cdef int get_api_coltype(int coltype):
if coltype in (SQLBIT, SQLINT1, SQLINT2, SQLINT4, SQLINT8, SQLINTN,
SQLFLT4, SQLFLT8, SQLFLTN):
Expand All @@ -782,6 +908,9 @@ cdef int get_api_coltype(int coltype):
else:
return BINARY

#######################
## Quoting Functions ##
#######################
cdef _quote_simple_value(value):

if value == None:
Expand Down Expand Up @@ -863,6 +992,7 @@ def quote_data(data):
return _quote_data(data)

cdef void init_mssql():
global _decimal_context
cdef RETCODE rtc
rtc = dbinit()
if rtc == FAIL:
Expand All @@ -871,4 +1001,6 @@ cdef void init_mssql():
dberrhandle(err_handler)
dbmsghandle(msg_handler)

_decimal_context = decimal.getcontext()

init_mssql()
38 changes: 38 additions & 0 deletions helperlib.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include <stdio.h>
#include <stdlib.h>

int rmv_lcl(char *s, char *buf, size_t buflen) {
char c, *lastsep = NULL, *p = s, *b = buf;
size_t l;

if (b == (char *)NULL) return 0;

if (s == (char *)NULL) {
*b = 0;
return 0;
}

/* find last separator and length of s */
while ((c = *p)) {
if ((c == '.') || (c == ',')) lastsep = p;
++p;
}

l = p - s; // strlen(s)
if (buflen < l) return 0;

/* copy the number skipping all but last separator and all other chars */
p = s;
while ((c = *p)) {
if (((c >= '0') && (c <= '9')) || (c == '-') || (c == '+'))
*b++ = c;
else if (p == lastsep)
*b++ = '.';
++p;
}

*b = 0;

// cast to int to make x64 happy, can do it because numbers are not so very long
return (int)(b - buf); // return new len
}
7 changes: 6 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
from setuptools import setup, Extension
from Cython.Distutils import build_ext

_extra_compile_args = [
'-DMSDBLIB'
]

if sys.platform == 'win32':
print ('ERROR: This version of pymssql is not support on windows')
sys.exit(1)
Expand Down Expand Up @@ -44,7 +48,8 @@
url = 'http://pymssql.sourceforge.net',
py_modules = ['pymssql'],
cmdclass = {'build_ext': build_ext},
ext_modules = [Extension('_mssql', ['_mssql.pyx'],
ext_modules = [Extension('_mssql', ['helperlib.c', '_mssql.pyx'],
extra_compile_args = _extra_compile_args,
include_dirs = include_dirs,
library_dirs = library_dirs,
libraries = libraries)],
Expand Down
42 changes: 25 additions & 17 deletions sqlfront.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ cdef extern from "sqlfront.h":
## Type Definitions ##
cdef struct tds_dblib_dbprocess:
pass
cdef struct tds_sysdep_real32_type:
pass
cdef struct tds_sysdep_real64_type:
pass

ctypedef tds_dblib_dbprocess DBPROCESS
cdef struct tds_dblib_loginrec:
pass
Expand All @@ -20,17 +25,23 @@ cdef extern from "sqlfront.h":
ctypedef int DBBIT
ctypedef unsigned char DBBOOL
ctypedef char DBCHAR
cdef struct DBDATETIME4:
DBUSMALLINT days
DBUSMALLINT minutes
ctypedef int DBINT
ctypedef tds_sysdep_real32_type DBREAL
ctypedef tds_sysdep_real64_type DBFLT8
cdef struct DBMONEY:
DBINT mnyhigh
unsigned int mnylow
cdef struct DBMONEY4:
DBINT mny4
ctypedef short int DBSMALLINT

ctypedef struct DBDATETIME:
DBINT dtdays
DBINT dttime
ctypedef struct DBDATETIME4:
DBUSMALLINT days
DBUSMALLINT minutes

## Constants ##
int FAIL
int SUCCEED
Expand Down Expand Up @@ -309,9 +320,6 @@ cdef extern from "sqlfront.h":
DBINT scale
ctypedef dbtypeinfo DBTYPEINFO
RETCODE bcp_colfmt_ps(DBPROCESS *, int, int, int, DBINT, BYTE *, int, int, DBTYPEINFO *)
cdef struct DBDATETIME:
DBINT dtdays
DBINT dttime
DBINT dbdatepart(DBPROCESS *, int, DBDATETIME *)
ctypedef int STATUS
STATUS dbsetrow(DBPROCESS *, DBINT)
Expand All @@ -325,16 +333,16 @@ cdef extern from "sqlfront.h":
STATUS dbrowtype(DBPROCESS *)
int dbspid(DBPROCESS *)
cdef struct dbdaterec:
DBINT dateyear
DBINT datemonth
DBINT datedmonth
DBINT datedyear
DBINT datedweek
DBINT datehour
DBINT dateminute
DBINT datesecond
DBINT datemsecond
DBINT datetzone
DBINT year
DBINT month
DBINT day
DBINT dayofyear
DBINT weekday
DBINT hour
DBINT minute
DBINT second
DBINT millisecond
DBINT tzone
ctypedef dbdaterec DBDATEREC
RETCODE dbdatecrack(DBPROCESS *, DBDATEREC *, DBDATETIME *)
RETCODE remove_xact(DBPROCESS *, DBINT, int)
Expand Down Expand Up @@ -598,7 +606,7 @@ cdef extern from "sqlfront.h":
CI_ALTERNATE = 2
CI_CURSOR = 3
ctypedef int BOOL
cdef struct DBCOL:
ctypedef struct DBCOL:
DBINT SizeOfStruct
DBCHAR * Name
DBCHAR * ActualName
Expand Down

0 comments on commit 9cead17

Please sign in to comment.