diff --git a/.gitignore b/.gitignore index b60bffe..af7b0ba 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ *.log *.debug *.txt +/.vs diff --git a/main/}bedrock.hier.clone.pro b/main/}bedrock.hier.clone.pro index 6e652ba..0913a1c 100644 --- a/main/}bedrock.hier.clone.pro +++ b/main/}bedrock.hier.clone.pro @@ -4,7 +4,7 @@ 586,"}Cubes" 585,"}Cubes" 564, -565,"wleeZe@zs7:tX9hx?u8=<0FaW__6oO_IW\i]GERwH5`Hw`6q9e0r_mjF4dnqAvM0p`FzSI9dbQewiAIAJZ:9z]onUjR5yxbZv@p]FnptevOM8bUkkO_:U`O0w2PB^a5Co7ez`=RVbLXZEWbsbvB0@4yrot2oaGz6vhKE_dKClT>LMiJVyd:dV_S^?O1bcMcbpNRR>w;_3DndoRD==nP@wj;Pc" 559,1 928,0 593, @@ -17,15 +17,15 @@ 801, 566,0 567,"," -588,"." -589,"," +588,"," +589,"." 568,"""" 570, 571,All 569,0 592,0 599,1000 -560,8 +560,10 pLogOutput pStrictErrorHandling pSrcDim @@ -34,7 +34,9 @@ pTgtDim pTgtHier pAttr pUnwind -561,8 +pIfNthanC +pSrcFilter +561,10 1 1 2 @@ -43,7 +45,9 @@ pUnwind 2 1 1 -590,8 +1 +2 +590,10 pLogOutput,0 pStrictErrorHandling,0 pSrcDim,"" @@ -52,15 +56,19 @@ pTgtDim,"" pTgtHier,"" pAttr,0 pUnwind,0 -637,8 +pIfNthanC,0 +pSrcFilter,"" +637,10 pLogOutput,"OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)" pStrictErrorHandling,"OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)" pSrcDim,"REQUIRED: Source Dimension" pSrcHier,"REQUIRED: Source Hierarchy" pTgtDim,"REQUIRED: Target Dimension (can be the same as source)" pTgtHier,"OPTIONAL: Target Hierarchy (will default to SrcHier_Clone if the dimensions are the same)" -pAttr,"OPTIONAL: Include Attributes? (Boolean 1=True)" +pAttr,"OPTIONAL: Include Attributes? (Boolean 1=True; 2 = only existing)" pUnwind,"REQUIRED: Unwind? (0 = Delete all Elements, 1 = Unwind Existing Elements, 2 = Do not change Existing Elements (Only relevant if target hierarchy exists) )" +pIfNthanC,"OPTIONAL: if 1 than all N-elemens will be created as c-elements" +pSrcFilter,"OPTIONAL: Source filter. Use Subset: or MDX:" 577,1 vEle 578,1 @@ -74,7 +82,7 @@ vEle 582,1 VarType=32 ColType=827 603,0 -572,227 +572,292 #Region CallThisProcess # A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete. If( 1 = 0 ); @@ -82,7 +90,7 @@ If( 1 = 0 ); 'pStrictErrorHandling', pStrictErrorHandling, 'pSrcDim', '', 'pSrcHier', '', 'pTgtDim', '', 'pTgtHier', '', - 'pAttr', 0, 'pUnwind', 0 + 'pAttr', 0, 'pUnwind', 0, 'pIfNthanC', 0, 'pSrcFilter', '' ); EndIf; #EndRegion CallThisProcess @@ -123,12 +131,16 @@ cRandomInt = NumberToString( INT( RAND( ) * 1000 )); cTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt; cMsgErrorLevel = 'ERROR'; cMsgErrorContent = '%cThisProcName% : %sMessage% : %cUserName%'; -cLogInfo = 'Process:%cThisProcName% run with parameters pSrcDim:%pSrcDim%, pSrcHier:%pSrcHier%, pTgtDim:%pTgtDim%, pTgtHier:%pTgtHier%, pAttr:%pAttr%, pUnwind:%pUnwind%.'; +cLogInfo = 'Process:%cThisProcName% run with parameters pSrcDim:%pSrcDim%, pSrcHier:%pSrcHier%, pTgtDim:%pTgtDim%, pTgtHier:%pTgtHier%, pAttr:%pAttr%, pUnwind:%pUnwind%, pIfNthanC:%pIfNthanC%, pSrcFilter:%pSrcFilter%.'; cLangDim = '}Cultures'; nNumLang = DimSiz( cLangDim ); nProcessSameNamedHier = 0; sEpilogTgtHier = ''; +nTempSubsetCreated = 0; +sTempSubset = ''; +sFilterPrefix = ''; +sFilterValue = ''; ## LogOutput parameters IF ( pLogoutput = 1 ); @@ -227,6 +239,60 @@ If( nErrors <> 0 ); EndIf; EndIf; +### Resolve pSrcFilter ### +If( Trim( pSrcFilter ) @<> '' ); + If( SubSt( pSrcFilter, 1, 7 ) @= 'Subset:' ); + sFilterPrefix = 'Subset'; + sFilterValue = Trim( SubSt( pSrcFilter, 8, Long( pSrcFilter ) ) ); + ElseIf( SubSt( pSrcFilter, 1, 4 ) @= 'MDX:' ); + sFilterPrefix = 'MDX'; + sFilterValue = Trim( SubSt( pSrcFilter, 5, Long( pSrcFilter ) ) ); + Else; + nErrors = 1; + sMessage = 'Invalid pSrcFilter prefix. Use \"Subset:\" or \"MDX:\".'; + LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) ); + EndIf; +EndIf; + +If( sFilterPrefix @= 'Subset' ); + If( SubsetExists( pSrcDim, sFilterValue ) = 0 ); + nErrors = 1; + sMessage = 'Subset not found: ' | sFilterValue | ' on dimension ' | pSrcDim; + LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) ); + Else; + sTempSubset = sFilterValue; + EndIf; +ElseIf( sFilterPrefix @= 'MDX' ); + sTempSubset = cTempSub; + nRet = ExecuteProcess( '}bedrock.hier.sub.create.bymdx', + 'pLogOutput', pLogOutput, + 'pStrictErrorHandling', pStrictErrorHandling, + 'pDim', pSrcDim, + 'pHier', pSrcHier, + 'pSub', sTempSubset, + 'pMDXExpr', sFilterValue, + 'pConvertToStatic', 1, + 'pTemp', 1 + ); + If( nRet = 0 ); + nTempSubsetCreated = 1; + Else; + nErrors = 1; + sMessage = 'Failed to create MDX subset. Check MDX expression: ' | sFilterValue; + LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) ); + EndIf; +Else; + sTempSubset = 'ALL'; +EndIf; + +If( nErrors <> 0 ); + If( pStrictErrorHandling = 1 ); + ProcessQuit; + Else; + ProcessBreak; + EndIf; +EndIf; + ### Create target dimension Hierarchy ### If( HierarchyExists( pTgtDim, pTgtHier) = 0 ); HierarchyCreate( pTgtDim, pTgtHier ); @@ -261,13 +327,18 @@ sSortComponentsSense = CELLGETS( '}DimensionProperties', sDimHier, 'SORTCOMPONE HierarchySortOrder(pTgtDim, pTgtHier, sSortComponentsType, sSortComponentsSense, sSortElementsType , sSortElementsSense); -nSourceHierSize = DimSiz(pSrcDim|':'|pSrcHier); +nSourceHierSize = SubsetGetSize( pSrcDim, sTempSubset ); nIndex = 1; WHILE( nIndex <= nSourceHierSize ); - sElName = ElementName(pSrcDim, pSrcHier, nIndex); - sElType = ElementType(pSrcDim, pSrcHier, sElName); - HierarchyElementInsert(pTgtDim, pTgtHier, '', sElName, sElType); + sElName = SubsetGetElementName( pSrcDim, sTempSubset, nIndex ); + sElType = ElementType( pSrcDim, pSrcHier, sElName ); + + if( sElType @<> 'S' & pIfNthanC = 1 ); + HierarchyElementInsert( pTgtDim, pTgtHier, '', sElName, 'C' ); + else; + HierarchyElementInsert( pTgtDim, pTgtHier, '', sElName, sElType ); + endif; nIndex = nIndex + 1; END; @@ -275,7 +346,7 @@ END; DatasourceNameForServer = pSrcDim|':'|pSrcHier; DataSourceType = 'SUBSET'; -DatasourceDimensionSubset = 'ALL'; +DatasourceDimensionSubset = sTempSubset; ### Replicate Attributes ### @@ -299,10 +370,12 @@ If( pAttr = 1 & DimensionExists( sAttrDim ) = 1 ); Endif; nCount = nCount + 1; End; +Elseif(pAttr > 1 & DimensionExists( sAttrDim ) = 1 ); + nNumAttrs = DimSiz( sAttrTragetDim ); EndIf; ### End Prolog ### -573,35 +573,38 #****Begin: Generated Statements*** #****End: Generated Statements**** @@ -326,19 +399,22 @@ EndIf; sElType = ElementType(pSrcDim, pSrcHier, vEle); + IF( sElType @= 'C' & ElementComponentCount( pSrcDim, pSrcHier, vEle ) > 0 ); nChildren = ElementComponentCount( pSrcDim, pSrcHier, vEle ); nCount = 1; While( nCount <= nChildren ); sChildElement = ElementComponent( pSrcDim, pSrcHier, vEle, nCount ); - sChildWeight = ElementWeight( pSrcDim,pSrcHier, vEle, sChildElement ); - HierarchyElementComponentAdd(pTgtDim, pTgtHier, vEle, sChildElement, sChildWeight); + sChildWeight = ElementWeight( pSrcDim, pSrcHier, vEle, sChildElement ); + If( HierarchyElementExists( pTgtDim, pTgtHier, sChildElement ) = 1 ); + HierarchyElementComponentAdd( pTgtDim, pTgtHier, vEle, sChildElement, sChildWeight ); + EndIf; nCount = nCount + 1; End; EndIf; ### End MetaData ### -574,90 +574,97 #****Begin: Generated Statements*** #****End: Generated Statements**** @@ -361,75 +437,82 @@ EndIf; ### Replicate Attributes ### # Note: DTYPE on Attr dim returns "AS", "AN" or "AA" need to strip off leading "A" -If( pAttr = 1 & DimensionExists( sAttrDim ) = 1 ); + +If( pAttr >= 1 & DimensionExists( sAttrTragetDim ) = 1 ); nAttr = 1; While( nAttr <= nNumAttrs ); - sAttrName = DimNm( sAttrDim, nAttr ); - sAttrType = SubSt( DTYPE( sAttrDim, sAttrName ), 2, 1 ); + sAttrName = DimNm( sAttrTragetDim, nAttr ); + sAttrType = SubSt( DTYPE( sAttrTragetDim, sAttrName ), 2, 1 ); - If( sAttrType @= 'S' % sAttrType @= 'A' ); - sAttrVal = ElementAttrS( pSrcDim, pSrcHier, vEle, sAttrName ); - - If( sAttrVal @<> '' ); - If( CellIsUpdateable( '}ElementAttributes_' | pTgtDim, pTgtHier:vEle, sAttrName ) = 1 ); - If( sAttrType @= 'A' ); - ElementAttrPutS( sAttrVal, pTgtDim, pTgtHier, vEle, sAttrName, 1 ); - Else; - ElementAttrPutS( sAttrVal, pTgtDim, pTgtHier, vEle, sAttrName ); - EndIf; - EndIf; - EndIf; - Else; - nAttrVal = ElementAttrN( pSrcDim, pSrcHier, vEle, sAttrName ); - If( nAttrVal <> 0 ); - If( CellIsUpdateable( '}ElementAttributes_' | pTgtDim, pTgtHier:vEle, sAttrName ) = 1 ); - ElementAttrPutN( nAttrVal, pTgtDim, pTgtHier, vEle, sAttrName ); - EndIf; - EndIf; - EndIf; - # check for localized attributes - If( CubeExists( sAttrLoc ) = 1 ); - nLang = 1; - While( nLang <= nNumLang ); - sLang = DimNm( cLangDim, nLang ); - If( sAttrType @= 'A' % sAttrType @= 'S' ); - sAttrVal = ElementAttrS( pSrcDim, pSrcHier, vEle, sAttrName ); - sAttrValLoc = ElementAttrSL( pSrcDim, pSrcHier, vEle, sAttrName, sLang ); - If( sAttrValLoc @= sAttrVal ); sAttrValLoc = ''; EndIf; - Else; - nAttrVal = ElementAttrN( pSrcDim, pSrcHier, vEle, sAttrName ); - nAttrValLoc = ElementAttrNL( pSrcDim, pSrcHier, vEle, sAttrName, sLang ); - EndIf; - If( CubeExists( sAttrLocTarget ) = 0 ); - If( sAttrType @= 'A' ); - ElementAttrPutS( sAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang, 1 ); - ElseIf( sAttrType @= 'N' ); - ElementAttrPutN( nAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang ); - Else; - ElementAttrPutS( sAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang ); - EndIf; - ElseIf(CubeExists( sAttrLocTarget ) = 1 ); - If( CellIsUpdateable( sAttrLocTarget, pTgtHier:vEle, sLang, sAttrName ) = 1 ); - If( sAttrType @= 'A' ); - ElementAttrPutS( sAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang, 1 ); - ElseIf( sAttrType @= 'N' ); - ElementAttrPutN( nAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang ); - Else; - ElementAttrPutS( sAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang ); - EndIf; - EndIf; - EndIf; - nLang = nLang + 1; - End; - EndIf; + if(pAttr > 1 & (DIMIX(sAttrTragetDim, sAttrName) = 0 % DIMIX(sAttrDim, sAttrName) = 0)); + #Do nothing, only existing attributes will be copied in this case + else; + + If( sAttrType @= 'S' % sAttrType @= 'A' ); + sAttrVal = ElementAttrS( pSrcDim, pSrcHier, vEle, sAttrName ); + + If( sAttrVal @<> '' ); + If( CellIsUpdateable( '}ElementAttributes_' | pTgtDim, pTgtHier:vEle, sAttrName ) = 1 ); + If( sAttrType @= 'A' ); + ElementAttrPutS( sAttrVal, pTgtDim, pTgtHier, vEle, sAttrName, 1 ); + Else; + ElementAttrPutS( sAttrVal, pTgtDim, pTgtHier, vEle, sAttrName ); + EndIf; + EndIf; + EndIf; + Else; + nAttrVal = ElementAttrN( pSrcDim, pSrcHier, vEle, sAttrName ); + If( nAttrVal <> 0 ); + If( CellIsUpdateable( '}ElementAttributes_' | pTgtDim, pTgtHier:vEle, sAttrName ) = 1 ); + ElementAttrPutN( nAttrVal, pTgtDim, pTgtHier, vEle, sAttrName ); + EndIf; + EndIf; + EndIf; + # check for localized attributes + If( CubeExists( sAttrLoc ) = 1 ); + + nLang = 1; + While( nLang <= nNumLang ); + sLang = DimNm( cLangDim, nLang ); + If( sAttrType @= 'A' % sAttrType @= 'S' ); + sAttrVal = ElementAttrS( pSrcDim, pSrcHier, vEle, sAttrName ); + sAttrValLoc = ElementAttrSL( pSrcDim, pSrcHier, vEle, sAttrName, sLang ); + If( sAttrValLoc @= sAttrVal ); sAttrValLoc = ''; EndIf; + Else; + nAttrVal = ElementAttrN( pSrcDim, pSrcHier, vEle, sAttrName ); + nAttrValLoc = ElementAttrNL( pSrcDim, pSrcHier, vEle, sAttrName, sLang ); + EndIf; + If( CubeExists( sAttrLocTarget ) = 0 ); + If( sAttrType @= 'A' ); + ElementAttrPutS( sAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang, 1 ); + ElseIf( sAttrType @= 'N' ); + ElementAttrPutN( nAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang ); + Else; + ElementAttrPutS( sAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang ); + EndIf; + ElseIf(CubeExists( sAttrLocTarget ) = 1 ); + If( CellIsUpdateable( sAttrLocTarget, pTgtHier:vEle, sLang, sAttrName ) = 1 ); + If( sAttrType @= 'A' ); + ElementAttrPutS( sAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang, 1 ); + ElseIf( sAttrType @= 'N' ); + ElementAttrPutN( nAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang ); + Else; + ElementAttrPutS( sAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang ); + EndIf; + EndIf; + EndIf; + nLang = nLang + 1; + End; + EndIf; + endif; nAttr = nAttr + 1; End; EndIf; ### End Data ### -575,54 +575,62 #****Begin: Generated Statements*** #****End: Generated Statements**** @@ -450,10 +533,16 @@ EndIf; CELLPUTS( sSortElementsSense, '}DimensionProperties', sTargetDimHier, 'SORTELEMENTSSENSE'); CELLPUTS( sSortComponentsType, '}DimensionProperties',sTargetDimHier, 'SORTCOMPONENTSTYPE'); CELLPUTS( sSortComponentsSense, '}DimensionProperties', sTargetDimHier, 'SORTCOMPONENTSSENSE'); + +### Clean up temporary subset ### +If( nTempSubsetCreated = 1 ); + SubsetDestroy( pSrcDim, sTempSubset ); + nTempSubsetCreated = 0; +EndIf; ### If a new dimension has been created, call the process recursively to clone the alternate hierarchy, after the same named hierarchy has been processed If( nProcessSameNamedHier = 1 ); - nRet = ExecuteProcess('}bedrock.hier.clone', + nRet = EXECUTEPROCESS(GetProcessName(), 'pLogOutput', pLogOutput, 'pStrictErrorHandling', pStrictErrorHandling, 'pSrcDim', pSrcDim, @@ -461,7 +550,9 @@ If( nProcessSameNamedHier = 1 ); 'pTgtDim', pTgtDim, 'pTgtHier', sEpilogTgtHier, 'pAttr', pAttr, - 'pUnwind', pUnwind + 'pUnwind', pUnwind, + 'pIfNthanC', pIfNthanC, + 'pSrcFilter', pSrcFilter ); EndIf; @@ -484,7 +575,7 @@ Else; EndIf; ### End Epilog ### -576, +576,CubeAction=1511 DataAction=1503 CubeLogChanges=0 930,0 638,1 804,0 @@ -516,7 +607,7 @@ EndIf; 917,0 918,1 919,0 -920,0 +920,50000 921,"" 922,"" 923,0 diff --git a/main_asJSON/}bedrock.hier.clone.json b/main_asJSON/}bedrock.hier.clone.json new file mode 100644 index 0000000..5c91f01 --- /dev/null +++ b/main_asJSON/}bedrock.hier.clone.json @@ -0,0 +1,89 @@ +{ + "Name": "}bedrock.hier.clone.LS", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.clone', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pSrcDim', '', 'pSrcHier', '',\r\n \t'pTgtDim', '', 'pTgtHier', '',\r\n \t'pAttr', 0, 'pUnwind', 0, 'pIfNthanC', 0, 'pSrcFilter', ''\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will clone the source dimension Hierarchy.\r\n\r\n# Use case: Mostly in Development.\r\n# 1/ Create a duplicate of an existing hierarchy for testing.\r\n\r\n# Note:\r\n# Valid source dimension name (pSrcDim) and target dimension (pTgtDim) names are mandatory otherwise the process will abort.\r\n# Valid source hierarchy name (pSrcHier) is mandatory otherwise the process will abort.\r\n\r\n# Caution:\r\n# - Target hierarchy cannot be `Leaves`.\r\n# - If the target dimension Hierarchy exists then it will be overwritten.\r\n#EndRegion @DOC\r\n\r\n### Global Varaibales ###\r\nStringGlobalVariable ('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode = 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = '%cThisProcName% : %sMessage% : %cUserName%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pSrcDim:%pSrcDim%, pSrcHier:%pSrcHier%, pTgtDim:%pTgtDim%, pTgtHier:%pTgtHier%, pAttr:%pAttr%, pUnwind:%pUnwind%, pIfNthanC:%pIfNthanC%, pSrcFilter:%pSrcFilter%.';\r\ncLangDim = '}Cultures';\r\nnNumLang = DimSiz( cLangDim );\r\n\r\nnProcessSameNamedHier = 0;\r\nsEpilogTgtHier = '';\r\nnTempSubsetCreated = 0;\r\nsTempSubset = '';\r\nsFilterPrefix = '';\r\nsFilterValue = '';\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pSrcDim ) > 0 & pSrcHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pSrcHier = SubSt( pSrcDim, Scan( ':', pSrcDim ) + 1, Long( pSrcDim ) );\r\n pSrcDim = SubSt( pSrcDim, 1, Scan( ':', pSrcDim ) - 1 );\r\nEndIf;\r\n\r\n## Validate Source dimension\r\nIF( Trim( pSrcDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No source dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIF( DimensionExists( pSrcDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid source dimension: ' | pSrcDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Source hierarchy\r\nIF( Trim( pSrcHier ) @= '' );\r\n pSrcHier = pSrcDim;\r\nElseIF(HierarchyExists(pSrcDim,pSrcHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid source hierarchy: ' | pSrcHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Target dimension\r\nIF( Trim( pTgtDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No target dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( Scan( ':', pTgtDim ) > 0 & pTgtHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pTgtHier = SubSt( pTgtDim, Scan( ':', pTgtDim ) + 1, Long( pTgtDim ) );\r\n pTgtDim = SubSt( pTgtDim, 1, Scan( ':', pTgtDim ) - 1 );\r\nEndIf;\r\n\r\nIf ( DimensionExists( pTgtDim ) = 0 );\r\n DimensionCreate( pTgtDim );\r\n ### In this case clone source hierarchy into same-named hierarchy of the new target dimension first. This will allow attributes to be processed in the data tab.\r\n nProcessSameNamedHier = 1;\r\nEndIf;\r\n\r\n# Validate target hierarchy\r\nIf( pSrcDim @= pTgtDim);\r\n If( pTgtHier @= '' % pTgtHier @= pSrcHier );\r\n pTgtHier = pSrcHier | '_Clone';\r\n EndIf;\r\nElseIf(pTgtHier @= '');\r\n If( nProcessSameNamedHier = 1 );\r\n sEpilogTgtHier = pTgtHier;\r\n pTgtHier = pTgtDim;\r\n Else;\r\n pTgtHier = pSrcHier;\r\n EndIf;\r\nElseIf( nProcessSameNamedHier = 1 );\r\n sEpilogTgtHier = pTgtHier;\r\n pTgtHier = pTgtDim;\r\nEndif;\r\n\r\npTgtHier = Trim(pTgtHier);\r\n\r\nIF(pTgtHier @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Leaves is an invalid selection for Target Hierarchy: ' | pTgtDim |':'|pTgtHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( DimensionExists( pTgtDim ) = 0 );\r\n If( pUnwind >= 1 );\r\n pUnwind = 2;\r\n EndIf;\r\nElseIf( HierarchyExists( pTgtDim, pTgtHier ) = 0 );\r\n If( pUnwind >= 1 );\r\n pUnwind = 2;\r\n EndIf;\r\nEndIf; \r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Resolve pSrcFilter ###\r\nIf( Trim( pSrcFilter ) @<> '' );\r\n If( SubSt( pSrcFilter, 1, 7 ) @= 'Subset:' );\r\n sFilterPrefix = 'Subset';\r\n sFilterValue = Trim( SubSt( pSrcFilter, 8, Long( pSrcFilter ) ) );\r\n ElseIf( SubSt( pSrcFilter, 1, 4 ) @= 'MDX:' );\r\n sFilterPrefix = 'MDX';\r\n sFilterValue = Trim( SubSt( pSrcFilter, 5, Long( pSrcFilter ) ) );\r\n Else;\r\n nErrors = 1;\r\n sMessage = 'Invalid pSrcFilter prefix. Use \\\"Subset:\\\" or \\\"MDX:\\\".';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\nEndIf;\r\n\r\nIf( sFilterPrefix @= 'Subset' );\r\n If( SubsetExists( pSrcDim, sFilterValue ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Subset not found: ' | sFilterValue | ' on dimension ' | pSrcDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n sTempSubset = sFilterValue;\r\n EndIf;\r\nElseIf( sFilterPrefix @= 'MDX' );\r\n sTempSubset = cTempSub;\r\n nRet = ExecuteProcess( '}bedrock.hier.sub.create.bymdx',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pSrcDim,\r\n 'pHier', pSrcHier,\r\n 'pSub', sTempSubset,\r\n 'pMDXExpr', sFilterValue,\r\n 'pConvertToStatic', 1,\r\n 'pTemp', 1\r\n );\r\n If( nRet = 0 );\r\n nTempSubsetCreated = 1;\r\n Else;\r\n nErrors = 1;\r\n sMessage = 'Failed to create MDX subset. Check MDX expression: ' | sFilterValue;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\nElse;\r\n sTempSubset = 'ALL';\r\nEndIf;\r\n\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Create target dimension Hierarchy ###\r\nIf( HierarchyExists( pTgtDim, pTgtHier) = 0 );\r\n HierarchyCreate( pTgtDim, pTgtHier );\r\nElse;\r\n IF(pUnwind = 1 );\r\n nRet = ExecuteProcess('}bedrock.hier.unwind',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pTgtDim,\r\n 'pHier', pTgtHier,\r\n 'pConsol', '*',\r\n 'pRecursive', 1\r\n );\r\n ELSEIF(pUnwind = 2 );\r\n #Do nothing\r\n ELSEIF(pUnwind = 0 );\r\n HierarchyDeleteAllElements( pTgtDim, pTgtHier );\r\n EndIf;\r\nEndIf;\r\n \r\nIf(pSrcDim @=pSrcHier);\r\n sDimHier = pSrcDim;\r\n Else;\r\n sDimHier =pSrcDim|':'|pSrcHier;\r\n Endif;\r\n \r\n### Set the target Sort Order ###\r\nsSortElementsType = CELLGETS( '}DimensionProperties', sDimHier, 'SORTELEMENTSTYPE');\r\nsSortElementsSense = CELLGETS( '}DimensionProperties', sDimHier, 'SORTELEMENTSSENSE');\r\nsSortComponentsType = CELLGETS( '}DimensionProperties', sDimHier, 'SORTCOMPONENTSTYPE');\r\nsSortComponentsSense = CELLGETS( '}DimensionProperties', sDimHier, 'SORTCOMPONENTSSENSE');\r\n\r\nHierarchySortOrder(pTgtDim, pTgtHier, sSortComponentsType, sSortComponentsSense, sSortElementsType , sSortElementsSense);\r\n\r\nnSourceHierSize = SubsetGetSize( pSrcDim, sTempSubset );\r\n\r\nnIndex = 1;\r\nWHILE( nIndex <= nSourceHierSize );\r\n sElName = SubsetGetElementName( pSrcDim, sTempSubset, nIndex );\r\n sElType = ElementType( pSrcDim, pSrcHier, sElName );\r\n \r\n if( sElType @<> 'S' & pIfNthanC = 1 );\r\n\tHierarchyElementInsert( pTgtDim, pTgtHier, '', sElName, 'C' );\r\n else;\r\n\tHierarchyElementInsert( pTgtDim, pTgtHier, '', sElName, sElType );\r\n endif;\r\n nIndex = nIndex + 1;\r\nEND;\r\n\r\n### Assign Data Source ###\r\n\r\nDatasourceNameForServer = pSrcDim|':'|pSrcHier;\r\nDataSourceType = 'SUBSET';\r\nDatasourceDimensionSubset = sTempSubset;\r\n\r\n### Replicate Attributes ###\r\n\r\n# Note: DType on Attr dim returns \"AS\", \"AN\" or \"AA\" need to strip off leading \"A\"\r\n\r\nsAttrDim = '}ElementAttributes_' | pSrcDim;\r\nsAttrLoc = '}LocalizedElementAttributes_' | pSrcDim;\r\nsAttrTragetDim = '}ElementAttributes_' | pTgtDim;\r\nsAttrLocTarget = '}LocalizedElementAttributes_' | pTgtDim;\r\n\r\nIf( pAttr = 1 & DimensionExists( sAttrDim ) = 1 );\r\n nNumAttrs = DimSiz( sAttrDim );\r\n nCount = 1;\r\n While( nCount <= nNumAttrs );\r\n sAttrName = DimNm( sAttrDim, nCount );\r\n sAttrType = SubSt(DType( sAttrDim, sAttrName ), 2, 1 );\r\n If ( DimensionExists( sAttrTragetDim ) = 0);\r\n AttrInsert(pTgtDim,'',sAttrName,sAttrType );\r\n ElseIF(DimIx(sAttrTragetDim, sAttrName) = 0);\r\n AttrInsert(pTgtDim,'',sAttrName,sAttrType );\r\n Endif;\r\n nCount = nCount + 1;\r\n End;\r\nElseif(pAttr > 1 & DimensionExists( sAttrDim ) = 1 );\r\n nNumAttrs = DimSiz( sAttrTragetDim );\r\nEndIf;\r\n\r\n### End Prolog ###", + "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n\r\n### Check for errors in prolog ###\r\n\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Add Elements to target dimension ###\r\n\r\nsElType = ElementType(pSrcDim, pSrcHier, vEle);\r\n\r\n\r\nIF( sElType @= 'C' & ElementComponentCount( pSrcDim, pSrcHier, vEle ) > 0 );\r\n nChildren = ElementComponentCount( pSrcDim, pSrcHier, vEle );\r\n nCount = 1;\r\n While( nCount <= nChildren );\r\n sChildElement = ElementComponent( pSrcDim, pSrcHier, vEle, nCount );\r\n sChildWeight = ElementWeight( pSrcDim, pSrcHier, vEle, sChildElement );\r\n If( SubsetGetIndex( pSrcDim, sTempSubset, sChildElement ) > 0 );\r\n HierarchyElementComponentAdd( pTgtDim, pTgtHier, vEle, sChildElement, sChildWeight );\r\n EndIf;\r\n nCount = nCount + 1;\r\n End;\r\nEndIf;\r\n\r\n### End MetaData ###", + "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n\r\n### Check for errors in prolog ###\r\n\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Replicate Attributes ###\r\n# Note: DTYPE on Attr dim returns \"AS\", \"AN\" or \"AA\" need to strip off leading \"A\"\r\n\r\n\r\nIf( pAttr >= 1 & DimensionExists( sAttrTragetDim ) = 1 );\r\n\r\n nAttr = 1;\r\n While( nAttr <= nNumAttrs );\r\n sAttrName = DimNm( sAttrTragetDim, nAttr );\r\n sAttrType = SubSt( DTYPE( sAttrTragetDim, sAttrName ), 2, 1 );\r\n \r\n\t\tif(pAttr > 1 & (DIMIX(sAttrTragetDim, sAttrName) = 0 % DIMIX(sAttrDim, sAttrName) = 0));\r\n\t\t\t#Do nothing, only existing attributes will be copied in this case\r\n\t\telse;\r\n\t\t\r\n\t\t\tIf( sAttrType @= 'S' % sAttrType @= 'A' );\r\n\t\t\t\tsAttrVal = ElementAttrS( pSrcDim, pSrcHier, vEle, sAttrName );\r\n\t\t\t\t\r\n\t\t\t\tIf( sAttrVal @<> '' );\r\n\t\t\t\t\tIf( CellIsUpdateable( '}ElementAttributes_' | pTgtDim, pTgtHier:vEle, sAttrName ) = 1 );\r\n\t\t\t\t\t\tIf( sAttrType @= 'A' );\r\n\t\t\t\t\t\t\tElementAttrPutS( sAttrVal, pTgtDim, pTgtHier, vEle, sAttrName, 1 );\r\n\t\t\t\t\t\tElse;\r\n\t\t\t\t\t\t\tElementAttrPutS( sAttrVal, pTgtDim, pTgtHier, vEle, sAttrName );\r\n\t\t\t\t\t\tEndIf;\r\n\t\t\t\t\tEndIf;\r\n\t\t\t\tEndIf;\r\n\t\t\tElse;\r\n\t\t\t\tnAttrVal = ElementAttrN( pSrcDim, pSrcHier, vEle, sAttrName );\r\n\t\t\t\tIf( nAttrVal <> 0 );\r\n\t\t\t\t\tIf( CellIsUpdateable( '}ElementAttributes_' | pTgtDim, pTgtHier:vEle, sAttrName ) = 1 );\r\n\t\t\t\t\t\tElementAttrPutN( nAttrVal, pTgtDim, pTgtHier, vEle, sAttrName );\r\n\t\t\t\t\tEndIf;\r\n\t\t\t\tEndIf; \r\n\t\t\tEndIf;\r\n\t\t\t# check for localized attributes\r\n\t\t\tIf( CubeExists( sAttrLoc ) = 1 );\r\n\t\t\t\r\n\t\t\t\tnLang = 1;\r\n\t\t\t\tWhile( nLang <= nNumLang );\r\n\t\t\t\t\tsLang = DimNm( cLangDim, nLang );\r\n\t\t\t\t\tIf( sAttrType @= 'A' % sAttrType @= 'S' );\r\n\t\t\t\t\t\tsAttrVal = ElementAttrS( pSrcDim, pSrcHier, vEle, sAttrName );\r\n\t\t\t\t\t\tsAttrValLoc = ElementAttrSL( pSrcDim, pSrcHier, vEle, sAttrName, sLang );\r\n\t\t\t\t\t\tIf( sAttrValLoc @= sAttrVal ); sAttrValLoc = ''; EndIf;\r\n\t\t\t\t\tElse;\r\n\t\t\t\t\t\tnAttrVal = ElementAttrN( pSrcDim, pSrcHier, vEle, sAttrName );\r\n\t\t\t\t\t\tnAttrValLoc = ElementAttrNL( pSrcDim, pSrcHier, vEle, sAttrName, sLang );\r\n\t\t\t\t\tEndIf;\r\n\t\t\t\t\tIf( CubeExists( sAttrLocTarget ) = 0 );\r\n\t\t\t\t\t\tIf( sAttrType @= 'A' );\r\n\t\t\t\t\t\t\tElementAttrPutS( sAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang, 1 );\r\n\t\t\t\t\t\tElseIf( sAttrType @= 'N' );\r\n\t\t\t\t\t\t\tElementAttrPutN( nAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang );\r\n\t\t\t\t\t\tElse;\r\n\t\t\t\t\t\t\tElementAttrPutS( sAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang );\r\n\t\t\t\t\t\tEndIf;\r\n\t\t\t\t\tElseIf(CubeExists( sAttrLocTarget ) = 1 );\r\n\t\t\t\t\t\tIf( CellIsUpdateable( sAttrLocTarget, pTgtHier:vEle, sLang, sAttrName ) = 1 );\r\n\t\t\t\t\t\t\tIf( sAttrType @= 'A' );\r\n\t\t\t\t\t\t\t\tElementAttrPutS( sAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang, 1 );\r\n\t\t\t\t\t\t\tElseIf( sAttrType @= 'N' );\r\n\t\t\t\t\t\t\t\tElementAttrPutN( nAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang );\r\n\t\t\t\t\t\t\tElse;\r\n\t\t\t\t\t\t\t\tElementAttrPutS( sAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang );\r\n\t\t\t\t\t\t\tEndIf;\r\n\t\t\t\t\t\tEndIf;\r\n\t\t\t\t\tEndIf;\r\n\t\t\t\t\tnLang = nLang + 1;\r\n\t\t\t\tEnd;\r\n\t\t\tEndIf;\r\n\t\tendif;\r\n nAttr = nAttr + 1;\r\n End;\r\n\r\nEndIf;\r\n\r\n### End Data ###", + "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0~~##\r\n################################################################################################# \r\n\r\n\r\nIf(pTgtDim @=pTgtHier);\r\n sTargetDimHier = pTgtDim;\r\nElse;\r\n sTargetDimHier =pTgtDim|':'|pTgtHier;\r\nEndIf;\r\n\r\n### Set the target Sort Order ###\r\n CELLPUTS( sSortElementsType, '}DimensionProperties', sTargetDimHier, 'SORTELEMENTSTYPE');\r\n CELLPUTS( sSortElementsSense, '}DimensionProperties', sTargetDimHier, 'SORTELEMENTSSENSE');\r\n CELLPUTS( sSortComponentsType, '}DimensionProperties',sTargetDimHier, 'SORTCOMPONENTSTYPE');\r\n CELLPUTS( sSortComponentsSense, '}DimensionProperties', sTargetDimHier, 'SORTCOMPONENTSSENSE');\r\n\r\n### Clean up temporary subset ###\r\nIf( nTempSubsetCreated = 1 );\r\n SubsetDestroy( pSrcDim, sTempSubset );\r\n nTempSubsetCreated = 0;\r\nEndIf;\r\n \r\n### If a new dimension has been created, call the process recursively to clone the alternate hierarchy, after the same named hierarchy has been processed\r\nIf( nProcessSameNamedHier = 1 );\r\n nRet = EXECUTEPROCESS(GetProcessName(),\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pSrcDim', pSrcDim,\r\n 'pSrcHier',pSrcHier,\r\n 'pTgtDim', pTgtDim,\r\n 'pTgtHier', sEpilogTgtHier,\r\n 'pAttr', pAttr,\r\n 'pUnwind', pUnwind,\r\n 'pIfNthanC', pIfNthanC,\r\n 'pSrcFilter', pSrcFilter\r\n );\r\nEndIf;\r\n \r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully cloned the %pSrcDim%:%pSrcHier% dimension:hierarchy to %pTgtDim%:%pTgtHier%' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", + "HasSecurityAccess": true, + "UIData": "CubeAction=1511\fDataAction=1503\fCubeLogChanges=0\f", + "DataSource": { + "Type": "TM1DimensionSubset", + "dataSourceNameForClient": "}Cubes", + "dataSourceNameForServer": "}Cubes", + "subset": "All" + }, + "Parameters": [ + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pSrcDim", + "Prompt": "REQUIRED: Source Dimension", + "Value": "", + "Type": "String" + }, + { + "Name": "pSrcHier", + "Prompt": "REQUIRED: Source Hierarchy", + "Value": "", + "Type": "String" + }, + { + "Name": "pTgtDim", + "Prompt": "REQUIRED: Target Dimension (can be the same as source)", + "Value": "", + "Type": "String" + }, + { + "Name": "pTgtHier", + "Prompt": "OPTIONAL: Target Hierarchy (will default to SrcHier_Clone if the dimensions are the same)", + "Value": "", + "Type": "String" + }, + { + "Name": "pAttr", + "Prompt": "OPTIONAL: Include Attributes? (Boolean 1=True; 2 = only existing)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pUnwind", + "Prompt": "REQUIRED: Unwind? (0 = Delete all Elements, 1 = Unwind Existing Elements, 2 = Do not change Existing Elements (Only relevant if target hierarchy exists) )", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pIfNthanC", + "Prompt": "OPTIONAL: if 1 than all N-elemens will be created as c-elements", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pSrcFilter", + "Prompt": "OPTIONAL: Source filter. Use Subset: or MDX:", + "Value": "", + "Type": "String" + } + ], + "Variables": [ + { + "Name": "vEle", + "Type": "String", + "Position": 1, + "StartByte": 0, + "EndByte": 0 + } + ], + "VariablesUIData": [ + "VarType=32\fColType=827\f" + ] +} \ No newline at end of file diff --git a/wiki_content/wiki_bedrock.hier.clone.md b/wiki_content/wiki_bedrock.hier.clone.md new file mode 100644 index 0000000..1eb16c7 --- /dev/null +++ b/wiki_content/wiki_bedrock.hier.clone.md @@ -0,0 +1,182 @@ +# }bedrock.hier.clone + +## Overview + +This process clones a source dimension hierarchy into a target dimension hierarchy. It replicates the element structure, consolidation relationships, sort order, and optionally element attributes (including localized attributes). + +**Bedrock Version:** 4.0+ +**GitHub:** [cubewise-code/bedrock](https://github.com/cubewise-code/bedrock) + +--- + +## Use Cases + +- Create a duplicate of an existing hierarchy for testing or development purposes. +- Use an existing dimension as a **structural skeleton** for a new, more detailed dimension by converting all leaf (N) elements to consolidation (C) elements (`pIfNthanC = 1`). +- Clone a hierarchy into a new dimension while optionally replicating or selectively copying element attributes. +- Clone only a **filtered subset of elements** from a large hierarchy using a named subset or an MDX expression (`pSrcFilter`). + +--- + +## Parameters + +| Parameter | Type | Required | Default | Description | +|-----------------------|---------|----------|---------|-------------| +| `pLogOutput` | Numeric | Optional | `0` | Write parameters and action summary to the server message log. `1` = enabled. | +| `pStrictErrorHandling`| Numeric | Optional | `0` | On any error, exit with major error status via `ProcessQuit`. `1` = enabled. | +| `pSrcDim` | String | Required | `""` | Source dimension name. May be supplied as `Dim:Hier` – the process will split it automatically. | +| `pSrcHier` | String | Required | `""` | Source hierarchy name. Defaults to the dimension name if left empty. | +| `pTgtDim` | String | Required | `""` | Target dimension name. May be the same as the source. If the dimension does not exist it will be created. | +| `pTgtHier` | String | Optional | `""` | Target hierarchy name. Defaults to `_Clone` when source and target dimension are the same. | +| `pAttr` | Numeric | Optional | `0` | Attribute handling. `0` = no attributes; `1` = create missing attributes and copy all values; `2` = copy values only for attributes that already exist on both source and target. | +| `pUnwind` | Numeric | Required | `0` | How to handle an existing target hierarchy. `0` = delete all elements; `1` = unwind existing consolidations; `2` = leave existing structure untouched. | +| `pIfNthanC` | Numeric | Optional | `0` | If `1`, all Numeric (N) elements from the source are inserted as Consolidated (C) elements in the target. String (S) elements are always kept as-is. | +| `pSrcFilter` | String | Optional | `""` | Element filter. `Subset:` uses an existing named subset; `MDX:` creates a temporary static subset from the MDX expression. Empty = clone all elements. | + +--- + +## Behaviour + +### Source & Target Resolution + +- If `pSrcDim` is supplied in `Dim:Hier` format and `pSrcHier` is empty, the process automatically splits the value into dimension and hierarchy. +- The same auto-split logic applies to `pTgtDim`. +- If the target dimension does not exist it is created automatically. In this case the process first clones into the same-named hierarchy of the new dimension (to allow attributes to be processed in the Data tab), then calls itself recursively to create the requested alternate hierarchy. + +### Element Insertion (`pIfNthanC`) + +By default, element types are copied 1:1 from source to target. +When `pIfNthanC = 1`: + +- All **N-elements** (Numeric/Leaf) are inserted as **C-elements** (Consolidated) in the target hierarchy. +- **S-elements** (String) are always inserted as S-elements regardless of `pIfNthanC`. + +This is useful when cloning a dimension that will serve as the structural basis for a new, more detailed dimension: all elements are immediately available as consolidations that can receive child members without needing a separate conversion step. + +### Consolidation Relationships (Metadata tab) + +The process iterates over all C-elements in the source hierarchy and replicates their child–weight relationships to the target hierarchy via `HierarchyElementComponentAdd`. + +### Sort Order + +The sort order (`SORTELEMENTSTYPE`, `SORTELEMENTSSENSE`, `SORTCOMPONENTSTYPE`, `SORTCOMPONENTSSENSE`) is read from the source hierarchy's `}DimensionProperties` and applied to the target hierarchy in both the Prolog and Epilog. + +### Attribute Replication (`pAttr`) + +| `pAttr` | Behaviour | +|---------|-----------| +| `0` | No attributes are copied. | +| `1` | Missing attributes are created on the target dimension. All attribute values (String, Numeric, Alias) are copied from source to target elements. | +| `2` | No new attributes are created. Only attribute values for attributes that already exist on **both** source and target dimension are copied. Useful when the target has a curated attribute schema that must not be altered. | + +Localized attributes (`}LocalizedElementAttributes_*`) are replicated when the source localization cube exists. + +### Element Filter (`pSrcFilter`) + +When `pSrcFilter` is supplied, only the elements resolved by the filter are cloned. Both the element insertion loop (Prolog) and the consolidation relationship loop (Metadata) are restricted to the working subset. + +| Prefix | Behaviour | +|--------|-----------| +| *(empty)* | No filter – full hierarchy is cloned (`ALL` subset). | +| `Subset:` | Uses the named subset on `pSrcDim:pSrcHier`. The subset must exist; an error is raised otherwise. | +| `MDX:` | Calls `}bedrock.hier.sub.create.bymdx` to create a temporary **public static** subset from the MDX expression. The subset is destroyed at the end of the Epilog. | + +**Partial hierarchy behaviour (Strategy A — strict):** +Consolidation relationships are only written when the child element is also present in the working subset. Parent elements whose children are entirely outside the filter are inserted without children. + +> If the MDX expression resolves to zero elements, the target hierarchy is created/cleared but left empty. No error is raised. + +### Unwind behaviour (`pUnwind`) + +| `pUnwind` | Behaviour | +|-----------|-----------| +| `0` | All elements in the target hierarchy are deleted before cloning (`HierarchyDeleteAllElements`). | +| `1` | Existing consolidations are unwound by calling `}bedrock.hier.unwind` before cloning. | +| `2` | The existing target hierarchy structure is left untouched; only missing elements/relationships are added. | + +> **Note:** If the target dimension or hierarchy does not yet exist, `pUnwind` is automatically set to `2` internally (nothing to unwind). + +--- + +## Notes & Cautions + +- **Target hierarchy cannot be `Leaves`** – the process will abort with an error if `pTgtHier` resolves to `Leaves`. +- If source and target dimension are the same and no `pTgtHier` is provided, the target hierarchy is automatically named `_Clone`. +- When `pIfNthanC = 1`, the Metadata tab still processes consolidation relationships based on the **source** element type. Only C-elements in the source have their children replicated. Elements that were N in the source but inserted as C in the target will have no children initially – they are ready to receive children as part of subsequent detailing work. +- `pAttr = 2` does not raise an error if no matching attributes are found; it simply copies nothing. +- `pSrcFilter` requires `}bedrock.hier.sub.create.bymdx` to be present on the server when using the `MDX:` prefix. +- The temporary subset created for `MDX:` filters uses the existing `cTempSub` constant (process name + timestamp + random int) and is automatically destroyed in the Epilog. It is safe under concurrent execution. +- An unrecognised `pSrcFilter` prefix (i.e. neither `Subset:` nor `MDX:`) causes an immediate abort. + +--- + +## Example Call + +``` +# Clone hierarchy and convert all N-elements to C-elements +ExecuteProcess( '}bedrock.hier.clone', + 'pLogOutput', 1, + 'pStrictErrorHandling', 0, + 'pSrcDim', 'Product', + 'pSrcHier', 'Product', + 'pTgtDim', 'Product_Detail', + 'pTgtHier', '', + 'pAttr', 2, + 'pUnwind', 0, + 'pIfNthanC', 1 +); +``` + +This call: +1. Clones the `Product` hierarchy into a new `Product_Detail` dimension. +2. Converts all N-elements to C-elements so the new dimension can immediately receive child members. +3. Copies attribute values only for attributes that already exist on the target (`pAttr = 2`). + +### Filter by named subset + +``` +ExecuteProcess( '}bedrock.hier.clone', + 'pLogOutput', 1, + 'pStrictErrorHandling', 0, + 'pSrcDim', 'Product', + 'pSrcHier', 'Product', + 'pTgtDim', 'Product_Region_A', + 'pTgtHier', '', + 'pAttr', 1, + 'pUnwind', 0, + 'pIfNthanC', 0, + 'pSrcFilter', 'Subset:Region_A_Products' +); +``` + +Clones only the elements contained in the named subset `Region_A_Products`. + +### Filter by MDX expression + +``` +ExecuteProcess( '}bedrock.hier.clone', + 'pLogOutput', 1, + 'pStrictErrorHandling', 1, + 'pSrcDim', 'Product', + 'pSrcHier', 'Product', + 'pTgtDim', 'Product_HW', + 'pTgtHier', '', + 'pAttr', 1, + 'pUnwind', 0, + 'pIfNthanC', 1, + 'pSrcFilter', 'MDX:{[Product].[Product].[Hardware].Children}' +); +``` + +Clones only the direct children of `Hardware`, inserts them as C-elements, and cleans up the temporary subset automatically. + +--- + +## Related Processes + +| Process | Description | +|---------|-------------| +| [`}bedrock.hier.unwind`](https://github.com/cubewise-code/bedrock/wiki/%7Dbedrock.hier.unwind) | Unwinds consolidation relationships in a hierarchy | +| [`}bedrock.dim.clone`](https://github.com/cubewise-code/bedrock/wiki/%7Dbedrock.dim.clone) | Clones an entire dimension including all hierarchies | +| [`}bedrock.hier.create`](https://github.com/cubewise-code/bedrock/wiki/%7Dbedrock.hier.create) | Creates a new hierarchy in an existing dimension | +| [`}bedrock.hier.sub.create.bymdx`](https://github.com/cubewise-code/bedrock/wiki/%7Dbedrock.hier.sub.create.bymdx) | Creates a named subset from an MDX expression (used internally by `pSrcFilter`) |