Contact: fumanchu@aminus.org

Log in as guest/geniusql to create tickets

root/trunk/geniusql/dbtypes.py

Revision 310 (checked in by lakin, 4 months ago)

geniusql - fixing whitespcae

  • Property svn:eol-style set to native
Line 
1 # Any otherwise-unattributed quotes in this module are probably from:
2 # http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt
3
4 import datetime
5 import math
6
7 from geniusql import adapters, errors, typerefs
8
9
10 class FixedTimeZone(datetime.tzinfo):
11     """Fixed offset in minutes east from UTC."""
12
13     def __init__(self, offset):
14         self._offset = offset
15
16     def utcoffset(self, dt):
17         return datetime.timedelta(minutes = self._offset)
18
19     def tzname(self, dt):
20         return "FixedTimeZone%s" % self._offset
21
22     def dst(self, dt):
23         return datetime.timedelta(0)
24
25     def __repr__(self):
26         cls = self.__class__
27         return "%s.%s(%r)" % (cls.__module__, cls.__name__, self._offset)
28
29
30
31 # ---------------------------- Base classes ---------------------------- #
32
33
34 class DatabaseType(object):
35     """A database type, such as 'REAL' or 'DATE' (with optional details).
36
37     DatabaseType is a place to collect information about each type used by
38     each provider; all providers should provide a separate subclass of this
39     for each (canonical) type they provide.
40
41     Each Column (and SQLExpression) should get its own instance of a
42     provider-specific subclass of this class.
43     """
44
45     # These are class-level attributes and should not be overridden or copied
46     # (they're only used at the class level, so it wouldn't make much sense).
47     default_pytype = None
48     default_adapters = None
49     synonyms = []
50
51     def __init__(self, **kwargs):
52         for k, v in kwargs.iteritems():
53             setattr(self, k, v)
54
55     def __repr__(self):
56         attrs = ", ".join(["%s=%r" % (k, getattr(self, k))
57                            for k in self.__dict__])
58         return "%s.%s(%s)" % (self.__module__, self.__class__.__name__, attrs)
59
60     def __copy__(self):
61         return self.__class__(**self.__dict__)
62     copy = __copy__
63
64     def ddl(self):
65         """Return the type for use in CREATE or ALTER statements."""
66         return self.__class__.__name__
67
68     def default_adapter(self, pytype):
69         """Return a default adapter instance for the given pytype, dbtype."""
70         # Use try for the common case where the pytype is in the dict.
71         try:
72             return self.default_adapters[pytype]
73         except KeyError:
74             defaults = self.default_adapters
75             if None in defaults:
76                 return defaults[None]
77             for p in pytype.__bases__:
78                 if p in defaults:
79                     return defaults[p]
80
81         raise TypeError("%s has no default adapter for %s. Looked for: "
82                         "%s, None, %s" %
83                         (self, pytype, pytype,
84                          ", ".join([repr(x) for x in pytype.__bases__])))
85
86
87 class FrozenByteType(DatabaseType):
88     """DatabaseType which specifies a frozen 'bytes' attribute.
89
90     A FrozenByteType does not imply that the type is a fixed-byte
91     type like CHAR as opposed to a variable-byte type like VARCHAR
92     (that difference is specified in the "variable" attribute).
93     Instead, a Frozen* type implies that the byte limit is not
94     user-specifiable; for example, Microsoft Access' MEMO type
95     is always 65535 bytes, and takes no size argument in DDL.
96     """
97
98     _bytes = max_bytes = 255
99     def _get_bytes(self):
100         return self._bytes
101     def _set_bytes(self, value):
102         pass
103     bytes = property(_get_bytes, _set_bytes,
104                      doc="The bytes used for all instances of this type.")
105
106
107 class AdjustableByteType(DatabaseType):
108     """DatabaseType which specifies an adjustable 'bytes' attribute."""
109
110     # The maximum allowable maximum.
111     max_bytes = 255
112
113     _bytes = 255
114     def _get_bytes(self):
115         return self._bytes
116     def _set_bytes(self, value):
117         if value is not None:
118             if value < 1:
119                 raise ValueError("%r is less than min bytes 1." % value)
120             elif value > self.max_bytes:
121                 raise ValueError("%r is greater than max bytes %r." %
122                                  (value, self.max_bytes))
123         self._bytes = value
124     bytes = property(_get_bytes, _set_bytes,
125                      doc="The maximum bytes specifiable for "
126                          "each instance of this type.")
127
128     def ddl(self):
129         """Return the type for use in CREATE or ALTER statements."""
130         return "%s(%s)" % (self.__class__.__name__, self.bytes)
131
132
133 class FrozenPrecisionType(DatabaseType):
134     """DatabaseType which specifies a frozen 'precision' attribute."""
135
136     _precision = max_precision = 53
137     def _get_precision(self):
138         return self._precision
139     def _set_precision(self, value):
140         pass
141     precision = property(_get_precision, _set_precision,
142                          doc="The frozen precision in binary digits (bits).")
143
144
145 class AdjustablePrecisionType(DatabaseType):
146     """DatabaseType which specifies an adjustable 'precision' attribute."""
147
148     # Max binary precision for floating-point columns. Python floats are
149     # implemented using C doubles; actual precision depends on platform
150     # (but is usually 53 binary digits, see adapters.maxfloat_digits).
151     # Many commercial DB's DOUBLE is 53 binary-digit precision.
152     max_precision = 53
153
154     _precision = 53
155     def _get_precision(self):
156         return self._precision
157     def _set_precision(self, value):
158         if value is not None:
159             if value < 1:
160                 raise ValueError("%r: %r is less than min precision 1." %
161                                  (self, value))
162             elif value > self.max_precision:
163                 raise ValueError("%r: %r is greater than max precision %r." %
164                                  (self, value, self.max_precision))
165         self._precision = value
166     precision = property(_get_precision, _set_precision,
167                          doc="The set precision in binary digits (bits).")
168
169     def ddl(self):
170         """Return the type for use in CREATE or ALTER statements."""
171         return "%s(%s)" % (self.__class__.__name__, self.precision)
172
173
174 class FixedRangeType(DatabaseType):
175     """DatabaseType which represents values within a fixed range."""
176     _min = None
177     _max = None
178
179     def range(self):
180         """Return self.max - self.min."""
181         return self._max - self._min
182
183     def min(self):
184         """Return the minimum value allowed."""
185         return self._min
186
187     def max(self):
188         """Return the maximum value allowed."""
189         return self._max
190
191
192
193 # --------------------------- Concrete types --------------------------- #
194
195 # SQL92 types: INTEGER (INT), SMALLINT, NUMERIC, DECIMAL, FLOAT, REAL,
196 #   DOUBLE PRECISION (DOUBLE), BIT, BIT VARYING, DATE, TIME, TIMESTAMP,
197 #   CHARACTER (CHAR), CHARACTER VARYING (VARCHAR), INTERVAL
198
199 class TEXT(FrozenByteType):
200     """DatabaseType for string types whose byte-length is not adjustable.
201
202     A Frozen*Type does not imply that the type is a fixed-byte
203     type like CHAR as opposed to a variable-byte type like VARCHAR
204     (that difference is specified in the "variable" attribute).
205     Instead, a Frozen* type implies that the type takes no size
206     argument in DDL; for example, Microsoft Access' MEMO type
207     is always 65535 bytes, and is not user-specifiable.
208     """
209
210     # CHAR vs VARCHAR
211     variable = True
212     encoding = 'utf8'
213
214     default_pytype = str
215     default_adapters = {str: adapters.str_to_SQL92VARCHAR(),
216                         unicode: adapters.unicode_to_SQL92VARCHAR(),
217                         float: adapters.number_to_TEXT(float),
218                         int: adapters.number_to_TEXT(int),
219                         long: adapters.number_to_TEXT(long),
220
221                         # Adapters for DB's with no native date/time types.
222                         # Fortunately, the adapters for native types work
223                         # just as well for TEXT.
224                         datetime.datetime: adapters.datetime_to_SQL92TIMESTAMP(),
225                         datetime.date: adapters.date_to_SQL92DATE(),
226                         datetime.time: adapters.time_to_SQL92TIME(),
227                         datetime.timedelta: adapters.timedelta_to_SQL92DECIMAL(),
228
229                         None: adapters.Pickler(),
230                         }
231     if typerefs.decimal:
232         if hasattr(typerefs.decimal, "Decimal"):
233             default_adapters[typerefs.decimal.Decimal] = adapters.decimal_to_TEXT()
234         else:
235             default_adapters[typerefs.decimal] = adapters.decimal_to_TEXT()
236     if typerefs.fixedpoint:
237         default_adapters[typerefs.fixedpoint.FixedPoint] = adapters.fixedpoint_to_TEXT()
238
239
240 class SQL92VARCHAR(AdjustableByteType):
241     """DatabaseType for adjustable-byte string types."""
242
243     # CHAR vs VARCHAR
244     variable = True
245     encoding = 'utf8'
246
247     default_pytype = str
248     default_adapters = {str: adapters.str_to_SQL92VARCHAR(),
249                         unicode: adapters.unicode_to_SQL92VARCHAR(),
250                         float: adapters.number_to_TEXT(float),
251                         int: adapters.number_to_TEXT(int),
252                         long: adapters.number_to_TEXT(long),
253                         datetime.timedelta: adapters.timedelta_to_SQL92DECIMAL(),  #??
254                         None: adapters.Pickler(),
255                         }
256     if typerefs.decimal:
257         if hasattr(typerefs.decimal, "Decimal"):
258             default_adapters[typerefs.decimal.Decimal] = adapters.decimal_to_TEXT()
259         else:
260             default_adapters[typerefs.decimal] = adapters.decimal_to_TEXT()
261     if typerefs.fixedpoint:
262         default_adapters[typerefs.fixedpoint.FixedPoint] = adapters.fixedpoint_to_TEXT()
263
264
265 class SQL92CHAR(SQL92VARCHAR):
266     variable = False
267
268
269 class SQL92INTEGER(FrozenByteType):
270     """A base class for DatabaseTypes which conform to SQL92 INTEGER.
271
272     "INTEGER specifies the data type exact numeric, with binary or
273     decimal precision and scale of 0. The choice of binary versus
274     decimal precision is implementation-defined, but shall be the
275     same as SMALLINT."
276     """
277
278     default_pytype = int
279     default_adapters = {int: adapters.int_to_SQL92INTEGER(),
280                         long: adapters.int_to_SQL92INTEGER(),
281                         bool: adapters.bool_to_SQL92BIT(),
282                         }
283     signed = True
284     _bytes = max_bytes = 4
285
286     def range(self):
287         """Return self.max - self.min."""
288         return 2 ** (self.bytes * 8)
289
290     def min(self):
291         """Return the minimum value allowed."""
292         if self.signed:
293             return 0 - (self.range() / 2)
294         else:
295             return 0
296
297     def max(self):
298         """Return the maximum value allowed."""
299         if self.signed:
300             return (self.range() / 2) - 1
301         else:
302             return self.range() - 1
303
304
305 class SQL92SMALLINT(SQL92INTEGER):
306     """Base class for SQL 92 SMALLINT types.
307
308     "The precision of SMALLINT shall be less than or equal to the
309     precision of INTEGER."
310     """
311     _bytes = max_bytes = 2
312
313
314 class SQL92FLOAT(AdjustablePrecisionType):
315     """Base class for SQL 92 FLOAT types.
316
317     "FLOAT specifies the data type approximate numeric, with binary
318     precision equal to or greater than the value of the specified
319     <precision>. The maximum value of <precision> is implementation-
320     defined. <precision> shall not be greater than this value."
321     """
322     default_pytype = float
323
324
325 class SQL92REAL(FrozenPrecisionType):
326     """Base class for SQL 92 REAL types.
327
328     "REAL specifies the data type approximate numeric, with implementation-
329     defined precision."
330     """
331     default_pytype = float
332     # By "precision" here, we mean the number of binary digits
333     # which can be safely round-tripped to the DB and back.
334     # Even though almost every DB will use 32 bits to represent this
335     # number (1 sign bit, 8 exponent bits, and 24 significand bits),
336     # we're only interested in the significand bits; therefore, the
337     # max() for this type should be (2 ** 24) - 1.
338     # See http://babbage.cs.qc.edu/IEEE-754/Decimal.html
339     _precision = max_precision = 24
340     default_adapters = {float: adapters.float_to_SQL92REAL()}
341     if typerefs.fixedpoint:
342         default_adapters[typerefs.fixedpoint.FixedPoint] = adapters.fixedpoint_to_SQL92REAL()
343     if typerefs.decimal:
344         if hasattr(typerefs.decimal, "Decimal"):
345             default_adapters[typerefs.decimal.Decimal] = adapters.decimal_to_SQL92REAL()
346         else:
347             default_adapters[typerefs.decimal] = adapters.decimal_to_SQL92REAL()
348
349 class SQL92DOUBLE(SQL92REAL):
350     """Base class for SQL 92 DOUBLE PRECISION types.
351
352     "DOUBLE PRECISION specifies the data type approximate numeric,
353     with implementation-defined precision that is greater than the
354     implementation-defined precision of REAL."
355     """
356     _precision = max_precision = 53
357     default_adapters = {float: adapters.float_to_SQL92DOUBLE()}
358     if typerefs.fixedpoint:
359         default_adapters[typerefs.fixedpoint.FixedPoint] = adapters.fixedpoint_to_SQL92DOUBLE()
360     if typerefs.decimal:
361         if hasattr(typerefs.decimal, "Decimal"):
362             default_adapters[typerefs.decimal.Decimal] = adapters.decimal_to_SQL92DOUBLE()
363         else:
364             default_adapters[typerefs.decimal] = adapters.decimal_to_SQL92DOUBLE()
365
366
367 class SQL92DECIMAL(AdjustablePrecisionType):
368     """Base class for SQL 92 DECIMAL types.
369
370     For exact numeric types, 'precision' and 'scale' refer to decimal digits.
371
372     SQL 92 says:
373         "NUMERIC specifies the data type exact numeric, with the decimal
374         precision and scale specified by the <precision> and <scale>."
375
376         "DECIMAL specifies the data type exact numeric, with the decimal
377         scale specified by the <scale> and the implementation-defined
378         decimal precision equal to or greater than the value of the
379         specified <precision>."
380
381     In terms of adaptation, there's not much difference between these.
382     Plenty of databases make them synonyms anyway.
383     """
384     scale = None
385     max_scale = 1000
386
387     _precision = 18
388     max_precision = 1000
389
390     if typerefs.decimal:
391         if hasattr(typerefs.decimal, "Decimal"):
392             default_pytype = typerefs.decimal.Decimal
393         else:
394             default_pytype = typerefs.decimal
395     elif typerefs.fixedpoint:
396         default_pytype = typerefs.fixedpoint.FixedPoint
397     else:
398         default_pytype = float
399
400     default_adapters = {int: adapters.number_to_SQL92DECIMAL(int),
401                         long: adapters.number_to_SQL92DECIMAL(long),
402                         float: adapters.number_to_SQL92DECIMAL(float),
403                         datetime.timedelta: adapters.timedelta_to_SQL92DECIMAL(),
404                         }
405     if typerefs.fixedpoint:
406         default_adapters[typerefs.fixedpoint.FixedPoint] = adapters.fixedpoint_to_SQL92DECIMAL()
407     if typerefs.decimal:
408         if hasattr(typerefs.decimal, "Decimal"):
409             default_adapters[typerefs.decimal.Decimal] = adapters.decimal_to_SQL92DECIMAL()
410         else:
411             default_adapters[typerefs.decimal] = adapters.decimal_to_SQL92DECIMAL()
412
413     def range(self):
414         """Return self.max - self.min."""
415         return (10 ** self.precision) * 2
416
417     def min(self):
418         """Return the minimum value allowed."""
419         prec = -((10 ** self.precision) - 1)
420         return prec / (10 ** self.scale)
421
422     def max(self):
423         """Return the maximum value allowed."""
424         prec = (10 ** self.precision) - 1
425         return prec / (10 ** self.scale)
426
427     def ddl(self):
428         """Return the type for use in CREATE or ALTER statements."""
429         if self.precision is not None:
430             if self.scale is not None:
431                 return "%s(%s, %s)" % (self.__class__.__name__,
432                                        self.precision, self.scale)
433             return "%s(%s)" % (self.__class__.__name__, self.precision)
434         return self.__class__.__name__
435
436
437 class SQL92TIMESTAMP(FixedRangeType):
438     default_pytype = datetime.datetime
439     default_adapters = {datetime.datetime: adapters.datetime_to_SQL92TIMESTAMP()}
440
441 class SQL92DATE(FixedRangeType):
442     default_pytype = datetime.date
443     default_adapters = {datetime.date: adapters.date_to_SQL92DATE()}
444
445 class SQL92TIME(DatabaseType):
446     default_pytype = datetime.time
447     default_adapters = {datetime.time: adapters.time_to_SQL92TIME()}
448
449
450 class SQL92BIT(DatabaseType):
451     """DatabaseType which uses boolean values (0, 1, Null)."""
452     default_pytype = bool
453     default_adapters = {bool: adapters.bool_to_SQL92BIT()}
454
455
456
457 # SQL99 types: CLOB, BLOB, BOOLEAN, ARRAY, ROW
458
459 class SQL99BOOLEAN(DatabaseType):
460     """DatabaseType which uses boolean values (True, False, Null).
461
462     ANSI SQL:1999 says something like:
463     "The data type boolean comprises the distinct truth values
464     true and false. Unless prohibited by a NOT NULL constraint,
465     the boolean data type also supports the unknown truth value as
466     the null value. This specification does not make a distinction
467     between the null value of the boolean data type and the unknown
468     truth value that is the result of an SQL <predicate>, <search
469     condition>, or <boolean value expression>; they may be used
470     interchangeably to mean exactly the same thing."
471     """
472     default_pytype = bool
473     default_adapters = {bool: adapters.bool_to_SQL99BOOLEAN()}
474
475
476
477 # ----------------------------- Type Sets ----------------------------- #
478
479
480 def getCoerceName(pytype):
481     """Return the name of the coercion method for a given Python type."""
482     mod = pytype.__module__
483     if mod == "__builtin__":
484         xform = "%s" % pytype.__name__
485     else:
486         xform = "%s_%s" % (mod, pytype.__name__)
487     xform = xform.replace(".", "_")
488     return xform
489
490
491 class DatabaseTypeSet(object):
492     """Determine the best database type for a given column + Python type.
493
494     When Geniusql is asked to create database tables, it must choose an
495     appropriate column data type for each Column based on the
496     type (and hints) of that property. This class recommends such
497     database types by returning a new instance of DatabaseType.
498     """
499
500     known_types = None
501
502     # You should REALLY check into your DB's encoding and override this.
503     encoding = 'utf8'
504     auto_pickle = True
505
506     def __copy__(self):
507         newset = self.__class__()
508         newset.update(self)
509         newset.known_types = self.known_types.copy()
510         return newset
511     copy = __copy__
512
513     def canonicalize(self, dbtypename):
514         """Return the canonical DatabaseType for the given synonym.
515
516         In order to avoid large amounts of code (in each provider module!)
517         that merely looks up synonyms, database types MUST be
518         canonicalized for all Column and SQLExpression objects.
519
520         Note that the caller is responsible to strip out any metadata from
521         the supplied type name; for example, "NUMERIC(18, 2)" should
522         (usually) be reduced to "NUMERIC" before calling this function.
523         However, this is not mandatory; some providers may need to use
524         such metadata to select the most appropriate type.
525         """
526         for typeset in self.known_types.itervalues():
527             for dbtype in typeset:
528                 if (dbtypename == dbtype.__name__
529                     or dbtypename in dbtype.synonyms):
530                     return dbtype
531         raise KeyError("No canonical name found for %r." % dbtypename)
532
533     def database_type(self, pytype, hints=None, value=None):
534         """Return a DatabaseType instance for the given Python type.
535
536         #TODO STRABS: Make the hints non-optional.
537
538         hints: if provided, this should be a dict of property attributes
539             which can be used to distinguish between similar database types.
540             Canonical keys include 'bytes', 'precision', 'scale', and 'signed'.
541             To coerce a particular type, provide a DatabaseType instance in
542             'dbtype'.
543         """
544         if hints is None:
545             hints = {}
546         elif 'dbtype' in hints:
547             return hints['dbtype']
548
549         coerce_name = getCoerceName(pytype)
550
551         if value is not None:
552             # If the value we have is not none, then the value itself may
553             # be able to hint at the expression we need to represent it properly
554             # in SQL. Use it to generate the appropriate hints.
555             hints_method = "hints_from_value_for_" + coerce_name
556             hints_method = getattr(self, hints_method, lambda v: {})
557             value_hints = hints_method(value)
558
559             # The passed in hints (from the type definition) override the value hints
560             value_hints.update(hints)
561             hints = value_hints
562
563
564         # Retrieve the method that will produce the appropriate dbtype for
565         # a given python type.
566         xform = "dbtype_for_" + coerce_name
567         try:
568             xform = getattr(self, xform)
569         except AttributeError:
570             # Assume we'll use a VARCHAR type and pickle the values.
571             if self.auto_pickle:
572                 return self.dbtype_for_str(hints)
573             else:
574                 raise TypeError("%r is not handled by %s. Tried %r" %
575                                 (pytype, self.__class__, xform))
576         return xform(hints)
577
578     def dbtype_for_float(self, hints):
579         """Return a DatabaseType for floats of the given binary precision."""
580         # Note that 'precision' is binary digits, not decimal digits or bytes.
581         # For example, most DOUBLE PRECISION types are implemented as
582         # 64 bits ~= 53 binary precision ~= 14 decimal precision
583         precision = int(hints.get('precision', adapters.maxfloat_digits))
584         if precision == 0:
585             # Use the maximum precision.
586             precision = max([0] + [dbtype.max_precision
587                                    for dbtype in self.known_types['float']])
588         for dbtype in self.known_types['float']:
589             if precision <= dbtype.max_precision:
590                 return dbtype(precision=precision)
591
592         # Unable to find a compatible floating-point type. Try to find a
593         # compatible fixed-point type instead (which usually allow higher
594         # precision). Rather than do all sorts of complicated calculations
595         # and extensive analysis of IEEE 754 representation, we just follow
596         # http://download-west.oracle.com/docs/html/A85397_01/sql_elem.htm
597         # and multiply bits by 0.30103 to get decimal precision.
598         dec_prec = int(math.ceil(precision * 0.30103))
599         # However, floating-point numbers essentially have no scale.
600         # For example, given a binary precision of 23, we get a decimal
601         # precision of (23 * 0.30103 =) 7, but that needs to allow both
602         # 1000000 and 0.0000001, so we actually need DECIMAL(14, 7).
603         return self.decimal_type(precision=dec_prec * 2, scale=dec_prec)
604
605     def dbtype_for_str(self, hints):
606         # The bytes hint shall not reflect the usual 4-byte base for varchar.
607         bytes = int(hints.get('bytes', 255))
608         if bytes == 0:
609             # Use the maximum bytes.
610             bytes = max([0] + [dbtype.max_bytes
611                                for dbtype in self.known_types['varchar']])
612         for dbtype in self.known_types['varchar']:
613             if bytes <= dbtype.max_bytes:
614                 return dbtype(bytes=bytes)
615         raise ValueError("%r is greater than the maximum bytes %r."
616                          % (bytes, dbtype.max_bytes))
617
618     def dbtype_for_unicode(self, hints):
619         return self.dbtype_for_str(hints)
620
621     def dbtype_for_bool(self, hints):
622         return self.known_types['bool'][0]()
623
624     # These are not adapter.push(bool) (which are used on one side of
625     # a comparison). Instead, these are used when the whole (sub)expression
626     # is True or False, e.g. "WHERE TRUE", or "WHERE TRUE and 'a'.'b' = 3".
627     expr_true = "TRUE"
628     expr_false = "FALSE"
629
630     # Because True and False get used so much in deparsing,
631     # we include a memoized function for obtaining SQLExpressions.
632     _adapted_bools = None
633     def bool_exprs(self, exprclass):
634         """Return SQLExpressions for expr_true, expr_false, comp_true and comp_false.
635
636         expr_true and expr_false are used when a (sub)expression is True or
637         False; for example, "WHERE TRUE and a.b = 3".
638
639         comp_true and comp_false are used in comparisons; for example,
640         "WHERE x.y == TRUE".
641
642         In many databases, these are equivalent. Microsoft SQL Server is a
643         notable exception, requiring "(1=1)" for expr_true, but "TRUE" for
644         comp_true.
645         """
646         t = self.database_type(bool)
647         adapter = t.default_adapter(bool)
648
649         expr_true = exprclass(self.expr_true, '', t, bool)
650         expr_true.adapter = adapter
651         expr_true.value = True
652
653         expr_false = exprclass(self.expr_false, '', t, bool)
654         expr_false.adapter = adapter
655         expr_false.value = False
656
657         if self._adapted_bools is None:
658             comp_true = adapter.push(True, t)
659             comp_false = adapter.push(False, t)
660             self._adapted_bools = (comp_true, comp_false)
661         else:
662             comp_true, comp_false = self._adapted_bools
663
664         comp_true = exprclass(comp_true, '', t, bool)
665         comp_true.adapter = adapter
666         comp_true.value = True
667
668         comp_false = exprclass(comp_false, '', t, bool)
669         comp_false.adapter = adapter
670         comp_false.value = False
671
672         return (expr_true, expr_false, comp_true, comp_false)
673
674     def hints_from_value_for_datetime_datetime(self, value):
675         """
676         Datetime values can be timezone naive or timezone aware.
677
678         If they are aware - indicate so in the hints dict.
679         """
680         if value and value.tzinfo:
681             return {'timezone_aware': True}
682         else:
683             return {'timezone_aware': False}
684
685     def dbtype_for_datetime_datetime(self, hints):
686         if hints.get('timezone_aware'):
687             for type in self.known_types['datetime']:
688                 if getattr(type, 'timezone_aware', False):
689                     return type()
690
691         return self.known_types['datetime'][0]()
692
693     def dbtype_for_datetime_date(self, hints):
694         return self.known_types['date'][0]()
695
696     def dbtype_for_datetime_time(self, hints):
697         return self.known_types['time'][0]()
698
699     def dbtype_for_datetime_timedelta(self, hints):
700         try:
701             # If your DB has an INTERVAL datatype, you should provide a
702             # native INTERVAL type. You'll also have to update the date
703             # arithmetic inside the deparser and add a timedelta adapter.
704             return self.known_types['timedelta'][0]()
705         except (KeyError, IndexError):
706             # Fallback for DB's which do not have an INTERVAL data type.
707             # Use decimal instead of float to avoid rounding errors.
708             # Using precision of 12 should allow +/- 31688 years.
709             return self.decimal_type(12, 0)
710
711     def numeric_max_precision(self):
712         return max([0] + [t.max_precision for t in self.known_types['numeric']])
713
714     def numeric_max_scale(self):
715         return max([0] + [t.max_scale for t in self.known_types['numeric']])
716
717     def decimal_type(self, precision, scale):
718         if scale > precision:
719             scale = precision
720
721         for dbtype in self.known_types['numeric']:
722             if (precision <= dbtype.max_precision and
723                 (scale is None or scale <= dbtype.max_scale)):
724                 return dbtype(precision=precision, scale=scale)
725
726         # Use a VARCHAR type (add 1 char for the decimal point and 1 for sign).
727         bytes = precision + 1
728         if scale:
729             bytes += 1
730         dbtype = self.dbtype_for_str({'bytes': bytes})
731
732         errors.warn("The given precision and scale (%s, %s) is greater than "
733                     "the maximum numeric precision and/or scale (%s/%s). "
734                     "Using %s instead."
735                     % (precision, scale, self.numeric_max_precision(),
736                        self.numeric_max_scale(), dbtype))
737         return dbtype
738
739     if typerefs.decimal:
740         if hasattr(typerefs.decimal, "Decimal"):
741             def dbtype_for_decimal_Decimal(self, hints):
742                 precision = int(hints.get('precision', 0))
743                 if precision == 0:
744                     precision = self.numeric_max_precision()
745                 # Assume most people use decimal for money; default scale = 2.
746                 scale = int(hints.get('scale', 2))
747                 return self.decimal_type(precision, scale)
748         else:
749             def dbtype_for_decimal(self, hints):
750                 precision = int(hints.get('precision', 0))
751                 if precision == 0:
752                     precision = self.numeric_max_precision()
753                 # Assume most people use decimal for money; default scale = 2.
754                 scale = int(hints.get('scale', 2))
755                 return self.decimal_type(precision, scale)
756
757     if typerefs.fixedpoint:
758         def dbtype_for_fixedpoint_FixedPoint(self, hints):
759             # Note that fixedpoint has no theoretical precision limit.
760             precision = int(hints.get('precision', 0))
761             if precision == 0:
762                 precision = self.numeric_max_precision()
763             # Assume most people use fixedpoint for money; default scale = 2.
764             scale = int(hints.get('scale', 2))
765             return self.decimal_type(precision, scale)
766
767     def dbtype_for_long(self, hints):
768         # Assume most people want signed numbers.
769         signed = hints.get('signed', True)
770
771         if 'bytes' in hints:
772             bytes = int(hints['bytes'])
773             maxprec = int(math.ceil(math.log(2 ** (bytes * 8), 10)))
774         else:
775             maxprec = self.numeric_max_precision()
776             bytes = int(math.ceil(math.log(10 ** maxprec, 2) / 8))
777
778         for dbtype in self.known_types['int']:
779             if bytes <= dbtype.max_bytes and signed == dbtype.signed:
780                 return dbtype(bytes=bytes)
781
782         return self.decimal_type(precision=maxprec, scale=0)
783
784     def dbtype_for_int(self, hints):
785         # Assume most people want signed numbers; maxint_bytes assumes it.
786         signed = hints.get('signed', True)
787         bytes = int(hints.get('bytes', adapters.maxint_bytes))
788
789         for dbtype in self.known_types['int']:
790             if bytes <= dbtype.max_bytes and signed == dbtype.signed:
791                 return dbtype(bytes=bytes)
792
793         maxprec = int(math.ceil(math.log(2 ** (bytes * 8), 10)))
794         # TODO STRABS: WTF? Why does int default to decimal?
795         return self.decimal_type(precision=maxprec, scale=0)
796
Note: See TracBrowser for help on using the browser.