1

我有一个这样的 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在某些记录上运行 a会返回 a 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 版本的上限。

根据this other question on truncation,您应该在指令前面加上SET TEXTSIZE nn 是以字节为单位的值,这将解决数据被截断的问题。所以我想知道这是否发生在我的案例中,以及它是否会解决它。

因此,我继续编写了一些仅使用光标和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,但SET TEXTSIZE 19456 SELECT [Notes].[note_id], [Notes].[note_content] FROM [Notes] WHERE [Notes].[note_id] = 1直接在 Server Management Studio 中运行似乎可以正常工作并返回正确数量的字符。

另请注意,保存工作

>>> 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)
>>> 
4

0 回答 0