无法使用pyodbc在Django中加载长度超过19455个字符的文本字段的记录

时间:2012-11-19 20:35:07

标签: sql-server django pyodbc django-pyodbc

我有一个类似的Note模型(这是从传统的MS SQL Server数据库中提取的,因此大部分记录都不是由Django创建的):

class Note(models.Model):
    id = models.AutoField(primary_key=True, db_column="note_id")
    content = models.TextField(db_column="note_content", blank=True, null=True)
    date_created = models.DateTimeField(db_column="date_created", auto_now_add=True)
    date_modified = models.DateTimeField(db_column="date_modified", null=True, blank=True)
    date_removed = models.DateTimeField(db_column="date_deleted", null=True, blank=True)

在某些记录上运行.get,即使它们存在于数据库中,也会返回DoesNotExist

当MS SQL Server TEXT(如,CREATE TABLE Foo ( content TEXT null))字段中的内容长度超过一定数量时,会发生这种情况;特别是19455个字符。

这是运作中的样子:

>>> note = Note.objects.get(pk=1)
>>> note.content = "x" * 19455
>>> note.save()
>>> note = Note.objects.get(pk=1)
>>> note.content = "x" * 19456
>>> note.save()
>>> note = Note.objects.get(pk=1)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/path/to/django/db/models/query.py", line 366, in get
    % self.model._meta.object_name)
DoesNotExist: Note matching query does not exist.

我正在使用FreeTDS,文本大小设置为2147483647,其中出现是我正在使用的MS SQL Server版本的上限。

根据这个other question on truncation,你应该在前面加上SET TEXTSIZE n指令,其中n是一个以字节为单位的值,这将解决数据被截断的问题。所以我想知道在我的情况下是否发生了这种情况,以及它是否会解决它。

所以,我继续编写了一些只使用游标和SET TEXTSIZE命令的代码。

首先,我们来看看应该在记录中的内容:

  
    
      

print“长度:%d;最后40个字符:%s”%(len(note.content),note.content [-40:])           长度:19456;最后40个字符:rVEF1cCJeRaTtcdkXMqqQUxEVLZapMGVGSxMfJ2T

    
  

现在我们循环了。每次我们增加TEXTSIZE设置并显示记录(如果有人喜欢)。我们还显示返回记录字段的长度和最后10个字符。

>>> for xx in xrange(19450, 19460):
...     cursor = connection.cursor()
...     try:
...         qrys = 'SET TEXTSIZE %d SELECT [Notes].[note_id], [Notes].[note_content] FROM [Notes] WHERE [Notes].[note_id] = 1' % xx
...         print qrys
...         qry = cursor.execute(qrys)
...         record = qry.fetchone()
...         if record:
...             record_id, record_content = record
...             print record_id, len(record_content), record_content[-10:]
...         else:
...             print "No record found after TEXTSIZE set to %d" % xx
...             break
...     except Exception, inst:
...         print "Error: %s (%s)" % (inst, type(inst))
...         break
...     finally:
...         cursor.close()
... 
SET TEXTSIZE 19450 SELECT [Notes].[note_id], [Notes].[note_content] FROM [Notes] WHERE [Notes].[note_id] = 1
1 19450 VLZapMGVGS
SET TEXTSIZE 19451 SELECT [Notes].[note_id], [Notes].[note_content] FROM [Notes] WHERE [Notes].[note_id] = 1
1 19451 LZapMGVGSx
SET TEXTSIZE 19452 SELECT [Notes].[note_id], [Notes].[note_content] FROM [Notes] WHERE [Notes].[note_id] = 1
1 19452 ZapMGVGSxM
SET TEXTSIZE 19453 SELECT [Notes].[note_id], [Notes].[note_content] FROM [Notes] WHERE [Notes].[note_id] = 1
1 19453 apMGVGSxMf
SET TEXTSIZE 19454 SELECT [Notes].[note_id], [Notes].[note_content] FROM [Notes] WHERE [Notes].[note_id] = 1
1 19454 pMGVGSxMfJ
SET TEXTSIZE 19455 SELECT [Notes].[note_id], [Notes].[note_content] FROM [Notes] WHERE [Notes].[note_id] = 1
1 19455 MGVGSxMfJ2
SET TEXTSIZE 19456 SELECT [Notes].[note_id], [Notes].[note_content] FROM [Notes] WHERE [Notes].[note_id] = 1
No record found after TEXTSIZE set to 19456
>>> 

因此,只要我们尝试检索TEXTSIZE设置为大于19456的数字的记录,就不会返回任何记录。而且你会注意到字符串的最后10个字符与减去上面的字符串匹配,因为它太短而错过了它们。例如,对于找到的最后一条记录,最后10个字符为MGVGSxMfJ2。它缺少真实记录中的T,因为19455的TEXTSIZE比所讨论的字段长度少一个。

所以现在我当然想知道,发生了什么?我是否可以做进一步的故障排除以确定这是django-pyodbc,pyodbc还是FreeTDS的问题?它可能也可能是SQL Server,但直接在Server Management Studio中运行SET TEXTSIZE 19456 SELECT [Notes].[note_id], [Notes].[note_content] FROM [Notes] WHERE [Notes].[note_id] = 1似乎可以正常工作并返回正确数量的字符。

另请注意,保存有效

>>> note.content = (note.content * 10)[:65536] # 65536 is max length allowed for TEXT, apparently
>>> len(note.content)
65536
>>> note.save()
>>> cursor = connection.cursor()
>>> qry = cursor.execute( 'SELECT [Notes].[note_id], DATALENGTH([Notes].[note_content]) FROM [Notes] WHERE [Notes].[note_id] = 1')
>>> record = qry.fetchone()
>>> record
(1, 65536)
>>> 

0 个答案:

没有答案