def get_table_info(self, tblname, tx): """ Retrieves the metadata for the specified table out of the catalog. :param tblname: the name of the table :param tx: the transaction :return: the table's stored metadata """ assert isinstance(tx, Transaction) tcatfile = RecordFile(self._tcat_info, tx) reclen = -1 while tcatfile.next(): if tcatfile.get_string("tblname") == tblname: reclen = tcatfile.get_int("reclength") break tcatfile.close() fcatfile = RecordFile(self._fcat_info, tx) sch = Schema() offsets = {} while fcatfile.next(): if fcatfile.get_string("tblname") == tblname: fldname = fcatfile.get_string("fldname") fldtype = fcatfile.get_int("type") fldlen = fcatfile.get_int("length") offset = fcatfile.get_int("offset") offsets[fldname] = offset sch.add_field(fldname, fldtype, fldlen) fcatfile.close() return TableInfo(tblname, sch, offsets, reclen)
class ProductPlan(Plan): """ The Plan class corresponding to the <i>product</i> relational algebra operator. """ def __init__(self, p1: Plan, p2: Plan): """ Creates a new product node in the query tree, having the two specified subqueries. :param p1: the left-hand subquery :param p2: the right-hand subquery """ self._p1 = p1 self._p2 = p2 self._schema = Schema() self._schema.add_all(p1.schema()) self._schema.add_all(p2.schema()) def open(self): """ Creates a product scan for this query. """ s1 = self._p1.open() s2 = self._p2.open() return ProductScan(s1, s2) def blocks_accessed(self): """ Estimates the number of block accesses in the product. The formula is: B(product(p1,p2)) = B(p1) + R(p1)*B(p2) """ return self._p1.blocks_accessed() + self._p1.records_output() * self._p2.blocks_accessed() def records_output(self): """ Estimates the number of output records in the product. The formula is: R(product(p1,p2)) = R(p1)*R(p2) """ return self._p1.records_output() * self._p2.records_output() def distinct_values(self, fldname): """ Estimates the distinct number of field values in the product. Since the product does not increase or decrease field values, the estimate is the same as in the appropriate underlying query. """ if self._p1.schema().has_field(fldname): return self._p1.distinct_values(fldname) else: return self._p2.distinct_values(fldname) def schema(self): """ Returns the schema of the product, which is the union of the schemas of the underlying queries. """ return self._schema
class ProductPlan(Plan): """ The Plan class corresponding to the <i>product</i> relational algebra operator. """ def __init__(self, p1: Plan, p2: Plan): """ Creates a new product node in the query tree, having the two specified subqueries. :param p1: the left-hand subquery :param p2: the right-hand subquery """ self._p1 = p1 self._p2 = p2 self._schema = Schema() self._schema.add_all(p1.schema()) self._schema.add_all(p2.schema()) def open(self): """ Creates a product scan for this query. """ s1 = self._p1.open() s2 = self._p2.open() return ProductScan(s1, s2) def blocks_accessed(self): """ Estimates the number of block accesses in the product. The formula is: B(product(p1,p2)) = B(p1) + R(p1)*B(p2) """ return self._p1.blocks_accessed( ) + self._p1.records_output() * self._p2.blocks_accessed() def records_output(self): """ Estimates the number of output records in the product. The formula is: R(product(p1,p2)) = R(p1)*R(p2) """ return self._p1.records_output() * self._p2.records_output() def distinct_values(self, fldname): """ Estimates the distinct number of field values in the product. Since the product does not increase or decrease field values, the estimate is the same as in the appropriate underlying query. """ if self._p1.schema().has_field(fldname): return self._p1.distinct_values(fldname) else: return self._p2.distinct_values(fldname) def schema(self): """ Returns the schema of the product, which is the union of the schemas of the underlying queries. """ return self._schema
def __init__(self, is_new, tbl_mgr: TableMgr, tx: Transaction): self._tbl_mgr = tbl_mgr if is_new: sch = Schema() sch.add_string_field("viewname", TableMgr.MAX_NAME) sch.add_string_field("viewdef", self.MAX_VIEWDEF) tbl_mgr.create_table("viewcat", sch, tx)
def get_table_info(self, tblname, tx): """ Retrieves the metadata for the specified table out of the catalog. :param tblname: the name of the table :param tx: the transaction :return: the table's stored metadata """ assert isinstance(tx, Transaction) tcatfile = RecordFile(self._tcat_info, tx) reclen = -1 while tcatfile.next(): if tcatfile.get_string("tblname") == tblname: reclen = tcatfile.get_int("reclength") break tcatfile.close() fcatfile = RecordFile(self._fcat_info, tx) sch = Schema() offsets = {} while fcatfile.next(): if fcatfile.get_string("tblname") == tblname: fldname = fcatfile.get_string("fldname") fldtype = fcatfile.get_int("type") fldlen = fcatfile.get_int("length") offset = fcatfile.get_int("offset") offsets[fldname] = offset sch.add_field(fldname, fldtype, fldlen) fcatfile.close() return TableInfo(tblname, sch, offsets, reclen)
def __field_type(self, fldname: str) -> Schema: schema = Schema() if self._lex.match_keyword("int"): self._lex.eat_keyword("int") schema.add_int_field(fldname) else: self._lex.eat_keyword("varchar") self._lex.eat_delim("(") str_len = self._lex.eat_int_constant() self._lex.eat_delim(")") schema.add_string_field(fldname, str_len) return schema
def __init__(self, p1: Plan, p2: Plan): """ Creates a new product node in the query tree, having the two specified subqueries. :param p1: the left-hand subquery :param p2: the right-hand subquery """ self._p1 = p1 self._p2 = p2 self._schema = Schema() self._schema.add_all(p1.schema()) self._schema.add_all(p2.schema())
class ProjectPlan(Plan): """ The Plan class corresponding to the project relational algebra operator. """ def __init__(self, p: Plan, fieldlist: list): self._schema = Schema() self._p = p for fldname in fieldlist: self._schema.add(fldname, p.schema()) def open(self): """ Creates a project scan for this query. """ s = self._p.open() return ProjectScan(s, self._schema.fields()) def blocks_accessed(self): """ Estimates the number of block accesses in the projection, which is the same as in the underlying query. """ return self._p.blocks_accessed() def records_output(self): """ Estimates the number of output records in the projection, which is the same as in the underlying query. """ return self._p.records_output() def distinct_values(self, fldname): """ Estimates the number of distinct field values in the projection, which is the same as in the underlying query. """ return self._p.distinct_values(fldname) def schema(self): """ Returns the schema of the projection, which is taken from the field list. """ return self._schema
def __init__(self, is_new, tblmgr, tx): """ Creates the index manager. This constructor is called during system startup. If the database is new, then the idxcat table is created. :param is_new: indicates whether this is a new database :param tx: the system startup transaction """ assert isinstance(tblmgr, TableMgr) assert isinstance(tx, Transaction) if is_new: sch = Schema() sch.add_string_field("indexname", TableMgr.MAX_NAME) sch.add_string_field("tablename", TableMgr.MAX_NAME) sch.add_string_field("fieldname", TableMgr.MAX_NAME) tblmgr.create_table("idxcat", sch, tx) self._ti = tblmgr.get_table_info("idxcat", tx)
class ProjectPlan(Plan): """ The Plan class corresponding to the project relational algebra operator. """ def __init__(self, p: Plan, fieldlist: list): self._schema = Schema() self._p = p for fldname in fieldlist: self._schema.add(fldname, p.schema()) def open(self): """ Creates a project scan for this query. """ s = self._p.open() return ProjectScan(s, self._schema.fields()) def blocks_accessed(self): """ Estimates the number of block accesses in the projection, which is the same as in the underlying query. """ return self._p.blocks_accessed() def records_output(self): """ Estimates the number of output records in the projection, which is the same as in the underlying query. """ return self._p.records_output() def distinct_values(self, fldname): """ Estimates the number of distinct field values in the projection, which is the same as in the underlying query. """ return self._p.distinct_values(fldname) def schema(self): """ Returns the schema of the projection, which is taken from the field list. """ return self._schema
def __schema(self) -> Schema: """ Returns the schema of the index records. The schema consists of the dataRID (which is represented as two integers, the block number and the record ID) and the dataval (which is the indexed field). Schema information about the indexed field is obtained via the table's metadata. :return the schema of the index records """ sch = Schema() sch.add_int_field("block") sch.add_int_field("id") if self._ti.schema().type(self._fldname) == INTEGER: sch.add_int_field("dataval") else: fldlen = self._ti.schema().length(self._fldname) sch.add_string_field("dataval", fldlen)
def __init__(self, p1: Plan, p2: Plan, ii: IndexInfo, joinfield: str, tx: Transaction): """ Implements the join operator, using the specified LHS and RHS plans. :param p1: the left-hand plan :param p2: the right-hand plan :param ii: information about the right-hand index :param joinfield: the left-hand field used for joining :param tx: the calling transaction """ self._sch = Schema() self._p1 = p1 self._p2 = p2 self._ii = ii self._joinfield = joinfield self._sch.add_all(p1.schema()) self._sch.add_all(p2.schema())
def __init__(self, p1: Plan, p2: Plan): """ Creates a new product node in the query tree, having the two specified subqueries. :param p1: the left-hand subquery :param p2: the right-hand subquery """ self._p1 = p1 self._p2 = p2 self._schema = Schema() self._schema.add_all(p1.schema()) self._schema.add_all(p2.schema())
def __init__(self, is_new, tbl_mgr: TableMgr, tx: Transaction): self._tbl_mgr = tbl_mgr if is_new: sch = Schema() sch.add_string_field("viewname", TableMgr.MAX_NAME) sch.add_string_field("viewdef", self.MAX_VIEWDEF) tbl_mgr.create_table("viewcat", sch, tx)
def __schema(self) -> Schema: """ Returns the schema of the index records. The schema consists of the dataRID (which is represented as two integers, the block number and the record ID) and the dataval (which is the indexed field). Schema information about the indexed field is obtained via the table's metadata. :return the schema of the index records """ sch = Schema() sch.add_int_field("block") sch.add_int_field("id") if self._ti.schema().type(self._fldname) == INTEGER: sch.add_int_field("dataval") else: fldlen = self._ti.schema().length(self._fldname) sch.add_string_field("dataval", fldlen)
def join_pred(self, sch1, sch2): """ Returns the subpredicate consisting of terms that apply to the union of the two specified schemas, but not to either schema separately. :param sch1: the first schema :param sch2: the second schema :return: the subpredicate whose terms apply to the union of the two schemas but not either schema separately. """ assert isinstance(sch1, Schema) assert isinstance(sch2, Schema) result = Predicate() newsch = Schema() newsch.add_all(sch1) newsch.add_all(sch2) for t in self._terms: if not t.applies_to(sch1) and not t.applies_to(sch2) and t.applies_to(newsch): result._terms.append(t) if len(result._terms) == 0: return None else: return result
def join_pred(self, sch1, sch2): """ Returns the subpredicate consisting of terms that apply to the union of the two specified schemas, but not to either schema separately. :param sch1: the first schema :param sch2: the second schema :return: the subpredicate whose terms apply to the union of the two schemas but not either schema separately. """ assert isinstance(sch1, Schema) assert isinstance(sch2, Schema) result = Predicate() newsch = Schema() newsch.add_all(sch1) newsch.add_all(sch2) for t in self._terms: if not t.applies_to(sch1) and not t.applies_to( sch2) and t.applies_to(newsch): result._terms.append(t) if len(result._terms) == 0: return None else: return result
def __init__(self, p1: Plan, p2: Plan, ii: IndexInfo, joinfield: str, tx: Transaction): """ Implements the join operator, using the specified LHS and RHS plans. :param p1: the left-hand plan :param p2: the right-hand plan :param ii: information about the right-hand index :param joinfield: the left-hand field used for joining :param tx: the calling transaction """ self._sch = Schema() self._p1 = p1 self._p2 = p2 self._ii = ii self._joinfield = joinfield self._sch.add_all(p1.schema()) self._sch.add_all(p2.schema())
def __field_type(self, fldname: str) -> Schema: schema = Schema() if self._lex.match_keyword("int"): self._lex.eat_keyword("int") schema.add_int_field(fldname) else: self._lex.eat_keyword("varchar") self._lex.eat_delim("(") str_len = self._lex.eat_int_constant() self._lex.eat_delim(")") schema.add_string_field(fldname, str_len) return schema
def __init__(self, idxname, leafsch, tx): """ Opens a B-tree index for the specified index. The method determines the appropriate files for the leaf and directory records, creating them if they did not exist. :param idxname: the name of the index :param leafsch: the schema of the leaf index records :param tx: the calling transaction """ assert isinstance(leafsch, Schema) assert isinstance(tx, Transaction) self._tx = tx self._leaf = None # deal with the leaves leaftbl = idxname + "leaf" self._leaf_ti = TableInfo(leaftbl, leafsch) if tx.size(self._leaf_ti.file_name() == 0): tx.append(self._leaf_ti.file_name(), BTPageFormatter(self._leaf_ti, -1)) # deal with the directory dirsch = Schema() dirsch.add("block", leafsch) dirsch.add("dataval", leafsch) dirtbl = idxname + "dir" self._dir_ti = TableInfo(dirtbl, dirsch) self._rootblk = Block(self._dir_ti.file_name(), 0) if tx.size(self._dir_ti.file_name() == 0): # create new root block tx.append(self._dir_ti.file_name(), BTPageFormatter(self._dir_ti, 0)) page = BTreePage(self._rootblk, self._dir_ti, tx) if page.get_num_recs() == 0: # insert initial directory entry fldtype = dirsch.type("dataval") minval = IntConstant(-sys.maxsize) if fldtype == INTEGER else StringConstant("") page.insert_dir(0, minval, 0) page.close()
def __init__(self, is_new, tblmgr, tx): """ Creates the index manager. This constructor is called during system startup. If the database is new, then the idxcat table is created. :param is_new: indicates whether this is a new database :param tx: the system startup transaction """ assert isinstance(tblmgr, TableMgr) assert isinstance(tx, Transaction) if is_new: sch = Schema() sch.add_string_field("indexname", TableMgr.MAX_NAME) sch.add_string_field("tablename", TableMgr.MAX_NAME) sch.add_string_field("fieldname", TableMgr.MAX_NAME) tblmgr.create_table("idxcat", sch, tx) self._ti = tblmgr.get_table_info("idxcat", tx)
class IndexJoinPlan(Plan): """ The Plan class corresponding to the <i>indexjoin</i> relational algebra operator. """ def __init__(self, p1: Plan, p2: Plan, ii: IndexInfo, joinfield: str, tx: Transaction): """ Implements the join operator, using the specified LHS and RHS plans. :param p1: the left-hand plan :param p2: the right-hand plan :param ii: information about the right-hand index :param joinfield: the left-hand field used for joining :param tx: the calling transaction """ self._sch = Schema() self._p1 = p1 self._p2 = p2 self._ii = ii self._joinfield = joinfield self._sch.add_all(p1.schema()) self._sch.add_all(p2.schema()) def open(self): """ Opens an indexjoin scan for this query """ s = self._p1.open() # throws an exception if p2 is not a tableplan assert isinstance(self._p2, TablePlan) ts = self._p2.open() idx = self._ii.open() assert isinstance(idx, Index) return IndexJoinScan(s, idx, self._joinfield, ts) def blocks_accessed(self): """ Estimates the number of block accesses to compute the join. The formula is: B(indexjoin(p1,p2,idx)) = B(p1) + R(p1)*B(idx) + R(indexjoin(p1,p2,idx) """ return self._p1.blocks_accessed() + self._p1.records_output() * self._ii.blocks_accessed() + \ self.records_output() def records_output(self): """ Estimates the number of output records in the join. The formula is: R(indexjoin(p1,p2,idx)) = R(p1)*R(idx) """ return self._p1.records_output() * self._ii.records_output() def distinct_values(self, fldname): """ Estimates the number of distinct values for the specified field. """ if self._p1.schema().has_field(fldname): return self._p1.distinct_values(fldname) else: return self._p2.distinct_values(fldname) def schema(self): """ Returns the schema of the index join. """ return self._sch
def __init__(self, p: Plan, fieldlist: list): self._schema = Schema() self._p = p for fldname in fieldlist: self._schema.add(fldname, p.schema())
class IndexJoinPlan(Plan): """ The Plan class corresponding to the <i>indexjoin</i> relational algebra operator. """ def __init__(self, p1: Plan, p2: Plan, ii: IndexInfo, joinfield: str, tx: Transaction): """ Implements the join operator, using the specified LHS and RHS plans. :param p1: the left-hand plan :param p2: the right-hand plan :param ii: information about the right-hand index :param joinfield: the left-hand field used for joining :param tx: the calling transaction """ self._sch = Schema() self._p1 = p1 self._p2 = p2 self._ii = ii self._joinfield = joinfield self._sch.add_all(p1.schema()) self._sch.add_all(p2.schema()) def open(self): """ Opens an indexjoin scan for this query """ s = self._p1.open() # throws an exception if p2 is not a tableplan assert isinstance(self._p2, TablePlan) ts = self._p2.open() idx = self._ii.open() assert isinstance(idx, Index) return IndexJoinScan(s, idx, self._joinfield, ts) def blocks_accessed(self): """ Estimates the number of block accesses to compute the join. The formula is: B(indexjoin(p1,p2,idx)) = B(p1) + R(p1)*B(idx) + R(indexjoin(p1,p2,idx) """ return self._p1.blocks_accessed() + self._p1.records_output() * self._ii.blocks_accessed() + \ self.records_output() def records_output(self): """ Estimates the number of output records in the join. The formula is: R(indexjoin(p1,p2,idx)) = R(p1)*R(idx) """ return self._p1.records_output() * self._ii.records_output() def distinct_values(self, fldname): """ Estimates the number of distinct values for the specified field. """ if self._p1.schema().has_field(fldname): return self._p1.distinct_values(fldname) else: return self._p2.distinct_values(fldname) def schema(self): """ Returns the schema of the index join. """ return self._sch
def __init__(self, is_new, tx): """ Creates a new catalog manager for the database system. If the database is new, then the two catalog tables are created. :param is_new: has the value true if the database is new :param tx: the startup transaction """ assert isinstance(tx, Transaction) tcat_schema = Schema() tcat_schema.add_string_field("tblname", self.MAX_NAME) tcat_schema.add_int_field("reclength") self._tcat_info = TableInfo("tblcat", tcat_schema) fcat_schema = Schema() fcat_schema.add_string_field("tblname", self.MAX_NAME) fcat_schema.add_string_field("fldname", self.MAX_NAME) fcat_schema.add_int_field("type") fcat_schema.add_int_field("length") fcat_schema.add_int_field("offset") self._fcat_info = TableInfo("fldcat", fcat_schema) if is_new: self.create_table("tblcat", tcat_schema, tx) self.create_table("fldcat", fcat_schema, tx)
def __init__(self, p: Plan, fieldlist: list): self._schema = Schema() self._p = p for fldname in fieldlist: self._schema.add(fldname, p.schema())
def __init__(self, is_new, tx): """ Creates a new catalog manager for the database system. If the database is new, then the two catalog tables are created. :param is_new: has the value true if the database is new :param tx: the startup transaction """ assert isinstance(tx, Transaction) tcat_schema = Schema() tcat_schema.add_string_field("tblname", self.MAX_NAME) tcat_schema.add_int_field("reclength") self._tcat_info = TableInfo("tblcat", tcat_schema) fcat_schema = Schema() fcat_schema.add_string_field("tblname", self.MAX_NAME) fcat_schema.add_string_field("fldname", self.MAX_NAME) fcat_schema.add_int_field("type") fcat_schema.add_int_field("length") fcat_schema.add_int_field("offset") self._fcat_info = TableInfo("fldcat", fcat_schema) if is_new: self.create_table("tblcat", tcat_schema, tx) self.create_table("fldcat", fcat_schema, tx)