[egenix-users] Max length of (N)VARCHAR; min length of TEXT
Charles Bearden
Charles.F.Bearden at uth.tmc.edu
Wed Aug 18 16:37:52 CEST 2004
> -----Original Message-----
> From: M.-A. Lemburg [mailto:mal at egenix.com]
> Sent: Wednesday, August 18, 2004 7:13 AM
>
> Charles Bearden wrote:
> > Egenix-mx-commercial-2.0.6, libiodbc-3.51.2, and freetds-0.62.4 on
RH 9,
> > and egenix-mx-commercial-2.0.6 with Windows ODBC driver on WinXP,
both
> > talking to MS SQL Server 2000.
> >
> > When I try to insert strings longer than 255 characters into a MS
SQL
> > column defined as nvarchar(1024) through FreeTDS/iODBC from Linux, I
get
> > the following exception:
> >
> > Traceback (most recent call last):
> > File "./convtest.py", line 32, in ?
> > try: mx_cur.execute(ins, t)
> > mxODBC.OperationalError: ('', 260, "[FreeTDS][SQL Server]Disallowed
> > implicit conversion from data type text to data type nvarchar, table
> > 'IfSH_Test.dbo.pmCite', column 'ArticleTitle'. Use the CONVERT
function
> > to run this query.", 4579)
>
> The problem here is that FreeTDS tries to convert the Python
> 8-bit string input into a UTF-16 string. Obviously SQL Server
> doesn't want to do this conversion implicitly (probably because
> it doesn't know the encoding of the input string).
>
> Have you tried passing in the data as Unicode string ?
Thanks! That's extremely helpful to know. I don't think I have tried
passing in a Unicode string, or if I have there was some other place in
the program where it caused a UnicodeDecodeError or something. I may
retool the script to implement your suggestion.
The solution I came up with is a bit more kludgy. I wrote a function
that takes the data from the '.description' attribute of the source
database cursor, after executing a 'select * from <tablename> limit 1'
to populate it correctly, in order to build an INSERT statmemt with
'CONVERT(?)' instead of simply '?' for those columns that might have
data longer than 255 bytes:
------------------------------------------------------
def mkIns(tname, cur):
cur.execute('select * from %s limit 1' % (tname,))
colinfo_lst = map(lambda t: (t[0],t[1],t[3]), cur.description)
clist = [] ; phlist = [] ## column name list and placeholder list
for colinfo in colinfo_lst:
colname, coltype, colsize = colinfo
clist.append(colname)
#-- 1043 is the PostgreSQL object id for type VARCHAR
if coltype == 1043 and colsize > 250:
phlist.append('CONVERT(nvarchar, ?)')
else:
phlist.append('?')
#-- put it all together and return
return '''
INSERT INTO %s
(%s)
VALUES
(%s)
''' % (tname, ', '.join(clist), ', '.join(phlist))
------------------------------------------------------
It's an ugly hack, but it seems to do the trick.
Thanks again for your response.
Chuck
More information about the egenix-users
mailing list