| //--------------------------------------------------------------------------- |
| // Greenplum Database |
| // Copyright (C) 2011 Greenplum, Inc. |
| // |
| // @filename: |
| // CMappingVarColId.cpp |
| // |
| // @doc: |
| // Implementation of base (abstract) var mapping class |
| // |
| // @test: |
| // |
| // |
| //--------------------------------------------------------------------------- |
| extern "C" { |
| #include "postgres.h" |
| |
| #include "nodes/primnodes.h" |
| #include "nodes/value.h" |
| } |
| #include "gpos/error/CAutoTrace.h" |
| |
| #include "gpopt/gpdbwrappers.h" |
| #include "gpopt/translate/CMappingVarColId.h" |
| #include "gpopt/translate/CTranslatorUtils.h" |
| #include "naucrates/dxl/CDXLUtils.h" |
| #include "naucrates/dxl/operators/CDXLScalarIdent.h" |
| #include "naucrates/dxl/operators/CDXLScalarProjElem.h" |
| #include "naucrates/exception.h" |
| #include "naucrates/md/IMDIndex.h" |
| |
| using namespace gpdxl; |
| using namespace gpmd; |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // CMappingVarColId::CMappingVarColId |
| // |
| // @doc: |
| // Ctor |
| // |
| //--------------------------------------------------------------------------- |
| CMappingVarColId::CMappingVarColId(CMemoryPool *mp) : m_mp(mp) |
| { |
| // This map can have many entries if there are many tables with many columns |
| // in the query, so use a larger hash map to minimize collisions |
| m_gpdb_att_opt_col_mapping = |
| GPOS_NEW(m_mp) GPDBAttOptColHashMap(m_mp, 2047); |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // CMappingVarColId::GetGPDBAttOptColMapping |
| // |
| // @doc: |
| // Given a gpdb attribute, return the mapping info to opt col |
| // |
| //--------------------------------------------------------------------------- |
| const CGPDBAttOptCol * |
| CMappingVarColId::GetGPDBAttOptColMapping( |
| ULONG current_query_level, const Var *var, |
| EPlStmtPhysicalOpType plstmt_physical_op_type) const |
| { |
| GPOS_ASSERT(nullptr != var); |
| GPOS_ASSERT(current_query_level >= var->varlevelsup); |
| |
| // absolute query level of var |
| ULONG abs_query_level = current_query_level - var->varlevelsup; |
| |
| // extract varno |
| ULONG var_no = var->varno; |
| if (EpspotWindow == plstmt_physical_op_type || |
| EpspotAgg == plstmt_physical_op_type || |
| EpspotMaterialize == plstmt_physical_op_type) |
| { |
| // Agg and Materialize need to employ OUTER, since they have other |
| // values in GPDB world |
| var_no = OUTER_VAR; |
| } |
| |
| CGPDBAttInfo *gpdb_att_info = |
| GPOS_NEW(m_mp) CGPDBAttInfo(abs_query_level, var_no, var->varattno); |
| CGPDBAttOptCol *gpdb_att_opt_col_info = |
| m_gpdb_att_opt_col_mapping->Find(gpdb_att_info); |
| |
| if (nullptr == gpdb_att_opt_col_info) |
| { |
| // TODO: Sept 09 2013, remove temporary fix (revert exception to assert) to avoid crash during algebrization |
| GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLError, |
| GPOS_WSZ_LIT("No variable")); |
| } |
| |
| gpdb_att_info->Release(); |
| return gpdb_att_opt_col_info; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // CMappingVarColId::GetOptColName |
| // |
| // @doc: |
| // Given a gpdb attribute, return a column name in optimizer world |
| // |
| //--------------------------------------------------------------------------- |
| const CWStringBase * |
| CMappingVarColId::GetOptColName( |
| ULONG current_query_level, const Var *var, |
| EPlStmtPhysicalOpType plstmt_physical_op_type) const |
| { |
| return GetGPDBAttOptColMapping(current_query_level, var, |
| plstmt_physical_op_type) |
| ->GetOptColInfo() |
| ->GetOptColName(); |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // CMappingVarColId::GetColId |
| // |
| // @doc: |
| // given a gpdb attribute, return a column id in optimizer world |
| // |
| //--------------------------------------------------------------------------- |
| ULONG |
| CMappingVarColId::GetColId(ULONG current_query_level, const Var *var, |
| EPlStmtPhysicalOpType plstmt_physical_op_type) const |
| { |
| return GetGPDBAttOptColMapping(current_query_level, var, |
| plstmt_physical_op_type) |
| ->GetOptColInfo() |
| ->GetColId(); |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // CMappingVarColId::Insert |
| // |
| // @doc: |
| // Insert a single entry into the hash map |
| // |
| //--------------------------------------------------------------------------- |
| void |
| CMappingVarColId::Insert(ULONG query_level, ULONG var_no, INT attrnum, |
| ULONG colid, CWStringBase *column_name) |
| { |
| // GPDB agg node uses 0 in Var, but that should've been taken care of |
| // by translator |
| GPOS_ASSERT(var_no > 0); |
| |
| // create key |
| CGPDBAttInfo *gpdb_att_info = |
| GPOS_NEW(m_mp) CGPDBAttInfo(query_level, var_no, attrnum); |
| |
| // create value |
| COptColInfo *opt_col_info = GPOS_NEW(m_mp) COptColInfo(colid, column_name); |
| |
| // key is part of value, bump up refcount |
| gpdb_att_info->AddRef(); |
| CGPDBAttOptCol *gpdb_att_opt_col_info = |
| GPOS_NEW(m_mp) CGPDBAttOptCol(gpdb_att_info, opt_col_info); |
| |
| BOOL result GPOS_ASSERTS_ONLY = m_gpdb_att_opt_col_mapping->Insert( |
| gpdb_att_info, gpdb_att_opt_col_info); |
| |
| GPOS_ASSERT(result); |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // CMappingVarColId::LoadTblColumns |
| // |
| // @doc: |
| // Load up information from GPDB's base table RTE and corresponding |
| // optimizer table descriptor |
| // |
| //--------------------------------------------------------------------------- |
| void |
| CMappingVarColId::LoadTblColumns(ULONG query_level, ULONG RTE_index, |
| const CDXLTableDescr *table_descr) |
| { |
| GPOS_ASSERT(nullptr != table_descr); |
| const ULONG size = table_descr->Arity(); |
| |
| // add mapping information for columns |
| for (ULONG i = 0; i < size; i++) |
| { |
| const CDXLColDescr *dxl_col_descr = table_descr->GetColumnDescrAt(i); |
| this->Insert(query_level, RTE_index, dxl_col_descr->AttrNum(), |
| dxl_col_descr->Id(), |
| dxl_col_descr->MdName()->GetMDName()->Copy(m_mp)); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // CMappingVarColId::LoadIndexColumns |
| // |
| // @doc: |
| // Load up information from GPDB index and corresponding |
| // optimizer table descriptor |
| // |
| //--------------------------------------------------------------------------- |
| void |
| CMappingVarColId::LoadIndexColumns(ULONG query_level, ULONG RTE_index, |
| const IMDIndex *index, |
| const CDXLTableDescr *table_descr) |
| { |
| GPOS_ASSERT(nullptr != table_descr); |
| |
| const ULONG size = index->Keys(); |
| |
| // add mapping information for columns |
| for (ULONG i = 0; i < size; i++) |
| { |
| ULONG pos = index->KeyAt(i); |
| const CDXLColDescr *dxl_col_descr = table_descr->GetColumnDescrAt(pos); |
| this->Insert(query_level, RTE_index, INT(i + 1), dxl_col_descr->Id(), |
| dxl_col_descr->MdName()->GetMDName()->Copy(m_mp)); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // CMappingVarColId::Load |
| // |
| // @doc: |
| // Load column mapping information from list of column names |
| // |
| //--------------------------------------------------------------------------- |
| void |
| CMappingVarColId::Load(ULONG query_level, ULONG RTE_index, |
| CIdGenerator *id_generator, List *col_names) |
| { |
| ListCell *col_name = nullptr; |
| ULONG i = 0; |
| |
| // add mapping information for columns |
| ForEach(col_name, col_names) |
| { |
| Value *value = (Value *) lfirst(col_name); |
| CHAR *col_name_char_array = strVal(value); |
| |
| CWStringDynamic *column_name = |
| CDXLUtils::CreateDynamicStringFromCharArray(m_mp, |
| col_name_char_array); |
| |
| this->Insert(query_level, RTE_index, INT(i + 1), |
| id_generator->next_id(), column_name->Copy(m_mp)); |
| |
| i++; |
| GPOS_DELETE(column_name); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // CMappingVarColId::LoadColumns |
| // |
| // @doc: |
| // Load up columns information from the array of column descriptors |
| // |
| //--------------------------------------------------------------------------- |
| void |
| CMappingVarColId::LoadColumns(ULONG query_level, ULONG RTE_index, |
| const CDXLColDescrArray *column_descrs) |
| { |
| GPOS_ASSERT(nullptr != column_descrs); |
| const ULONG size = column_descrs->Size(); |
| |
| // add mapping information for columns |
| for (ULONG i = 0; i < size; i++) |
| { |
| const CDXLColDescr *dxl_col_descr = (*column_descrs)[i]; |
| this->Insert(query_level, RTE_index, dxl_col_descr->AttrNum(), |
| dxl_col_descr->Id(), |
| dxl_col_descr->MdName()->GetMDName()->Copy(m_mp)); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // CMappingVarColId::LoadDerivedTblColumns |
| // |
| // @doc: |
| // Load up information from column information in derived tables |
| // |
| //--------------------------------------------------------------------------- |
| void |
| CMappingVarColId::LoadDerivedTblColumns( |
| ULONG query_level, ULONG RTE_index, |
| const CDXLNodeArray *derived_columns_dxl, List *target_list) |
| { |
| GPOS_ASSERT(nullptr != derived_columns_dxl); |
| GPOS_ASSERT((ULONG) gpdb::ListLength(target_list) >= |
| derived_columns_dxl->Size()); |
| |
| ULONG drvd_tbl_col_counter = |
| 0; // counter for the dynamic array of DXL nodes |
| ListCell *lc = nullptr; |
| ForEach(lc, target_list) |
| { |
| TargetEntry *target_entry = (TargetEntry *) lfirst(lc); |
| if (!target_entry->resjunk) |
| { |
| GPOS_ASSERT(0 < target_entry->resno); |
| CDXLNode *dxlnode = (*derived_columns_dxl)[drvd_tbl_col_counter]; |
| GPOS_ASSERT(nullptr != dxlnode); |
| CDXLScalarIdent *dxl_sc_ident = |
| CDXLScalarIdent::Cast(dxlnode->GetOperator()); |
| const CDXLColRef *dxl_colref = dxl_sc_ident->GetDXLColRef(); |
| this->Insert(query_level, RTE_index, INT(target_entry->resno), |
| dxl_colref->Id(), |
| dxl_colref->MdName()->GetMDName()->Copy(m_mp)); |
| drvd_tbl_col_counter++; |
| } |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // CMappingVarColId::LoadCTEColumns |
| // |
| // @doc: |
| // Load CTE column mappings |
| // |
| //--------------------------------------------------------------------------- |
| void |
| CMappingVarColId::LoadCTEColumns(ULONG query_level, ULONG RTE_index, |
| const ULongPtrArray *CTE_columns, |
| List *target_list) |
| { |
| GPOS_ASSERT(nullptr != CTE_columns); |
| GPOS_ASSERT((ULONG) gpdb::ListLength(target_list) >= CTE_columns->Size()); |
| |
| ULONG idx = 0; |
| ListCell *lc = nullptr; |
| ForEach(lc, target_list) |
| { |
| TargetEntry *target_entry = (TargetEntry *) lfirst(lc); |
| if (!target_entry->resjunk) |
| { |
| GPOS_ASSERT(0 < target_entry->resno); |
| ULONG CTE_colid = *((*CTE_columns)[idx]); |
| |
| CWStringDynamic *column_name = |
| CDXLUtils::CreateDynamicStringFromCharArray( |
| m_mp, target_entry->resname); |
| this->Insert(query_level, RTE_index, INT(target_entry->resno), |
| CTE_colid, column_name); |
| idx++; |
| } |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // CMappingVarColId::LoadProjectElements |
| // |
| // @doc: |
| // Load up information from projection list created from GPDB join expression |
| // |
| //--------------------------------------------------------------------------- |
| void |
| CMappingVarColId::LoadProjectElements(ULONG query_level, ULONG RTE_index, |
| const CDXLNode *project_list_dxlnode) |
| { |
| GPOS_ASSERT(nullptr != project_list_dxlnode); |
| const ULONG size = project_list_dxlnode->Arity(); |
| // add mapping information for columns |
| for (ULONG i = 0; i < size; i++) |
| { |
| CDXLNode *dxlnode = (*project_list_dxlnode)[i]; |
| CDXLScalarProjElem *dxl_proj_elem = |
| CDXLScalarProjElem::Cast(dxlnode->GetOperator()); |
| this->Insert(query_level, RTE_index, INT(i + 1), dxl_proj_elem->Id(), |
| dxl_proj_elem->GetMdNameAlias()->GetMDName()->Copy(m_mp)); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // CMappingVarColId::CopyMapColId |
| // |
| // @doc: |
| // Create a deep copy |
| // |
| //--------------------------------------------------------------------------- |
| CMappingVarColId * |
| CMappingVarColId::CopyMapColId(ULONG query_level) const |
| { |
| CMappingVarColId *var_colid_mapping = GPOS_NEW(m_mp) CMappingVarColId(m_mp); |
| |
| // iterate over full map |
| GPDBAttOptColHashMapIter col_map_iterator(this->m_gpdb_att_opt_col_mapping); |
| while (col_map_iterator.Advance()) |
| { |
| const CGPDBAttOptCol *gpdb_att_opt_col_info = col_map_iterator.Value(); |
| const CGPDBAttInfo *gpdb_att_info = |
| gpdb_att_opt_col_info->GetGPDBAttInfo(); |
| const COptColInfo *opt_col_info = |
| gpdb_att_opt_col_info->GetOptColInfo(); |
| |
| if (gpdb_att_info->GetQueryLevel() <= query_level) |
| { |
| // include all variables defined at same query level or before |
| CGPDBAttInfo *gpdb_att_info_new = GPOS_NEW(m_mp) CGPDBAttInfo( |
| gpdb_att_info->GetQueryLevel(), gpdb_att_info->GetVarNo(), |
| gpdb_att_info->GetAttNo()); |
| COptColInfo *opt_col_info_new = GPOS_NEW(m_mp) COptColInfo( |
| opt_col_info->GetColId(), |
| GPOS_NEW(m_mp) CWStringConst( |
| m_mp, opt_col_info->GetOptColName()->GetBuffer())); |
| gpdb_att_info_new->AddRef(); |
| CGPDBAttOptCol *gpdb_att_opt_col_new = GPOS_NEW(m_mp) |
| CGPDBAttOptCol(gpdb_att_info_new, opt_col_info_new); |
| |
| // insert into hashmap |
| BOOL result GPOS_ASSERTS_ONLY = |
| var_colid_mapping->m_gpdb_att_opt_col_mapping->Insert( |
| gpdb_att_info_new, gpdb_att_opt_col_new); |
| GPOS_ASSERT(result); |
| } |
| } |
| |
| return var_colid_mapping; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // CMappingVarColId::CopyMapColId |
| // |
| // @doc: |
| // Create a deep copy |
| // |
| //--------------------------------------------------------------------------- |
| CMappingVarColId * |
| CMappingVarColId::CopyMapColId(CMemoryPool *mp) const |
| { |
| CMappingVarColId *var_colid_mapping = GPOS_NEW(mp) CMappingVarColId(mp); |
| |
| // iterate over full map |
| GPDBAttOptColHashMapIter col_map_iterator(this->m_gpdb_att_opt_col_mapping); |
| while (col_map_iterator.Advance()) |
| { |
| const CGPDBAttOptCol *gpdb_att_opt_col_info = col_map_iterator.Value(); |
| const CGPDBAttInfo *gpdb_att_info = |
| gpdb_att_opt_col_info->GetGPDBAttInfo(); |
| const COptColInfo *opt_col_info = |
| gpdb_att_opt_col_info->GetOptColInfo(); |
| |
| CGPDBAttInfo *gpdb_att_info_new = GPOS_NEW(mp) |
| CGPDBAttInfo(gpdb_att_info->GetQueryLevel(), |
| gpdb_att_info->GetVarNo(), gpdb_att_info->GetAttNo()); |
| COptColInfo *opt_col_info_new = GPOS_NEW(mp) COptColInfo( |
| opt_col_info->GetColId(), |
| GPOS_NEW(mp) |
| CWStringConst(mp, opt_col_info->GetOptColName()->GetBuffer())); |
| gpdb_att_info_new->AddRef(); |
| CGPDBAttOptCol *gpdb_att_opt_col_new = |
| GPOS_NEW(mp) CGPDBAttOptCol(gpdb_att_info_new, opt_col_info_new); |
| |
| // insert into hashmap |
| BOOL result GPOS_ASSERTS_ONLY = |
| var_colid_mapping->m_gpdb_att_opt_col_mapping->Insert( |
| gpdb_att_info_new, gpdb_att_opt_col_new); |
| GPOS_ASSERT(result); |
| } |
| |
| return var_colid_mapping; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // CMappingVarColId::CopyRemapColId |
| // |
| // @doc: |
| // Create a copy of the mapping replacing the old column ids by new ones |
| // |
| //--------------------------------------------------------------------------- |
| CMappingVarColId * |
| CMappingVarColId::CopyRemapColId(CMemoryPool *mp, ULongPtrArray *old_colids, |
| ULongPtrArray *new_colids) const |
| { |
| GPOS_ASSERT(nullptr != old_colids); |
| GPOS_ASSERT(nullptr != new_colids); |
| GPOS_ASSERT(new_colids->Size() == old_colids->Size()); |
| |
| // construct a mapping old cols -> new cols |
| UlongToUlongMap *old_new_col_mapping = |
| CTranslatorUtils::MakeNewToOldColMapping(mp, old_colids, new_colids); |
| |
| CMappingVarColId *var_colid_mapping = GPOS_NEW(mp) CMappingVarColId(mp); |
| |
| GPDBAttOptColHashMapIter col_map_iterator(this->m_gpdb_att_opt_col_mapping); |
| while (col_map_iterator.Advance()) |
| { |
| const CGPDBAttOptCol *gpdb_att_opt_col_info = col_map_iterator.Value(); |
| const CGPDBAttInfo *gpdb_att_info = |
| gpdb_att_opt_col_info->GetGPDBAttInfo(); |
| const COptColInfo *opt_col_info = |
| gpdb_att_opt_col_info->GetOptColInfo(); |
| |
| CGPDBAttInfo *gpdb_att_info_new = GPOS_NEW(mp) |
| CGPDBAttInfo(gpdb_att_info->GetQueryLevel(), |
| gpdb_att_info->GetVarNo(), gpdb_att_info->GetAttNo()); |
| ULONG colid = opt_col_info->GetColId(); |
| ULONG *new_colid = old_new_col_mapping->Find(&colid); |
| if (nullptr != new_colid) |
| { |
| colid = *new_colid; |
| } |
| |
| COptColInfo *opt_col_info_new = GPOS_NEW(mp) COptColInfo( |
| colid, GPOS_NEW(mp) CWStringConst( |
| mp, opt_col_info->GetOptColName()->GetBuffer())); |
| gpdb_att_info_new->AddRef(); |
| CGPDBAttOptCol *gpdb_att_opt_col_new = |
| GPOS_NEW(mp) CGPDBAttOptCol(gpdb_att_info_new, opt_col_info_new); |
| |
| BOOL result GPOS_ASSERTS_ONLY = |
| var_colid_mapping->m_gpdb_att_opt_col_mapping->Insert( |
| gpdb_att_info_new, gpdb_att_opt_col_new); |
| GPOS_ASSERT(result); |
| } |
| |
| old_new_col_mapping->Release(); |
| |
| return var_colid_mapping; |
| } |
| |
| // EOF |