Changeset 172
- Timestamp:
- 02/27/06 23:48:09
- Files:
-
- trunk/storage/db.py (modified) (31 diffs)
- trunk/storage/storeado.py (modified) (14 diffs)
- trunk/storage/storemysql.py (modified) (6 diffs)
- trunk/storage/storepypgsql.py (modified) (2 diffs)
- trunk/storage/storesqlite.py (modified) (3 diffs)
- trunk/test/zoo_fixture.py (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/storage/db.py
r171 r172 14 14 assume no limit, although you may choose whatever default size you wish 15 15 (255 is common for strings). 16 17 ENCODING ISSUES 18 =============== 19 All SQL sent to the database must be strings, not unicode. You can set the 20 encoding of the Adapters (I may add a more centralized encoding context in 21 the future). We must use encoded strings so that we can mix encodings 22 within the same string; for example, we might have a DB which understands 23 utf8, but a pickle value which will be encoded in raw-unicode-escape inline 24 with that. All values, therefore, must be coerced before we try to join 25 them into an SQL statement string. 26 16 27 """ 17 28 … … 106 117 def coerce_float(self, cls, key): 107 118 prop = getattr(cls, key) 108 bytes = int(prop.hints.get( u'bytes', '8'))119 bytes = int(prop.hints.get('bytes', '8')) 109 120 if bytes < 5: 110 121 # In MySQL, REAL is still probably 8 bytes. Meh. 111 return u"REAL"122 return "REAL" 112 123 else: 113 124 # Python floats are implemented using C doubles; 114 125 # actual precision depends on platform. PostgreSQL 115 126 # DOUBLE is 8 bytes (15 decimal-digit precision). 116 return u"DOUBLE PRECISION"127 return "DOUBLE PRECISION" 117 128 118 129 def coerce_str(self, cls, key): 119 130 # The bytes hint shall not reflect the usual 4-byte base for varchar. 120 131 prop = getattr(cls, key) 121 bytes = int(prop.hints.get( u'bytes', '0'))132 bytes = int(prop.hints.get('bytes', '0')) 122 133 if bytes: 123 return u"VARCHAR(%s)" % bytes134 return "VARCHAR(%s)" % bytes 124 135 else: 125 136 # TEXT is not an SQL standard, but it's common. 126 return u"TEXT"137 return "TEXT" 127 138 128 139 def coerce_dict(self, cls, key): … … 135 146 return self.coerce_str(cls, key) 136 147 137 def coerce_bool(self, cls, key): return u"BOOLEAN"138 139 def coerce_datetime_datetime(self, cls, key): return u"TIMESTAMP"140 def coerce_datetime_date(self, cls, key): return u"DATE"141 def coerce_datetime_time(self, cls, key): return u"TIME"148 def coerce_bool(self, cls, key): return "BOOLEAN" 149 150 def coerce_datetime_datetime(self, cls, key): return "TIMESTAMP" 151 def coerce_datetime_date(self, cls, key): return "DATE" 152 def coerce_datetime_time(self, cls, key): return "TIME" 142 153 143 154 # I was seriously disinterested in writing a parser for interval. … … 158 169 precision = self.numeric_max_precision 159 170 # Assume most people use decimal for money; default scale = 2. 160 scale = int(prop.hints.get( u'scale', 2))161 return u"NUMERIC(%s, %s)" % (precision, scale)171 scale = int(prop.hints.get('scale', 2)) 172 return "NUMERIC(%s, %s)" % (precision, scale) 162 173 163 174 def coerce_decimal(self, cls, key): … … 171 182 precision = self.numeric_max_precision 172 183 # Assume most people use decimal for money; default scale = 2. 173 scale = int(prop.hints.get( u'scale', 2))174 return u"NUMERIC(%s, %s)" % (precision, scale)184 scale = int(prop.hints.get('scale', 2)) 185 return "NUMERIC(%s, %s)" % (precision, scale) 175 186 176 187 def coerce_long(self, cls, key): 177 188 prop = getattr(cls, key) 178 bytes = int(prop.hints.get( u'bytes', 0))189 bytes = int(prop.hints.get('bytes', 0)) 179 190 if bytes <= 4: 180 191 return self.coerce_int(cls, key) … … 194 205 def coerce_int(self, cls, key): 195 206 prop = getattr(cls, key) 196 bytes = int(prop.hints.get( u'bytes', '4'))207 bytes = int(prop.hints.get('bytes', '4')) 197 208 if bytes == 1: 198 209 return "BOOLEAN" … … 202 213 ## return "MEDIUMINT" 203 214 else: 204 return u"INTEGER"215 return "INTEGER" 205 216 206 217 … … 211 222 """ 212 223 224 # You should REALLY check into your DB's encoding and override this. 225 encoding = 'utf8' 226 213 227 # Notice these are ordered pairs. Escape \ before introducing new ones. 228 # Values in these two lists should be strings encoded with self.encoding. 214 229 escapes = [("'", "''"), ("\\", r"\\")] 215 230 like_escapes = [("%", r"\%"), ("_", r"\_")] … … 223 238 def escape_like(self, value): 224 239 """Prepare a string value for use in a LIKE comparison.""" 240 if not isinstance(value, str): 241 value = value.encode(self.encoding) 225 242 # Notice we strip leading and trailing quote-marks. 226 243 value = value.strip("'\"") … … 235 252 236 253 def tostr(self, value): 237 return str(value) 254 if isinstance(value, basestring): 255 return value.encode(self.encoding) 256 else: 257 return str(value) 238 258 239 259 def coerce_NoneType(self, value): … … 249 269 # and comparisons will still work! 250 270 def coerce_datetime_datetime(self, value): 251 return ( u"'%04d-%02d-%02d %02d:%02d:%02d'" %271 return ("'%04d-%02d-%02d %02d:%02d:%02d'" % 252 272 (value.year, value.month, value.day, 253 273 value.hour, value.minute, value.second)) 254 274 255 275 def coerce_datetime_date(self, value): 256 return u"'%04d-%02d-%02d'" % (value.year, value.month, value.day)276 return "'%04d-%02d-%02d'" % (value.year, value.month, value.day) 257 277 258 278 def coerce_datetime_time(self, value): 259 return u"'%02d:%02d:%02d'" % (value.hour, value.minute, value.second)279 return "'%02d:%02d:%02d'" % (value.hour, value.minute, value.second) 260 280 261 281 def coerce_datetime_timedelta(self, value): … … 267 287 268 288 def do_pickle(self, value): 269 return self.coerce_str(pickle.dumps(value)) 289 # Note: dumps with protocol 0 uses the 'raw-unicode-escape' 290 # encoding, and we take pains not to re-encode it with 291 # self.encoding. 292 value = pickle.dumps(value) 293 return self.coerce_str(value, skip_encoding=True) 270 294 271 295 coerce_dict = do_pickle … … 279 303 coerce_long = tostr 280 304 281 def coerce_str(self, value): 305 def coerce_str(self, value, skip_encoding=False): 306 if not skip_encoding and not isinstance(value, str): 307 value = value.encode(self.encoding) 282 308 for pat, repl in self.escapes: 283 309 value = value.replace(pat, repl) … … 300 326 This base class is designed to work out-of-the-box with PostgreSQL 8. 301 327 """ 328 329 # You should REALLY check into your DB's encoding and override this. 330 encoding = 'utf8' 302 331 303 332 def coerce(self, value, coltype, valuetype=None): … … 323 352 def do_pickle(self, value, coltype): 324 353 # Coerce to str for pickle.loads restriction. 354 if isinstance(value, unicode): 355 value = value.encode(self.encoding) 325 356 value = str(value) 326 357 return pickle.loads(value) … … 369 400 370 401 def coerce_str(self, value, coltype): 371 return str(value) 402 if isinstance(value, basestring): 403 return value.encode(self.encoding) 404 else: 405 return str(value) 372 406 373 407 coerce_tuple = do_pickle 374 408 375 409 def coerce_unicode(self, value, coltype): 376 # You should REALLY check into your DB's encoding and override this. 377 return unicode(value, "utf8") 410 if isinstance(value, unicode): 411 return value 412 else: 413 return unicode(value, self.encoding) 378 414 379 415 380 416 # -------------------------- SQL DECOMPILATION -------------------------- # 381 417 382 class ConstWrapper( unicode):418 class ConstWrapper(str): 383 419 """Wraps a constant for use in SQLDecompiler's stack. 384 420 … … 388 424 """ 389 425 def __new__(self, basevalue, coerced_value): 390 newobj = unicode.__new__(ConstWrapper, coerced_value)426 newobj = str.__new__(ConstWrapper, coerced_value) 391 427 newobj.basevalue = basevalue 392 428 return newobj 393 394 def __str__(self):395 return str(self)396 397 def __unicode__(self):398 return self399 400 def __repr__(self):401 return self402 429 403 430 … … 774 801 return adapter_class 775 802 776 adapter = get_adapter_option( u'Type Adapter')803 adapter = get_adapter_option('Type Adapter') 777 804 if adapter: self.typeAdapter = adapter 778 adapter = get_adapter_option( u'To Adapter')805 adapter = get_adapter_option('To Adapter') 779 806 if adapter: self.toAdapter = adapter 780 adapter = get_adapter_option( u'From Adapter')807 adapter = get_adapter_option('From Adapter') 781 808 if adapter: self.fromAdapter = adapter 782 809 783 self.pool_size = int(allOptions.get( u'Pool Size', '10'))810 self.pool_size = int(allOptions.get('Pool Size', '10')) 784 811 785 812 self.refs = {} … … 791 818 self.threaded = True 792 819 793 self.prefix = allOptions.get( u'Prefix', u"djv")820 self.prefix = allOptions.get('Prefix', "djv") 794 821 self.reserve_lock = threading.Lock() 795 822 796 823 ec = {} 797 for prop in allOptions.get( u'Expanded Columns', '').split(","):824 for prop in allOptions.get('Expanded Columns', '').split(","): 798 825 if prop: 799 826 cls, type = [x.strip() for x in prop.split(":", 1)] … … 924 951 fields = [self.column_name(clsname, x) for x in fields] 925 952 if distinct: 926 sql = u'SELECT DISTINCT %s FROM %s'953 sql = 'SELECT DISTINCT %s FROM %s' 927 954 else: 928 sql = u'SELECT %s FROM %s'929 sql = sql % ( u', '.join(fields), tablename)930 else: 931 sql = u'SELECT * FROM %s' % tablename955 sql = 'SELECT %s FROM %s' 956 sql = sql % (', '.join(fields), tablename) 957 else: 958 sql = 'SELECT * FROM %s' % tablename 932 959 933 960 w, i = self.where((clsname,), expr) 934 961 if len(w) > 0: 935 w = u" WHERE " + w936 else: 937 w = u""962 w = " WHERE " + w 963 else: 964 w = "" 938 965 sql += w + ";" 939 966 return sql, i … … 947 974 if conn is None: 948 975 conn = self.connection() 976 if isinstance(query, unicode): 977 query = query.encode(self.toAdapter.encoding) 949 978 self.arena.log(query, LOGSQL) 950 return conn.query(query .encode('utf8'))979 return conn.query(query) 951 980 952 981 def fetch(self, query, conn=None): … … 1014 1043 id_fields = [self.column_name(clsname, prop.key) 1015 1044 for prop in cls.identifiers] 1016 data, cols = self.fetch( u'SELECT %s FROM %s;' %1045 data, cols = self.fetch('SELECT %s FROM %s;' % 1017 1046 (', '.join(id_fields), tablename)) 1018 1047 if data: … … 1045 1074 values.append(val) 1046 1075 1047 fields = u", ".join(fields) 1048 values = u", ".join(values) 1076 fields = ", ".join(fields) 1077 try: 1078 values = ", ".join(values) 1079 except UnicodeDecodeError: 1080 print values 1081 raise 1049 1082 self.execute('INSERT INTO %s (%s) VALUES (%s);' % 1050 ( tablename, fields, values))1083 (str(tablename), fields, values)) 1051 1084 unit.cleanse() 1052 1085 finally: … … 1082 1115 if parms: 1083 1116 sql = ('UPDATE %s SET %s WHERE %s;' % 1084 (self.table_name(clsname), u", ".join(parms),1117 (self.table_name(clsname), ", ".join(parms), 1085 1118 self.id_clause(unit))) 1086 1119 self.execute(sql) … … 1095 1128 # Just drop the old table and start with a new one. 1096 1129 try: 1097 self.execute( u"DROP TABLE %s;" % table)1130 self.execute("DROP TABLE %s;" % table) 1098 1131 except: 1099 1132 pass … … 1106 1139 else: 1107 1140 ftype = getattr(self.typeAdapter, "coerce_" + subtype)(unitcls, key) 1108 self.execute( u"CREATE TABLE %s (EXPVAL %s);" % (table, ftype))1141 self.execute("CREATE TABLE %s (EXPVAL %s);" % (table, ftype)) 1109 1142 1110 1143 for v in val: 1111 self.execute( u"INSERT INTO %s (EXPVAL) VALUES ('%s');"1144 self.execute("INSERT INTO %s (EXPVAL) VALUES ('%s');" 1112 1145 % (table, self.toAdapter.coerce(v))) 1113 1146 … … 1118 1151 table = self.table_name("_%s_%s_%s" % (unitcls.__name__, id, key)) 1119 1152 try: 1120 data, col_defs = self.fetch( u"SELECT EXPVAL FROM %s" % table)1153 data, col_defs = self.fetch("SELECT EXPVAL FROM %s" % table) 1121 1154 except: 1122 1155 values = None … … 1138 1171 else: 1139 1172 star = "" 1140 self.execute( u'DELETE%s FROM %s WHERE %s;' %1173 self.execute('DELETE%s FROM %s WHERE %s;' % 1141 1174 (star, self.table_name(unit.__class__.__name__), 1142 1175 self.id_clause(unit))) … … 1284 1317 1285 1318 statement = ("SELECT %s FROM %s WHERE %s" % 1286 ( u', '.join(colnames), joins, w))1319 (', '.join(colnames), joins, w)) 1287 1320 return statement, imp, cols 1288 1321 … … 1346 1379 fields = [] 1347 1380 for key in cls.properties(): 1348 fields.append( u'%s %s' % (self.column_name(clsname, key),1381 fields.append('%s %s' % (self.column_name(clsname, key), 1349 1382 typename(cls, key))) 1350 self.execute( u'CREATE TABLE %s (%s);' % (tablename, ", ".join(fields)))1383 self.execute('CREATE TABLE %s (%s);' % (tablename, ", ".join(fields))) 1351 1384 1352 1385 for index in cls.indices(): 1353 1386 i = self.table_name("i" + clsname + index) 1354 self.execute( u'CREATE INDEX %s ON %s (%s);' %1387 self.execute('CREATE INDEX %s ON %s (%s);' % 1355 1388 (i, tablename, self.column_name(clsname, index))) 1356 1389 … … 1366 1399 1367 1400 def drop_storage(self, cls): 1368 self.execute( u'DROP TABLE %s;' % self.table_name(cls.__name__))1401 self.execute('DROP TABLE %s;' % self.table_name(cls.__name__)) 1369 1402 1370 1403 def add_property(self, cls, name): trunk/storage/storeado.py
r171 r172 86 86 class AdapterFromADO(db.AdapterFromDB): 87 87 """Coerce incoming values from ADO to Dejavu datatypes.""" 88 89 encoding = 'ISO-8859-1' 88 90 89 91 def coerce_datetime_datetime(self, value, coltype): … … 150 152 if isinstance(value, (basestring, buffer)): 151 153 try: 152 return unicode(value, "ISO-8859-1")154 return unicode(value, self.encoding) 153 155 except UnicodeError: 154 156 raise StandardError(type(value)) … … 338 340 if conn is None: 339 341 conn = self.connection() 342 if isinstance(query, unicode): 343 query = query.encode(self.toAdapter.encoding) 340 344 self.arena.log(query, dejavu.LOGSQL) 341 345 try: … … 431 435 class AdapterToADOSQL_SQLServer(db.AdapterToSQL): 432 436 437 encoding = 'ISO-8859-1' 438 433 439 escapes = [("'", "''")] 434 440 like_escapes = [("%", "[%]"), ("_", "[_]")] … … 450 456 numeric_max_precision = 38 451 457 452 def coerce_bool(self, cls, key): return u"BIT" 458 def coerce_bool(self, cls, key): 459 return "BIT" 453 460 454 461 def coerce_datetime_datetime(self, cls, key): 455 return u"DATETIME"462 return "DATETIME" 456 463 457 464 def coerce_datetime_date(self, cls, key): 458 return u"DATETIME"465 return "DATETIME" 459 466 460 467 def coerce_datetime_time(self, cls, key): 461 return u"DATETIME"468 return "DATETIME" 462 469 463 470 def coerce_str(self, cls, key): 464 471 # The bytes hint does not reflect the usual 4-byte base for varchar. 465 472 prop = getattr(cls, key) 466 bytes = int(prop.hints.get( u'bytes', '0'))473 bytes = int(prop.hints.get('bytes', '0')) 467 474 if bytes == 0: 468 475 # Okay, what the @#$%& is wrong with Redmond??!?! We can't even … … 480 487 # might exceed the max size (8060) for a record. We could calc the 481 488 # total requested record size, and adjust accordingly. Meh. 482 return u"VARCHAR(%s)" % bytes489 return "VARCHAR(%s)" % bytes 483 490 484 491 … … 491 498 db.StorageManagerDB.__init__(self, name, arena, allOptions) 492 499 493 self.connstring = allOptions[ u'Connect']500 self.connstring = allOptions['Connect'] 494 501 atoms = self.connatoms() 495 self.dbname = atoms[ u'INITIAL CATALOG']502 self.dbname = atoms['INITIAL CATALOG'] 496 503 497 504 def create_database(self): … … 554 561 numeric_max_precision = 15 555 562 556 def coerce_bool(self, cls, key): return u"BIT"557 558 def coerce_datetime_datetime(self, cls, key): return u"DATETIME"559 def coerce_datetime_date(self, cls, key): return u"DATETIME"560 def coerce_datetime_time(self, cls, key): return u"DATETIME"563 def coerce_bool(self, cls, key): return "BIT" 564 565 def coerce_datetime_datetime(self, cls, key): return "DATETIME" 566 def coerce_datetime_date(self, cls, key): return "DATETIME" 567 def coerce_datetime_time(self, cls, key): return "DATETIME" 561 568 562 569 def numeric_type(self, cls, key, precision, scale): … … 600 607 precision = decimal.getcontext().prec 601 608 # Assume most people use decimal for money; default scale = 2. 602 scale = int(prop.hints.get( u'scale', 2))609 scale = int(prop.hints.get('scale', 2)) 603 610 return self.numeric_type(cls, key, precision, scale) 604 611 … … 609 616 precision = self.numeric_max_precision 610 617 # Assume most people use decimal for money; default scale = 2. 611 scale = int(prop.hints.get( u'scale', 2))618 scale = int(prop.hints.get('scale', 2)) 612 619 return self.numeric_type(cls, key, precision, scale) 613 620 614 621 def coerce_int(self, cls, key): 615 622 prop = getattr(cls, key) 616 bytes = int(prop.hints.get( u'bytes', '4'))623 bytes = int(prop.hints.get('bytes', '4')) 617 624 if bytes == 1: 618 625 return "BIT" 619 626 else: 620 return u"INTEGER"627 return "INTEGER" 621 628 622 629 def coerce_long(self, cls, key): 623 630 prop = getattr(cls, key) 624 bytes = int(prop.hints.get( u'bytes', 0))631 bytes = int(prop.hints.get('bytes', 0)) 625 632 return self.numeric_type(cls, key, precision, 0) 626 633 … … 628 635 # The bytes hint shall not reflect the usual 4-byte base for varchar. 629 636 prop = getattr(cls, key) 630 bytes = int(prop.hints.get( u'bytes', '0'))637 bytes = int(prop.hints.get('bytes', '0')) 631 638 if bytes and bytes <= 255: 632 639 # 255 chars is the upper limit for TEXT / VARCHAR in MS Access. 633 return u"VARCHAR(%s)" % bytes640 return "VARCHAR(%s)" % bytes 634 641 else: 635 642 # MEMO is 1 GB max when set programatically (only 64K when set … … 641 648 % (cls.__name__, key), 642 649 dejavu.StorageWarning) 643 return u"MEMO"650 return "MEMO" 644 651 645 652 … … 647 654 """Coerce Expression constants to ADO SQL.""" 648 655 656 encoding = 'ISO-8859-1' 657 649 658 escapes = [("'", "''")] 650 659 like_escapes = [("%", "[%]"), ("_", "[_]")] 651 660 652 661 def coerce_datetime_datetime(self, value): 653 return ( u'#%s/%s/%s %02d:%02d:%02d#' %662 return ('#%s/%s/%s %02d:%02d:%02d#' % 654 663 (value.month, value.day, value.year, 655 664 value.hour, value.minute, value.second)) 656 665 657 666 def coerce_datetime_date(self, value): 658 return u'#%s/%s/%s#' % (value.month, value.day, value.year)667 return '#%s/%s/%s#' % (value.month, value.day, value.year) 659 668 660 669 def coerce_datetime_time(self, value): 661 return u'#%02d:%02d:%02d#' % (value.hour, value.minute, value.second)670 return '#%02d:%02d:%02d#' % (value.hour, value.minute, value.second) 662 671 663 672 … … 674 683 db.StorageManagerDB.__init__(self, name, arena, allOptions) 675 684 676 self.connstring = allOptions[ u'Connect']685 self.connstring = allOptions['Connect'] 677 686 atoms = self.connatoms() 678 self.dbname = (atoms.get( u'DATA SOURCE') or679 atoms.get( u'DATA SOURCE NAME') or680 atoms.get( u'DBQ'))687 self.dbname = (atoms.get('DATA SOURCE') or 688 atoms.get('DATA SOURCE NAME') or 689 atoms.get('DBQ')) 681 690 # MS Access can't use a pool, because there doesn't seem 682 691 # to be a commit timeout. trunk/storage/storemysql.py
r171 r172 29 29 bool_false = "0" 30 30 31 def coerce_str(self, value): 31 def coerce_str(self, value, skip_encoding=False): 32 if not skip_encoding and not isinstance(value, str): 33 value = value.encode(self.encoding) 32 34 return "'" + _mysql.escape_string(value) + "'" 33 35 … … 46 48 value = (value == '1') 47 49 return bool(value) 48 49 def coerce_unicode(self, value, coltype):50 return unicode(value, "utf-8")51 50 52 51 … … 93 92 def coerce_str(self, cls, key): 94 93 prop = getattr(cls, key) 95 bytes = int(prop.hints.get( u'bytes', '0'))94 bytes = int(prop.hints.get('bytes', '0')) 96 95 if bytes: 97 96 # MySQL VARBINARY/BLOBs will do case-sensitive comparisons. 98 97 # They also won't truncate trailing spaces like VARCHAR does. 99 98 if bytes <= 255: 100 return u"VARBINARY(%s)" % bytes99 return "VARBINARY(%s)" % bytes 101 100 elif bytes < 2 ** 16: 102 101 return "BLOB" 103 102 elif bytes < 2 ** 24: 104 103 return "MEDIUMBLOB" 105 return u"LONGBLOB"104 return "LONGBLOB" 106 105 107 106 def coerce_bool(self, cls, key): 108 107 # We could use BOOLEAN, but it wasn't introduced until 4.1.0. 109 return u"BOOL"108 return "BOOL" 110 109 111 110 def coerce_datetime_datetime(self, cls, key): 112 return u"DATETIME"111 return "DATETIME" 113 112 114 113 … … 188 187 def destroy(self, unit): 189 188 """destroy(unit). Delete the unit.""" 190 self.execute( u'DELETE FROM %s WHERE %s;' %189 self.execute('DELETE FROM %s WHERE %s;' % 191 190 (self.table_name(unit.__class__.__name__), 192 191 self.id_clause(unit))) … … 220 219 fields = [] 221 220 for key in cls.properties(): 222 fields.append( u'%s %s' % (self.column_name(clsname, key),221 fields.append('%s %s' % (self.column_name(clsname, key), 223 222 coerce(cls, key))) 224 self.execute( u'CREATE TABLE %s (%s);' % (tablename, ", ".join(fields)))223 self.execute('CREATE TABLE %s (%s);' % (tablename, ", ".join(fields))) 225 224 226 225 for index in cls.indices(): … … 231 230 # MySQL won't allow indexes on a BLOB field 232 231 # without a specific length. 233 self.execute( u'CREATE INDEX %s ON %s (%s(%s));' %232 self.execute('CREATE INDEX %s ON %s (%s(%s));' % 234 233 (i, tablename, 235 234 self.column_name(clsname, index), 255)) 236 235 else: 237 self.execute( u'CREATE INDEX %s ON %s (%s);' %236 self.execute('CREATE INDEX %s ON %s (%s);' % 238 237 (i, tablename, 239 238 self.column_name(clsname, index))) trunk/storage/storepypgsql.py
r171 r172 50 50 51 51 # connstring = (host=h port=p dbname=d user=u password=p options=o tty=t) 52 self.connstring = allOptions[ u'Connect']52 self.connstring = allOptions['Connect'] 53 53 atoms = self.connstring.split(" ") 54 54 for atom in atoms: … … 112 112 def has_storage(self, cls): 113 113 # For some odd reason, libpq errors if you try to filter by tablename. 114 sql = u"SELECT tablename FROM pg_tables"114 sql = "SELECT tablename FROM pg_tables" 115 115 data, cols = self.fetch(sql) 116 116 return [self.table_name(cls.__name__, quoted=False)] in data trunk/storage/storesqlite.py
r171 r172 143 143 db.StorageManagerDB.__init__(self, name, arena, allOptions) 144 144 145 dbfile = allOptions.get( u'Database', '')145 dbfile = allOptions.get('Database', '') 146 146 if not os.path.isabs(dbfile): 147 147 dbfile = os.path.join(os.getcwd(), dbfile) 148 148 self.database = dbfile 149 149 150 self.mode = int(allOptions.get( u'Mode', '0755'), 8)150 self.mode = int(allOptions.get('Mode', '0755'), 8) 151 151 152 152 def sql_name(self, name, quoted=True): … … 179 179 if conn is None: 180 180 conn = self.connection() 181 if isinstance(query, unicode): 182 query = query.encode(self.toAdapter.encoding) 181 183 self.arena.log(query, dejavu.LOGSQL) 182 return conn.execute(query .encode('utf8'))184 return conn.execute(query) 183 185 # ^^^^^^^ 184 186 except Exception, x: … … 259 261 fields = [self.column_name(clsname, key) for key in cls.properties()] 260 262 261 self.execute( u'CREATE TABLE %s (%s);' % (tablename, ", ".join(fields)))263 self.execute('CREATE TABLE %s (%s);' % (tablename, ", ".join(fields))) 262 264 for index in cls.indices(): 263 265 i = self.table_name("i" + clsname + index) 264 self.execute( u'CREATE INDEX %s ON %s (%s);' %266 self.execute('CREATE INDEX %s ON %s (%s);' % 265 267 (i, tablename, self.column_name(clsname, index))) 266 268 trunk/test/zoo_fixture.py
r171 r172 105 105 Animals = UnitProperty(list) 106 106 PettingAllowed = UnitProperty(bool) 107 Creators = UnitProperty(tuple) 108 107 109 if decimal: 108 110 Acreage = UnitProperty(decimal.Decimal) … … 222 224 PettingAllowed = True, 223 225 Acreage = "3.21", 226 # See ticket #45 227 Creators = (u'Richard F\xfcrst', u'Sonja Martin'), 224 228 ) 225 229 box.memorize(pe) … … 744 748 """Dejavu logger (writes to error.log).""" 745 749 if flag & arena.logflags: 746 s = "%s %s" % (datetime.datetime.now().isoformat(), 747 message.encode('utf8')) 750 if isinstance(message, unicode): 751 message = message.encode('utf8') 752 s = "%s %s" % (datetime.datetime.now().isoformat(), message) 748 753 fname = os.path.join(os.path.dirname(__file__), "djvtest.log") 749 754 f = open(fname, 'ab')
