55 import os, sys, string, types, re
62 LOGGING_STATUS[DEV_UPDATE] = 1
63 LOGGING_STATUS[DEV_SELECT] = 1
64 LOGGING_STATUS[DEV_REPORT] = 1
83 class eNonUniqueMatchSpec(odb_Exception):
121 def get(self, data, options):
124 def set(self, val, options):
130 except UnicodeEncodeError:
131 return data.encode(
"utf-8")
137 def needEscape(self):
return False 139 def compressionOk(self):
return False 143 def sqlColType(self, options):
151 except (ValueError,TypeError):
152 raise eInvalidData, data
164 class _ODB_IncInteger(_ODB_Integer):
166 def sqlColType(self, options):
171 def set(self, data, options):
173 n = options[
"enum_values"][data]
175 raise eInvalidData, data
178 def get(self, val, options):
179 return options[
'inv_enum_values'][int(val)]
184 def sqlColType(self, options):
185 sz = options.get(
'size',
None)
186 if sz
is None: coltype =
'char' 187 else: coltype =
"char(%s)" % sz
192 def needQuoting(self):
return True 196 def sqlColType(self, options):
197 sz = options.get(
'size',
None)
198 if sz
is None: coltype =
'varchar' 199 else: coltype =
"varchar(%s)" % sz
204 def sqlColType(self, options):
return "text" 207 if options.get(
"compress_ok",
False):
208 cdata = zlib.compress(data, 9)
209 if len(cdata) < len(data):
214 if options.get(
'compress_ok',
False)
and val:
216 data = zlib.decompress(val)
223 def compressionOk(self):
return True 227 def sqlColType(self, options):
return "text" 230 def needEncode(self):
return True 233 class _ODB_DateTime(_ODB_FixedString):
235 def sqlColType(self, options):
return "datetime" 239 def sqlColType(self, options):
return "timestamp" 243 def odbType(self):
return "kCreatedStamp" 245 row[colname] = int(time.time())
249 def odbType(self):
return "kCreatedStampMS" 251 row[colname] = time.time()
255 def beforeUpdate(self, row, colname):
256 row[colname] = int(time.time())
263 def sqlColType(self, options):
return "real" 271 except (ValueError,TypeError):
272 raise eInvalidData, val
277 class _ODB_GUID(_ODB_FixedString):
279 def sqlColType(self, options):
282 return guid.generate()
319 patStr =
"([a-z]+)(\(([0-9]+)\))?" 320 pat = re.compile(patStr)
321 dataStr = dataStr.lower().strip()
322 m = pat.match(dataStr)
326 dataType = m.group(1)
329 if dataType ==
"integer":
331 elif dataType ==
"varchar":
332 fieldType = kVarString
333 elif dataType ==
"real":
335 elif dataType ==
"datetime":
336 fieldType = kDateTime
337 elif dataType ==
"timestamp":
338 fieldType = kTimeStamp
339 elif dataType ==
"text":
340 fieldType = kBigString
342 fieldType = kVarString
356 return self.cursor.execute(sql)
362 return self.cursor.fetchone()
365 return self.cursor.fetchmany(size=size, keep=keep)
368 return self.cursor.fetchall()
371 raise "Unimplemented Error" 374 return self.cursor.close()
381 return Cursor(self._conn.cursor())
387 return self._conn.commit()
390 return self._conn.rollback()
393 return self._conn.close()
396 return coltype,
"AUTO_INCREMENT" 403 def listTriggers(self):
404 raise Unimplemented,
"triggers are not implemented in this connection type." 428 for tblName
in self._tables.keys():
429 if tblName.find(
"_repl_") == 0:
continue 430 tblList.append(tblName)
434 if self._tables.has_key(
"_repl_log"):
return True 442 self.
_cursor = self.conn.cursor()
448 return "%%%02X" % ord(c)
450 return re.sub(
"('|\0|%)",subfn,str)
454 hexnum = int(m.group(1),16)
456 return re.sub(
"%(..)",subfn,str)
460 return self.conn.escape(str)
462 return self.conn.encode(str)
464 return self.conn.decode(str)
478 def addTable(self, attrname, tblname, tblclass,
484 tbl = tblclass(self, tblname, rowClass=rowClass, check=check,
485 create=create, rowListClass=rowListClass,
486 replication=replication)
495 if self.conn
is not None:
496 cursor = self.defaultCursor()
509 raise AttributeError,
"odb.Database: not initialized properly, self._tables does not exist" 512 return self._tables[tblname]
514 raise AttributeError,
"odb.Database: unknown table %s" % (tblname)
519 raise AttributeError,
"odb.Database: not initialized properly, self._tables does not exist" 522 table_dict = getattr(self,
"_tables")
523 return table_dict[key]
525 raise AttributeError,
"odb.Database: unknown attribute %s" % (key)
529 cursor = self.defaultCursor()
530 dlog(DEV_UPDATE,
"begin")
536 cursor = self.defaultCursor()
537 dlog(DEV_UPDATE,
"commit")
543 cursor = self.defaultCursor()
544 dlog(DEV_UPDATE,
"rollback")
553 tables = self.listTables()
555 for attrname, tbl
in self._tables.items():
556 tblname = tbl.getTableName()
558 if tblname
not in tables:
562 invalidAppCols, invalidDBCols = tbl.checkTable()
567 for attrname, tbl
in self._tables.items():
568 indices = self.listIndices(tbl.getTableName())
569 for indexName, (columns, unique)
in tbl.getIndices().
items():
570 if indexName
in indices:
continue 573 tbl.createIndex(columns, indexName=indexName, unique=unique)
576 cursor = self.defaultCursor()
577 indices = self.listIndices(
"")
578 for indexName
in indices:
579 sql =
"DROP INDEX %s" % indexName
583 triggers = self.listTriggers()
585 for attrname, tbl
in self._tables.items():
586 for triggerName, triggerSQL
in tbl._triggers.items():
588 if triggerName
in triggers:
589 self.dropTrigger(triggerName)
590 triggers.remove(triggerName)
591 self.createTrigger(triggerName, triggerSQL)
594 for trigger
in triggers:
595 self.dropTrigger(triggerName)
598 if cursor
is None: cursor = self.defaultCursor()
602 if cursor
is None: cursor = self.defaultCursor()
603 sql =
"DROP TRIGGER %s" % triggerName
609 tables = self.listTables()
610 for tablename
in tables:
611 tbl = self.addTable(tablename, tablename, _ReflectTable)
615 tables = self.listTables()
617 cursor = self.defaultCursor()
618 for attrname, tbl
in self._tables.items():
619 tblname = tbl.getTableName()
620 self.conn.alterTableToMatch(tbl, cursor)
623 if self.conn.supportsTriggers():
624 self.createTriggers()
627 if cursor
is None: cursor = self.defaultCursor()
628 return self.conn.listTables(cursor)
631 if cursor
is None: cursor = self.defaultCursor()
632 return self.conn.listTriggers(cursor)
635 if cursor
is None: cursor = self.defaultCursor()
636 return self.conn.listIndices(tableName, cursor)
640 if cursor
is None: cursor = self.defaultCursor()
641 return self.conn.listFieldsDict(table_name, cursor)
644 columns = self.listFieldsDict(table_name, cursor=cursor)
645 return columns.keys()
656 def __init__(self,database,table_name,
662 self.
__db = weakref.ref(database)
698 self.__replication.addTable(self)
721 coltype = coltype.sqlColType(options)
725 if options.get(
'notnull', 0): coldef = coldef +
" NOT NULL" 726 if options.get(
'autoincrement', 0):
727 coltype, acoldef = self.
getDB().conn.auto_increment(coltype)
729 coldef = coldef +
" " + acoldef
731 if options.get(
'unique', 0): coldef = coldef +
" UNIQUE" 734 if options.get(
'primarykey', 0): coldef = coldef +
" PRIMARY KEY" 736 if options.has_key(
'default'):
737 defaultValue = options.get(
'default')
738 if defaultValue
is None:
739 coldef = coldef +
" DEFAULT NULL" 740 elif type(defaultValue)
in (types.IntType, types.LongType, types.FloatType):
741 coldef = coldef +
" DEFAULT %s" % defaultValue
743 coldef = coldef +
" DEFAULT '%s'" % defaultValue
746 coldef =
"%s %s %s" % (colname, coltype, coldef)
761 if len(primarykeys) == 1: singlePrimaryKey = 1
767 defs = string.join(defs,
", ")
770 if singlePrimaryKey == 0:
773 primarykey_str =
", PRIMARY KEY (" + string.join(primarykeys,
",") +
")" 778 sql =
"CREATE TABLE %s (%s %s)" % (self.
__table_name, defs, primarykey_str)
782 if cursor
is None: cursor = self.
__db().defaultCursor()
785 sql = self.
__db().conn.createTable(sql, cursor)
787 debug(
"CREATING TABLE:", sql)
792 if cursor
is None: cursor = self.
__db().defaultCursor()
795 except self.
getDB().SQLError, reason:
799 if cursor
is None: cursor = self.
__db().defaultCursor()
802 except self.
getDB().SQLError, reason:
806 if cursor
is None: cursor = self.
__db().defaultCursor()
808 cursor.execute(
"rename table %s to %s" % (self.
__table_name, newTableName))
809 except self.
getDB().SQLError, reason:
825 dbcoldef = dbcolumns.get(colname,
None)
827 invalidAppCols[colname] = 1
829 for colname, row
in dbcolumns.items():
830 coldef = self.__col_def_hash.get(colname,
None)
832 invalidDBCols[colname] = 1
835 if 'docid' in invalidAppCols: del invalidAppCols[
'docid']
836 if 'rowid' in invalidAppCols: del invalidAppCols[
'rowid']
840 warn(
"----- WARNING ------------------------------------------")
841 warn(
" There are columns defined in the database schema that do")
843 warn(
" columns:", invalidDBCols.keys())
844 warn(
"--------------------------------------------------------")
847 warn(
"----- WARNING ------------------------------------------")
848 warn(
" There are new columns defined in the application schema")
850 warn(
" columns:", invalidAppCols.keys())
851 warn(
"--------------------------------------------------------")
853 return invalidAppCols, invalidDBCols
857 if cursor
is None: cursor = self.defaultCursor()
858 return self.conn.alterTableToMatch(cursor)
860 def addIndex(self, columns, indexName=None, unique=0):
861 if indexName
is None:
862 indexName = self.
getTableName() +
"_index_" + string.join(columns,
"_")
864 self.
__indices[indexName] = (columns, unique)
866 def createIndex(self, columns, indexName=None, unique=0, cursor=None):
867 if cursor
is None: cursor = self.
__db().defaultCursor()
868 cols = string.join(columns,
",")
870 if indexName
is None:
871 indexName = self.
getTableName() +
"_index_" + string.join(columns,
"_")
875 uniquesql =
" UNIQUE" 876 sql =
"CREATE %s INDEX %s ON %s (%s)" % (uniquesql, indexName, self.
getTableName(), cols)
877 debug(
"creating index: ", sql)
886 except eNoSuchColumn:
898 if column_name.startswith(
"_"):
899 parts = column_name[1:].split(
".")
901 table_column_name = parts[0]
902 column_name = parts[1]
905 foreign_table = c_options[
"foreign_table"]
906 foreign_key = c_options[
"foreign_key"]
908 a_table = self.
getDB()[foreign_table]
909 return a_table.getColumnDef(column_name)
927 c_name,c_type,c_options = col_def
929 if c_type == kBigString:
930 if c_options.get(
"compress_ok",0)
and self.
__db().compression_enabled:
931 z_size = len(zlib.compress(data,9))
949 return options[optionName]
961 c_name,c_type,c_options = col_def
973 c_name,c_type,c_options = col_def
975 if c_type == kIncInteger:
978 if data
is None:
return None 981 val = c_type.set(data, c_options)
983 except eInvalidData, reason:
984 raise eInvalidData(
"invalid data (%s) for col (%s:%s) on table (%s)" % (repr(data),col_name,c_type,self.
__table_name))
993 if options.get(
'primarykey', 0): primary_keys.append(col_name)
995 return tuple(primary_keys)
1001 return self.__col_def_hash.has_key(name)
1003 return self.__vcol_def_hash.has_key(name)
1007 raise odb_Exception(
"can't instantiate base odb.Table type, make a subclass and override _defineRows()")
1014 if self.__has_value_column:
1015 self.d_addColumn(
"odb_value",kBlob,
None, default=
'', notnull=1)
1018 self.__columns_locked = 1
1021 primary_key_list = []
1023 for a_col
in self.__column_list:
1024 name,type,options = a_col
1025 col_def_hash[name] = a_col
1026 if options.has_key(
'primarykey'):
1027 primary_key_list.append(name)
1029 self.__col_def_hash = col_def_hash
1030 self.__primary_key_list = primary_key_list
1034 if (
not self.__has_value_column)
and (len(self.__vcolumn_list) > 0):
1035 raise odb_Exception(
"can't define vcolumns on table without ValueColumn, call d_addValueColumn() in your _defineRows()")
1038 for a_col
in self.__vcolumn_list:
1039 name,type,options = a_col
1040 vcol_def_hash[name] = a_col
1042 self.__vcol_def_hash = vcol_def_hash
1047 raise odb_Exception(
"can't change column definitions outside of subclass' _defineRows() method!")
1062 def d_addColumn(self,col_name,ctype,size=None,primarykey = 0,
1063 notnull = 0,indexed=0,
1077 if ctype
in (kCreatedStamp, kModifiedStamp):
1081 options[
'default'] = default
1083 options[
'primarykey'] = primarykey
1085 options[
'unique'] = unique
1087 options[
'indexed'] = indexed
1090 options[
'safeupdate'] = safeupdate
1092 options[
'autoincrement'] = autoincrement
1094 options[
'autoguid'] = autoguid
1096 raise eInvalidData(
"cannot set autoguid for non-kGUID columns")
1098 options[
'notnull'] = notnull
1100 options[
'size'] = size
1102 options[
'no_export'] = no_export
1104 if ctype
not in (kInteger, kCreatedStamp, kModifiedStamp):
1105 raise eInvalidData(
"can't flag columns int_date unless they are kInteger")
1107 options[
'int_date'] = int_date
1110 options[
'enum_values'] = enum_values
1111 inv_enum_values = {}
1112 for k,v
in enum_values.items():
1113 if inv_enum_values.has_key(v):
1116 inv_enum_values[v] = k
1117 options[
'inv_enum_values'] = inv_enum_values
1120 foreign_table, foreign_column_name = foreign_key.split(
".")
1122 foreign_table = foreign_key
1123 foreign_column_name = col_name
1124 options[
'foreign_table'] = foreign_table
1125 options[
'foreign_key'] = foreign_column_name
1129 options[
'relations'] = relations
1130 for a_relation
in relations:
1131 table, foreign_column_name = a_relation
1132 if self.__relations_by_table.has_key(table):
1133 raise eInvalidData(
"multiple relations for the same foreign table are not yet supported" )
1135 if compress_ok
and self.
__db().compression_enabled:
1136 if ctype.compressionOk():
1137 options[
'compress_ok'] = 1
1139 raise eInvalidData(
"this column cannot be compress_ok=1")
1141 self.__column_list.append( (col_name,ctype,options) )
1144 sql =
"CREATE TRIGGER %s INSERT ON %s\n BEGIN\n %s;\n END;" % (triggerName, self.
getTableName(), tsql)
1148 sql =
"CREATE TRIGGER %s UPDATE ON %s\n BEGIN\n %s;\n END;" % (triggerName, self.
getTableName(), tsql)
1152 sql =
"CREATE TRIGGER %s UPDATE OF %s ON %s\n BEGIN\n %s;\n END;" % (triggerName, string.join(columns,
","), self.
getTableName(), tsql)
1156 sql =
"CREATE TRIGGER %s DELETE ON %s\n BEGIN\n %s;\n END;" % (triggerName, self.
getTableName(), tsql)
1168 raise odb_Exception(
"can't define VColumns on table without ValueColumn, call d_addValueColumn() first")
1172 options[
'default'] = default
1174 options[
'size'] = size
1176 self.__vcolumn_list.append( (col_name,type,options) )
1184 def d_belongsTo(self, col_name, tblNameStr=None, foreign_key=None, order=None):
1185 if foreign_key
is None: foreign_key = col_name
1189 def d_hasMany(self, tblname, col_name, foreign_key=None, order=None):
1190 if foreign_key
is None: foreign_key = col_name
1193 def d_hasOne(self, col_name, tblname, foreign_key=None, order=None):
1194 if foreign_key
is None: foreign_key = col_name
1197 options[
'foreign.table'] = tblname
1198 options[
'foreign.key'] = foreign_key
1213 if type(col_match_spec) == type([]):
1214 if type(col_match_spec[0]) != type((0,)):
1216 elif type(col_match_spec) == type((0,)):
1217 col_match_spec = [ col_match_spec ]
1218 elif type(col_match_spec) == type(
None):
1219 if should_match_unique_row:
1226 unique_column_lists = []
1228 if should_match_unique_row:
1231 my_primary_key_list = []
1233 my_primary_key_list.append(a_key)
1237 col_name,a_type,options = a_col
1238 if options.has_key(
'unique'):
1239 unique_column_lists.append( (col_name, [col_name]) )
1243 unique_column_lists.append((indexName, list(columns)))
1245 unique_column_lists.append( (
'primary_key', my_primary_key_list) )
1247 new_col_match_spec = []
1248 for a_col
in col_match_spec:
1253 if not self.__col_def_hash.has_key(newname):
1254 raise eNoSuchColumn(
"no such column in match spec: '%s'" % str(newname))
1256 new_col_match_spec.append( (newname,val) )
1258 if should_match_unique_row:
1259 for name,a_list
in unique_column_lists:
1261 a_list.remove(newname)
1266 if should_match_unique_row:
1267 for name,a_list
in unique_column_lists:
1268 if len(a_list) == 0:
1271 return new_col_match_spec
1278 return new_col_match_spec
1283 if not col_match_spec
is None:
1284 for m_col
in col_match_spec:
1285 m_col_name,m_col_val = m_col
1290 if m_col_val
is None:
1291 sql_where_list.append(
"%s = NULl" % (c_name,))
1294 val = c_type.convertFrom(m_col_val, c_options)
1295 except eInvalidData, data:
1299 if c_type.needEscape():
1300 val2 = self.
__db().escape(val)
1301 elif c_type.needEncode():
1302 val2 = self.
__db().encode(val)
1306 if c_type.needQuoting():
1307 sql_where_list.append(
"%s = '%s'" % (c_name, val2))
1309 sql_where_list.append(
"%s = %s" % (c_name, val2))
1312 if other_clauses
is None:
1314 elif type(other_clauses) == type(
""):
1315 sql_where_list = sql_where_list + [other_clauses]
1316 elif type(other_clauses) == type([]):
1317 sql_where_list = sql_where_list + other_clauses
1319 raise eInvalidData(
"unknown type of extra where clause: %s" % repr(other_clauses))
1321 return sql_where_list
1323 def __fetchRows(self,col_match_spec,cursor = None, where = None,
1324 order_by =
None, limit_to =
None,
1325 skip_to =
None, join =
None,
1330 cursor = self.
__db().defaultCursor()
1334 if column_list
is None:
1337 for name
in column_list:
1338 sql_columns.append(
"%s.%s" % (self.
__table_name, name))
1343 joined_cols_hash = {}
1345 if not join
is None:
1346 for a_table,retrieve_foreign_cols
in join:
1348 if isinstance(a_table, Table):
1350 a_table = atbl.getTableName()
1352 parts = a_table.split(
".")
1354 for atbln
in parts[:-1]:
1355 atbl = self.
getDB()[atbln]
1359 except KeyError,reason:
1360 raise eInvalidJoinSpec(
"can't find table %s in defined relations for %s (%s) reason=%s" % (a_table,self.
__table_name, repr(self.__relations_by_table.items()), reason))
1362 for a_col
in retrieve_foreign_cols:
1363 full_col_name =
"%s.%s" % (a_table,a_col)
1364 joined_cols_hash[full_col_name] = 1
1365 joined_cols.append(full_col_name)
1366 sql_columns.append( full_col_name )
1368 join_clauses.append(
" left join %s on %s.%s=%s.%s " % (a_table,atbl.getTableName(),my_col,a_table, foreign_col))
1370 if not join2
is None:
1373 foreign_table = c_options[
"foreign_table"]
1374 foreign_key = c_options[
"foreign_key"]
1377 a_table = self.
getDB()[foreign_table]
1380 joinTable =
"_%s" % (col, )
1381 joinColumn =
"%s.%s" % (joinTable, foreign_key)
1383 for col_name, ctype, options
in a_table.getAppColumnList():
1384 full_col_name =
"%s.%s" % (joinTable, col_name)
1386 joined_cols_hash[full_col_name] = 1
1387 joined_cols.append(full_col_name)
1388 sql_columns.append(full_col_name)
1390 join_clauses.append(
" left join %s AS %s on %s.%s=%s " % (a_table.getTableName(), joinTable, self.
getTableName(), col, joinColumn))
1394 sql =
"SELECT %s FROM %s" % (string.join(sql_columns,
","),
1399 sql = sql + string.join(join_clauses,
" ")
1404 sql = sql +
" WHERE %s" % (string.join(sql_where_list,
" and "))
1409 for col
in order_by:
1411 if type(col) == types.TupleType:
1413 elif type(col) == types.StringType:
1414 aparts = col.split(
" ", 1)
1415 if len(aparts) == 2:
1418 if col.find(
".") == -1:
1424 obstr = obstr +
" " + order
1429 sql = sql +
" ORDER BY %s " % string.join(ob,
",")
1432 if not limit_to
is None:
1433 if not skip_to
is None:
1435 if self.
__db().conn.getConnType() ==
"sqlite":
1436 sql = sql +
" LIMIT %s OFFSET %s " % (limit_to,skip_to)
1438 sql = sql +
" LIMIT %s, %s" % (skip_to,limit_to)
1440 sql = sql +
" LIMIT %s" % limit_to
1442 if not skip_to
is None:
1443 raise eInvalidData(
"can't specify skip_to without limit_to in MySQL")
1445 dlog(DEV_SELECT,sql)
1455 return_rows = self.__defaultRowListClass()
1458 all_rows = cursor.fetchall()
1459 if raw_rows ==
True:
1462 for a_row
in all_rows:
1469 for fullname
in sql_columns:
1470 parts = string.split(fullname,
".", 1)
1474 if self.__col_def_hash.has_key(name)
or joined_cols_hash.has_key(fullname):
1476 if joined_cols_hash.has_key(fullname):
1477 data_dict[fullname] = a_row[col_num]
1478 elif self.__col_def_hash.has_key(name):
1479 c_name,c_type,c_options = self.__col_def_hash[name]
1480 if a_row[col_num]
is None:
1481 data_dict[name] =
None 1483 aval = a_row[col_num]
1485 if c_type.needEncode():
1486 aval = self.__db().decode(aval)
1487 data_dict[name] = c_type.convertFrom(aval, c_options)
1489 data_dict[name] = a_row[col_num]
1491 col_num = col_num + 1
1493 newrowobj = self.__defaultRowClass(self,data_dict,joined_cols = joined_cols)
1494 return_rows.append(newrowobj)
1502 cursor = self.__db().defaultCursor()
1505 match_spec = a_row.getPKMatchSpec()
1506 sql_where_list = self.__buildWhereClause (match_spec)
1508 sql =
"DELETE FROM %s WHERE %s" % (self.__table_name,
1509 string.join(sql_where_list,
" and "))
1510 dlog(DEV_UPDATE,sql)
1513 if self.__replication:
1514 self.__replication.deleteRow(self, a_row)
1520 cursor = self.__db().defaultCursor()
1522 for a_row
in a_row_list:
1523 for name,c_type,options
in self.__column_list:
1524 if hasattr(c_type,
"beforeUpdate"):
1525 c_type.beforeUpdate(a_row, name)
1527 update_list = a_row.changedList()
1532 for a_change
in update_list:
1533 col_name,col_val,col_inc_val = a_change
1534 c_name,c_type,c_options = self.__col_def_hash[col_name]
1536 if c_type != kIncInteger
and col_val
is None:
1537 sql_set_list.append(
"%s = NULL" % c_name)
1538 elif c_type == kIncInteger
and col_inc_val
is None:
1539 sql_set_list.append(
"%s = 0" % c_name)
1541 if c_type == kIncInteger:
1542 sql_set_list.append(
"%s = %s + %d" % (c_name,c_name,long(col_inc_val)))
1545 sql_set_list.append(
"%s = NULL" % c_name)
1547 val = c_type.convertTo(col_val, c_options)
1549 if c_type.needEscape():
1550 val2 = self.__db().escape(val)
1551 elif c_type.needEncode():
1552 val2 = self.__db().encode(val)
1556 if c_type.needQuoting():
1557 sql_set_list.append(
"%s = '%s'" % (c_name, val2))
1559 sql_set_list.append(
"%s = %s" % (c_name, val2))
1563 match_spec = a_row.getPKMatchSpec()
1564 sql_where_list = self.__buildWhereClause (match_spec)
1567 sql =
"UPDATE %s SET %s WHERE %s" % (self.__table_name,
1568 string.join(sql_set_list,
","),
1569 string.join(sql_where_list,
" and "))
1571 dlog(DEV_UPDATE,sql)
1574 except Exception, reason:
1575 if string.find(str(reason),
"Duplicate entry") != -1:
1579 if self.__replication:
1580 self.__replication.updateRow(self, a_row)
1586 cursor = self.__db().defaultCursor()
1590 auto_increment_column_name =
None 1592 a_row_obj.changedList()
1594 for name,c_type,options
in self.__column_list:
1596 if not a_row_obj.has_key(name):
1597 if hasattr(c_type,
"beforeInsert"):
1598 c_type.beforeInsert(a_row_obj, name)
1600 data = a_row_obj._getRaw(name, convert=0)
1602 sql_col_list.append(name)
1604 sql_data_list.append(
"NULL")
1606 if c_type.needEscape():
1607 val = c_type.convertTo(data, options)
1608 val2 = self.__db().escape(val)
1609 elif c_type.needEncode():
1610 val = c_type.convertTo(data, options)
1611 val2 = self.__db().encode(val)
1615 if c_type.needQuoting():
1616 sql_data_list.append(
"'%s'" % val2)
1618 sql_data_list.append(str(val2))
1620 except KeyError, reason:
1621 if options.has_key(
"autoguid"):
1622 sql_col_list.append(name)
1623 a_row_obj[name] = c_type.generate()
1624 sql_data_list.append(
"'%s'" % a_row_obj[name])
1625 elif options.has_key(
"autoincrement"):
1626 if auto_increment_column_name:
1627 raise eInternalError(
"two autoincrement columns (%s,%s) in table (%s)" % (auto_increment_column_name, name,self.__table_name))
1629 auto_increment_column_name = name
1632 sql =
"REPLACE INTO %s (%s) VALUES (%s)" % (self.__table_name,
1633 string.join(sql_col_list,
","),
1634 string.join(sql_data_list,
","))
1636 sql =
"INSERT INTO %s (%s) VALUES (%s)" % (self.__table_name,
1637 string.join(sql_col_list,
","),
1638 string.join(sql_data_list,
","))
1640 dlog(DEV_UPDATE,sql)
1644 except Exception, reason:
1646 log(
"error in statement: " + sql +
"\n")
1647 if string.find(str(reason),
"Duplicate entry") != -1:
1651 if self.__replication:
1652 self.__replication.updateRow(self, a_row_obj)
1654 if auto_increment_column_name:
1655 a_row_obj[auto_increment_column_name] = cursor.insert_id(self.__table_name, auto_increment_column_name)
1672 self.__deleteRow(a_row_obj, cursor = curs)
1684 self.__updateRowList([a_row_obj], cursor = curs)
1695 self.__insertRow(a_row_obj, cursor = curs,replace=replace)
1715 n_match_spec = self._fixColMatchSpec(col_match_spec)
1716 cursor = self.__db().defaultCursor()
1719 sql_where_list = self.__buildWhereClause (n_match_spec,where)
1720 if not sql_where_list:
1723 sql =
"DELETE FROM %s WHERE %s" % (self.__table_name, string.join(sql_where_list,
" and "))
1725 dlog(DEV_UPDATE,sql)
1738 def fetchRow(self, col_match_spec, cursor = None, join2=None):
1739 n_match_spec = self._fixColMatchSpec(col_match_spec, should_match_unique_row = 1)
1741 rows = self.__fetchRows(n_match_spec, cursor = cursor, join2=join2)
1746 raise eInternalError(
"unique where clause shouldn't return > 1 row")
1759 def fetchRows(self, col_match_spec = None, cursor = None,
1760 where =
None, order_by =
None, limit_to =
None,
1761 skip_to =
None, join =
None,
1765 n_match_spec = self._fixColMatchSpec(col_match_spec)
1767 return self.__fetchRows(n_match_spec,
1770 order_by = order_by,
1771 limit_to = limit_to,
1775 column_list = column_list,
1776 raw_rows = raw_rows)
1779 cursor =
None, where =
None):
1780 n_match_spec = self._fixColMatchSpec(col_match_spec)
1781 sql_where_list = self.__buildWhereClause (n_match_spec,where)
1782 sql =
"SELECT COUNT(*) FROM %s" % self.__table_name
1784 sql =
"%s WHERE %s" % (sql,string.join(sql_where_list,
" and "))
1786 cursor = self.__db().defaultCursor()
1787 dlog(DEV_SELECT,sql)
1790 count, = cursor.fetchone()
1805 return self.__fetchRows([], join2=join2)
1806 except eNoMatchingRows:
1808 return self.__defaultRowListClass()
1811 row = self.__defaultRowClass(self,
None,create=1,replace=replace)
1812 for (cname, ctype, opts)
in self.__column_list:
1813 if opts[
'default']
is not None and ctype
is not kIncInteger:
1814 row[cname] = opts[
'default']
1816 for k,v
in kws.items():
1825 kl = self.getPrimaryKeyList()
1827 if len(kl) != len(args):
1828 raise eInternalData(
"wrong number of primary key arguments")
1833 keylist.append((field, args[i]))
1836 return self.fetchRow(keylist)
1840 for k,v
in kws.items():
1841 keylist.append((k,v))
1844 row = self.fetchRow(keylist, join2=join2)
1845 except eNoMatchingRows:
1851 for k,v
in kws.items():
1852 keylist.append((k,v))
1855 rows = self.fetchRows(keylist, join2=join2)
1856 except eNoMatchingRows:
1861 row = self.lookup(**kws)
1865 for k,v
in kws.items():
1872 __instance_data_locked = 0
1876 def __init__(self,_table,data_dict,create=0,joined_cols = None,replace=0):
1890 for a_col
in joined_cols
or []:
1896 if type(data_dict) != type({}):
1897 raise eInternalError,
"rowdict instantiate with bad data_dict" 1910 return self._table.getDB()
1913 self._joinedRows.append(another_row)
1919 changed_list = self.changedList()
1920 if len(changed_list):
1928 for key
in self.__inc_coldata.keys():
1936 for col_name
in self._table.getPrimaryKeyList():
1938 rdata = self[col_name]
1940 raise eInternalError,
"must have primary key data filled in to save %s:Row(col:%s)" % (self._table.getTableName(),col_name)
1942 new_match_spec.append( (col_name, rdata) )
1946 if self._table.hasValueColumn():
1947 if self.__coldata.has_key(
"odb_value")
and self.
__coldata[
'odb_value']:
1949 val2 = self.
getDB().unescape_string(val)
1961 if self._table.hasValueColumn():
1962 self.__coldata[
'odb_value'] = self.getDB().escape_string(marshal.dumps(self.__vcoldata))
1963 self.__colchanged_dict[
'odb_value'] = 1
1970 changed_list = self.changedList()
1971 if len(changed_list):
1972 info =
"unsaved Row for table (%s) lost, call discard() to avoid this error. Lost changes: %s\n" % (self._table.getTableName(), repr(changed_list)[:256])
1974 raise eUnsavedObjectLost, info
1976 sys.stderr.write(info)
1980 return "Row from (%s): %s" % (self._table.getTableName(),repr(self.__coldata) + repr(self.__vcoldata))
1985 if self._inside_getattr:
1986 raise AttributeError,
"recursively called __getattr__ (%s,%s)" % (key,self._table.getTableName())
1988 self._inside_getattr = 1
1992 if self._table.hasColumn(key)
or self._table.hasVColumn(key):
1995 raise AttributeError,
"unknown field '%s' in Row(%s)" % (key,self._table.getTableName())
1997 self._inside_getattr = 0
2000 if not self.__instance_data_locked:
2001 self.__dict__[key] = val
2003 my_dict = self.__dict__
2004 if my_dict.has_key(key):
2010 except KeyError, reason:
2011 raise AttributeError, reason
2017 self.checkRowActive()
2020 c_name, c_type, c_options = self._table.getColumnDef(key)
2021 except eNoSuchColumn:
2029 if c_type == kIncInteger:
2030 c_data = self.__coldata.get(key, 0)
2031 if c_data
is None: c_data = 0
2032 i_data = self.__inc_coldata.get(key, 0)
2033 if i_data
is None: i_data = 0
2034 return c_data + i_data
2038 return c_type.get(self.__coldata[key], c_options)
2040 return self.__coldata[key]
2044 return self.__vcoldata[key]
2046 for a_joined_row
in self._joinedRows:
2048 return a_joined_row[key]
2052 raise KeyError,
"unknown column %s in '%s'" % (key,self.getTable().getTableName())
2056 return self._getRaw(key)
2059 self.checkRowActive()
2062 newdata = self._table.convertDataForColumn(data,key)
2063 except eNoSuchColumn, reason:
2064 raise KeyError, reason
2066 if self._table.hasColumn(key):
2067 self.__coldata[key] = newdata
2068 self.__colchanged_dict[key] = 1
2069 elif self._table.hasVColumn(key):
2070 self.__vcoldata[key] = newdata
2071 self.__vcolchanged = 1
2073 for a_joined_row
in self._joinedRows:
2075 a_joined_row[key] = data
2079 raise KeyError,
"unknown column name %s" % key
2083 self.checkRowActive()
2085 if self.table.hasVColumn(key):
2086 del self.__vcoldata[key]
2088 for a_joined_row
in self._joinedRows:
2090 del a_joined_row[key]
2094 raise KeyError,
"unknown column name %s" % key
2098 for name,t,options
in self._table.getColumnList():
2099 if not options.has_key(
"autoincrement"):
2100 self[name] = source[name]
2106 self.checkRowActive()
2109 for name,t,options
in self._table.getColumnList():
2110 key_list.append(name)
2111 for name
in self.__joined_cols_dict.keys():
2112 key_list.append(name)
2114 for a_joined_row
in self._joinedRows:
2115 key_list = key_list + a_joined_row.keys()
2121 self.checkRowActive()
2124 for name,t,options
in self._table.getColumnList():
2125 item_list.append( (name,self[name]) )
2127 for name
in self.__joined_cols_dict.keys():
2128 item_list.append( (name,self[name]) )
2130 for a_joined_row
in self._joinedRows:
2131 item_list = item_list + a_joined_row.items()
2137 self.checkRowActive()
2139 value_list = self.__coldata.values() + self.__vcoldata.values()
2141 for a_joined_row
in self._joinedRows:
2142 value_list = value_list + a_joined_row.values()
2148 self.checkRowActive()
2150 my_len = len(self.__coldata) + len(self.__vcoldata)
2152 for a_joined_row
in self._joinedRows:
2153 my_len = my_len + len(a_joined_row)
2158 self.checkRowActive()
2160 if self.__coldata.has_key(key)
or self.__vcoldata.has_key(key):
2164 for a_joined_row
in self._joinedRows:
2165 if a_joined_row.has_key(key):
2169 def get(self,key,default = None):
2170 self.checkRowActive()
2174 if self.__coldata.has_key(key):
2175 return self.__coldata[key]
2176 elif self.__vcoldata.has_key(key):
2177 return self.__vcoldata[key]
2179 for a_joined_row
in self._joinedRows:
2181 return a_joined_row.get(key,default)
2182 except eNoSuchColumn:
2185 if self._table.hasColumn(key):
2188 raise eNoSuchColumn,
"no such column %s" % key
2191 self.checkRowActive()
2193 if self._table.hasColumn(key):
2195 self.__inc_coldata[key] = self.__inc_coldata[key] + count
2197 self.__inc_coldata[key] = count
2199 self.__colchanged_dict[key] = 1
2201 raise AttributeError,
"unknown field '%s' in Row(%s)" % (key,self._table.getTableName())
2209 for field_def
in self._table.fieldList():
2210 name,type,size,options = field_def
2211 if options.has_key(
"default"):
2212 self[name] = options[
"default"]
2222 if self.__vcolchanged:
2223 self.__packVColumn()
2226 for a_col
in self.__colchanged_dict.keys():
2227 changed_list.append( (a_col,self.get(a_col,
None),self.__inc_coldata.get(a_col,
None)) )
2232 self.__coldata =
None 2233 self.__vcoldata =
None 2234 self.__colchanged_dict = {}
2235 self.__vcolchanged = 0
2238 self.checkRowActive()
2240 fromTable = self._table
2242 fromTable.r_deleteRow(self,cursor=curs)
2243 self._rowInactive =
"deleted" 2248 toTable = self._table
2250 self.checkRowActive()
2252 if self._should_insert:
2253 toTable.r_insertRow(self,replace=self._should_replace)
2254 self._should_insert = 0
2255 self._should_replace = 0
2259 toTable.r_updateRow(self,cursor = curs)
2265 if self._rowInactive:
2266 raise eInvalidData,
"row is inactive: %s" % self._rowInactive
2269 return self._table.databaseSizeForData_ColumnName_(self[key],key)
2278 for fieldname, dict
in fields.items():
2294 self.
getDB().
addTable(
"_repl_keyval",
"repl_keyval", Replication_KeyValueTable)
2295 self.
getDB().
addTable(
"_repl_log",
"repl_log", Replication_LogTable,
2296 rowClass = Replication_LogRow)
2297 self.
getDB().
addTable(
"_repl_deleted",
"repl_deleted", Replication_DeletedTable)
2303 tbl.d_addColumn(
"__modified", kModifiedStamp, no_export=1)
2307 row = self.
getDB()._repl_keyval.lookup(key=
"server_guid")
2315 for col_name
in tbl.getPrimaryKeyList():
2316 val = str(row[col_name])
2317 keyList.append(
"%s,%s,%s" % (col_name, len(val), val))
2318 key = string.join(keyList,
",")
2322 rrow = self.
getDB()._repl_log.newRow(replace=1)
2323 rrow.tableName = tbl.getTableName()
2340 drow = self.
getDB()._repl_deleted.newRow(replace=1)
2341 drow.tableName = tbl.getTableName()
2348 rows = self.
getDB()._repl_log.fetchRows((
'tableName', tableName), where = [
'timestamp >= %s' % startTime,
'timestamp <= %s' % endTime])
2357 self.
d_addColumn(
"key", kVarString, primarykey = 1)
2361 Table.createTable(self, cursor=cursor)
2366 server_guid = guid.generate()
2367 row = self.
getDB()._repl_keyval.newRow(replace=1,key=
"server_guid", val=server_guid)
2374 self.
d_addColumn(
"server_guid", kGUID, primarykey = 1)
2377 self.
d_addColumn(
"timestamp", kCreatedStampMS, primarykey = 1)
2380 self.
d_addColumn(
"rep_guid", kGUID, primarykey = 1, autoguid=1)
2395 self.
d_addColumn(
"tableName", kVarString, primarykey = 1)
2398 self.
d_addColumn(
"key", kVarString, primarykey = 1)
2409 j = key.find(
",", i)
2411 columnName = key[i:j]
2414 k = key.find(
",", j)
2417 valLength = key[j:k]
2420 i = k + int(valLength)
2424 keyList.append((columnName, val))
def columnType(self, col_name)
def __lockColumnsAndInit(self)
def delete(self, cursor=None)
def enabledCompression(self)
def listTriggers(self, cursor=None)
def lookup(self, join2=None, kws)
def inc(self, key, count=1)
def auto_increment(self, coltype)
def dropTable(self, cursor=None)
def getDefaultRowListClass(self)
def convertDataForColumn(self, data, col_name)
def convertTo(self, data, options)
def dropTrigger(self, triggerName, cursor=None)
def newRow(self, replace=0, save=0, kws)
def beforeInsert(self, row, colname)
def __recordUpdate(self, tbl, key)
def d_addValueColumn(self)
def lookupRows(self, join2=None, kws)
def set(self, val, options)
def parseFieldType(dataStr)
def d_addUpdateTrigger(self, triggerName, tsql)
def listFields(self, table_name, cursor=None)
def __buildWhereClause(self, col_match_spec, other_clauses=None)
def __getitem__(self, tblname)
def r_updateRow(self, a_row_obj, cursor=None)
r_updateRow(a_row_obj,cursor = None)
def __fetchRows(self, col_match_spec, cursor=None, where=None, order_by=None, limit_to=None, skip_to=None, join=None, join2=None, column_list=None, raw_rows=False)
def createTable(self, cursor=None)
def setDefaultRowListClass(self, clss)
def d_addInsertTrigger(self, triggerName, tsql)
def __init__(self, database, table_name, rowClass=None, check=0, create=0, rowListClass=None, replication=None)
def deleteRow(self, col_match_spec, where=None)
deleteRow(col_match_spec)
def __setattr__(self, key, val)
def commitTransaction(self, cursor=None)
def r_deleteRow(self, a_row_obj, cursor=None)
r_deleteRow(a_row_obj,cursor = None)
def createTable(self, sql, cursor)
def addIndex(self, columns, indexName=None, unique=0)
def save(self, cursor=None)
def fillDefaults(self)
real interface
def sqlColType(self, options)
def d_addDeleteTrigger(self, triggerName, tsql)
def fetchRowCount(self, col_match_spec=None, cursor=None, where=None)
def reflect(self)
parse the schema of an existing db and build table objects to reflect the schema. ...
def _getRaw(self, key, convert=1)
-— dict emulation ------------------------------—
def setTableName(self, tablename)
def hasColumn(self, column_name)
Column Definition.
def databaseSizeForColumn(self, key)
def fetchRows(self, col_match_spec=None, cursor=None, where=None, order_by=None, limit_to=None, skip_to=None, join=None, join2=None, column_list=None, raw_rows=False)
fetchRows(col_match_spec)
def convertFrom(self, val, options)
def __setitem__(self, key, data)
def listTables(self, cursor=None)
def get(self, val, options)
def d_hasMany(self, tblname, col_name, foreign_key=None, order=None)
def d_hasOne(self, col_name, tblname, foreign_key=None, order=None)
def convertTo(self, data, options)
def repl_parsePrimaryKey(key)
def _createTableSQL(self)
def r_insertRow(self, a_row_obj, cursor=None, replace=0)
InsertRow(a_row_obj,cursor = None)
def joinRowData(self, another_row)
def convertTo(self, data, options)
convertTo - converts 'data' to database representation from the local representation ...
def __deleteRow(self, a_row, cursor=None)
def createIndex(self, columns, indexName=None, unique=0, cursor=None)
def __init__(self, _table, data_dict, create=0, joined_cols=None, replace=0)
def d_addVColumn(self, col_name, type, size=None, default=None)
def fetchmany(self, size=None, keep=None)
def synchronizeSchema(self)
def deleteAllRows(self, cursor=None)
def escape_string(self, str)
def convertFrom(self, val, options)
convertFrom - converts 'val' from database representation to the local representation ...
def get(self, key, default=None)
def hasVColumn(self, name)
def __checkColumnLock(self)
def __getattr__(self, key)
-— class emulation -----------------------------—
def get(self, data, options)
def fetchRowUsingPrimaryKey(self, args)
def createTable(self, cursor=None)
def fetchAllRows(self, join2=None)
fetchAllRows()
def updateRow(self, tbl, row)
def listFieldsDict(self, table_name, cursor=None)
def d_addColumn(self, col_name, ctype, size=None, primarykey=0, notnull=0, indexed=0, default=None, unique=0, autoincrement=0, autoguid=0, safeupdate=0, enum_values=None, no_export=0, relations=None, foreign_key=None, compress_ok=0, int_date=0)
def d_fullTextSearch(self)
def getColumnDef(self, column_name)
def convertTo(self, data, options)
def createTrigger(self, triggerName, sql, cursor=None)
def renameTable(self, newTableName, cursor=None)
def supportsTriggers(self)
def getTableColumnsFromDB(self)
def listIndices(self, tableName, cursor=None)
def __delitem__(self, key, data)
def __insertRow(self, a_row_obj, cursor=None, replace=0)
def createTables(self)
schema creation code
int __instance_data_locked
def __unpackVColumn(self)
def changedList(self)
changedList()
def copyFrom(self, source)
def __del__(self)
--— utility stuff -------------------------------—
def _colTypeToSQLType(self, colname, coltype, options, singlePrimaryKey=0)
def getColumnOption(self, columnName, optionName)
def getAppColumnList(self)
def beginTransaction(self, cursor=None)
def sqlColType(self, options)
def defaultRowListClass(self)
def __init__(self, cursor)
def rollbackTransaction(self, cursor=None)
def convertTo(self, val, options)
def addTable(self, attrname, tblname, tblclass, rowClass=None, check=0, create=0, rowListClass=None, replication=None)
def __makeServerGUID(self)
def convertFrom(self, val, options)
def fetchRow(self, col_match_spec, cursor=None, join2=None)
fetchRow(col_match_spec)
def __init__(self, conn, debug=0)
def unescape_string(self, str)
def setDefaultRowClass(self, clss)
def alterTableToMatch(self, cursor=None)
def d_belongsTo(self, col_name, tblNameStr=None, foreign_key=None, order=None)
def beforeInsert(self, row, colname)
def getDefaultRowClass(self)
def databaseSizeForData_ColumnName_(self, data, col_name)
def getPrimaryKeyList(self)
def __getPrimaryKeyForTable(self, tbl, row)
def lookupCreate(self, kws)
def convertFrom(self, val, options)
def __packVColumn(self)
#warn(self) val2 = self.getDB().decode(val) warn("val2", repr(val2)) self.__vcoldata = marshal...
def _defineRelations(self)
def deleteRow(self, tbl, row)
def convertFrom(self, val, options)
def d_addUpdateColumnsTrigger(self, triggerName, columns, tsql)
def createIndices(self)
self.alterTableToMatch(tbl)
def getLogSince(self, tableName, startTime, endTime)
def checkTable(self, warnflag=1)
def __init__(self, message)
def _fixColMatchSpec(self, col_match_spec, should_match_unique_row=0)
_checkColMatchSpec(col_match_spec,should_match_unique_row = 0)
def defaultRowClass(self)
def __updateRowList(self, a_row_list, cursor=None)