Ticket #5052: db2_9.patch

File db2_9.patch, 41.3 KB (added by Koen Biermans <koen.biermans@…>, 8 years ago)

DB2 backend

Line 
1=== django/db/models/query.py
2==================================================================
3--- django/db/models/query.py   (/local/django/db2_9)   (revision 3643)
4
5+++ django/db/models/query.py   (/mirror/django/trunk)  (revision 3643)
6
7@@ -963,10 +963,7 @@
8
9         # Does the name belong to a defined many-to-many field?
10         field = find_field(name, current_opts.many_to_many, False)
11         if field:
12-            if hasattr(backend, 'get_alias'):
13-                new_table = backend.get_alias(current_table, name)
14-            else:
15-                new_table = current_table + '__' + name
16+            new_table = current_table + '__' + name
17             new_opts = field.rel.to._meta
18             new_column = new_opts.pk.column
19 
20@@ -983,10 +980,7 @@
21
22         # Does the name belong to a reverse defined many-to-many field?
23         field = find_field(name, current_opts.get_all_related_many_to_many_objects(), True)
24         if field:
25-            if hasattr(backend, 'get_alias'):
26-                new_table = backend.get_alias(current_table, name)
27-            else:
28-                new_table = current_table + '__' + name
29+            new_table = current_table + '__' + name
30             new_opts = field.opts
31             new_column = new_opts.pk.column
32 
33@@ -1003,10 +997,7 @@
34
35         # Does the name belong to a one-to-many field?
36         field = find_field(name, current_opts.get_all_related_objects(), True)
37         if field:
38-            if hasattr(backend, 'get_alias'):
39-                new_table = backend.get_alias(current_table, name)
40-            else:
41-                new_table = current_table + '__' + name
42+            new_table = table + '__' + name
43             new_opts = field.opts
44             new_column = field.field.column
45             join_column = opts.pk.column
46@@ -1020,10 +1011,7 @@
47
48         field = find_field(name, current_opts.fields, False)
49         if field:
50             if field.rel: # One-to-One/Many-to-one field
51-                if hasattr(backend, 'get_alias'):
52-                    new_table = backend.get_alias(current_table, name)
53-                else:
54-                    new_table = current_table + '__' + name
55+                new_table = current_table + '__' + name
56                 new_opts = field.rel.to._meta
57                 new_column = new_opts.pk.column
58                 join_column = field.column
59=== django/db/backends/db2_9    (deleted directory)
60==================================================================
61=== django/db/backends/db2_9/base.py
62==================================================================
63--- django/db/backends/db2_9/base.py    (/local/django/db2_9)   (revision 3643)
64
65+++ django/db/backends/db2_9/base.py    (/mirror/django/trunk)  (revision 3643)
66
67@@ -1,624 +0,0 @@
68
69-"""
70
71-
72
73-IBM DB2 database backend for Django
74
75-
76
77-Requires PyDB2: http://sourceforge.net/projects/pydb2/
78
79-With this patch: http://sourceforge.net/tracker/index.php?func=detail&aid=1731609&group_id=67548&atid=518208
80
81-
82
83-Authors:
84
85-    Javier Villavicencio
86
87-    Koen Biermans
88
89-
90
91-Current issues:
92
93-    DB2 does not support deferring foreign key constraint checking.
94
95-        --> prereferencing does not work (e.g. in serializer_regress test)
96
97-
98
99-    No regex lookups.
100
101-   
102
103-    Character sets:
104
105-        put encoding/decoding into settings.DATABASE_CHARSET into the cursor code.
106
107-
108
109-    Floats as primary key does not work.
110
111-
112
113-Specific items:
114
115-    Connection:
116
117-        use a DNS for DATABASE_NAME
118
119-        this DNS can be system DNS or defined in db2cli.ini
120
121-            example for db2cli.ini:
122
123-                   [DNSNAME]
124
125-                Protocol=TCPIP
126
127-                Hostname=DB2HOST
128
129-                ServiceName=50001
130
131-                Database=DATABASE
132
133-                Port=50001
134
135-       
136
137-    Tables may be set in models.py with their schema: 'db_table = SCHEMA.TABLENAME'
138
139-    --> modified query.py to use get_alias function (no dots allowed in alias,
140
141-    default implementation uses db_table)
142
143-
144
145-    DB2 table names may be 128 characters, but constraint names are limited to 18.
146
147-    --> modified management.py to use get_max_constraint_length function
148
149-
150
151-"""
152
153-
154
155-from django.db.backends import util
156
157-import re
158
159-from django.utils.encoding import smart_str, force_unicode
160
161-
162
163-try:
164
165-       import DB2 as Database
166
167-except ImportError, e:
168
169-       from django.core.exceptions import ImproperlyConfigured
170
171-       raise ImproperlyConfigured, "Error loading DB2 python module: %s" % e
172
173-import datetime
174
175-from django.utils.datastructures import SortedDict
176
177-
178
179-Warning                        = Database.Warning
180
181-Error                  = Database.Error
182
183-InterfaceError         = Database.InterfaceError
184
185-DatabaseError          = Database.DatabaseError
186
187-DataError              = Database.DataError
188
189-OperationalError       = Database.OperationalError
190
191-IntegrityError         = Database.IntegrityError
192
193-InternalError          = Database.InternalError
194
195-ProgrammingError       = Database.ProgrammingError
196
197-NotSupportedError      = Database.NotSupportedError
198
199-
200
201-class Cursor(Database.Cursor):
202
203-    """Return a cursor.
204
205-    Doing some translation tricks here.
206
207-    Set the database charset in DATABASE_CHARSET setting"""
208
209-    try:
210
211-        charset = settings.DATABASE_CHARSET
212
213-    except:
214
215-        charset = 'iso-8859-1'
216
217-
218
219-    def _rewrite_args(self, query, params=None):
220
221-        # formatting parameters into charset
222
223-        if params is None:
224
225-            params = []
226
227-        else:
228
229-            params = self._format_params(params)
230
231-        # formatting query into charset
232
233-        query = smart_str(query, self.charset)
234
235-        a = query.find('CREATE')
236
237-        if a >= 0 and a < 10: # assuming this is a create command
238
239-            # DB2 doesn't want a 'lone' NULL (it's implied).
240
241-            query = re.sub('(?<!NOT) NULL', '', query)
242
243-            # DB2 does not like primary key definition without NOT NULL
244
245-            query = re.sub('(?<!NOT NULL) PRIMARY KEY', ' NOT NULL PRIMARY KEY',query)
246
247-        # PyDB2 uses '?' as the parameter style.
248
249-        query = query.replace("%s", "?")
250
251-        return query, params
252
253-
254
255-    def _format_params(self, params=None):
256
257-        return self._smart_str(params)
258
259-
260
261-    def execute(self, query, params=None):
262
263-        query, params = self._rewrite_args(query, params)
264
265-        try:
266
267-            return Database.Cursor.execute(self, query, params)
268
269-        except:
270
271-            print 'Error executing query %s with params %s' % (query, params)
272
273-            raise
274
275-
276
277-    def executemany(self, query, params=None):
278
279-        query, params = self._rewrite_args(query, params)
280
281-        return Database.Cursor.executemany(self, query, params)
282
283-
284
285-    def fetchone(self):
286
287-        # force results into unicode
288
289-        return self._force_unicode(Database.Cursor.fetchone(self))
290
291-
292
293-    def fetchmany(self, size=None):
294
295-        if size is None:
296
297-            size = self.arraysize
298
299-        # force results into unicode
300
301-        return self._force_unicode(Database.Cursor.fetchmany(self, size))
302
303-
304
305-    def fetchall(self):
306
307-        # is this ever used ?
308
309-        # force results into unicode
310
311-        return self._force_unicode(Database.Cursor.fetchall(self))
312
313-
314
315-    def _smart_str(self, s=None):
316
317-        if s is None:
318
319-            return s
320
321-        if isinstance(s, dict):
322
323-            result = {}
324
325-            for key, value in s.items():
326
327-                result[_smart_str(key)] = self._smart_str(value)
328
329-            return result
330
331-        elif isinstance(s, (tuple,list)):
332
333-            return tuple([self._smart_str(p) for p in s])
334
335-        else:
336
337-            if isinstance(s, basestring):
338
339-                try:
340
341-                    return smart_str(s, self.charset, True)
342
343-                except UnicodeEncodeError:
344
345-                    return ''
346
347-            return s
348
349-
350
351-    def _force_unicode(self,s=None):
352
353-        if s is None:
354
355-            return s
356
357-        if isinstance(s, dict):
358
359-            result = {}
360
361-            for key, value in s.items():
362
363-                result[force_unicode(key, charset)] = self._force_unicode(value, charset)
364
365-            return result
366
367-        elif isinstance(s, (tuple,list)):
368
369-            return tuple([self._force_unicode(p) for p in s])
370
371-        else:
372
373-            if isinstance(s, basestring):
374
375-                try:
376
377-                    return force_unicode(s, encoding=self.charset)
378
379-                except UnicodeEncodeError:
380
381-                    return u''
382
383-            return s
384
385-
386
387-class Connection(Database.Connection):
388
389-       def cursor(self):
390
391-               return Cursor(self._db.cursor())
392
393-
394
395-Database.connect = Connection
396
397-
398
399-class DatabaseWrapper(object):
400
401-       def __init__(self, **kwargs):
402
403-               self.connection = None
404
405-               self.queries = []
406
407-               self.server_version = None
408
409-               self.options = kwargs
410
411-       
412
413-       def _valid_connection(self):
414
415-               return self.connection is not None
416
417-       
418
419-       def cursor(self):
420
421-               from django.conf import settings
422
423-               from warnings import filterwarnings
424
425-               if self.connection is None:
426
427-                       conn_dict = {}
428
429-                       # A DB2 client is configured with nodes, and then with databases connected
430
431-                       # to these nodes, I don't know if there is a way of specifying a complete
432
433-                       # DSN with a hostname and port, the PyDB2 module shows no sign of this either.
434
435-                       # So this DSN is actually the database name configured in the host's client instance.
436
437-                       if settings.DATABASE_NAME == '':
438
439-                               from django.core.exceptions import ImproperlyConfigured
440
441-                               raise ImproperlyConfigured, "You need to specify DATABASE_NAME in your Django settings file."
442
443-                       conn_dict['dsn'] = settings.DATABASE_NAME
444
445-                       if settings.DATABASE_USER == '':
446
447-                               from django.core.exceptions import ImproperlyConfigured
448
449-                               raise ImproperlyConfigured, "You need to specify DATABASE_USER in your Django settings file."
450
451-                       conn_dict['uid'] = settings.DATABASE_USER
452
453-                       if settings.DATABASE_PASSWORD == '':
454
455-                               from django.core.exceptions import ImproperlyConfigured
456
457-                               raise ImproperlyConfigured, "You need to specify DATABASE_PASSWORD in your Django settings file."
458
459-                       conn_dict['pwd'] = settings.DATABASE_PASSWORD
460
461-                       # Just imitating others here, I haven't seen any "options" for DB2.
462
463-                       conn_dict.update(self.options)
464
465-                       self.connection = Database.connect(**conn_dict)
466
467-                       cursor = self.connection.cursor()
468
469-               else:
470
471-                       cursor = self.connection.cursor()
472
473-               if settings.DEBUG:
474
475-                       return util.CursorDebugWrapper(cursor, self)
476
477-               return cursor
478
479-
480
481-       def _commit(self):
482
483-               if self.connection is not None:
484
485-                       return self.connection.commit()
486
487-       
488
489-       def _rollback(self):
490
491-               if self.connection is not None:
492
493-                       return self.connection.rollback()
494
495-       
496
497-       def close(self):
498
499-               if self.connection is not None:
500
501-                       self.connection.close()
502
503-                       self.connection = None
504
505-
506
507-allows_group_by_ordinal = False
508
509-allows_unique_and_pk = True
510
511-needs_datetime_string_cast = True
512
513-needs_upper_for_iops = True
514
515-autoindexes_primary_keys = True
516
517-supports_constraints = True
518
519-supports_tablespaces = False
520
521-supports_compound_statements = True
522
523-uses_case_insensitive_names = True
524
525-
526
527-def quote_name(name):
528
529-    """Name quoting.
530
531-    Names of type schema.tablename become "schema"."tablename"."""
532
533-    from django.conf import settings
534
535-    if not name.startswith('"') and not name.endswith('"'):
536
537-        return '.'.join(['"%s"' % util.truncate_name(f.upper(), get_max_name_length()) for f in name.split('.')])
538
539-    return name.upper()
540
541-
542
543-dictfetchone = util.dictfetchone
544
545-dictfetchmany = util.dictfetchmany
546
547-dictfetchall = util.dictfetchall
548
549-
550
551-def get_last_insert_id(cursor, table_name, pk_name):
552
553-       # There is probably a 'better' way to do this.
554
555-       cursor.execute("SELECT MAX(%s) FROM %s" % (quote_name(pk_name), quote_name(table_name)))
556
557-       a = cursor.fetchone()
558
559-       if a is None:
560
561-               return 0
562
563-       return a[0]
564
565-
566
567-def get_date_extract_sql(lookup_type, field_name):
568
569-       # lookup_type is 'year', 'month', 'day'
570
571-       if lookup_type == 'year':
572
573-               return "YEAR(%s)" % field_name
574
575-       elif lookup_type == 'month':
576
577-               return "MONTH(%s)" % field_name
578
579-       elif lookup_type == 'day':
580
581-               return "DAY(%s)" % field_name
582
583-
584
585-def get_date_trunc_sql(lookup_type, field_name):
586
587-       # lookup_type is 'year', 'month', 'day'
588
589-       # Hard one. I have seen TRUNC_TIMESTAMP somewhere but is not present
590
591-       # in any of my databases.
592
593-       # Doesn't work 'directly' since the GROUP BY needs this as well,
594
595-       # DB2 can't take "GROUP BY 1"
596
597-       if lookup_type == 'year':
598
599-               return "TIMESTAMP(DATE(%s -DAYOFYEAR(%s) DAYS +1 DAY),'00:00:00')" % (field_name, field_name)
600
601-       elif lookup_type == 'month':
602
603-               return "TIMESTAMP(DATE(%s -DAY(%s) DAYS +1 DAY),'00:00:00')" % (field_name, field_name)
604
605-       elif lookup_type == 'day':
606
607-               return "TIMESTAMP(DATE(%s),'00:00:00')" % field_name
608
609-
610
611-def get_datetime_cast_sql():
612
613-    return ""
614
615-
616
617-def get_limit_offset_sql(limit, offset=None):
618
619-    # Limits and offset are too complicated to be handled here.
620
621-    # Instead, they are handled in DB2QuerySet.
622
623-    return ""
624
625-
626
627-def get_random_function_sql():
628
629-       return "RAND()"
630
631-
632
633-def get_deferrable_sql():
634
635-    # DB2 does not support deferring constraints to end of transaction
636
637-    # using cascade avoid constraint problems
638
639-    return " ON DELETE CASCADE"
640
641-
642
643-def get_fulltext_search_sql(field_name):
644
645-       # DB2 has some nice extra packages that enables a CONTAINS() function,
646
647-       # but they're not available in my dbs.
648
649-       raise NotImplementedError
650
651-
652
653-def get_drop_foreignkey_sql():
654
655-       return "DROP CONSTRAINT"
656
657-
658
659-def get_pk_default_value():
660
661-       return "DEFAULT"
662
663-
664
665-def get_max_name_length():
666
667-    return 128;
668
669-
670
671-def get_max_constraint_length():
672
673-    # This needs a patch of management.py to detect and use this function
674
675-    # 18 for primarykeys and constraint names
676
677-    return 18;
678
679-
680
681-def get_alias(table, column):
682
683-    if table.count('.')==0:
684
685-        return "%s__%s" % (table, column)
686
687-    return "%s__%s" % (table.split('.')[-1], column)
688
689-
690
691-def get_start_transaction_sql():
692
693-    return "BEGIN;"
694
695-
696
697-def get_autoinc_sql(table):
698
699-    return None
700
701-
702
703-def get_drop_sequence(table):
704
705-    return "DROP SEQUENCE %s;" % quote_name(get_sequence_name(table))
706
707-
708
709-def _get_sequence_reset_sql():
710
711-    return 'ALTER TABLE %s ALTER COLUMN %s RESTART WITH %s'
712
713-
714
715-def _get_sql_flush(style, table, emptytables):
716
717-    """ Recursive function to retrieve the list of delete statements in the
718
719-    right order.
720
721-    """
722
723-    from django.db.backends.db2_9.introspection import get_foreignkey_relations
724
725-    from django.db import connection
726
727-    from django.utils.encoding import smart_str
728
729-    cursor = connection.cursor()
730
731-    sql = []
732
733-    te = []
734
735-    if emptytables:
736
737-        temptytables = emptytables[:]
738
739-    else:
740
741-        temptytables = []
742
743-    relations = get_foreignkey_relations(cursor, table)
744
745-    for relation in relations:
746
747-        relation = smart_str(relation)
748
749-        if relation not in temptytables:
750
751-            if temptytables:
752
753-                tt2 = temptytables[:].extend(table) # avoid circular reference endless loop
754
755-            else:
756
757-                tt2 = [table]
758
759-            tsql, tem = _get_sql_flush(style, relation, tt2)
760
761-            sql.extend(tsql)
762
763-            te.extend(tem)
764
765-            temptytables.extend(tem)
766
767-    if table not in temptytables:
768
769-        sql.append('%s %s %s;' % (style.SQL_KEYWORD('DELETE'), style.SQL_KEYWORD('FROM'),
770
771-        style.SQL_FIELD(quote_name(table))))
772
773-        te.append(table)
774
775-    return sql, te
776
777-
778
779-def get_sql_flush(style, tables, sequences):
780
781-    """Return a list of SQL statements required to remove all data from
782
783-    all tables in the database (without actually removing the tables
784
785-    themselves) and put the database in an empty 'initial' state"""
786
787-    if tables:
788
789-        emptytables = []
790
791-        sql = []
792
793-        for table in tables:
794
795-            if table.count('.') == 0:
796
797-                if table not in emptytables:
798
799-                    tsql, te = _get_sql_flush(style, table, emptytables)
800
801-                    sql.extend(tsql)
802
803-                    emptytables.extend(te)
804
805-        for sequence_info in sequences:
806
807-            if sequence_info['table'].upper() == table.upper():
808
809-                column = sequence_info['column']
810
811-                if column is not None:
812
813-                    query = _get_sequence_reset_sql() % (quote_name(table),quote_name(column),1)
814
815-                    sql.append(query)
816
817-        return sql
818
819-    else:
820
821-        return []
822
823-
824
825-def get_sql_sequence_reset(style, model_list):
826
827-    "Returns a list of the SQL statements to reset sequences for the given models."
828
829-    from django.db import models
830
831-    from django.db import connection
832
833-    output = []
834
835-    query = _get_sequence_reset_sql()
836
837-    for model in model_list:
838
839-        for f in model._meta.fields:
840
841-            if isinstance(f, models.AutoField):
842
843-                cursor = connection.cursor()
844
845-                max_id = get_last_insert_id(cursor, model._meta.db_table, f.column) + 1
846
847-                output.append(query % (quote_name(model._meta.db_table), quote_name(f.column), max_id))
848
849-                cursor.close()
850
851-                cursor = None
852
853-                break # Only one AutoField is allowed per model, so don't bother continuing.
854
855-        #~ for f in model._meta.many_to_many:
856
857-            #~ cursor = connection.cursor()
858
859-            #~ max_id = get_last_insert_id(cursor, model._meta.db_table, f.column) + 1
860
861-            #~ output.append(query % (quote_name(f.m2m_db_table()), quote_name(f.m2m_column_name()), max_id))
862
863-    return output
864
865-
866
867-def get_query_set_class(DefaultQuerySet):
868
869-    "Create a custom QuerySet class for DB2."
870
871-
872
873-    from django.db import backend, connection
874
875-    from django.db.models.query import EmptyResultSet, GET_ITERATOR_CHUNK_SIZE, quote_only_if_word
876
877-
878
879-    class DB2QuerySet(DefaultQuerySet):
880
881-
882
883-        def iterator(self):
884
885-            "Performs the SELECT database lookup of this QuerySet."
886
887-
888
889-            from django.db.models.query import get_cached_row
890
891-
892
893-            # self._select is a dictionary, and dictionaries' key order is
894
895-            # undefined, so we convert it to a list of tuples.
896
897-            extra_select = self._select.items()
898
899-
900
901-            full_query = None
902
903-
904
905-            try:
906
907-                try:
908
909-                    select, sql, params, full_query = self._get_sql_clause(get_full_query=True)
910
911-                except TypeError:
912
913-                    select, sql, params = self._get_sql_clause()
914
915-            except EmptyResultSet:
916
917-                raise StopIteration
918
919-            if not full_query:
920
921-                full_query = "SELECT %s%s\n%s" % \
922
923-                             ((self._distinct and "DISTINCT " or ""),
924
925-                              ', '.join(select), sql)
926
927-
928
929-            cursor = connection.cursor()
930
931-            cursor.execute(full_query, params)
932
933-
934
935-            fill_cache = self._select_related
936
937-            fields = self.model._meta.fields
938
939-            index_end = len(fields)
940
941-
942
943-            # so here's the logic;
944
945-            # 1. retrieve each row in turn
946
947-            # 2. convert NCLOBs
948
949-
950
951-            while 1:
952
953-                rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)
954
955-                if not rows:
956
957-                    raise StopIteration
958
959-                for row in rows:
960
961-                    row = self.resolve_columns(row, fields)
962
963-                    if fill_cache:
964
965-                        obj, index_end = get_cached_row(klass=self.model, row=row,
966
967-                                                        index_start=0, max_depth=self._max_related_depth)
968
969-                    else:
970
971-                        obj = self.model(*row[:index_end])
972
973-                    for i, k in enumerate(extra_select):
974
975-                        setattr(obj, k[0], row[index_end+i])
976
977-                    yield obj
978
979-
980
981-        def _get_sql_clause(self, get_full_query=False):
982
983-            from django.db.models.query import fill_table_cache, \
984
985-                handle_legacy_orderlist, orderfield2column
986
987-
988
989-            opts = self.model._meta
990
991-
992
993-            select = ["%s.%s" % (backend.quote_name(opts.db_table), backend.quote_name(f.column)) for f in opts.fields]
994
995-            tables = [quote_only_if_word(t) for t in self._tables]
996
997-            joins = SortedDict()
998
999-            where = self._where[:]
1000
1001-            params = self._params[:]
1002
1003-
1004
1005-            # Convert self._filters into SQL.
1006
1007-            joins2, where2, params2 = self._filters.get_sql(opts)
1008
1009-            joins.update(joins2)
1010
1011-            where.extend(where2)
1012
1013-            params.extend(params2)
1014
1015-
1016
1017-            # Add additional tables and WHERE clauses based on select_related.
1018
1019-            if self._select_related:
1020
1021-                fill_table_cache(opts, select, tables, where, opts.db_table, [opts.db_table])
1022
1023-
1024
1025-            # Add any additional SELECTs.
1026
1027-            if self._select:
1028
1029-                select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()])
1030
1031-
1032
1033-            # Start composing the body of the SQL statement.
1034
1035-            sql = [" FROM", backend.quote_name(opts.db_table)]
1036
1037-
1038
1039-            # Compose the join dictionary into SQL describing the joins.
1040
1041-            if joins:
1042
1043-                sql.append(" ".join(["%s %s %s ON %s" % (join_type, table, alias, condition)
1044
1045-                                for (alias, (table, join_type, condition)) in joins.items()]))
1046
1047-
1048
1049-            # Compose the tables clause into SQL.
1050
1051-            if tables:
1052
1053-                sql.append(", " + ", ".join(tables))
1054
1055-
1056
1057-            # Compose the where clause into SQL.
1058
1059-            if where:
1060
1061-                sql.append(where and "WHERE " + " AND ".join(where))
1062
1063-
1064
1065-            # ORDER BY clause
1066
1067-            order_by = []
1068
1069-            if self._order_by is not None:
1070
1071-                ordering_to_use = self._order_by
1072
1073-            else:
1074
1075-                ordering_to_use = opts.ordering
1076
1077-            for f in handle_legacy_orderlist(ordering_to_use):
1078
1079-                if f == '?': # Special case.
1080
1081-                    order_by.append(backend.get_random_function_sql())
1082
1083-                else:
1084
1085-                    if f.startswith('-'):
1086
1087-                        col_name = f[1:]
1088
1089-                        order = "DESC"
1090
1091-                    else:
1092
1093-                        col_name = f
1094
1095-                        order = "ASC"
1096
1097-                    if "." in col_name:
1098
1099-                        table_prefix, col_name = col_name.split('.', 1)
1100
1101-                        table_prefix = backend.quote_name(table_prefix) + '.'
1102
1103-                    else:
1104
1105-                        # Use the database table as a column prefix if it wasn't given,
1106
1107-                        # and if the requested column isn't a custom SELECT.
1108
1109-                        if "." not in col_name and col_name not in (self._select or ()):
1110
1111-                            table_prefix = backend.quote_name(opts.db_table) + '.'
1112
1113-                        else:
1114
1115-                            table_prefix = ''
1116
1117-                    order_by.append('%s%s %s' % (table_prefix, backend.quote_name(orderfield2column(col_name, opts)), order))
1118
1119-            if order_by:
1120
1121-                sql.append("ORDER BY " + ", ".join(order_by))
1122
1123-
1124
1125-            # Look for column name collisions in the select elements
1126
1127-            # and fix them with an AS alias.  This allows us to do a
1128
1129-            # SELECT * later in the paging query.
1130
1131-            cols = [clause.split('.')[-1] for clause in select]
1132
1133-            for index, col in enumerate(cols):
1134
1135-                if cols.count(col) > 1:
1136
1137-                    col = '%s%d' % (col.replace('"', ''), index)
1138
1139-                    cols[index] = col
1140
1141-                    select[index] = '%s AS %s' % (select[index], col)
1142
1143-
1144
1145-            # LIMIT and OFFSET clauses
1146
1147-            # To support limits and offsets, Oracle requires some funky rewriting of an otherwise normal looking query.
1148
1149-            select_clause = ",".join(select)
1150
1151-            distinct = (self._distinct and "DISTINCT " or "")
1152
1153-
1154
1155-            if order_by:
1156
1157-                order_by_clause = " OVER (ORDER BY %s )" % (", ".join(order_by))
1158
1159-            else:
1160
1161-                #DB2's row_number() function always requires an order-by clause.
1162
1163-                #So we need to define a default order-by, since none was provided.
1164
1165-                order_by_clause = " OVER (ORDER BY %s.%s)" % \
1166
1167-                    (backend.quote_name(opts.db_table),
1168
1169-                    backend.quote_name(opts.fields[0].db_column or opts.fields[0].column))
1170
1171-            # limit_and_offset_clause
1172
1173-            if self._limit is None:
1174
1175-                assert self._offset is None, "'offset' is not allowed without 'limit'"
1176
1177-
1178
1179-            if self._offset is not None:
1180
1181-                offset = int(self._offset)
1182
1183-            else:
1184
1185-                offset = 0
1186
1187-            if self._limit is not None:
1188
1189-                limit = int(self._limit)
1190
1191-            else:
1192
1193-                limit = None
1194
1195-#            if limit == 0:
1196
1197-#                limit = None
1198
1199-            limit_and_offset_clause = ''
1200
1201-            if limit is not None:
1202
1203-                limit_and_offset_clause = "WHERE rn > %s AND rn <= %s" % (offset, limit+offset)
1204
1205-            elif offset:
1206
1207-                limit_and_offset_clause = "WHERE rn > %s" % (offset)
1208
1209-
1210
1211-            if len(limit_and_offset_clause) > 0:
1212
1213-                if limit is not None:
1214
1215-                    fmt = "SELECT * FROM (SELECT %s%s, ROW_NUMBER()%s AS rn %s FETCH FIRST %s ROWS ONLY) AS foo %s"
1216
1217-                    full_query = fmt % (distinct, select_clause,
1218
1219-                                    order_by_clause, ' '.join(sql).strip(), limit+offset,
1220
1221-                                    limit_and_offset_clause)
1222
1223-                else:
1224
1225-                    fmt = "SELECT * FROM (SELECT %s%s, ROW_NUMBER()%s AS rn %s ) AS foo %s"
1226
1227-                    full_query = fmt % (distinct, select_clause,
1228
1229-                                    order_by_clause, ' '.join(sql).strip(),
1230
1231-                                    limit_and_offset_clause)
1232
1233-
1234
1235-            else:
1236
1237-                full_query = None
1238
1239-
1240
1241-            if get_full_query:
1242
1243-                return select, " ".join(sql), params, full_query
1244
1245-            else:
1246
1247-                return select, " ".join(sql), params
1248
1249-
1250
1251-        def resolve_columns(self, row, fields=()):
1252
1253-            from django.db.models.fields import Field, CharField, BooleanField, TextField
1254
1255-            values = []
1256
1257-            for value, field in map(None, row, fields):
1258
1259-                # strip trailing spaces in char and text fields
1260
1261-                #if isinstance(field, (CharField, TextField,)):
1262
1263-                if isinstance(value, basestring):
1264
1265-                    if value:
1266
1267-                        value = value.strip()
1268
1269-                # create real booleans
1270
1271-                if isinstance(field, BooleanField):
1272
1273-                    value = {0: False, 1: True}.get(value, False)
1274
1275-                values.append(value)
1276
1277-            return values
1278
1279-
1280
1281-    return DB2QuerySet
1282
1283-
1284
1285-# UPPER needs typecasting or DB2 does not know which upper function to use
1286
1287-# it does not matter if the typecast is correct
1288
1289-OPERATOR_MAPPING = {
1290
1291-       'exact': "= %s",
1292
1293-       'iexact': "= UPPER(CAST(%s AS VARCHAR(50)))",
1294
1295-       'contains': "LIKE %s ESCAPE '\\'",
1296
1297-       'icontains': "LIKE UPPER(CAST(%s AS VARCHAR(50))) ESCAPE '\\'",
1298
1299-       'gt': "> %s",
1300
1301-       'gte': ">= %s",
1302
1303-       'lt': "< %s",
1304
1305-       'lte': "<= %s",
1306
1307-       'startswith': "LIKE %s ESCAPE '\\'",
1308
1309-       'endswith': "LIKE %s ESCAPE '\\'",
1310
1311-       'istartswith': "LIKE UPPER(CAST(%s AS VARCHAR(50))) ESCAPE '\\'",
1312
1313-       'iendswith': "LIKE UPPER(CAST(%s AS VARCHAR(50))) ESCAPE '\\'",
1314
1315-}
1316
1317=== django/db/backends/db2_9/client.py
1318==================================================================
1319--- django/db/backends/db2_9/client.py  (/local/django/db2_9)   (revision 3643)
1320
1321+++ django/db/backends/db2_9/client.py  (/mirror/django/trunk)  (revision 3643)
1322
1323@@ -1,7 +0,0 @@
1324
1325-from django.conf import settings
1326-import os
1327-
1328-def runshell():
1329-       # Nothing fancy here, as the environment should have the
1330-       # instnace properly configured for anything to work at all.
1331-       os.execvp('db2')
1332=== django/db/backends/db2_9/__init__.py
1333==================================================================
1334=== django/db/backends/db2_9/introspection.py
1335==================================================================
1336--- django/db/backends/db2_9/introspection.py   (/local/django/db2_9)   (revision 3643)
1337
1338+++ django/db/backends/db2_9/introspection.py   (/mirror/django/trunk)  (revision 3643)
1339
1340@@ -1,177 +0,0 @@
1341
1342-"""
1343
1344-Optional: use a DATABASE_SCHEMA setting to let inspectdb find only tables from
1345
1346-a specific schema.
1347
1348-"""
1349
1350-from django.db.backends.db2_9.base import quote_name
1351
1352-from django.conf import settings
1353
1354-
1355
1356-def get_table_list(cursor):
1357
1358-       """ Here's the tricky part. The tables are accessed by their schema
1359
1360-       for example, all the systems tables are prefixed by SYSIBM as their schema.
1361
1362-       Since we can get really *lots* of tables without filtering by creator this can get
1363
1364-       really messy, So I've used DATABASE_SCHEMA to filter it.
1365
1366-       RTRIMs are needed because the fields return in full column size filled with spaces.
1367
1368-       Using the SYSIBM.TABLES VIEW.
1369
1370-       """
1371
1372-       from django.conf import settings
1373
1374-       from django.utils.encoding import smart_str, force_unicode
1375
1376-       try:
1377
1378-               schema = settings.DATABASE_SCHEMA.upper()
1379
1380-       except:
1381
1382-               schema = ''
1383
1384-       if schema != '':
1385
1386-               cursor.execute("""SELECT RTRIM(table_name) as TABLES, RTRIM(table_schema) as SCHEMA FROM SYSIBM.TABLES
1387
1388-               WHERE TABLE_SCHEMA = %s AND TABLE_TYPE = 'BASE TABLE' ORDER BY table_name""", [schema])
1389
1390-       else: # Fallback to everything but SYS*
1391
1392-               cursor.execute("""SELECT RTRIM(table_name) as TABLES, RTRIM(table_schema) as SCHEMA FROM SYSIBM.tables
1393
1394-               WHERE table_schema NOT LIKE 'SYS%%' AND TABLE_TYPE = 'BASE TABLE' ORDER BY table_name""", [])
1395
1396-       rows = cursor.fetchall()
1397
1398-       res = []
1399
1400-       # for tables from the user: do not append schema, others: use SCHEMA.TABLE as name
1401
1402-       for row in rows:
1403
1404-               if row[1].upper() == settings.DATABASE_USER.upper():
1405
1406-                       res.append(smart_str(row[0].upper()))
1407
1408-               else:
1409
1410-                       res.append(smart_str("%s.%s" % (row[1].upper(), row[0].upper())))
1411
1412-       return res
1413
1414-
1415
1416-def get_table_description(cursor, table_name):
1417
1418-       "Returns a description of the table with the DB-API cursor.description interface."
1419
1420-       cursor.execute("SELECT * FROM %s FETCH FIRST 1 ROWS ONLY" % (table_name,))
1421
1422-       return cursor.description
1423
1424-
1425
1426-def _name_to_index(cursor, table_name):
1427
1428-    """
1429
1430-    Returns a dictionary of {field_name: field_index} for the given table.
1431
1432-    Indexes are 0-based.
1433
1434-    """
1435
1436-    return dict([(d[0], i) for i, d in enumerate(get_table_description(cursor, table_name))])
1437
1438-
1439
1440-def get_relations(cursor, table_name):
1441
1442-       """
1443
1444-       Returns a dictionary of {field_index: (field_index_other_table, other_table)}
1445
1446-       representing all relationships to the given table. Indexes are 0-based.
1447
1448-       Beware, PyDB2 returns the full length of the field, filled with spaces,
1449
1450-       I have to .strip() every single string field >.<
1451
1452-       """
1453
1454-       from django.conf import settings
1455
1456-       
1457
1458-       if table_name.count('.') == 1:
1459
1460-               schema, tn = table_name.split('.')
1461
1462-       else:
1463
1464-               tn = table_name
1465
1466-               schema = settings.DATABASE_USER
1467
1468-       cursor.execute("""SELECT fk.ORDINAL_POSITION, pk.ORDINAL_POSITION, pk.TABLE_NAME
1469
1470-                       FROM SYSIBM.SQLFOREIGNKEYS r, SYSIBM.SQLCOLUMNS fk, SYSIBM.SQLCOLUMNS pk
1471
1472-                       WHERE r.FKTABLE_SCHEM = %s AND r.FKTABLE_NAME = %s
1473
1474-                       AND r.FKTABLE_SCHEM = fk.TABLE_SCHEM AND r.FKTABLE_NAME = fk.TABLE_NAME
1475
1476-                       AND r.FKCOLUMN_NAME = fk.COLUMN_NAME
1477
1478-                       AND r.PKTABLE_SCHEM = pk.TABLE_SCHEM AND r.PKTABLE_NAME = pk.TABLE_NAME
1479
1480-                       AND r.PKCOLUMN_NAME = pk.COLUMN_NAME
1481
1482-               """, (schema.upper(), tn))
1483
1484-               
1485
1486-       relations = {}
1487
1488-       for row in cursor.fetchall():
1489
1490-               relations[int(row[0]) - 1] = (int(row[1]) -1, row[2].strip())
1491
1492-       return relations
1493
1494-       
1495
1496-def get_foreignkey_relations(cursor, table_name):
1497
1498-       """
1499
1500-       Returns a dictionary of {field_index: other_table}
1501
1502-       representing all relationships to other tables. Indexes are 0-based.
1503
1504-       Beware, PyDB2 returns the full length of the field, filled with spaces,
1505
1506-       I have to .strip() every single string field >.<
1507
1508-       """
1509
1510-       from django.conf import settings
1511
1512-
1513
1514-       if table_name.count('.') == 1:
1515
1516-               schema, tn = table_name.split('.')
1517
1518-       else:
1519
1520-               tn = table_name
1521
1522-               schema = settings.DATABASE_USER
1523
1524-       cursor.execute("""SELECT r.FKCOLUMN_NAME, r.PKTABLE_NAME
1525
1526-                       FROM SYSIBM.SQLFOREIGNKEYS r
1527
1528-                       WHERE r.FKTABLE_SCHEM = %s AND r.FKTABLE_NAME = %s
1529
1530-               """, (schema.upper(), tn))
1531
1532-
1533
1534-       relations = []
1535
1536-       for row in cursor.fetchall():
1537
1538-               relations.append(row[1].strip())
1539
1540-       return relations
1541
1542-
1543
1544-def get_indexes(cursor, table_name):
1545
1546-       """
1547
1548-       Returns a dictionary of fieldname -> infodict for the given table,
1549
1550-       where each infodict is in the format:
1551
1552-               {'primary_key': boolean representing whether it's the primary key,
1553
1554-               'unique': boolean representing whether it's a unique index}
1555
1556-       DB2 is weird here, like this seems to be ok but I don't get 100% of the indexes
1557
1558-               syscolumns.keyseq means the column part of a "parent key".
1559
1560-               sysindexes.uniquerule == P means it's primary, U == unique,
1561
1562-                       and D == duplicates allowed.
1563
1564-       """     
1565
1566-       from django.conf import settings
1567
1568-       if table_name.count('.') == 1:
1569
1570-               schema, tn = table_name.split('.')
1571
1572-       else:
1573
1574-               tn = table_name
1575
1576-               schema = settings.DATABASE_USER
1577
1578-       cursor.execute("""SELECT c.COLUMN_NAME, i.UNIQUERULE
1579
1580-                       FROM SYSIBM.SQLCOLUMNS c, SYSCAT.INDEXES i, SYSCAT.INDEXCOLUSE k
1581
1582-                       WHERE c.TABLE_SCHEM = %s AND c.TABLE_NAME = %s
1583
1584-                       AND C.TABLE_SCHEM = i.TABSCHEMA AND c.TABLE_NAME = i.TABNAME
1585
1586-                       AND i.INDSCHEMA = k.INDSCHEMA AND i.INDNAME = k.INDNAME
1587
1588-                       AND c.COLUMN_NAME = k.COLNAME
1589
1590-               """, (schema.upper(), tn))
1591
1592-
1593
1594-       indexes = {}
1595
1596-       for row in cursor.fetchall():
1597
1598-               urule = row[1].strip()
1599
1600-               name = row[0].strip()
1601
1602-               if urule == "P":
1603
1604-                       # Override everything, as this is a primary key.
1605
1606-                       indexes[name] = {'primary_key':True, 'unique':False}
1607
1608-               elif urule == "U":
1609
1610-                       try:
1611
1612-                               if indexes[name]['primary_key'] == True:
1613
1614-                                       # Can appear twice, but primary is primary anyway.
1615
1616-                                       continue
1617
1618-                               else:
1619
1620-                                       indexes[name] = {'primary_key':False, 'unique':True}
1621
1622-                       except: # TODO: Only a keyerror can happen here, right?
1623
1624-                               indexes[name] = {'primary_key':False, 'unique':True}
1625
1626-               else: # urule = "D" not sure if there are others.
1627
1628-                       try:
1629
1630-                               # Should never happen, but...
1631
1632-                               if indexes[name]['primary_key'] == True or indexes[name]['unique'] == True:
1633
1634-                                       continue
1635
1636-                               else:
1637
1638-                                       indexes[name] = {'primary_key':False, 'unique':False}
1639
1640-                       except: # TODO: same as above ^_^
1641
1642-                               indexes[name] = {'primary_key':False, 'unique':False}
1643
1644-       return indexes
1645
1646-
1647
1648-DATA_TYPES_REVERSE = {
1649
1650-       -99:'TextField', # CLOB
1651
1652-       -98:'TextField', # BLOB
1653
1654-       -97:'TextField', # Long VarGraphic
1655
1656-       -96:'TextField', # VarGraphic
1657
1658-       -95:'TextField', # Graphic
1659
1660-       -5: 'IntegerField', # Big Int
1661
1662-       -4: 'TextField', # Binary Long VarChar
1663
1664-       -3: 'TextField', # Binary VarChar
1665
1666-       -2: 'TextField', # Binary
1667
1668-       -1: 'TextField', # Long VarChar
1669
1670-       1: 'CharField',  # Char
1671
1672-       2: 'FloatField', # Numeric
1673
1674-       3: 'FloatField', # Decimal
1675
1676-       4: 'IntegerField', # Integer
1677
1678-       5: 'BooleanField', # SmallInt
1679
1680-       6: 'FloatField', # Float
1681
1682-       7: 'FloatField', # Real
1683
1684-       8: 'FloatField', # Double
1685
1686-       12: 'CharField', # VarChar
1687
1688-       91: 'DateField', # Date
1689
1690-       92: 'TimeField', # Time
1691
1692-       93: 'DateTimeField', # TimeStamp
1693
1694-}
1695
1696=== django/db/backends/db2_9/creation.py
1697==================================================================
1698--- django/db/backends/db2_9/creation.py        (/local/django/db2_9)   (revision 3643)
1699
1700+++ django/db/backends/db2_9/creation.py        (/mirror/django/trunk)  (revision 3643)
1701
1702@@ -1,80 +0,0 @@
1703
1704-"""
1705
1706-TEST_DATABASE_USER must be an existing user (DB2 v9 uses OS authentication)
1707
1708-"""
1709
1710-import sys, time
1711
1712-from django.core import management
1713
1714-from django.db.models.signals import pre_save
1715
1716-from django.db.backends.db2_9 import base
1717
1718-
1719
1720-# Not quite sure about the Boolean and Float fields.
1721
1722-# Not sure what to use for Boolean, since there seems to be a 'BOOLEAN' type,
1723
1724-# but it isn't 'documented' anywhere. For Float, we have DOUBLE, DECIMAL and NUMERIC
1725
1726-# to choose from :+/, too many.
1727
1728-DATA_TYPES = {
1729
1730-       'AutoField':                    'INTEGER GENERATED BY DEFAULT AS IDENTITY', # ALWAYS breaks basic test (specifying key explicitly)
1731
1732-       'BooleanField':                 'SMALLINT',
1733
1734-       'CharField':                    'VARCHAR(%(maxlength)s)',
1735
1736-       'CommaSeparatedIntegerField':   'VARCHAR(%(maxlength)s)',
1737
1738-       'DateField':                    'DATE',
1739
1740-       'DateTimeField':                'TIMESTAMP',
1741
1742-       'DecimalField':                 'DECIMAL(%(max_digits)s, %(decimal_places)s)',
1743
1744-       'FileField':                    'VARCHAR(100)',
1745
1746-       'FilePathField':                'VARCHAR(100)',
1747
1748-       'FloatField':                   'FLOAT',
1749
1750-       'ImageField':                   'VARCHAR(100)',
1751
1752-       'IntegerField':                 'INTEGER',
1753
1754-       'IPAddressField':               'CHAR(15)',
1755
1756-       'ManyToManyField':              None,
1757
1758-       'NullBooleanField':             'SMALLINT',
1759
1760-       'OneToOneField':                'INTEGER',
1761
1762-       'PhoneNumberField':             'CHAR(20)',
1763
1764-       'PositiveIntegerField':         'INTEGER',
1765
1766-       'PositiveSmallIntegerField':    'SMALLINT',
1767
1768-       'SlugField':                    'VARCHAR(%(maxlength)s)',
1769
1770-       'SmallIntegerField':            'SMALLINT',
1771
1772-       'TextField':                    'LONG VARCHAR',
1773
1774-       'TimeField':                    'TIME',
1775
1776-       'USStateField':                 'CHAR(2)',
1777
1778-}
1779
1780-
1781
1782-REMEMBER = {}
1783
1784-
1785
1786-def create_test_db(settings, connection, backend, verbosity=1, autoclobber=False):
1787
1788-    """Assuming here that a TEST_DATABASE_USER is set in settings that is known to the OS and DB2
1789
1790-    with DB2ADM rights.
1791
1792-    Best is that this user has a separate default tablespace defined in DB2 (but this is not required)."""
1793
1794-    REMEMBER['user'] = settings.DATABASE_USER
1795
1796-    REMEMBER['passwd'] = settings.DATABASE_PASSWORD
1797
1798-    settings.DATABASE_USER = settings.TEST_DATABASE_USER
1799
1800-    settings.DATABASE_PASSWORD = settings.TEST_DATABASE_PASSWORD
1801
1802-    management.syncdb(verbosity, interactive=False)
1803
1804-
1805
1806-def destroy_test_db(settings, connection, backend, old_database_name, verbosity=1):
1807
1808-    """Delete all tables from the test user."""
1809
1810-    connection.close()
1811
1812-   
1813
1814-    settings.DATABASE_USER = REMEMBER['user']
1815
1816-    settings.DATABASE_PASSWORD = REMEMBER['passwd']
1817
1818-   
1819
1820-    cursor = connection.cursor()
1821
1822-
1823
1824-    time.sleep(1) # To avoid "database is being accessed by other users" errors.
1825
1826-
1827
1828-    if verbosity >= 2:
1829
1830-        print "_destroy_test_db(): removing tables from schema %s" % settings.TEST_DATABASE_USER
1831
1832-
1833
1834-    cursor.execute("""SELECT RTRIM(table_name) as TABLES FROM SYSIBM.TABLES
1835
1836-        WHERE TABLE_SCHEMA = %s AND TABLE_TYPE = 'BASE TABLE' ORDER BY table_name""", [settings.TEST_DATABASE_USER.upper()])
1837
1838-
1839
1840-    rows = cursor.fetchall()
1841
1842-    for row in rows:
1843
1844-        stmt = 'DROP TABLE %s.%s' % (settings.TEST_DATABASE_USER.upper(), row[0])
1845
1846-        if verbosity >= 2:
1847
1848-            print stmt
1849
1850-        try:
1851
1852-            cursor.execute(stmt)
1853
1854-        except Exception, err:
1855
1856-            sys.stderr.write("Failed (%s)\n" % (err))
1857
1858-            raise
1859
1860-    connection._commit()
1861
1862-    connection.close()
1863
1864\ No newline at end of file
1865
1866
1867Property changes on: django/db/backends/db2_9
1868___________________________________________________________________
1869Name: svn:ignore
1870 -*.pyc
1871 -
1872
1873=== django/core/management.py
1874==================================================================
1875--- django/core/management.py   (/local/django/db2_9)   (revision 3643)
1876
1877+++ django/core/management.py   (/mirror/django/trunk)  (revision 3643)
1878
1879@@ -235,12 +235,8 @@
1880
1881                 # For MySQL, r_name must be unique in the first 64 characters.
1882                 # So we are careful with character usage here.
1883                 r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))
1884-                if hasattr(backend, 'get_max_constraint_length'):
1885-                    get_max = backend.get_max_constraint_length
1886-                else:
1887-                    get_max = backend.get_max_name_length
1888                 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
1889-                    (backend.quote_name(r_table), truncate_name(r_name, get_max()),
1890+                    (backend.quote_name(r_table), truncate_name(r_name, backend.get_max_name_length()),
1891                     backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col),
1892                     backend.get_deferrable_sql()))
1893             del pending_references[model]
1894@@ -923,7 +919,7 @@
1895
1896                     extra_params['decimal_places'] = row[5]
1897 
1898                 # Add primary_key and unique, if necessary.
1899-                column_name = extra_params.get('db_column', row[0])
1900+                column_name = extra_params.get('db_column', att_name)
1901                 if column_name in indexes:
1902                     if indexes[column_name]['primary_key']:
1903                         extra_params['primary_key'] = True
Back to Top