18 |
# $Source$ |
# $Source$ |
19 |
# $Id$ |
# $Id$ |
20 |
|
|
|
import os |
|
|
import weakref |
|
21 |
from sqlite import connect |
from sqlite import connect |
22 |
|
|
23 |
from base import TitledObject |
from base import TitledObject |
160 |
""" |
""" |
161 |
return self.column_map.has_key(col) |
return self.column_map.has_key(col) |
162 |
|
|
163 |
def ReadRowAsDict(self, index): |
def RowIdToOrdinal(self, gid): |
164 |
|
"""Return the row ordinal given its id |
165 |
|
|
166 |
|
At the moment the transient tables are only used for tables that |
167 |
|
don't distinguish between row number and row id, so the value is |
168 |
|
returned unchanged. |
169 |
|
""" |
170 |
|
return gid |
171 |
|
|
172 |
|
def RowOrdinalToId(self, num): |
173 |
|
"""Return the rowid for given its ordinal |
174 |
|
|
175 |
|
At the moment the transient tables are only used for tables that |
176 |
|
don't distinguish between row number and row id, so the value is |
177 |
|
returned unchanged. |
178 |
|
""" |
179 |
|
return num |
180 |
|
|
181 |
|
def ReadRowAsDict(self, index, row_is_ordinal = 0): |
182 |
|
"""Return the entire row as a dictionary with column names as keys |
183 |
|
|
184 |
|
The row_is_ordinal is ignored because at the moment the |
185 |
|
transient tables are only used for DBF files where it doesn't |
186 |
|
matter. |
187 |
|
""" |
188 |
# Implementation Strategy: Executing a completely new select |
# Implementation Strategy: Executing a completely new select |
189 |
# statement every time this method is called is too slow. The |
# statement every time this method is called is too slow. The |
190 |
# most important usage is to read the records more or less |
# most important usage is to read the records more or less |
232 |
self.read_record_last_row = index |
self.read_record_last_row = index |
233 |
return dict(zip(self.orig_names, result)) |
return dict(zip(self.orig_names, result)) |
234 |
|
|
235 |
def ReadValue(self, row, col): |
def ReadValue(self, row, col, row_is_ordinal = 0): |
236 |
"""Return the value of the specified row and column |
"""Return the value of the specified row and column |
237 |
|
|
238 |
The col parameter may be the index of the column or its name. |
The col parameter may be the index of the column or its name. |
239 |
|
|
240 |
|
The row_is_ordinal is ignored because at the moment the |
241 |
|
transient tables are only used for DBF files where it doesn't |
242 |
|
matter. |
243 |
""" |
""" |
244 |
# Depending on the actual access patterns of the table data, it |
# Depending on the actual access patterns of the table data, it |
245 |
# might be a bit faster in some circumstances to not implement |
# might be a bit faster in some circumstances to not implement |
271 |
def Width(self, col): |
def Width(self, col): |
272 |
"""Return the maximum width of values in the column |
"""Return the maximum width of values in the column |
273 |
|
|
274 |
The return value is the the maximum length of string representation |
The return value is the the maximum length of string |
275 |
of the values in the column (represented by index or name).""" |
representation of the values in the column (represented by index |
276 |
|
or name). |
277 |
|
""" |
278 |
max = 0 |
max = 0 |
279 |
|
|
280 |
type = self.column_map[col].type |
type = self.column_map[col].type |
281 |
iname = self.column_map[col].internal_name |
iname = self.column_map[col].internal_name |
282 |
cursor = self.db.cursor() |
cursor = self.db.cursor() |
285 |
if not values: |
if not values: |
286 |
return None |
return None |
287 |
|
|
288 |
if type == sql_type_map[table.FIELDTYPE_DOUBLE]: |
if type == table.FIELDTYPE_DOUBLE: |
289 |
format = "%.12f" |
format = "%.12f" |
290 |
elif type == sql_type_map[table.FIELDTYPE_INT]: |
elif type == table.FIELDTYPE_INT: |
291 |
format = "%d" |
format = "%d" |
292 |
else: |
else: |
293 |
format = "%s" |
format = "%s" |
407 |
that the value of the left_field column the the left table is |
that the value of the left_field column the the left table is |
408 |
equal to the value of the right_field in the right_table. |
equal to the value of the right_field in the right_table. |
409 |
|
|
410 |
The joined table contains all columns of the input tables with |
The joined table contains all columns of the input tables, |
411 |
one exception: Any column in the right_table with the same name |
however, the column names of the right table may be changed |
412 |
as one of the columns in the left_table will be omitted. This is |
slightly to make them unique in the joined table. This is |
413 |
somewhat of an implementation detail, but is done so that the |
currently done by appending a sufficient number of underscores |
414 |
column names of the joined table can be the same as the column |
('_'). |
|
names of the input tables without having to create prefixes. |
|
415 |
""" |
""" |
416 |
TransientTableBase.__init__(self, transient_db) |
TransientTableBase.__init__(self, transient_db) |
417 |
self.dependencies = (left_table, right_table) |
self.dependencies = (left_table, right_table) |
442 |
# column names are the same they will be mapped to the same |
# column names are the same they will be mapped to the same |
443 |
# internal name afterwards. |
# internal name afterwards. |
444 |
internal_left_col = self.left_table.orig_to_internal[self.left_field] |
internal_left_col = self.left_table.orig_to_internal[self.left_field] |
445 |
internal_right_col = self.right_table.orig_to_internal[self.right_field] |
internal_right_col =self.right_table.orig_to_internal[self.right_field] |
446 |
|
|
447 |
# Coalesce the column information |
# Coalesce the column information |
448 |
visited = {} |
visited = {} |
449 |
columns = [] |
columns = [] |
450 |
newcolumns = [] |
newcolumns = [] |
451 |
for table, col in ( |
for table in (self.left_table, self.right_table): |
452 |
[ (self.left_table.tablename, c) for c in self.left_table.columns ] |
for col in table.Columns(): |
453 |
+ [ (self.right_table.tablename, c) for c in self.right_table.columns]): |
colname = col.name |
454 |
if col.name in visited: |
# We can't allow multiple columns with the same |
455 |
if col.name == self.left_field: |
# original name, so append '_' to this one until |
456 |
continue |
# it is unique. |
457 |
else: |
# FIXME: There should be a better solution. |
458 |
# We can't allow multiple columns with the same original |
while colname in visited: |
459 |
# name, so append '_' to this one until it is unique. |
colname = colname + '_' |
460 |
# FIXME: There should be a better solution. |
columns.append((table.tablename, col)) |
461 |
while col.name in visited: |
newcol = ColumnReference(colname, col.type, |
462 |
col.name = col.name + '_' |
"Col%03d" % (len(newcolumns)+1)) |
463 |
columns.append((table, col)) |
newcolumns.append(newcol) |
464 |
newcol = ColumnReference(col.name, col.type, |
visited[colname] = 1 |
|
"Col%03d" % (len(newcolumns)+1)) |
|
|
newcolumns.append(newcol) |
|
|
visited[col.name] = 1 |
|
465 |
TransientTableBase.create(self, newcolumns) |
TransientTableBase.create(self, newcolumns) |
466 |
|
|
467 |
# Copy the joined data to the table. |
# Copy the joined data to the table. |
491 |
"""Return a tuple with the two tables the join depends on.""" |
"""Return a tuple with the two tables the join depends on.""" |
492 |
return self.dependencies |
return self.dependencies |
493 |
|
|
494 |
|
def JoinType(self): |
495 |
|
"""Return the type of the join (either 'INNER' or 'LEFT OUTER')""" |
496 |
|
if self.outer_join: |
497 |
|
return "LEFT OUTER" |
498 |
|
else: |
499 |
|
return "INNER" |
500 |
|
|
501 |
|
|
502 |
class AutoTransientTable(TitledObject, table.OldTableInterfaceMixin): |
class AutoTransientTable(TitledObject, table.OldTableInterfaceMixin): |
503 |
|
|
530 |
def NumColumns(self): |
def NumColumns(self): |
531 |
return self.table.NumColumns() |
return self.table.NumColumns() |
532 |
|
|
533 |
def ReadRowAsDict(self, record): |
def RowIdToOrdinal(self, gid): |
534 |
|
"""Return the row ordinal given its id""" |
535 |
|
if self.t_table is not None: |
536 |
|
return self.t_table.RowIdToOrdinal(gid) |
537 |
|
else: |
538 |
|
return self.table.RowIdToOrdinal(gid) |
539 |
|
|
540 |
|
def RowOrdinalToId(self, num): |
541 |
|
"""Return the rowid for given its ordinal""" |
542 |
|
if self.t_table is not None: |
543 |
|
return self.t_table.RowOrdinalToId(num) |
544 |
|
else: |
545 |
|
return self.table.RowOrdinalToId(num) |
546 |
|
|
547 |
|
def ReadRowAsDict(self, record, row_is_ordinal = 0): |
548 |
"""Return the record no. record as a dict mapping field names to values |
"""Return the record no. record as a dict mapping field names to values |
549 |
""" |
""" |
550 |
if self.t_table is not None: |
if self.t_table is not None: |
551 |
return self.t_table.ReadRowAsDict(record) |
return self.t_table.ReadRowAsDict(record, |
552 |
|
row_is_ordinal = row_is_ordinal) |
553 |
else: |
else: |
554 |
return self.table.ReadRowAsDict(record) |
return self.table.ReadRowAsDict(record, |
555 |
|
row_is_ordinal = row_is_ordinal) |
556 |
|
|
557 |
def ReadValue(self, row, col): |
def ReadValue(self, row, col, row_is_ordinal = 0): |
558 |
"""Return the value of the specified row and column |
"""Return the value of the specified row and column |
559 |
|
|
560 |
The col parameter may be the index of the column or its name. |
The col parameter may be the index of the column or its name. |
561 |
""" |
""" |
562 |
if self.t_table is not None: |
if self.t_table is not None: |
563 |
return self.t_table.ReadValue(row, col) |
return self.t_table.ReadValue(row, col, |
564 |
|
row_is_ordinal = row_is_ordinal) |
565 |
else: |
else: |
566 |
return self.table.ReadValue(row, col) |
return self.table.ReadValue(row, col, |
567 |
|
row_is_ordinal = row_is_ordinal) |
568 |
|
|
569 |
def copy_to_transient(self): |
def copy_to_transient(self): |
570 |
"""Internal: Create a transient table and copy the data into it""" |
"""Internal: Create a transient table and copy the data into it""" |