Code

Ticket #399: bigint-patch-2009-12-09.diff

File bigint-patch-2009-12-09.diff, 12.0 KB (added by ikelly, 5 years ago)

Added Oracle introspection and test

Line 
1Index: django/db/models/fields/__init__.py
2===================================================================
3--- django/db/models/fields/__init__.py (revision 11807)
4+++ django/db/models/fields/__init__.py (working copy)
5@@ -714,6 +714,25 @@
6         defaults.update(kwargs)
7         return super(IntegerField, self).formfield(**defaults)
8 
9+class BigIntegerField(IntegerField):
10+    MAX_BIGINT = 9223372036854775807
11+    empty_strings_allowed = False
12+    def get_internal_type(self):
13+        return "BigIntegerField"
14+
15+    def get_db_prep_save(self, value):
16+        value = long(value)
17+        if value > BigIntegerField.MAX_BIGINT or value < -BigIntegerField.MAX_BIGINT - 1:
18+            raise ValueError("Value is to small/large to fit this field")
19+        return super(BigIntegerField, self).get_db_prep_save(value)
20+
21+    def formfield(self, **kwargs):
22+        defaults = {'min_value': -BigIntegerField.MAX_BIGINT - 1,
23+                    'max_value': BigIntegerField.MAX_BIGINT}
24+        defaults.update(kwargs)
25+        return super(BigIntegerField, self).formfield(**defaults)
26+
27+
28 class IPAddressField(Field):
29     empty_strings_allowed = False
30     def __init__(self, *args, **kwargs):
31Index: django/db/backends/postgresql/introspection.py
32===================================================================
33--- django/db/backends/postgresql/introspection.py      (revision 11807)
34+++ django/db/backends/postgresql/introspection.py      (working copy)
35@@ -4,6 +4,7 @@
36     # Maps type codes to Django Field types.
37     data_types_reverse = {
38         16: 'BooleanField',
39+        20: 'BigIntegerField',
40         21: 'SmallIntegerField',
41         23: 'IntegerField',
42         25: 'TextField',
43Index: django/db/backends/postgresql/creation.py
44===================================================================
45--- django/db/backends/postgresql/creation.py   (revision 11807)
46+++ django/db/backends/postgresql/creation.py   (working copy)
47@@ -18,6 +18,7 @@
48         'FilePathField':     'varchar(%(max_length)s)',
49         'FloatField':        'double precision',
50         'IntegerField':      'integer',
51+        'BigIntegerField':   'bigint',
52         'IPAddressField':    'inet',
53         'NullBooleanField':  'boolean',
54         'OneToOneField':     'integer',
55Index: django/db/backends/sqlite3/introspection.py
56===================================================================
57--- django/db/backends/sqlite3/introspection.py (revision 11807)
58+++ django/db/backends/sqlite3/introspection.py (working copy)
59@@ -16,6 +16,7 @@
60         'smallinteger': 'SmallIntegerField',
61         'int': 'IntegerField',
62         'integer': 'IntegerField',
63+        'bigint': 'BigIntegerField',
64         'integer unsigned': 'PositiveIntegerField',
65         'decimal': 'DecimalField',
66         'real': 'FloatField',
67Index: django/db/backends/sqlite3/creation.py
68===================================================================
69--- django/db/backends/sqlite3/creation.py      (revision 11807)
70+++ django/db/backends/sqlite3/creation.py      (working copy)
71@@ -19,6 +19,7 @@
72         'FilePathField':                'varchar(%(max_length)s)',
73         'FloatField':                   'real',
74         'IntegerField':                 'integer',
75+        'BigIntegerField':                 'bigint',
76         'IPAddressField':               'char(15)',
77         'NullBooleanField':             'bool',
78         'OneToOneField':                'integer',
79Index: django/db/backends/mysql/introspection.py
80===================================================================
81--- django/db/backends/mysql/introspection.py   (revision 11807)
82+++ django/db/backends/mysql/introspection.py   (working copy)
83@@ -17,7 +17,7 @@
84         FIELD_TYPE.FLOAT: 'FloatField',
85         FIELD_TYPE.INT24: 'IntegerField',
86         FIELD_TYPE.LONG: 'IntegerField',
87-        FIELD_TYPE.LONGLONG: 'IntegerField',
88+        FIELD_TYPE.LONGLONG: 'BigIntegerField',
89         FIELD_TYPE.SHORT: 'IntegerField',
90         FIELD_TYPE.STRING: 'CharField',
91         FIELD_TYPE.TIMESTAMP: 'DateTimeField',
92Index: django/db/backends/mysql/creation.py
93===================================================================
94--- django/db/backends/mysql/creation.py        (revision 11807)
95+++ django/db/backends/mysql/creation.py        (working copy)
96@@ -18,6 +18,7 @@
97         'FilePathField':     'varchar(%(max_length)s)',
98         'FloatField':        'double precision',
99         'IntegerField':      'integer',
100+        'BigIntegerField':   'bigint',
101         'IPAddressField':    'char(15)',
102         'NullBooleanField':  'bool',
103         'OneToOneField':     'integer',
104@@ -63,4 +64,4 @@
105                 field.rel.to._meta.db_table, field.rel.to._meta.pk.column)
106             ]
107         return table_output, deferred
108-       
109\ No newline at end of file
110+       
111Index: django/db/backends/oracle/introspection.py
112===================================================================
113--- django/db/backends/oracle/introspection.py  (revision 11807)
114+++ django/db/backends/oracle/introspection.py  (working copy)
115@@ -29,7 +29,10 @@
116     def get_field_type(self, data_type, description):
117         # If it's a NUMBER with scale == 0, consider it an IntegerField
118         if data_type == cx_Oracle.NUMBER and description[5] == 0:
119-            return 'IntegerField'
120+            if description[4] > 11:
121+                return 'BigIntegerField'
122+            else:
123+                return 'IntegerField'
124         else:
125             return super(DatabaseIntrospection, self).get_field_type(
126                 data_type, description)
127Index: django/db/backends/oracle/creation.py
128===================================================================
129--- django/db/backends/oracle/creation.py       (revision 11807)
130+++ django/db/backends/oracle/creation.py       (working copy)
131@@ -27,6 +27,7 @@
132         'FilePathField':                'NVARCHAR2(%(max_length)s)',
133         'FloatField':                   'DOUBLE PRECISION',
134         'IntegerField':                 'NUMBER(11)',
135+        'BigIntegerField':              'NUMBER(19)',
136         'IPAddressField':               'VARCHAR2(15)',
137         'NullBooleanField':             'NUMBER(1) CHECK ((%(qn_column)s IN (0,1)) OR (%(qn_column)s IS NULL))',
138         'OneToOneField':                'NUMBER(11)',
139Index: django/contrib/admin/options.py
140===================================================================
141--- django/contrib/admin/options.py     (revision 11807)
142+++ django/contrib/admin/options.py     (working copy)
143@@ -42,14 +42,15 @@
144         'form_class': forms.SplitDateTimeField,
145         'widget': widgets.AdminSplitDateTime
146     },
147-    models.DateField:    {'widget': widgets.AdminDateWidget},
148-    models.TimeField:    {'widget': widgets.AdminTimeWidget},
149-    models.TextField:    {'widget': widgets.AdminTextareaWidget},
150-    models.URLField:     {'widget': widgets.AdminURLFieldWidget},
151-    models.IntegerField: {'widget': widgets.AdminIntegerFieldWidget},
152-    models.CharField:    {'widget': widgets.AdminTextInputWidget},
153-    models.ImageField:   {'widget': widgets.AdminFileWidget},
154-    models.FileField:    {'widget': widgets.AdminFileWidget},
155+    models.DateField:       {'widget': widgets.AdminDateWidget},
156+    models.TimeField:       {'widget': widgets.AdminTimeWidget},
157+    models.TextField:       {'widget': widgets.AdminTextareaWidget},
158+    models.URLField:        {'widget': widgets.AdminURLFieldWidget},
159+    models.IntegerField:    {'widget': widgets.AdminIntegerFieldWidget},
160+    models.BigIntegerField: {'widget': widgets.AdminIntegerFieldWidget},
161+    models.CharField:       {'widget': widgets.AdminTextInputWidget},
162+    models.ImageField:      {'widget': widgets.AdminFileWidget},
163+    models.FileField:       {'widget': widgets.AdminFileWidget},
164 }
165 
166 
167Index: tests/regressiontests/model_fields/tests.py
168===================================================================
169--- tests/regressiontests/model_fields/tests.py (revision 11807)
170+++ tests/regressiontests/model_fields/tests.py (working copy)
171@@ -6,7 +6,7 @@
172 from django.db import models
173 from django.core.exceptions import ValidationError
174 
175-from models import Foo, Bar, Whiz, BigD, BigS, Image
176+from models import Foo, Bar, Whiz, BigD, BigS, Image, BigInt
177 
178 try:
179     from decimal import Decimal
180@@ -144,3 +144,30 @@
181         bs = BigS.objects.create(s = 'slug'*50)
182         bs = BigS.objects.get(pk=bs.pk)
183         self.assertEqual(bs.s, 'slug'*50)
184+
185+class BigIntegerFieldTests(django.test.TestCase):
186+    def test_existence(self):
187+        self.assertEqual(len(BigInt.objects.all()), 0)
188+
189+    def test_limits(self):
190+        self.assertRaises(ValueError, BigInt(value = 9223372036854775809111111111111111111).save)
191+        self.assertRaises(ValueError, BigInt(value = -9223372036854775809111111111111111111).save)
192+        self.assertRaises(ValueError, BigInt(value = 9223372036854775808).save)
193+        self.assertRaises(ValueError, BigInt(value = -9223372036854775809).save)
194+        self.assertEqual(BigInt(value = -9223372036854775808).save(), None)
195+        self.assertEqual(BigInt(value = 9223372036854775807).save(), None)
196+        self.assertEqual(BigInt(value = 0).save(), None)
197+
198+    def test_types(self):
199+        b = BigInt(value = 0)
200+        self.assertTrue(isinstance(b.value, (int, long)))
201+        b.save()
202+        self.assertTrue(isinstance(b.value, (int, long)))
203+        b = BigInt.objects.all()[0]
204+        self.assertTrue(isinstance(b.value, (int, long)))
205+
206+    def test_coercing(self):
207+        b = BigInt(value = 10)
208+        b.save()
209+        self.assertEqual(b.value, 10)
210+        self.assertEqual(unicode(b), unicode(10))
211Index: tests/regressiontests/model_fields/models.py
212===================================================================
213--- tests/regressiontests/model_fields/models.py        (revision 11807)
214+++ tests/regressiontests/model_fields/models.py        (working copy)
215@@ -51,7 +51,12 @@
216 class BigS(models.Model):
217     s = models.SlugField(max_length=255)
218 
219+class BigInt(models.Model):
220+    value = models.BigIntegerField()
221 
222+    def __unicode__(self):
223+        return unicode(self.value)
224+
225 ###############################################################################
226 # ImageField
227 
228Index: tests/regressiontests/introspection/tests.py
229===================================================================
230--- tests/regressiontests/introspection/tests.py        (revision 11807)
231+++ tests/regressiontests/introspection/tests.py        (working copy)
232@@ -77,7 +77,7 @@
233         cursor = connection.cursor()
234         desc = connection.introspection.get_table_description(cursor, Reporter._meta.db_table)
235         self.assertEqual([datatype(r[1], r) for r in desc],
236-                          ['IntegerField', 'CharField', 'CharField', 'CharField'])
237+                          ['IntegerField', 'CharField', 'CharField', 'CharField', 'BigIntegerField'])
238 
239     # Regression test for #9991 - 'real' types in postgres
240     if settings.DATABASE_ENGINE.startswith('postgresql'):
241Index: tests/regressiontests/introspection/models.py
242===================================================================
243--- tests/regressiontests/introspection/models.py       (revision 11807)
244+++ tests/regressiontests/introspection/models.py       (working copy)
245@@ -4,6 +4,7 @@
246     first_name = models.CharField(max_length=30)
247     last_name = models.CharField(max_length=30)
248     email = models.EmailField()
249+    facebook_user_id = models.BigIntegerField()
250 
251     def __unicode__(self):
252         return u"%s %s" % (self.first_name, self.last_name)
253@@ -17,4 +18,4 @@
254         return self.headline
255 
256     class Meta:
257-        ordering = ('headline',)
258\ No newline at end of file
259+        ordering = ('headline',)
260Index: docs/ref/models/fields.txt
261===================================================================
262--- docs/ref/models/fields.txt  (revision 11807)
263+++ docs/ref/models/fields.txt  (working copy)
264@@ -641,6 +641,18 @@
265 An integer. The admin represents this as an ``<input type="text">`` (a
266 single-line input).
267 
268+``bigintegerfield``
269+~~~~~~~~~~~~~~~~
270+
271+.. class:: BigIntegerField([**options])
272+
273+A big integer. The admin represents this as an ``<input type="text">``
274+(a single-line input).
275+
276+a 64 bit type like an ``integerfield``, except that it fits numbers from
277+-9223372036854775808 to 9223372036854775807
278+
279+
280 ``IPAddressField``
281 ------------------
282