DBA Data[Home] [Help]

PACKAGE BODY: APPS.BSC_AW_ADAPTER_KPI

Source


1 package body BSC_AW_ADAPTER_KPI AS
2 /*$Header: BSCAWAKB.pls 120.30 2006/05/20 02:10:19 vsurendr ship $*/
3 
4 procedure create_kpi(p_kpi_list dbms_sql.varchar2_table) is
5 l_kpi kpi_tb;
6 Begin
7   for i in 1..p_kpi_list.count loop
8     l_kpi(i).kpi:=p_kpi_list(i);
9   end loop;
10   for i in 1..l_kpi.count loop
11     create_kpi(l_kpi(i));
12   end loop;
13 Exception when others then
14   log_n('Exception in create_kpi '||sqlerrm);
15   raise;
16 End;
17 
18 procedure create_kpi(p_kpi in out nocopy kpi_r) is
19 --
20 Begin
21   --first we need to get the dimension sets of the kpi
22   --get_kpi_properties gets calendar etc
23   if g_debug then
24     log_n('=====================================================');
25     log('KPI Adapter. Process KPI ->'||p_kpi.kpi);
26   end if;
27   /*
28   if the kpi is already implemented as AW, we do
29   1. if recreate is specified, its all cleaned up and recretaed
30   2. else , return. do nothing
31   */
32   if check_kpi_create(p_kpi.kpi) then
33     bsc_aw_bsc_metadata.get_kpi_properties(p_kpi);--gets calendar
34     bsc_aw_bsc_metadata.get_kpi_dim_sets(p_kpi);
35     --for each dim set, get the bsc dim levels in it. for these levels, get the cc dim
36     for i in 1..p_kpi.dim_set.count loop
37       get_dim_set_properties(p_kpi.kpi,p_kpi.dim_set(i)); --forecast yes or no
38       get_dim_set_dims(p_kpi.kpi,p_kpi.dim_set(i));
39       identify_standalone_levels(p_kpi.kpi,p_kpi.dim_set(i)); --user specifies city and country with no parent child relation
40       create_missing_dim_levels(p_kpi.kpi,p_kpi.dim_set(i)); --if intermediate levels are not specified for the kpi
41       get_dim_set_std_dims(p_kpi.kpi,p_kpi.dim_set(i));--type and projection dim
42       get_dim_set_calendar(p_kpi,p_kpi.dim_set(i));
43       --we go to bsc olap metadata to get the dim properties
44       get_dim_set_dim_properties(p_kpi.kpi,p_kpi.dim_set(i)); --recursive, multi level, time or normal
45       set_dim_level_positions(p_kpi.kpi,p_kpi.dim_set(i));
46       set_dim_order(p_kpi.dim_set(i));
47       get_dim_set_measures(p_kpi.kpi,p_kpi.dim_set(i));
48     end loop;
49     --get the targets at higher level info (if there are targets at higher levels)
50     get_dim_set_targets(p_kpi);
51     --set_dim_agg_level will set the agg level for each dim
52     set_dim_agg_level(p_kpi);
53     set_calendar_agg_level(p_kpi);
54     --
55     for i in 1..p_kpi.dim_set.count loop
56       get_s_views(p_kpi.kpi,p_kpi.dim_set(i)); --gets both regular and z views
57       get_dim_set_data_source(p_kpi,p_kpi.dim_set(i));
58       if p_kpi.dim_set(i).targets_higher_levels='Y' then
59         get_dim_set_data_source(p_kpi,p_kpi.target_dim_set(i));
60       end if;
61     end loop;
62     /*set the DS levels. this has to be set before check_compressed_composite*/
63     for i in 1..p_kpi.dim_set.count loop
64       set_DS_dim_levels(p_kpi,p_kpi.dim_set(i));
65       if p_kpi.dim_set(i).targets_higher_levels='Y' then
66         set_DS_dim_levels(p_kpi,p_kpi.target_dim_set(i));
67       end if;
68     end loop;
69     /*see if we can set the sql_aggregated flag for non std agg to Y. this can enable compressed composites and partitions */
70     set_sql_aggregations(p_kpi,'set');
71     /*first set the partition for target, only then actual. actual can be partitioned only of target can also be partitioned
72     set_dimset_partition_info can change the agg_level of the dimensions if hash partitions are involved */
73     for i in 1..p_kpi.dim_set.count loop
74       check_compressed_composite(p_kpi.dim_set(i),p_kpi.target_dim_set(i));
75       set_dimset_partition_info(p_kpi.kpi,p_kpi.dim_set(i),p_kpi.target_dim_set(i));
76     end loop;
77     /*if we do not have partitions, we can unset the sql_aggregation flag */
78     set_sql_aggregations(p_kpi,'unset');
79     --make the sql stmt etc
80     for i in 1..p_kpi.dim_set.count loop
81       /*set the PT info in the dimset */
82       set_data_source_PT(p_kpi,p_kpi.dim_set(i));
83       set_dim_set_data_source(p_kpi,p_kpi.dim_set(i));
84       if p_kpi.dim_set(i).targets_higher_levels='Y' then
85         set_data_source_PT(p_kpi,p_kpi.target_dim_set(i));
86         set_dim_set_data_source(p_kpi,p_kpi.target_dim_set(i));
87       end if;
88     end loop;
89     --set properties like pre-calculated dimset etc
90     set_dim_set_properties(p_kpi);
91     --metadata read complete.
92     --create_aw_object_names gives the names to the aw objects like dim, cubes
93     create_aw_object_names(p_kpi);
94     make_agg_formula(p_kpi);
95     if g_debug then
96       dmp_kpi(p_kpi);
97     end if;
98     create_kpi_aw(p_kpi);--create the aw objects
99     --create the kpi metadata
100     bsc_aw_md_api.create_kpi(p_kpi);
101   end if;
102 Exception when others then
103   log_n('Exception in create_kpi '||sqlerrm);
104   raise;
105 End;
106 
107 /*
108 given a kpi object filled with all reqd metadata, this creates the aw objects.
109 can be used later to recreate kpi from olap metadata. we fill kpi_r and send it
110 to this api
111 we do not create the metadata here since its already there in case of recreate
112 */
113 procedure create_kpi_aw(p_kpi in out nocopy kpi_r) is
114 Begin
115   create_kpi_objects(p_kpi);
116   create_kpi_program(p_kpi);
117   create_kpi_program_parallel(p_kpi); --creates program based on partition or program based on measure
118   create_kpi_view(p_kpi); --creates the S views based on olap table functions
119 Exception when others then
120   log_n('Exception in create_kpi '||sqlerrm);
121   raise;
122 End;
123 
124 /*
125 see if recreate is specified. if yes, drop the kpi (if it exists)
126 if RECREATE is specified, aw objects are dropped
127 */
128 function check_kpi_create(p_kpi varchar2) return boolean is
129 Begin
130   --see if the kpi exists
131   if bsc_aw_md_api.is_kpi_present(p_kpi) then
132     if bsc_aw_utility.get_parameter_value(bsc_aw_utility.g_options,'RECREATE KPI')='Y' then
133       drop_kpi_objects(p_kpi); --drops aw objects and olap metadata
134       return true;
135     else
136       return false; --do not create the kpi. already present
137     end if;
138   else --new kpi
139     return true;
140   end if;
141 Exception when others then
142   log_n('Exception in check_kpi_create '||sqlerrm);
143   raise;
144 End;
145 
146 
147 /*
148 from bsc olap metadata, get the dim properties
149 we consider time and other dim separately. time is considered in calendars, not in dim
150 
151 here we are getting level properties in 2 parts.
152 bsc_aw_bsc_metadata.get_dim_level_properties gets it from metadata
153 for rec dim, we also do bsc_aw_md_api.get_bsc_olap_object_relation to find the rec_parent_level.
154 this is ok since rec_parent_level is not a bsc metadata property. its specific to our implementation.
155 */
156 procedure get_dim_set_dim_properties(p_kpi varchar2,p_dim_set in out nocopy dim_set_r) is
157 Begin
158   for i in 1..p_dim_set.dim.count loop
159     get_dim_properties(p_kpi,p_dim_set.dim(i));
160   end loop;
161   --need to see if we need zero code on the dim
162   bsc_aw_bsc_metadata.check_dim_zero_code(p_kpi,p_dim_set);
163 Exception when others then
164   log_n('Exception in get_dim_set_dim_properties '||sqlerrm);
165   raise;
166 End;
167 
168 procedure get_dim_properties(p_kpi varchar2,p_dim in out nocopy dim_r) is
169 --
170 l_olap_object_relation bsc_aw_md_wrapper.bsc_olap_object_relation_tb;
171 Begin
172   bsc_aw_md_api.get_dim_properties(p_dim); --recursive, multi level, time or normal, concat?, base value cube etc
173   bsc_aw_bsc_metadata.get_dim_level_properties(p_kpi,p_dim); --pk,fk,datatype for the levels and the filter
174   l_olap_object_relation.delete;
175   --'zero code level'  'recursive parent level'
176   bsc_aw_md_api.get_bsc_olap_object_relation(null,null,null,p_dim.dim_name,'dimension',l_olap_object_relation);
177   for i in 1..l_olap_object_relation.count loop
178     if l_olap_object_relation(i).object_type='dimension level' and l_olap_object_relation(i).relation_type='zero code level' then
179       for j in 1..p_dim.levels.count loop
180         if l_olap_object_relation(i).object=p_dim.levels(j).level_name then
181           p_dim.levels(j).zero_code_level:=l_olap_object_relation(i).relation_object;
182           exit;
183         end if;
184       end loop;
185     elsif l_olap_object_relation(i).object_type='dimension level' and l_olap_object_relation(i).relation_type='recursive parent level' then
186       for j in 1..p_dim.levels.count loop
187         if l_olap_object_relation(i).object=p_dim.levels(j).level_name then
188           p_dim.levels(j).rec_parent_level:=l_olap_object_relation(i).relation_object;
189           exit;
190         end if;
191       end loop;
192     end if;
193   end loop;
194 Exception when others then
195   log_n('Exception in get_dim_properties '||sqlerrm);
196   raise;
197 End;
198 
199 /*set the level position by reading the olap metadata
200 required for set_dim_agg_level
201 */
202 procedure set_dim_level_positions(p_kpi varchar2,p_dim_set in out nocopy dim_set_r) is
203 Begin
204   for i in 1..p_dim_set.dim.count loop
205     set_dim_level_positions(p_dim_set.dim(i));
206   end loop;
207   --std dim
208   for i in 1..p_dim_set.std_dim.count loop
209     set_dim_level_positions(p_dim_set.std_dim(i));
210   end loop;
211 Exception when others then
212   log_n('Exception in set_dim_level_positions '||sqlerrm);
213   raise;
214 End;
215 
216 procedure set_dim_level_positions(p_dim in out nocopy dim_r) is
217 l_olap_object bsc_aw_md_wrapper.bsc_olap_object_tb;
218 Begin
219   l_olap_object.delete;
220   bsc_aw_md_api.get_bsc_olap_object(null,'dimension level',p_dim.dim_name,'dimension',l_olap_object);
221   for i in 1..p_dim.levels.count loop
222     --standalone dim for each dim level do not have dimension levels with them.
223     p_dim.levels(i).position:=1;
224     for j in 1..l_olap_object.count loop
225       if p_dim.levels(i).level_name=l_olap_object(j).object then
226         p_dim.levels(i).position:=bsc_aw_utility.get_parameter_value(l_olap_object(j).property1,'position',',');
227         exit;
228       end if;
229     end loop;
230   end loop;
231 Exception when others then
232   log_n('Exception in set_dim_level_positions '||sqlerrm);
233   raise;
234 End;
235 
236 /*
237 given a kpi and dim set, find out the calendar and the periodicity info
238 calendar is at kpi level, we store it at dimset level to keep consistent with other dim
239 NOTE!! for calendar,we cannot assume that periodicity(1) is the lowest level
240 simply because there can be multiple lowest levels. so we have a flag in periodicity_r called
241 lowest_level
242 */
243 procedure get_dim_set_calendar(p_kpi kpi_r,p_dim_set in out nocopy dim_set_r) is
244 l_pc cal_parent_child_tb;
245 Begin
246   p_dim_set.calendar.calendar:=p_kpi.calendar;
247   bsc_aw_bsc_metadata.get_dim_set_calendar(p_kpi.kpi,p_dim_set);
248   --give the aw dim names
249   p_dim_set.calendar.aw_dim:=bsc_aw_calendar.get_calendar_name(p_dim_set.calendar.calendar);
250   --set the relation name, periodicity aw name
251   bsc_aw_md_api.get_dim_set_calendar(p_kpi,p_dim_set);
252   --now, get the missing periodicity, and mark lowest level
253   get_missing_periodicity(p_kpi,p_dim_set);
254   /*of all hier relations in the calendar, grab only those that are relevant to the dimset */
255   get_relevant_cal_hier(p_dim_set.calendar.periodicity,p_dim_set.calendar.parent_child,l_pc);
256   if p_dim_set.calendar.periodicity.count>1 and l_pc.count=0 then
257     log('correct_relevant_cal_hier could not get the relevant cal hier');
258     raise bsc_aw_utility.g_exception;
259   end if;
260   p_dim_set.calendar.parent_child.delete;
261   for i in 1..l_pc.count loop
262     p_dim_set.calendar.parent_child(i):=l_pc(i);
263   end loop;
264 Exception when others then
265   log_n('Exception in get_dim_set_calendar '||sqlerrm);
266   raise;
267 End;
268 
269 /*
270 given a dim set, finds out the levels in it and also finds from olap metadata
271 what the cc dim is. the data structure is then loaded
272 in get_dim_set_dims, we expect the dim levels come with the lowest levels first. this means we can assume
273 that the first level for any dim is the lowest level
274 
275 get_dim_set_dims returns the missing levels. so if the kpi has city and country, the api will also return
276 state
277 */
278 procedure get_dim_set_dims(
279 p_kpi varchar2,
280 p_dim_set in out nocopy dim_set_r) is
281 --
282 l_dim_level dbms_sql.varchar2_table;
283 l_mo_dim_group dbms_sql.varchar2_table; --used to see if a level is stand alone or part of parent child
284 l_skip_level dbms_sql.varchar2_table;
285 l_dim varchar2(300);
286 Begin
287   bsc_aw_bsc_metadata.get_dim_set_dims(p_kpi,p_dim_set.dim_set,l_dim_level,l_mo_dim_group,l_skip_level);
288   for i in 1..l_dim_level.count loop
289     bsc_aw_md_api.get_dim_for_level(l_dim_level(i),l_dim);
290     if g_debug then
291       log('For level '||l_dim_level(i)||' got dim '||l_dim);
292     end if;
293     set_dim_and_level(p_dim_set,l_dim,l_dim_level(i),l_mo_dim_group(i),l_skip_level(i)); --level properties are set in get_dim_set_dim_properties
294   end loop;
295 Exception when others then
296   log_n('Exception in get_dim_set_dims '||sqlerrm);
297   raise;
298 End;
299 
300 /*
301 given a cc dim and level, see if  the cc dim exists. if not create it . if yes,
302 see if the level is already in. if not, add it.
303 */
304 procedure set_dim_and_level(
305 p_dim_set in out nocopy dim_set_r,
306 p_dim varchar2,
307 p_level varchar2,
308 p_mo_dim_group varchar2,
309 p_skip_level varchar2
310 ) is
311 Begin
312   for i in 1..p_dim_set.dim.count loop
313     if p_dim_set.dim(i).dim_name=p_dim then
314       for j in 1..p_dim_set.dim(i).levels.count loop
315         if p_dim_set.dim(i).levels(j).level_name=p_level then
316           return;
317         end if;
318       end loop;
319       --at this point, p_level was not in the levels list...so add it
320       p_dim_set.dim(i).levels(p_dim_set.dim(i).levels.count+1).level_name:=p_level;
321       p_dim_set.dim(i).levels(p_dim_set.dim(i).levels.count).property:='mo dim group='||p_mo_dim_group||',skip level='||
322       nvl(p_skip_level,'N');
323       return;
324     end if;
325   end loop;
326   --here, p_dim was not found in the dim set. create the dim and add the level
327   p_dim_set.dim(p_dim_set.dim.count+1).dim_name:=p_dim;
328   p_dim_set.dim(p_dim_set.dim.count).levels(p_dim_set.dim(p_dim_set.dim.count).levels.count+1).level_name:=p_level;
329   p_dim_set.dim(p_dim_set.dim.count).levels(p_dim_set.dim(p_dim_set.dim.count).levels.count).property:='mo dim group='||
330   p_mo_dim_group||',skip level='||nvl(p_skip_level,'N');
331 Exception when others then
332   log_n('Exception in set_dim_and_level '||sqlerrm);
333   raise;
334 End;
335 
336 /*
337 in the composite, the order of dim is
338 dim with no agg, no zero code
339 dim with no agg, zero code
340 dim with agg
341 rec dim
342 time
343 also, in the load program, we follow the same order. this api just rearranges the dim in this order
344 please note that time dim is handled differently in calendar in the dim set
345 */
346 procedure set_dim_order(p_dim_set in out nocopy dim_set_r)  is
350 Begin
347 l_order dbms_sql.number_table;
348 l_rank number;
349 l_dim dim_tb;
351   for i in 1..p_dim_set.dim.count loop
352     l_order(i):=null;
353   end loop;
354   l_rank:=0;
355   for i in 1..p_dim_set.dim.count loop
356     log_n('prop='||p_dim_set.dim(i).property||' rec='||p_dim_set.dim(i).recursive||' count='||p_dim_set.dim(i).levels.count||' zero='||
357     p_dim_set.dim(i).zero_code);
358     if p_dim_set.dim(i).property='normal' and p_dim_set.dim(i).recursive='N' and p_dim_set.dim(i).levels.count=1
359     and p_dim_set.dim(i).zero_code='N' then
360       l_rank:=l_rank+1;
361       l_order(i):=l_rank;
362     end if;
363   end loop;
364   for i in 1..p_dim_set.dim.count loop
365     if p_dim_set.dim(i).property='normal' and p_dim_set.dim(i).recursive='N' and p_dim_set.dim(i).levels.count=1
366     and p_dim_set.dim(i).zero_code='Y' and l_order(i) is null then
367       l_rank:=l_rank+1;
368       l_order(i):=l_rank;
369     end if;
370   end loop;
371   for i in 1..p_dim_set.dim.count loop
372     if p_dim_set.dim(i).property='normal' and p_dim_set.dim(i).recursive='N' and l_order(i) is null then
373       l_rank:=l_rank+1;
374       l_order(i):=l_rank;
375     end if;
376   end loop;
377   for i in 1..p_dim_set.dim.count loop
378     if p_dim_set.dim(i).property='normal' and p_dim_set.dim(i).recursive='Y' and l_order(i) is null then
379       l_rank:=l_rank+1;
380       l_order(i):=l_rank;
381     end if;
382   end loop;
383   --copy back in the correct order
384   l_dim:=p_dim_set.dim;
385   p_dim_set.dim.delete;
386   for i in 1..l_rank loop
387     for j in 1..l_dim.count loop
388       if l_order(j)=i then
389         p_dim_set.dim(p_dim_set.dim.count+1):=l_dim(j);
390         exit;
391       end if;
392     end loop;
393   end loop;
394 Exception when others then
395   log_n('Exception in set_dim_order '||sqlerrm);
396   raise;
397 End;
398 
399 /*
400 get properties like
401 1. are there targets at higher levels
402 2. is there forecast
403 */
404 procedure get_dim_set_properties(p_kpi varchar2,p_dim_set in out nocopy dim_set_r) is
405 Begin
406   p_dim_set.dim_set_type:='actual';
407 Exception when others then
408   log_n('Exception in get_dim_set_properties '||sqlerrm);
409   raise;
410 End;
411 
412 procedure get_dim_set_measures(p_kpi varchar2,p_dim_set in out nocopy dim_set_r) is
413 Begin
414   bsc_aw_bsc_metadata.get_dim_set_measures(p_kpi,p_dim_set.dim_set,p_dim_set.measure);
415   /*if there are BALANCE LAST VALUE measures add the .period and .year property, used in measure name dim or cubes in 9i */
416   /* NOTE the period cube and year cube name change in create_PT_comp_names for 9i*/
417   for i in 1..p_dim_set.measure.count loop
418     if p_dim_set.measure(i).measure_type=g_balance_last_value_prop then
419       bsc_aw_utility.merge_property(p_dim_set.measure(i).property,'period cube',null,p_dim_set.measure(i).measure||'.period');
420       bsc_aw_utility.merge_property(p_dim_set.measure(i).property,'year cube',null,p_dim_set.measure(i).measure||'.year');
421     end if;
422   end loop;
423 Exception when others then
424   log_n('Exception in get_dim_set_measures '||sqlerrm);
425   raise;
426 End;
427 
428 /*
429 get the target dim and the dim levels
430 given the kpi and the dim set we see if there is targets at this dim set
431 for each dimset see if there are targets implemented
432 */
433 procedure get_dim_set_targets(p_kpi in out nocopy kpi_r) is
434 Begin
435   for i in 1..p_kpi.dim_set.count loop
436     p_kpi.dim_set(i).targets_higher_levels:=bsc_aw_bsc_metadata.is_target_at_higher_level(p_kpi.kpi,p_kpi.dim_set(i).dim_set);
437     if p_kpi.dim_set(i).targets_higher_levels='Y' then
438       p_kpi.target_dim_set(i):=p_kpi.dim_set(i);--copy all dim set properties excluding s_views and data source
439       --change the dimset name. append .target to it
440       p_kpi.target_dim_set(i).dim_set_name:=p_kpi.target_dim_set(i).dim_set_name||'.tgt';
441       p_kpi.target_dim_set(i).dim_set_type:='target';
442       p_kpi.target_dim_set(i).base_dim_set:=p_kpi.dim_set(i).dim_set_name;--for actuals, base_dim_set is null
443       bsc_aw_bsc_metadata.get_target_dim_levels(p_kpi.kpi,p_kpi.target_dim_set(i));
444       bsc_aw_bsc_metadata.get_target_dim_periodicity(p_kpi.kpi,p_kpi.target_dim_set(i));
445     else
446       p_kpi.target_dim_set(i).dim_set:=null;
447     end if;
448   end loop;
449 Exception when others then
450   log_n('Exception in get_dim_set_targets '||sqlerrm);
451   raise;
452 End;
453 
454 --get both regular MV and ZMV
455 procedure get_s_views(p_kpi varchar2,p_dim_set in out nocopy dim_set_r) is
456 Begin
457   bsc_aw_bsc_metadata.get_s_views(p_kpi,p_dim_set);
458 Exception when others then
459   log_n('Exception in get_s_views '||sqlerrm);
460   raise;
461 End;
462 
463 /*
464 This is an imp procedure!
465 this procedure will create the data sources for dim sets. finds out the base tables, finds out the level
466 of the base tables and create the sql statements as data source
467 
468 at this point in time, we assume that all dim properties have been set. for example, dim levels
469 filters etc. we assign data_source.dim=dim_set.dim inside bsc_aw_bsc_metadata.get_dim_set_data_source
470 --
471 each data source is at a certain periodicity. they also contain
472 */
473 procedure get_dim_set_data_source(p_kpi kpi_r,p_dim_set in out nocopy dim_set_r) is
474 Begin
475   --get_dim_set_data_source fills data_source and inc_data_source
476   bsc_aw_bsc_metadata.get_dim_set_data_source(p_kpi.kpi,p_dim_set);
477 Exception when others then
478   log_n('Exception in get_dim_set_data_source '||sqlerrm);
479   raise;
480 End;
481 
482 procedure set_dim_set_data_source(p_kpi kpi_r,p_dim_set in out nocopy dim_set_r) is
483 Begin
487   get_change_vector sets the change vector for initial, inc and target data sources
484   /*
485   get the change vector value. we look at bsc_olap_object_relation to see what change vectors are currently
486   used for base tables. then we allocate the next higher number
488 
489   we have obsoleted the old approach to inc load as mentioned above . (date today is 18 may 2005)
490   we change the inc approach to not using the aw table. we will not have a bsc_b_aw table. we will have the change_vector column in the b table
491   it will be indexed. every time we load the b table or process it, we will load a unique value into this column. then we will also register
492   in olap metadata what the latest value is. this value is from a seq
493   in olap metadaat, for b table and dimset relation, we will have
494   current change vector
495   current change vector is the value that this b->dimset looked at.
496   current is what is in b table now.
497   we will create the aw programs to accept 2 more parameters . the sql will look as
498   select ...from b table where change_vector between min value and max value from a temp table
499   we will insert into the temp table the min value and max value . min value is what the dim set last loaded +1
500   max value is the value for change vector from the base table
501   if the kpi has less keys, we will replace the aw table with in - line sql again with where change_vector between min and max
502   after loading, we will do update set last change vector=current change vector
503   when b table is loaded, it will call an api that will update the current change vector for this b table.
504   we will not call bsc_aw_md_api.get_change_vector(p_kpi.kpi,p_dim_set) or correct_change_vector(p_kpi,p_dim_set) anymore
505 
506   issue is : what if the b table already exists with data and we are creating the kpi. in this case, what will we set
507   current change vector to?
508   we will set it to 0. during load time, we check the b table for max(change_vector), set the current change vector
509   to that value and then continue. we want this at load time and not at optimizer time. after mo is run, someone can
510   load the b table.
511 
512   at this time the following are true
513   -we have the base table names in each data source
514   -the levels in the base table have the level names. also pk and fk.
515   -the measure in data source has measure names and formula. no other info
516   -the measure record of the dim set does not have the formula info.
517   to construct the data source from the base table level info, this package must get the level relation info from
518   bsc olap metadata and construct the sql. it needs to go to olap metadata since the level info from the dim set
519   will not contain the in-between levels from the base table to the first level in the dim set
520   */
521   for i in 1..p_dim_set.data_source.count loop
522     create_data_source_sql(p_kpi.kpi,p_dim_set,p_dim_set.data_source(i));
523   end loop;
524   for i in 1..p_dim_set.inc_data_source.count loop
525     create_data_source_sql(p_kpi.kpi,p_dim_set,p_dim_set.inc_data_source(i));
526   end loop;
527   /*
528   the data source sql is mainly driven by the base table. we encountered perf issue 4549680 where we had 6 baes tables. each base table
529   feeds one measure. the load went sequentially loading from each base table. this added to the time. if there are multiple data source
530   and we load the dimset, we need to load all the cubes 1 shot. create new virtual data source with base tables together. this will be
531   invoked when the dimset is loaded
532   */
533   create_dimset_data_source_sql(p_kpi.kpi,p_dim_set,p_dim_set.data_source);
534   create_dimset_data_source_sql(p_kpi.kpi,p_dim_set,p_dim_set.inc_data_source);
535 Exception when others then
536   log_n('Exception in set_dim_set_data_source '||sqlerrm);
537   raise;
538 End;
539 
540 /*
541 4642937 need to correct the levels of a data source. kpi can be a pre-calc kpi. this means there is B table data at upper levels also
542 if B table data comes at higher levels, we consider the dimset pre-calculated
543 data source has levels from the dimset. this means for targets, are already at higher level.
544 All B tables in a DS must have the same dim levels
545 status:correct,lower,higher,extra,skip
546 */
547 procedure set_DS_dim_levels(p_kpi kpi_r,p_dim_set in out nocopy dim_set_r) is
548 Begin
549   for i in 1..p_dim_set.data_source.count loop
550     set_DS_dim_levels(p_kpi.kpi,p_dim_set,p_dim_set.data_source(i));
551   end loop;
552   for i in 1..p_dim_set.inc_data_source.count loop
553     set_DS_dim_levels(p_kpi.kpi,p_dim_set,p_dim_set.inc_data_source(i));
554   end loop;
555 Exception when others then
556   log_n('Exception in set_DS_dim_levels '||sqlerrm);
557   raise;
558 End;
559 
560 procedure set_DS_dim_levels(p_kpi varchar2,p_dim_set in out nocopy dim_set_r,p_data_source in out nocopy data_source_r) is
561 l_base_table base_table_r;
562 l_dim dim_r;
563 l_level level_r;
564 l_ds_dim_set dbms_sql.varchar2_table;
565 Begin
566   for i in 1..p_data_source.base_tables.count loop
567     set_DS_dim_levels(p_kpi,p_dim_set,p_data_source,p_data_source.base_tables(i));
568   end loop;
569   --correct the ds dim levels. since all B tables have the same dim levels in a DS, take just the first one
570   l_base_table:=p_data_source.base_tables(1);
571   for i in 1..l_base_table.levels.count loop
572     if l_base_table.level_status(i)='higher' then
573       l_dim:=get_kpi_level_dim_r(p_dim_set,l_base_table.levels(i).level_name);
574       l_level:=get_dim_level_r(l_dim,l_base_table.levels(i).level_name);
575       l_ds_dim_set(l_ds_dim_set.count+1):=l_dim.dim_name;
576       for j in 1..p_data_source.dim.count loop
577         if p_data_source.dim(j).dim_name=l_dim.dim_name then
578           p_data_source.dim(j).levels.delete;
579           p_data_source.dim(j).levels(p_data_source.dim(j).levels.count+1):=l_level;
580           exit;
581         end if;
582       end loop;
583     end if;
584   end loop;
585   --set lower and correct keys
589       p_data_source.dim(i).levels.delete;
586   for i in 1..p_data_source.dim.count loop
587     if bsc_aw_utility.in_array(l_ds_dim_set,p_data_source.dim(i).dim_name)=false then
588       l_level:=p_data_source.dim(i).levels(1);
590       p_data_source.dim(i).levels(p_data_source.dim(i).levels.count+1):=l_level;
591     end if;
592   end loop;
593 Exception when others then
594   log_n('Exception in set_DS_dim_levels '||sqlerrm);
595   raise;
596 End;
597 
598 /*status:correct,lower,higher,extra,skip keys
599 we need from MO api as to what level B table feeds
600 */
601 procedure set_DS_dim_levels(p_kpi varchar2,p_dim_set dim_set_r,p_data_source data_source_r,p_base_table in out nocopy base_table_r) is
602 l_dim dim_r;
603 l_oo_dim varchar2(100);
604 l_ds_dim_set dbms_sql.varchar2_table;
605 Begin
606   for i in 1..p_base_table.levels.count loop
607     p_base_table.level_status(i):=null;
608   end loop;
609   --mark correct keys
610   for i in 1..p_base_table.levels.count loop
611     if p_base_table.feed_levels(i)='Y' then
612       l_dim:=get_kpi_level_dim_r(p_dim_set,p_base_table.levels(i).level_name);
613       if l_dim.dim_name is null then --lower or higher
614         bsc_aw_md_api.get_dim_for_level(p_base_table.levels(i).level_name,l_oo_dim);
615         if g_debug then
616           log('Level '||p_base_table.levels(i).level_name||' has no dim in this dimset '||p_dim_set.dim_set||', found dim '||
617           l_oo_dim||' from oo metadata');
618         end if;
619         l_dim:=get_dim_given_dim_name(l_oo_dim,p_dim_set);
620       end if;
621       l_ds_dim_set(l_ds_dim_set.count+1):=l_dim.dim_name;
622       if p_base_table.levels(i).level_name=l_dim.levels(1).level_name then
623         p_base_table.level_status(i):='correct';
624       else --higher or lower
625         p_base_table.level_status(i):='lower';
626         for j in 1..l_dim.levels.count loop
627           if p_base_table.levels(i).level_name=l_dim.levels(j).level_name then --higher
628             p_base_table.level_status(i):='higher';
629             exit;
630           end if;
631         end loop;
632       end if;
633     end if;
634   end loop;
635   --now mark the extra keys as extra or skip
636   for i in 1..p_base_table.levels.count loop
637     if p_base_table.feed_levels(i)='N' then
638       l_dim:=get_kpi_level_dim_r(p_dim_set,p_base_table.levels(i).level_name);
639       if l_dim.dim_name is null then
640         bsc_aw_md_api.get_dim_for_level(p_base_table.levels(i).level_name,l_oo_dim);
641       else
642         l_oo_dim:=l_dim.dim_name;
643       end if;
644       if l_oo_dim is null or bsc_aw_utility.in_array(l_ds_dim_set,l_oo_dim)=false then
645         p_base_table.level_status(i):='extra';
646       else
647         p_base_table.level_status(i):='skip';
648       end if;
649     end if;
650   end loop;
651   if g_debug then
652     log('set_DS_dim_levels dimset='||p_dim_set.dim_set||', base table='||p_base_table.base_table_name);
653     for i in 1..p_base_table.levels.count loop
654       log('Level '||p_base_table.levels(i).level_name||', Status '||p_base_table.level_status(i));
655     end loop;
656   end if;
657 Exception when others then
658   log_n('Exception in set_DS_dim_levels '||sqlerrm);
659   raise;
660 End;
661 
662 /*
663 group all DS with the same dim levels and periodicity
664 note>>> we usually have 2 scenarios. B tables witl column merge or B tables with row merge. row merge is diff periodicities
665 if we have a scenario with row merge and same periodicity (i dont think this will ever happen), we can have an issue when we load
666 dimset vs we load B tables separately. dimset has union all and group by. so the data is added up.
667 this api will increase the number of p_data_source
668 */
669 procedure create_dimset_data_source_sql(
670 p_kpi varchar2,
671 p_dim_set dim_set_r,
672 p_data_source in out nocopy data_source_tb
673 ) is
674 --
675 l_distinct_levels dbms_sql.varchar2_table;
676 l_level_string dbms_sql.varchar2_table;
677 l_data_source data_source_tb;
678 l_new_data_source data_source_tb;
679 Begin
680   if p_data_source.count=0 then
681     return;
682   end if;
683   for i in 1..p_data_source.count loop
684     l_level_string(i):=null;
685     for j in 1..p_data_source(i).dim.count loop
686       l_level_string(i):=l_level_string(i)||p_data_source(i).dim(j).levels(1).level_name||'.';
687     end loop;
688     for j in 1..p_data_source(i).std_dim.count loop
689       l_level_string(i):=l_level_string(i)||p_data_source(i).std_dim(j).levels(1).level_name||'.';
690     end loop;
691     l_level_string(i):=l_level_string(i)||p_data_source(i).calendar.periodicity(1).periodicity;
692     --
693     bsc_aw_utility.merge_value(l_distinct_levels,l_level_string(i));
694   end loop;
695   if g_debug then
696     log('create_dimset_data_source_sql: Distinct level combinations');
697     for i in 1..l_distinct_levels.count loop
698       log(l_distinct_levels(i));
699     end loop;
700   end if;
701   for i in 1..l_distinct_levels.count loop
702     l_data_source.delete;
703     for j in 1..l_level_string.count loop
704       if l_level_string(j)=l_distinct_levels(i) then
705         l_data_source(l_data_source.count+1):=p_data_source(j);
706       end if;
707     end loop;
708     --l_data_source has the same dim levels and periodicity
709     --if we have 1 data source, we do not need to merge data source sql for performance
710     if l_data_source.count>1 then
711       l_new_data_source(l_new_data_source.count+1).ds_type:=l_data_source(1).ds_type||',dimset'; --initial dimset or inc dimset
712       create_dimset_data_source_sql(p_kpi,p_dim_set,l_data_source,l_new_data_source(l_new_data_source.count));
713     end if;
714   end loop;
715   --
716   for i in 1..l_new_data_source.count loop
720   log_n('Exception in create_dimset_data_source_sql '||sqlerrm);
717     p_data_source(p_data_source.count+1):=l_new_data_source(i);
718   end loop;
719 Exception when others then
721   raise;
722 End;
723 
724 /*
725 this generates sql for pulling into dimset
726 each DS is a unit of data. filter is inside DS. this is fine. tested perf with prototype.
727 */
728 procedure create_dimset_data_source_sql(
729 p_kpi varchar2,
730 p_dim_set dim_set_r,
731 p_data_source data_source_tb,
732 p_new_data_source in out nocopy data_source_r
733 ) is
734 --
735 j integer;
736 l_measure_index bsc_aw_utility.number_table;
737 l_balance_loaded_column dbms_sql.varchar2_table;
738 Begin
739   p_new_data_source.dim:=p_data_source(1).dim;
740   p_new_data_source.std_dim:=p_data_source(1).std_dim;
741   p_new_data_source.calendar:=p_data_source(1).calendar;
742   p_new_data_source.data_source_PT:=p_data_source(1).data_source_PT;
743   /*here we make a copy of data_source_PT from the first DS of the dimset. to make a new DS with many DS in it, all the DS must share the
744   same PT characteristics */
745   --get the B tables
746   bsc_aw_utility.init_is_new_value(1);
747   for i in 1..p_data_source.count loop
748     for j in 1..p_data_source(i).base_tables.count loop
749       if bsc_aw_utility.is_new_value(p_data_source(i).base_tables(j).base_table_name,1) then
750         p_new_data_source.base_tables(p_new_data_source.base_tables.count+1):=p_data_source(i).base_tables(j);
751       end if;
752     end loop;
753   end loop;
754   --get the measures in all the datasource
755   bsc_aw_utility.init_is_new_value(1);
756   for i in 1..p_data_source.count loop
757     for j in 1..p_data_source(i).measure.count loop
758       if bsc_aw_utility.is_new_value(p_data_source(i).measure(j).measure,1) then
759         p_new_data_source.measure(p_new_data_source.measure.count+1):=
760         p_data_source(i).measure(j);
761       end if;
762     end loop;
763   end loop;
764   /*merge all the properties like dimension filter or balance last value */
765   for i in 1..p_data_source.count loop
766     for j in 1..p_data_source(i).property.count loop
767       bsc_aw_utility.merge_property(p_new_data_source.property,p_data_source(i).property(j).property_name,p_data_source(i).property(j).property_type,
768       p_data_source(i).property(j).property_value);
769     end loop;
770   end loop;
771   if g_debug then
772     log('New datasource dmp');
773     dmp_data_source(p_new_data_source);
774   end if;
775   p_new_data_source.data_source_stmt.delete;
776   p_new_data_source.data_source_stmt_type.delete;
777   --
778   p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):='sql declare c1 cursor for select';
779   p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='sql select';
780   for i in 1..p_new_data_source.dim.count loop
781     p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):=p_new_data_source.dim(i).levels(1).fk||',';
782     p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='dimension='||p_new_data_source.dim(i).dim_name;
783   end loop;
784   for i in 1..p_dim_set.std_dim.count loop
785     p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):=p_dim_set.std_dim(i).levels(1).fk||',';
786     p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='dimension='||p_dim_set.std_dim(i).dim_name;
787   end loop;
788   --time
789   p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):='period,';
790   p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='dimension=time';
791   if bsc_aw_utility.get_property(p_new_data_source.property,g_balance_last_value_prop).property_value='Y' then
792     /*period.temp and year.temp */
793     p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):=g_period_temp||',';
794     p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='temp time='||g_period_temp;
795     p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):=g_year_temp||',';
796     p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='temp time='||g_year_temp;
797   end if;
798   --
799   if p_dim_set.number_partitions>0 then
800     p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):=p_new_data_source.data_source_PT.partition_template.template_dim||',';
801     p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='partition dim';
802   end if;
803   --measures
804   for i in 1..p_new_data_source.measure.count loop
805     --we need here the agg fn from the formula for the measure. its not the formula or the agg formula!
806     p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):=
807     substr(p_new_data_source.measure(i).formula,1,instr(p_new_data_source.measure(i).formula,'(')-1)||'('||p_new_data_source.measure(i).measure||') '||
808     p_new_data_source.measure(i).measure||',';
809     p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='measure='||upper(p_new_data_source.measure(i).measure);
810   end loop;
811   /*balance loaded column */
812   for i in 1..p_new_data_source.measure.count loop
813     l_balance_loaded_column(i):=null;
814     if p_new_data_source.measure(i).measure_type=g_balance_last_value_prop then
815       l_balance_loaded_column(i):=bsc_aw_utility.get_property(p_new_data_source.measure(i).property,g_balance_loaded_column_prop).property_value;
816       if l_balance_loaded_column(i) is not null then /*balance loaded column is always summed up */
817         p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):='SUM('||l_balance_loaded_column(i)||') '||
818         l_balance_loaded_column(i)||',';
819         p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='temp balance loaded column='||
823   end loop;
820         p_new_data_source.measure(i).measure;
821       end if;
822     end if;
824   --the markers for the fk
825   for i in 1..p_new_data_source.dim.count loop
826     p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):='1,';
827     p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='limit cube='||p_new_data_source.dim(i).dim_name;
828   end loop;
829   --markers for std dim
830   for i in 1..p_dim_set.std_dim.count loop
831     p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):='1,';
832     p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='limit cube='||p_dim_set.std_dim(i).dim_name;
833   end loop;
834   --marker for time
835   p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):='1';
836   p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='limit cube=time';
837   p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):='from (';
838   p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='sql from';
839   --
840   --
841   --now we have the sql from the data sources
842   /*
843   each data source has its measues. we need to place null for the other measures. each data source must only contain its measures
844   and also, the DS stmt have the filter in them
845   */
846   for i in 1..p_data_source.count loop
847     if i<>1 then
848       p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):='union all';
849       p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='sql union all';
850     end if;
851     j:=1;
852     loop
853       if substr(p_data_source(i).data_source_stmt_type(j),1,8)='measure=' then
854         --first insert nulls
855         for k in 1..p_new_data_source.measure.count loop
856           p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):=
857           'null '||p_new_data_source.measure(k).measure||',';
858           p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):=
859           'measure='||upper(p_new_data_source.measure(k).measure);
860           l_measure_index(upper(p_new_data_source.measure(k).measure)):=p_new_data_source.data_source_stmt.count;
861         end loop;
862         loop
863           p_new_data_source.data_source_stmt(l_measure_index(substr(p_data_source(i).data_source_stmt_type(j),9))):=
864           p_data_source(i).data_source_stmt(j);
865           j:=j+1;
866           if substr(p_data_source(i).data_source_stmt_type(j),1,8)<>'measure=' then
867             exit;
868           end if;
869         end loop;
870         l_measure_index.delete;
871         /*balance loaded column temp balance loaded column=*/
872         if bsc_aw_utility.get_property(p_new_data_source.property,g_balance_last_value_prop).property_value='Y' then
873           for k in 1..p_new_data_source.measure.count loop
874             if p_new_data_source.measure(k).measure_type=g_balance_last_value_prop and l_balance_loaded_column(k) is not null then
875               p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):=
876               '0 '||l_balance_loaded_column(k)||',';
877               p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='temp balance loaded column='||
878               p_new_data_source.measure(k).measure;
879               l_measure_index(p_new_data_source.measure(k).measure):=p_new_data_source.data_source_stmt.count;
880             end if;
881           end loop;
882           loop
883             if substr(p_data_source(i).data_source_stmt_type(j),1,27)<>'temp balance loaded column=' then
884               exit;
885             end if;
886             p_new_data_source.data_source_stmt(l_measure_index(substr(p_data_source(i).data_source_stmt_type(j),28))):=
887             p_data_source(i).data_source_stmt(j);
888             j:=j+1;
889           end loop;
890         end if;
891       end if;
892       --
893       if p_data_source(i).data_source_stmt_type(j)='sql select' and p_data_source(i).data_source_stmt(j)='sql declare c1 cursor for select' then
894         p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):='select';
895         p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):=p_data_source(i).data_source_stmt_type(j);
896       elsif substr(p_data_source(i).data_source_stmt_type(j),1,11)='limit cube=' then
897         null; --do not add this
898       else
899         if p_data_source(i).data_source_stmt_type(j)='sql from' and p_data_source(i).data_source_stmt_type(j-1)<>'sql from' then
900           --if the last stmt has a trailing , remove it . this must happen only for the first <sql from>
901           if substr(p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count),
902           length(p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count)))=',' then
903             p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count):=substr(
904             p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count),1,
905             length(p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count))-1);
906           end if;
907         end if;
908         p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):=p_data_source(i).data_source_stmt(j);
909         p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):=p_data_source(i).data_source_stmt_type(j);
910         /*if the new data source has balance last value and the individual data source does not, we have to force adding period temp and year temp
911         p_data_source(i) will not have period_temp and year_temp*/
912         if p_data_source(i).data_source_stmt_type(j)='dimension=time' then
913           if bsc_aw_utility.get_property(p_new_data_source.property,g_balance_last_value_prop).property_value='Y'
917               p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='temp time='||g_period_temp;
914           and bsc_aw_utility.get_property(p_data_source(i).property,g_balance_last_value_prop).property_value is null then
915             if p_data_source(i).data_source_stmt_type(j+1)<>'temp time='||g_period_temp then
916               p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):='period '||g_period_temp||',';
918               p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):='year '||g_year_temp||',';
919               p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='temp time='||g_year_temp;
920             end if;
921           end if;
922         end if;
923       end if;
924       j:=j+1;
925       if j>p_data_source(i).data_source_stmt.count then
926         exit;
927       end if;
928     end loop;
929   end loop;
930   p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):=') BSC_B';
931   p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='sql from';
932   p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):='group by';
933   p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='sql group by';
934   for i in reverse 1..p_dim_set.std_dim.count loop
935     p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):=p_dim_set.std_dim(i).levels(1).fk||',';
936     p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='sql group by stmt';
937   end loop;
938   for i in reverse 1..p_new_data_source.dim.count loop
939     p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):=p_new_data_source.dim(i).levels(1).fk||',';
940     p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='sql group by stmt';
941   end loop;
942   --time
943   p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):='period,';
944   p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='sql group by stmt';
945   if bsc_aw_utility.get_property(p_new_data_source.property,g_balance_last_value_prop).property_value='Y' then
946     p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):=g_period_temp||',';
947     p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='sql group by stmt';
948     p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):=g_year_temp||',';
949     p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='sql group by stmt';
950   end if;
951   --
952   if p_dim_set.number_partitions>0 then
953     p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count+1):=p_new_data_source.data_source_PT.partition_template.template_dim||',';
954     p_new_data_source.data_source_stmt_type(p_new_data_source.data_source_stmt.count):='sql group by stmt';
955   end if;
956   --remove the trailing ,
957   p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count):=
958   substr(p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count),1,
959   length(p_new_data_source.data_source_stmt(p_new_data_source.data_source_stmt.count))-1);
960 Exception when others then
961   log_n('Exception in create_dimset_data_source_sql '||sqlerrm);
962   raise;
963 End;
964 
965 /*
966 given a data source, create the sql data source stmt
967 if the level of the base table is the same as that of the lowest level of the dim set, no need to
968 join to dim tables. else, have to join
969 if the base table has the same number of keys as the dim set, no agg needed. else agg needed
970 this generates the sql for driving from B table
971 */
972 procedure create_data_source_sql(
973 p_kpi varchar2,
974 p_dim_set dim_set_r,
975 p_data_source in out nocopy data_source_r
976 ) is
977 --
978 l_balance_loaded_column varchar2(40);
979 l_DS_dim_parent_child parent_child_tb;
980 Begin
981   p_data_source.data_source_stmt.delete;
982   p_data_source.data_source_stmt_type.delete;
983   /*set the properties */
984   if is_filter_in_data_source(p_data_source)='Y' then
985     bsc_aw_utility.merge_property(p_data_source.property,'dimension filter',null,'Y');
986   end if;
987   if is_balance_last_value_in_DS(p_data_source)='Y' then
988     bsc_aw_utility.merge_property(p_data_source.property,g_balance_last_value_prop,null,'Y');
989   end if;
990   --for now, we only have 1 base table per data source. not any more...we can have the prj table as the second b table in the DS
991   for i in 1..p_data_source.base_tables.count loop
992     if i=1 then
993       p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):='sql declare c1 cursor for select';
994     else
995       p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):='select';
996     end if;
997     p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='sql select';
998     --for each base table, keys are the same
999     for j in 1..p_data_source.dim.count loop
1000       if instr(lower(p_data_source.dim(j).levels(1).data_type),'varchar')>0 then
1001         p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):='to_char('||p_data_source.dim(j).levels(1).fk||') '||
1002         p_data_source.dim(j).levels(1).fk||',';
1003       else
1004         p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):=p_data_source.dim(j).levels(1).fk||',';
1005       end if;
1006       p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='dimension='||p_data_source.dim(j).dim_name;
1007     end loop;
1008     --std dim
1009     for j in 1..p_dim_set.std_dim.count loop
1010       if instr(lower(p_dim_set.std_dim(j).levels(1).data_type),'varchar')>0 then
1011         p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):='to_char('||p_dim_set.std_dim(j).levels(1).fk||') '||
1012         p_dim_set.std_dim(j).levels(1).fk||',';
1016       p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='dimension='||p_dim_set.std_dim(j).dim_name;
1013       else
1014         p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):=p_dim_set.std_dim(j).levels(1).fk||',';
1015       end if;
1017     end loop;
1018     --time
1019     p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):='period||\''.\''||year period,';
1020     p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='dimension=time';
1021     if bsc_aw_utility.get_property(p_data_source.property,g_balance_last_value_prop).property_value='Y' then
1022       /*select period and year separately to load period.temp and year.temp. used for BALANCE LAST VALUE
1023       Q: classified as temp or measure? keep temp for now*/
1024       p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):='period '||g_period_temp||',';
1025       p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='temp time='||g_period_temp;
1026       p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):='year '||g_year_temp||',';
1027       p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='temp time='||g_year_temp;
1028     end if;
1029     /*
1030     if we have partition, we want to select the partiton key here
1031     the partition key is made of the dim keys
1032     we set the partition_dim of the data source only if there are partitions in the dimset
1033     */
1034     --
1035     if p_dim_set.number_partitions>0 then
1036       /*we need to see in the future how to support range partitions etc. for now, we only support hash partitons(list)
1037       if the B table is list partitioned, we can simply select from the B table partition
1038       all B tables in a DS have the same partition type
1039       note>>>diff DS can have diff partitions. one B table may have list, another may have no partitions at all
1040       this is not ok. if a dimset has multiple DS, we cannot be sure of the partition value in the B table. each B table may have diff
1041       keys and the order used may be diff. so a row from B1 and a corresponding row from B2 may show diff partition list values. in this case,
1042       we cannot channel them to separate PT and then calculated measures(formula) will be wrong.
1043       */
1044       if p_dim_set.partition_type='list' then
1045         p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):=
1046         p_data_source.base_tables(1).table_partition.main_partition.partition_column||' '||p_data_source.data_source_PT.partition_template.template_dim||',';
1047         p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='partition dim list';
1048       else /*hash partitions */
1049         /*now hpt_data drives what dimensions are in the hash list */
1050         /*Q:do we have master pt or cube pt? we will have master pt. cube pt holds physical info like axis name etc. the logical properties
1051         must be in master PT. for each DS, we see which dim from hpt_data match and use them. example one DS may be at week level, another at month
1052         level. hpt_data contains both week and month
1053         DS must have partition info set. DS cannot be feeding levels that have no partitions
1054         p_data_source.data_source_PT should be set if there are hash partitions. when there are multiple DS, the order of dim keys in the hash
1055         function is important*/
1056         p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):=get_DS_PT_hash_stmt(p_dim_set,p_data_source)||' '||
1057         p_data_source.data_source_PT.partition_template.template_dim||',';
1058         p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='partition dim hash';
1059       end if;
1060     end if;
1061     --measures...measures are dependent on the data source
1062     --a data source always feeds the same measures, even if there are multiple base tables
1063     for j in 1..p_data_source.measure.count loop
1064       --please note that the formula is already resolved in create_base_table_sql and aliased to p_data_source.measure(j).measure
1065       p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):=p_data_source.measure(j).measure||',';
1066       p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='measure='||upper(p_data_source.measure(j).measure);
1067     end loop;
1068     /*balance loaded column */
1069     for j in 1..p_data_source.measure.count loop
1070       if p_data_source.measure(j).measure_type=g_balance_last_value_prop then
1071         l_balance_loaded_column:=bsc_aw_utility.get_property(p_data_source.measure(j).property,g_balance_loaded_column_prop).property_value;
1072         if l_balance_loaded_column is not null then
1073           p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):=l_balance_loaded_column||',';
1074           p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='temp balance loaded column='||p_data_source.measure(j).measure;
1075         end if;
1076       end if;
1077     end loop;
1078     --the markers for the fk
1079     for j in 1..p_data_source.dim.count loop
1080       p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):='1,';
1081       p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='limit cube='||p_data_source.dim(j).dim_name;
1082     end loop;
1083     --markers for std dim
1084     for j in 1..p_dim_set.std_dim.count loop
1085       p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):='1,';
1086       p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='limit cube='||p_dim_set.std_dim(j).dim_name;
1087     end loop;
1088     --marker for time
1089     p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):='1';
1090     p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='limit cube=time';
1091     --we then create the sql for the base tables
1092     create_base_table_sql(p_dim_set,p_data_source,p_data_source.base_tables(i));
1093     p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):='from ';
1094     p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='sql from';
1098       p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='sql from table';
1095     --base_table_sql is o the form (select...from base where ...)
1096     for j in 1..p_data_source.base_tables(i).base_table_sql.count loop
1097       p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):=p_data_source.base_tables(i).base_table_sql(j);
1099     end loop;
1100     /*if we have partition dim levels at higher level than the floor level of the DS, we need to join to levels or calendar to get
1101     the higher keys */
1102     for j in 1..p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions.count loop
1103       l_DS_dim_parent_child.delete;
1104       l_DS_dim_parent_child:=p_data_source.data_source_PT.dim_parent_child(
1105       p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions(j).dim_name);
1106       if l_DS_dim_parent_child.count>0 then
1107         bsc_aw_utility.init_is_new_value(1);
1108         for k in 1..l_DS_dim_parent_child.count loop
1109           if bsc_aw_utility.is_new_value(l_DS_dim_parent_child(k).child_level,1) then
1110             p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):=','||l_DS_dim_parent_child(k).child_level;
1111             p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='sql from table';
1112           end if;
1113         end loop;
1114       end if;
1115     end loop;
1116     if p_data_source.data_source_PT.cal_parent_child.count>0 then
1117       p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):=',(select distinct year pt_year';
1118       bsc_aw_utility.init_is_new_value(1);
1119       for j in 1..p_data_source.data_source_PT.cal_parent_child.count loop
1120         if bsc_aw_utility.is_new_value(p_data_source.data_source_PT.cal_parent_child(j).child_dim_name,1) then /*child_dim_name is db_column_name */
1121           p_data_source.data_source_stmt(p_data_source.data_source_stmt.count):=p_data_source.data_source_stmt(p_data_source.data_source_stmt.count)||','||
1122           p_data_source.data_source_PT.cal_parent_child(j).child_dim_name;
1123         end if;
1124         if bsc_aw_utility.is_new_value(p_data_source.data_source_PT.cal_parent_child(j).parent_dim_name,1) then /*parent_dim_name is db_column_name */
1125           p_data_source.data_source_stmt(p_data_source.data_source_stmt.count):=p_data_source.data_source_stmt(p_data_source.data_source_stmt.count)||','||
1126           p_data_source.data_source_PT.cal_parent_child(j).parent_dim_name;
1127         end if;
1128       end loop;
1129       p_data_source.data_source_stmt(p_data_source.data_source_stmt.count):=p_data_source.data_source_stmt(p_data_source.data_source_stmt.count)||
1130       ' from bsc_db_calendar) bsc_db_calendar';
1131       p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='sql from table';
1132     end if;
1133     --
1134     p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):=' where 1=1 ';
1135     p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='sql where';
1136     --add the filter
1137     --check for the filter at the lowest level
1138     --filter is (select..from bsc_sys_filters...)
1139     for j in 1..p_data_source.dim.count loop
1140       if p_data_source.dim(j).levels(1).filter.count > 0 then
1141         p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):=' and '||p_data_source.base_tables(i).base_table_name||'.'||
1142         p_data_source.dim(j).levels(1).fk||' in ';
1143         p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='sql where stmt';
1144         for k in 1..p_data_source.dim(j).levels(1).filter.count loop
1145           p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):=p_data_source.dim(j).levels(1).filter(k);
1146           p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='sql where stmt';
1147         end loop;
1148       end if;
1149     end loop;
1150     /*now add the join if there are higher level partitions */
1151     for j in 1..p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions.count loop
1152       l_DS_dim_parent_child.delete;
1153       l_DS_dim_parent_child:=p_data_source.data_source_PT.dim_parent_child(
1154       p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions(j).dim_name);
1155       if l_DS_dim_parent_child.count>0 then
1156         /*first the B table join */
1157         for k in 1..p_data_source.dim.count loop
1158           /*assumption: l_DS_dim_parent_child.count has the lowest level which the level of the DS */
1159           if p_data_source.dim(k).dim_name=p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions(j).dim_name then
1160             p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):=' and '||p_data_source.base_tables(i).base_table_name||'.'||
1161             p_data_source.dim(k).levels(1).fk||'='||l_DS_dim_parent_child(l_DS_dim_parent_child.count).child_level||'.'||
1162             l_DS_dim_parent_child(l_DS_dim_parent_child.count).parent_pk;/*assume parent_pk is same like CODE across levels */
1163             p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='sql where stmt';
1164             --
1165             exit;
1166           end if;
1167         end loop;
1168         /*now, the join between the levels */
1169         for k in 2..l_DS_dim_parent_child.count loop /*we start from 2 since we do not include the top most level for perf reasons */
1170           p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):=' and '||l_DS_dim_parent_child(k).child_level||'.'||
1171           l_DS_dim_parent_child(k).child_fk||'='||l_DS_dim_parent_child(k).parent_level||'.'||l_DS_dim_parent_child(k).parent_pk;
1172           p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='sql where stmt';
1173         end loop;
1174       end if;
1175     end loop;
1176     /*now the calendar */
1177     if p_data_source.data_source_PT.cal_parent_child.count>0 then
1178       /*first the B table join */
1179       p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):=' and '||p_data_source.base_tables(i).base_table_name||'.year='||
1183     end if;
1180       'bsc_db_calendar.pt_year and '||p_data_source.base_tables(i).base_table_name||'.period=bsc_db_calendar.'||
1181       p_data_source.data_source_PT.cal_parent_child(1).child_dim_name;/*cal_parent_child(1).child_dim_name will all be the DS periodicity */
1182       p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='sql where stmt';
1184     if p_data_source.base_tables.count>1 and i<>p_data_source.base_tables.count then
1185       p_data_source.data_source_stmt(p_data_source.data_source_stmt.count+1):=' union all ';
1186       p_data_source.data_source_stmt_type(p_data_source.data_source_stmt.count):='sql union all';
1187     end if;
1188   end loop;
1189 Exception when others then
1190   log_n('Exception in create_data_source_sql '||sqlerrm);
1191   raise;
1192 End;
1193 
1194 /*
1195 this procedure creates the base table sql. the base table can be at a lower level than the first level of the dim set.
1196 in this case, it need to rollup the data before loading the kpi dim set
1197 base table can have larger number of keys. in this case also rollup.
1198 the base table can have the same number of keys at the same level. in this case no rollup. remove the agg function from
1199 the formula
1200 agg formula is like MIN(Gr_806Sim1/DECODE(Gr_806Sim2,0,NULL,Gr_806Sim2)) change it to
1201 (Gr_806Sim1/DECODE(Gr_806Sim2,0,NULL,Gr_806Sim2))
1202 
1203 if the base table has more keys than the dim set, when we move data from the _AW table, we have to join with the base table.
1204 if the base table has more keys, then the aw table is used only as a fk table. the sql will be
1205 select
1206 base.k1,
1207 base.k2,
1208 ..
1209 formula(base.m1) m1,
1210 formula(base.m2) m1,
1211 ...
1212 from
1213 base,
1214 (select distinct k1,k2... from base_aw where bitand(...)) base_aw
1215 where base.k1=base_aw.k1 and ...
1216 
1217 if the number of keys in the base and dimset are the same, we only need the base_aw table in the inc mode
1218 */
1219 procedure create_base_table_sql(
1220 p_dim_set dim_set_r,
1221 p_data_source data_source_r,
1222 p_base_table in out nocopy base_table_r
1223 ) is
1224 --
1225 l_dim varchar2(300);
1226 l_parent_child bsc_aw_adapter_dim.dim_parent_child_tb;
1227 l_pc_subset bsc_aw_adapter_dim.dim_parent_child_tb;
1228 l_from_sql dbms_sql.varchar2_table;
1229 l_where_sql dbms_sql.varchar2_table;
1230 l_group_sql dbms_sql.varchar2_table;
1231 l_base_cal_column varchar2(100); --lower periodicity column name from bsc_db_calendar
1232 l_dimset_cal_column varchar2(100);
1233 l_remove_agg_flag boolean;
1234 l_formula varchar(4000);
1235 l_flag boolean;
1236 --l_base_aw_join_flag is used only for inc load if the number of keys in the base > that in the dim set
1237 --keeps track of what keys to join between base and base_aw
1238 l_base_aw_join_flag dbms_sql.varchar2_table;
1239 l_alias varchar2(100);
1240 l_aw_table_fk_driver_only boolean;--if true the aw table is only a fk driver table
1241 l_balance_loaded_column varchar2(40);
1242 Begin
1243   p_base_table.base_table_sql.delete;
1244   l_aw_table_fk_driver_only:=false;
1245   if p_data_source.ds_type='inc' then
1246     if bsc_aw_utility.in_array(p_base_table.level_status,'extra') then
1247       l_aw_table_fk_driver_only:=true;
1248     end if;
1249   end if;
1250   l_from_sql.delete;
1251   l_where_sql.delete;
1252   p_base_table.base_table_sql(1):='(select ';
1253   if (p_data_source.ds_type='initial') or (p_data_source.ds_type='inc' and l_aw_table_fk_driver_only) then
1254     --in this case, bsc_aw_temp_cv is in the inner sql
1255     l_from_sql(1):=' from '||p_base_table.base_table_name;
1256     l_alias:=p_base_table.base_table_name;
1257     l_where_sql(1):=' where 1=1 ';
1258   else
1259     l_from_sql(1):=' from bsc_aw_temp_cv,'||p_base_table.base_table_name;
1260     l_alias:=p_base_table.base_table_name;
1261     l_where_sql(1):=' where 1=1 ';
1262     l_where_sql(l_where_sql.count+1):=' and bsc_aw_temp_cv.change_vector_base_table=\'''||upper(p_base_table.base_table_name)||'\'' and '||
1263     l_alias||'.change_vector between bsc_aw_temp_cv.change_vector_min_value and bsc_aw_temp_cv.change_vector_max_value ';
1264   end if;
1265   l_group_sql(1):='group by ';
1266   --for all the keys that are N, we need to further process
1267   for i in 1..p_base_table.levels.count loop
1268     l_base_aw_join_flag(i):='N';
1269     if p_base_table.level_status(i)='lower' then --the level is lower than the lowest level of dim set
1270       l_parent_child.delete;
1271       l_pc_subset.delete;
1272       bsc_aw_md_api.get_dim_for_level(p_base_table.levels(i).level_name,l_dim);
1273       bsc_aw_md_api.get_dim_parent_child(l_dim,l_parent_child);
1274       l_pc_subset:=bsc_aw_adapter_dim.get_hier_subset(l_parent_child,get_dim_given_dim_name(l_dim,p_data_source.dim).levels(1).level_name,
1275       p_base_table.levels(i).level_name);
1276       if l_pc_subset.count=0 then
1277         log('Could not rollup from B table to dimset '||p_base_table.base_table_name||', at level '||p_base_table.levels(i).level_name);
1278         raise bsc_aw_utility.g_exception;
1279       end if;
1280       l_base_aw_join_flag(i):='Y';
1281       --first entry is the data source level
1282       p_base_table.base_table_sql(p_base_table.base_table_sql.count+1):=l_pc_subset(1).child_level||'.'||l_pc_subset(1).child_fk||',';
1283       l_group_sql(l_group_sql.count+1):=l_pc_subset(1).child_level||'.'||l_pc_subset(1).child_fk||',';
1284       l_where_sql(l_where_sql.count+1):=' and '||l_alias||'.'||p_base_table.levels(i).fk||'='||
1285       l_pc_subset(l_pc_subset.count).child_level||'.'||l_pc_subset(l_pc_subset.count).parent_pk;
1286       for j in 1..l_pc_subset.count loop
1287         l_from_sql(l_from_sql.count+1):=','||l_pc_subset(j).child_level;
1288         if j <> 1 then --we do not include the last level...for performance
1289           l_where_sql(l_where_sql.count+1):=' and '||l_pc_subset(j).child_level||'.'||l_pc_subset(j).child_fk||
1290           '='||l_pc_subset(j).parent_level||'.'||l_pc_subset(j).parent_pk;
1291         end if;
1292       end loop;
1296       l_group_sql(l_group_sql.count+1):=l_alias||'.'||p_base_table.levels(i).fk||',';
1293     elsif p_base_table.level_status(i)='correct' or p_base_table.level_status(i)='higher' then
1294       l_base_aw_join_flag(i):='Y';--base table key has to join with the _AW table key
1295       p_base_table.base_table_sql(p_base_table.base_table_sql.count+1):=l_alias||'.'||p_base_table.levels(i).fk||',';
1297     else --the skip key
1298       --if the lowest key and a higher key exists in the base table, we dont have to group by the lowest key since the data
1299       --is already at the lowest key granularity
1300       null;
1301     end if;
1302   end loop;
1303   --now the std dim, type and projection
1304   for i in 1..p_data_source.std_dim.count loop
1305     p_base_table.base_table_sql(p_base_table.base_table_sql.count+1):=l_alias||'.'||p_data_source.std_dim(i).levels(1).fk||',';
1306     l_group_sql(l_group_sql.count+1):=l_alias||'.'||p_data_source.std_dim(i).levels(1).fk||',';
1307   end loop;
1308   --now period and year
1309   --if the base table is at lower perioidicity than the dim set, also have to rollup on time
1310   --p_dim_set.calendar.periodicity(1) is the lowest level in time: NO this is not true. look at lowest_level flag
1311   --if p_base_table.periodicity.periodicity <> p_data_source.calendar.periodicity(1).periodicity then
1312   /*there is an interesting issue here. what if the measure is a balance measure and we have to rollup B table on time? so far this
1313   issue has not come up because balance is at day level */
1314   if p_base_table.periodicity.periodicity <> p_data_source.calendar.periodicity(1).periodicity then --then this is coming at a lower level
1315     l_base_cal_column:=bsc_aw_bsc_metadata.get_db_calendar_column(p_dim_set.calendar.calendar,p_base_table.periodicity.periodicity);
1316     --note>>>datasource has one periodicity. see get_dim_set_data_source in bsc_aw_bsc_metadata
1317     l_dimset_cal_column:=bsc_aw_bsc_metadata.get_db_calendar_column(p_dim_set.calendar.calendar,p_data_source.calendar.periodicity(1).periodicity);
1318     p_base_table.base_table_sql(p_base_table.base_table_sql.count+1):='bsc_db_calendar.'||l_dimset_cal_column||' period,'||
1319     'bsc_db_calendar.year year,';
1320     l_group_sql(l_group_sql.count+1):='bsc_db_calendar.'||l_dimset_cal_column||',bsc_db_calendar.year,';
1321     l_from_sql(l_from_sql.count+1):=',(select distinct '||l_base_cal_column||','||l_dimset_cal_column||',year from bsc_db_calendar where calendar_id='||
1322     p_data_source.calendar.calendar||') bsc_db_calendar';
1323     l_where_sql(l_where_sql.count+1):=' and bsc_db_calendar.'||l_base_cal_column||'='||l_alias||'.period and '||
1324     'bsc_db_calendar.year='||l_alias||'.year';
1325   else
1326     --base table at the same periodicity as the dim set
1327     p_base_table.base_table_sql(p_base_table.base_table_sql.count+1):=l_alias||'.period,'||l_alias||'.year,';
1328     l_group_sql(l_group_sql.count+1):=l_alias||'.period,'||l_alias||'.year,';
1329   end if;
1330   --if base keys > dim set keys and inc load
1331   --in this case the aw table is only a key drive table. data comes from base table
1332   --please note that if the extra keys are keys with l_ok(i)='S', we do not have to do this.
1333   --skip keys are simply ignored. its as if they did not exist
1334   --do p_base_table.levels.count - p_data_source.dim.count if this is > count(l_ok='S') then we have to do this
1335   if p_data_source.ds_type='inc' and l_aw_table_fk_driver_only then
1336     --make the from clause
1337     l_from_sql(l_from_sql.count+1):=',(select distinct ';
1338     for i in 1..p_base_table.levels.count loop
1339       if l_base_aw_join_flag(i)='Y' then
1340         --we have _AW appended to the fk from the _AW table (in line sql) to avoid the issue of having to correctly
1341         --specify the table name in the select and group by part.
1342         l_from_sql(l_from_sql.count+1):=p_base_table.base_table_name||'.'||p_base_table.levels(i).fk||' '||p_base_table.levels(i).fk||'_AW,';
1343       end if;
1344     end loop;
1345     --we need the std dim
1346     for i in 1..p_data_source.std_dim.count loop
1347       l_from_sql(l_from_sql.count+1):=p_base_table.base_table_name||'.'||p_data_source.std_dim(i).levels(1).fk||' '||
1348       p_data_source.std_dim(i).levels(1).fk||'_AW,';
1349     end loop;
1350     --also we need period and year
1351     /*in caes of partitions, the filter on the partition is added in  create_kpi_program_partition*/
1352     l_from_sql(l_from_sql.count+1):=p_base_table.base_table_name||'.period period_aw,'||
1353     p_base_table.base_table_name||'.year year_aw from bsc_aw_temp_cv,'||p_base_table.base_table_name;
1354     l_from_sql(l_from_sql.count+1):=' where 1=1 ';
1355     l_from_sql(l_from_sql.count+1):='and bsc_aw_temp_cv.change_vector_base_table=\'''||upper(p_base_table.base_table_name)||'\'' and '||
1356     p_base_table.base_table_name||'.change_vector between bsc_aw_temp_cv.change_vector_min_value and bsc_aw_temp_cv.change_vector_max_value) B_AW';
1357     --make the where clause
1358     for i in 1..p_base_table.levels.count loop
1359       if l_base_aw_join_flag(i)='Y' then
1360         --we have _AW appended to the fk from the _AW table (in line sql) to avoid the issue of having to correctly
1361         --specify the table name in the select and group by part.
1362         l_where_sql(l_where_sql.count+1):=' and '||l_alias||'.'||p_base_table.levels(i).fk||'='||
1363         'B_AW.'||p_base_table.levels(i).fk||'_AW';
1364       end if;
1365     end loop;
1366     --std dim
1367     for i in 1..p_data_source.std_dim.count loop
1368       l_where_sql(l_where_sql.count+1):=' and '||l_alias||'.'||p_data_source.std_dim(i).levels(1).fk||'='||
1369       'B_AW.'||p_data_source.std_dim(i).levels(1).fk||'_AW';
1370     end loop;
1371     --join period and year
1372     l_where_sql(l_where_sql.count+1):=' and '||l_alias||'.period=B_AW.period_AW';
1373     l_where_sql(l_where_sql.count+1):=' and '||l_alias||'.year=B_AW.year_AW';
1374   end if;
1375   --if we have list partitions, include the list partition column also
1376   /*we can select partition col only if dimset is partitioned. otherwise, group by batch from B table will make data loaded into dimset incorrect
1377   there is no group by at data source level
1381     if p_base_table.table_partition.main_partition.partition_type='LIST' then
1378   if dimset partition type is list, then we can be assured that B table is partitioned by list partitions, with the same number of partitions
1379   as the dimset. this is done in api load_master_PT*/
1380   if p_dim_set.number_partitions>0 and p_dim_set.partition_type='list' then
1382       p_base_table.base_table_sql(p_base_table.base_table_sql.count+1):=l_alias||'.'||p_base_table.table_partition.main_partition.partition_column||',';
1383       l_group_sql(l_group_sql.count+1):=l_alias||'.'||p_base_table.table_partition.main_partition.partition_column||',';
1384     end if;
1385   end if;
1386   --now the measures
1387   l_remove_agg_flag:=false;
1388   if bsc_aw_utility.in_array(p_base_table.level_status,'lower')=false and bsc_aw_utility.in_array(p_base_table.level_status,'extra')=false
1389   and p_base_table.periodicity.periodicity=p_data_source.calendar.periodicity(1).periodicity then
1390     --there are no keys with rollup or there are no extra keys and the periodicity of base is same as dimset
1391     --this means we can remove the agg function
1392     l_remove_agg_flag:=true;
1393     --see if count is a part of the agg function. if yes, we have to force agg, make l_remove_agg_flag:=false
1394     --we saw if we can hardcode 1 in parse_out_agg_function. but AW threw error
1395     --ORA-34738: (NOUPDATE) A severe problem has been detected. Analytic workspace operations have been disabled.
1396     --ORA-06512: at "APPS.BSC_AW_UTILITY", line 466
1397     --ORA-06512: at "APPS.BSC_AW_LOAD", line 112.  it was confusing 1 with true/false 1 so we are forced to have agg when count is involved
1398     --maybe we can use sql fetch c1 loop into...but for now, lets keep the agg when count is involved
1399     --database does not suffer too much in perf with a group by. note here that there is no joins involbed. its just group by on the
1400     --base table
1401     for i in 1..p_data_source.measure.count loop
1402       if lower(ltrim(rtrim(substr(p_data_source.measure(i).formula,1,instr(p_data_source.measure(i).formula,'(')-1))))='count' then
1403         l_remove_agg_flag:=false;
1404         exit;
1405       end if;
1406     end loop;
1407   end if;
1408   for i in 1..p_data_source.measure.count loop
1409     l_balance_loaded_column:=bsc_aw_utility.get_property(p_data_source.measure(i).property,g_balance_loaded_column_prop).property_value;
1410     if l_remove_agg_flag then
1411       --l_formula has no agg, we can have 3 types of agg in BSC
1412       --Apply aggregation method to the each element of the formula, e.g.: SUM(source_column1)/SUM(source_column2)
1413       --Apply aggregation method to the overall formula, e.g.: SUM(source_column1/source_column2)
1414       --Formulas between 2 calculated Measures e.g.: SUM(source_col1/source_col2)/AVG(source_col3+source_col4)
1415       bsc_aw_utility.parse_out_agg_function(p_data_source.measure(i).formula,l_formula);
1416       p_base_table.base_table_sql(p_base_table.base_table_sql.count+1):=l_formula||' '||p_data_source.measure(i).measure||',';
1417       if p_data_source.measure(i).measure_type=g_balance_last_value_prop and l_balance_loaded_column is not null then
1418         p_base_table.base_table_sql(p_base_table.base_table_sql.count+1):='decode('||l_balance_loaded_column||',\''Y\'',1,0) '||
1419         l_balance_loaded_column||',';
1420       end if;
1421     else
1422       p_base_table.base_table_sql(p_base_table.base_table_sql.count+1):=p_data_source.measure(i).formula||' '||
1423       p_data_source.measure(i).measure||',';
1424       if p_data_source.measure(i).measure_type=g_balance_last_value_prop and l_balance_loaded_column is not null then
1425         p_base_table.base_table_sql(p_base_table.base_table_sql.count+1):='SUM(decode('||l_balance_loaded_column||',\''Y\'',1,0)) '||
1426         l_balance_loaded_column||',';
1427       end if;
1428     end if;
1429   end loop;
1430   p_base_table.base_table_sql(p_base_table.base_table_sql.count):=substr(p_base_table.base_table_sql(p_base_table.base_table_sql.count),
1431   1,length(p_base_table.base_table_sql(p_base_table.base_table_sql.count))-1);
1432   for i in 1..l_from_sql.count loop
1433     p_base_table.base_table_sql(p_base_table.base_table_sql.count+1):=l_from_sql(i);
1434   end loop;
1435   for i in 1..l_where_sql.count loop
1436     p_base_table.base_table_sql(p_base_table.base_table_sql.count+1):=l_where_sql(i);
1437   end loop;
1438   --if l_remove_agg_flag=false, this means that there is either a rollup or an extra key
1439   if l_remove_agg_flag=false then
1440     --remove the trailing "," from groupby
1441     l_group_sql(l_group_sql.count):=substr(l_group_sql(l_group_sql.count),1,length(l_group_sql(l_group_sql.count))-1);
1442     for i in 1..l_group_sql.count loop
1443       p_base_table.base_table_sql(p_base_table.base_table_sql.count+1):=l_group_sql(i);
1444     end loop;
1445   end if;
1446   p_base_table.base_table_sql(p_base_table.base_table_sql.count+1):=') '||p_base_table.base_table_name;
1447 Exception when others then
1448   log_n('Exception in create_base_table_sql '||sqlerrm);
1449   raise;
1450 End;
1451 
1452 /*
1453 given a dim record, loop through the levels in it to see if the given level is a part of the dim or not
1454 used by trim_parent_child, which in turn is used by create_base_table_sql
1455 */
1456 function is_level_in_dim(p_dim dim_r,p_level varchar2) return boolean is
1457 Begin
1458   for i in 1..p_dim.levels.count loop
1459     if p_dim.levels(i).level_name=p_level then
1460       return true;
1461     end if;
1462   end loop;
1463   return false;
1464 Exception when others then
1465   log_n('Exception in is_level_in_dim '||sqlerrm);
1466   raise;
1467 End;
1468 
1469 /*
1470 given a CC dim name, get the dim_r object
1471 */
1472 function get_dim_given_dim_name(p_dim varchar2,p_dim_set dim_set_r) return dim_r is
1473 Begin
1474   return get_dim_given_dim_name(p_dim,p_dim_set.dim);
1475 Exception when others then
1476   log_n('Exception in get_dim_given_dim_name '||sqlerrm);
1477   raise;
1478 End;
1479 
1480 function get_dim_given_dim_name(p_dim varchar2,p_dim_t dim_tb) return dim_r is
1484       return p_dim_t(i);
1481 Begin
1482   for i in 1..p_dim_t.count loop
1483     if p_dim_t(i).dim_name=p_dim then
1485     end if;
1486   end loop;
1487   return null;
1488 Exception when others then
1489   log_n('Exception in get_dim_given_dim_name '||sqlerrm);
1490   raise;
1491 End;
1492 
1493 function is_dim_in_dimset(p_dim_set dim_set_r,p_dim varchar2) return boolean is
1494 Begin
1495   for i in 1..p_dim_set.dim.count loop
1496     if p_dim_set.dim(i).dim_name=p_dim then
1497       return true;
1498     end if;
1499   end loop;
1500   return false;
1501 Exception when others then
1502   log_n('Exception in is_dim_in_dimset '||sqlerrm);
1503   raise;
1504 End;
1505 
1506 procedure drop_kpi_objects(p_kpi varchar2) is
1507 Begin
1508   if g_debug then
1509     log_n('Drop KPI '||p_kpi);
1510   end if;
1511   drop_kpi_objects_aw(p_kpi);
1512   drop_kpi_objects_relational(p_kpi);
1513   --drop kpi metadata
1514   bsc_aw_md_api.drop_kpi(p_kpi);
1515 Exception when others then
1516   log_n('Exception in drop_kpi_objects '||sqlerrm);
1517   raise;
1518 End;
1519 
1520 procedure drop_kpi_objects_aw(p_kpi varchar2) is
1521 --
1522 l_objects bsc_aw_utility.object_tb; --object_t is object_name and object_type
1523 l_flag dbms_sql.varchar2_table;
1524 Begin
1525   bsc_aw_md_api.get_kpi_olap_objects(p_kpi,l_objects,'all');
1526   for i in 1..l_objects.count loop
1527     l_flag(i):='N';
1528   end loop;
1529   --get_kpi_olap_objects will only populate l_objects when olap object type is not null
1530   for i in 1..l_objects.count loop
1531     if l_flag(i)='N' and l_objects(i).object_type <> 'partition template' and
1532     l_objects(i).object_type <> 'dimension' and l_objects(i).object_type <> 'composite' then
1533       bsc_aw_utility.delete_aw_object(l_objects(i).object_name);
1534       l_flag(i):='Y';
1535     end if;
1536   end loop;
1537   --partition template
1538   for i in 1..l_objects.count loop
1539     if l_flag(i)='N' and l_objects(i).object_type = 'partition template' then
1540       bsc_aw_utility.delete_aw_object(l_objects(i).object_name);
1541       l_flag(i):='Y';
1542     end if;
1543   end loop;
1544   --composite
1545   for i in 1..l_objects.count loop
1546     if l_flag(i)='N' and l_objects(i).object_type = 'composite' then
1547       bsc_aw_utility.delete_aw_object(l_objects(i).object_name);
1548       l_flag(i):='Y';
1549     end if;
1550   end loop;
1551   --dimensions
1552   for i in 1..l_objects.count loop
1553     if l_flag(i)='N' and l_objects(i).object_type = 'dimension' then
1554       bsc_aw_utility.delete_aw_object(l_objects(i).object_name);
1555       l_flag(i):='Y';
1556     end if;
1557   end loop;
1558   --all the other objects
1559   for i in 1..l_objects.count loop
1560     if l_flag(i)='N' then
1561       bsc_aw_utility.delete_aw_object(l_objects(i).object_name);
1562       l_flag(i):='Y';
1563     end if;
1564   end loop;
1565   /*
1566   we do not want to drop olap table function types and views since the drop is permanent, if there is failure
1567   we cannot rollback
1568   This is no more true. we drop these objects. (In drop_kpi_objects_relational). we drop them because we have
1569   to clean up old objects. if midway the drop fails, the system is in unusuable state anyway
1570   */
1571   ---
1572 Exception when others then
1573   log_n('Exception in drop_kpi_objects_aw '||sqlerrm);
1574   raise;
1575 End;
1576 
1577 /*
1578 we will hold the type and view name in bsc olap objects. olap_object column will be null. so
1579 drop_kpi_objects_relational action is final. due to database commit, if there is a failure in between, we cannot guarantee
1580 the system. drop has to be rerun till successful
1581 */
1582 procedure drop_kpi_objects_relational(p_kpi varchar2) is
1583 l_flag dbms_sql.varchar2_table;
1584 l_olap_object bsc_aw_md_wrapper.bsc_olap_object_tb;
1585 Begin
1586   bsc_aw_md_api.get_bsc_olap_object(null,null,p_kpi,'kpi',l_olap_object);
1587   for i in 1..l_olap_object.count loop
1588     l_flag(i):='N';
1589   end loop;
1590   --
1591   for i in 1..l_olap_object.count loop
1592     if l_flag(i)='N' and l_olap_object(i).object_type='relational view' then
1593       bsc_aw_utility.execute_stmt_ne('drop view '||l_olap_object(i).object);
1594       l_flag(i):='Y';
1595     end if;
1596   end loop;
1597   --
1598   for i in 1..l_olap_object.count loop
1599     if l_flag(i)='N' and l_olap_object(i).object_type='relational type' then
1600       bsc_aw_utility.execute_stmt_ne('drop type '||l_olap_object(i).object||'_tab'); --assume naming convention
1601       bsc_aw_utility.execute_stmt_ne('drop type '||l_olap_object(i).object);
1602       l_flag(i):='Y';
1603     end if;
1604   end loop;
1605   --
1606 Exception when others then
1607   log_n('Exception in drop_kpi_objects_relational '||sqlerrm);
1608   raise;
1609 End;
1610 
1611 /*
1612 set the partition info.
1613 note>>> we need to set this before the call to set_dim_set_data_source
1614 by default, there are no partitions.
1615 --
1616 if there are non std agg, we have difficulty with hahs partitions. consider the case where we have bugnew=bugopen/bugclosed
1617 here, the data looked as
1618                ------------------------------------DATACUBE.1.4014------------------------------------
1619                ----------------------------------HASH_PARTITION_DIM-----------------------------------
1620 MEASURENAME.1.
1621 4014               0          1          2          3          4          5          6          7
1622 -------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
1623 BUGOPEN            200.00      20.00         NA         NA         NA         NA         NA         NA
1624 BUGCLOSED          100.00      10.00         NA         NA         NA         NA         NA         NA
1628 the soln is not to materialize the formulas. we can define a formula as bugnew=total(bugopen)/total(bugclosed) and this formula is in the
1625 BUGNEW               2.00       2.00         NA         NA         NA         NA         NA         NA
1626 the formula was correctly calculated for each partition. however, when we sum the measure, we get a value 4. this is incorrect
1627 since the real value is 220/110 = 2 and not 4.
1629 view.also note the impact for avg measure. for now, we will disable partitions when we have non std agg
1630 if 10.1.04 and greater and we have 2 times the cpu count as partitions reqd, try partition out.
1631 */
1632 procedure set_dimset_partition_info(p_kpi varchar2,p_actual_dim_set in out nocopy dim_set_r,p_target_dim_set in out nocopy dim_set_r) is
1633 Begin
1634   if g_debug then
1635     log('set_dimset_partition_info dimset='||p_actual_dim_set.dim_set_name||', with target='||p_target_dim_set.dim_set_name);
1636   end if;
1637   p_actual_dim_set.number_partitions:=0;
1638   p_target_dim_set.number_partitions:=0;
1639   load_master_PT(p_actual_dim_set,p_target_dim_set);
1640 Exception when others then
1641   log_n('Exception in set_dimset_partition_info '||sqlerrm);
1642   raise;
1643 End;
1644 
1645 /*
1646 create_aw_object_names gives names to cubes, programs etc
1647 */
1648 procedure create_aw_object_names(p_kpi in out nocopy kpi_r) is
1649 --
1650 l_dim_index bsc_aw_utility.number_table;--used to populate limit cubes into data source.dim
1651 l_measure_index bsc_aw_utility.number_table;--used to populate cubes into data source.measure
1652 Begin
1653   for i in 1..p_kpi.dim_set.count loop
1654     --
1655     p_kpi.dim_set(i).aggmap_operator.measure_dim:='measuredim.'||p_kpi.dim_set(i).dim_set||'.'||p_kpi.kpi;
1656     p_kpi.dim_set(i).aggmap_operator.opvar:='opvar.'||p_kpi.dim_set(i).dim_set||'.'||p_kpi.kpi;
1657     p_kpi.dim_set(i).aggmap_operator.argvar:='argvar.'||p_kpi.dim_set(i).dim_set||'.'||p_kpi.kpi;
1658     --
1659     p_kpi.dim_set(i).agg_map.agg_map:='aggmap.'||p_kpi.dim_set(i).dim_set||'.'||p_kpi.kpi;
1660     p_kpi.dim_set(i).agg_map.aggmap_operator:=p_kpi.dim_set(i).aggmap_operator;
1661     --
1662     p_kpi.dim_set(i).agg_map_notime.agg_map:='aggmap.'||p_kpi.dim_set(i).dim_set||'.'||p_kpi.kpi||'.notime';
1663     p_kpi.dim_set(i).agg_map_notime.aggmap_operator:=p_kpi.dim_set(i).aggmap_operator;
1664     --
1665     p_kpi.dim_set(i).initial_load_program.program_name:='load.'||p_kpi.dim_set(i).dim_set||'.'||p_kpi.kpi||'.initial';
1666     p_kpi.dim_set(i).inc_load_program.program_name:='load.'||p_kpi.dim_set(i).dim_set||'.'||p_kpi.kpi||'.inc';
1667     --
1668     p_kpi.dim_set(i).initial_load_program_parallel.program_name:='load.'||p_kpi.dim_set(i).dim_set||'.'||p_kpi.kpi||'.initial.parallel';
1669     p_kpi.dim_set(i).inc_load_program_parallel.program_name:='load.'||p_kpi.dim_set(i).dim_set||'.'||p_kpi.kpi||'.inc.parallel';
1670     --
1671     p_kpi.dim_set(i).aggregate_marker_program:='aggmark.'||p_kpi.dim_set(i).dim_set||'.'||p_kpi.kpi||'.program';
1672     --for 10g, targets will need a separate program so it can run in parallel
1673     for j in 1..p_kpi.dim_set(i).dim.count loop
1674       l_dim_index(p_kpi.dim_set(i).dim(j).dim_name):=j;
1675       p_kpi.dim_set(i).dim(j).limit_cube:='kpi.'||p_kpi.kpi||'.'||p_kpi.dim_set(i).dim_set||'.'||p_kpi.dim_set(i).dim(j).dim_name||'.LB';
1676       p_kpi.dim_set(i).dim(j).reset_cube:='kpi.'||p_kpi.kpi||'.'||p_kpi.dim_set(i).dim_set||'.'||p_kpi.dim_set(i).dim(j).dim_name||'.RB';
1677       if nvl(bsc_aw_utility.get_parameter_value('NO LIMIT CUBE COMPOSITE'),'N')='N' then
1678         p_kpi.dim_set(i).dim(j).limit_cube_composite:='c.'||p_kpi.dim_set(i).dim(j).limit_cube;
1679       end if;
1680       p_kpi.dim_set(i).dim(j).aggregate_marker:='aggmark.'||p_kpi.kpi||'.'||p_kpi.dim_set(i).dim_set||'.'||p_kpi.dim_set(i).dim(j).dim_name;
1681       p_kpi.dim_set(i).dim(j).agg_map.agg_map:='aggmap.'||p_kpi.dim_set(i).dim(j).dim_name||'.'||p_kpi.dim_set(i).dim_set||'.'||p_kpi.kpi;
1682       p_kpi.dim_set(i).dim(j).agg_map.aggmap_operator:=p_kpi.dim_set(i).aggmap_operator;
1683     end loop;
1684     --std dim
1685     for j in 1..p_kpi.dim_set(i).std_dim.count loop
1686       l_dim_index(p_kpi.dim_set(i).std_dim(j).dim_name):=j;
1687       p_kpi.dim_set(i).std_dim(j).limit_cube:='kpi.'||p_kpi.kpi||'.'||p_kpi.dim_set(i).dim_set||'.'||p_kpi.dim_set(i).std_dim(j).dim_name||'.LB';
1688       if nvl(bsc_aw_utility.get_parameter_value('NO LIMIT CUBE COMPOSITE'),'N')='N' then
1689         p_kpi.dim_set(i).std_dim(j).limit_cube_composite:='c.'||p_kpi.dim_set(i).std_dim(j).limit_cube;
1690       end if;
1691     end loop;
1692     --time limit cube
1693     p_kpi.dim_set(i).calendar.limit_cube:='kpi.'||p_kpi.kpi||'.'||p_kpi.dim_set(i).dim_set||'.'||p_kpi.dim_set(i).calendar.aw_dim||'.LB';
1694     if nvl(bsc_aw_utility.get_parameter_value('NO LIMIT CUBE COMPOSITE'),'N')='N' then
1695       p_kpi.dim_set(i).calendar.limit_cube_composite:='c.'||p_kpi.dim_set(i).calendar.limit_cube;
1696     end if;
1697     p_kpi.dim_set(i).calendar.aggregate_marker:='aggmark.'||p_kpi.kpi||'.'||p_kpi.dim_set(i).dim_set||'.'||p_kpi.dim_set(i).calendar.aw_dim;
1698     /*also add aggmap for calendar. used to aggregate non bal measures uptime if bal measure also present in dimset */
1699     p_kpi.dim_set(i).calendar.agg_map.agg_map:='aggmap.'||p_kpi.dim_set(i).calendar.aw_dim||'.'||p_kpi.dim_set(i).dim_set||'.'||p_kpi.kpi;
1700     p_kpi.dim_set(i).calendar.agg_map.aggmap_operator:=p_kpi.dim_set(i).aggmap_operator;
1701     --measures
1702     --first, load the partition, composite and cube info
1703     --names partitions, composites, cubes and measure cubes
1704     create_PT_comp_names(p_kpi.kpi,p_kpi.dim_set(i));
1705     --
1706     for j in 1..p_kpi.dim_set(i).measure.count loop
1707       l_measure_index(p_kpi.dim_set(i).measure(j).measure):=j;
1708     end loop;
1709     --give cube names to data source measures
1710     for j in 1..p_kpi.dim_set(i).data_source.count loop
1711       for k in 1..p_kpi.dim_set(i).data_source(j).measure.count loop
1712         p_kpi.dim_set(i).data_source(j).measure(k).cube:=p_kpi.dim_set(i).measure(l_measure_index(p_kpi.dim_set(i).data_source(j).measure(k).measure)).cube;
1713         p_kpi.dim_set(i).data_source(j).measure(k).property:=
1717       for k in 1..p_kpi.dim_set(i).data_source(j).dim.count loop
1714         p_kpi.dim_set(i).measure(l_measure_index(p_kpi.dim_set(i).data_source(j).measure(k).measure)).property;
1715       end loop;
1716       --set the dim limit cubes
1718         p_kpi.dim_set(i).data_source(j).dim(k).limit_cube:=
1719         p_kpi.dim_set(i).dim(l_dim_index(p_kpi.dim_set(i).data_source(j).dim(k).dim_name)).limit_cube;
1720       end loop;
1721       for k in 1..p_kpi.dim_set(i).data_source(j).std_dim.count loop
1722         p_kpi.dim_set(i).data_source(j).std_dim(k).limit_cube:=
1723         p_kpi.dim_set(i).std_dim(l_dim_index(p_kpi.dim_set(i).data_source(j).std_dim(k).dim_name)).limit_cube;
1724       end loop;
1725       p_kpi.dim_set(i).data_source(j).calendar.limit_cube:=p_kpi.dim_set(i).calendar.limit_cube;
1726     end loop;
1727     for j in 1..p_kpi.dim_set(i).inc_data_source.count loop
1728       for k in 1..p_kpi.dim_set(i).inc_data_source(j).measure.count loop
1729         p_kpi.dim_set(i).inc_data_source(j).measure(k).cube:=p_kpi.dim_set(i).measure(
1730         l_measure_index(p_kpi.dim_set(i).inc_data_source(j).measure(k).measure)).cube;
1731         p_kpi.dim_set(i).inc_data_source(j).measure(k).property:=p_kpi.dim_set(i).measure(
1732         l_measure_index(p_kpi.dim_set(i).inc_data_source(j).measure(k).measure)).property;
1733       end loop;
1734       for k in 1..p_kpi.dim_set(i).inc_data_source(j).dim.count loop
1735         p_kpi.dim_set(i).inc_data_source(j).dim(k).limit_cube:=
1736         p_kpi.dim_set(i).dim(l_dim_index(p_kpi.dim_set(i).inc_data_source(j).dim(k).dim_name)).limit_cube;
1737       end loop;
1738       for k in 1..p_kpi.dim_set(i).inc_data_source(j).std_dim.count loop
1739         p_kpi.dim_set(i).inc_data_source(j).std_dim(k).limit_cube:=
1740         p_kpi.dim_set(i).std_dim(l_dim_index(p_kpi.dim_set(i).inc_data_source(j).std_dim(k).dim_name)).limit_cube;
1741       end loop;
1742       p_kpi.dim_set(i).inc_data_source(j).calendar.limit_cube:=p_kpi.dim_set(i).calendar.limit_cube;
1743     end loop;
1744     --targets only have cubes, limit cubes and load programs
1745     if p_kpi.dim_set(i).targets_higher_levels='Y' then
1746       p_kpi.target_dim_set(i).agg_map.agg_map:=null;
1747       --
1748       p_kpi.target_dim_set(i).initial_load_program.program_name:=p_kpi.dim_set(i).initial_load_program.program_name||'.tgt';
1749       p_kpi.target_dim_set(i).inc_load_program.program_name:=p_kpi.dim_set(i).inc_load_program.program_name||'.tgt';
1750       p_kpi.target_dim_set(i).initial_load_program_parallel.program_name:=p_kpi.dim_set(i).initial_load_program_parallel.program_name||'.tgt';
1751       p_kpi.target_dim_set(i).inc_load_program_parallel.program_name:=p_kpi.dim_set(i).inc_load_program_parallel.program_name||'.tgt';
1752       --for 10g, targets will need a separate program so it can run in parallel
1753       for j in 1..p_kpi.target_dim_set(i).dim.count loop
1754         p_kpi.target_dim_set(i).dim(j).limit_cube:=p_kpi.dim_set(i).dim(j).limit_cube||'.tgt';
1755         if nvl(bsc_aw_utility.get_parameter_value('NO LIMIT CUBE COMPOSITE'),'N')='N' then
1756           p_kpi.target_dim_set(i).dim(j).limit_cube_composite:='c.'||p_kpi.target_dim_set(i).dim(j).limit_cube;
1757         end if;
1758       end loop;
1759       --std dim
1760       for j in 1..p_kpi.target_dim_set(i).std_dim.count loop
1761         p_kpi.target_dim_set(i).std_dim(j).limit_cube:=p_kpi.dim_set(i).std_dim(j).limit_cube||'.tgt';
1762         if nvl(bsc_aw_utility.get_parameter_value('NO LIMIT CUBE COMPOSITE'),'N')='N' then
1763           p_kpi.target_dim_set(i).std_dim(j).limit_cube_composite:='c.'||p_kpi.target_dim_set(i).std_dim(j).limit_cube;
1764         end if;
1765       end loop;
1766       --time limit cube
1767       p_kpi.target_dim_set(i).calendar.limit_cube:=p_kpi.dim_set(i).calendar.limit_cube||'.tgt';
1768       if nvl(bsc_aw_utility.get_parameter_value('NO LIMIT CUBE COMPOSITE'),'N')='N' then
1769         p_kpi.target_dim_set(i).calendar.limit_cube_composite:='c.'||p_kpi.target_dim_set(i).calendar.limit_cube;
1770       end if;
1771       --
1772       create_PT_comp_names(p_kpi.kpi,p_kpi.target_dim_set(i));
1773       --give cube names to data source measures
1774       for j in 1..p_kpi.target_dim_set(i).data_source.count loop
1775         for k in 1..p_kpi.target_dim_set(i).data_source(j).measure.count loop
1776           p_kpi.target_dim_set(i).data_source(j).measure(k).cube:=p_kpi.target_dim_set(i).measure(l_measure_index(p_kpi.target_dim_set(i).data_source(j).measure(k).measure)).cube;
1777           p_kpi.target_dim_set(i).data_source(j).measure(k).property:=
1778           p_kpi.target_dim_set(i).measure(l_measure_index(p_kpi.target_dim_set(i).data_source(j).measure(k).measure)).property;
1779         end loop;
1780         --set the dim limit cubes
1781         for k in 1..p_kpi.target_dim_set(i).data_source(j).dim.count loop
1782           p_kpi.target_dim_set(i).data_source(j).dim(k).limit_cube:=
1783           p_kpi.target_dim_set(i).dim(l_dim_index(p_kpi.target_dim_set(i).data_source(j).dim(k).dim_name)).limit_cube;
1784         end loop;
1785         for k in 1..p_kpi.target_dim_set(i).data_source(j).std_dim.count loop
1786           p_kpi.target_dim_set(i).data_source(j).std_dim(k).limit_cube:=
1787           p_kpi.target_dim_set(i).std_dim(l_dim_index(p_kpi.target_dim_set(i).data_source(j).std_dim(k).dim_name)).limit_cube;
1788         end loop;
1789         p_kpi.target_dim_set(i).data_source(j).calendar.limit_cube:=p_kpi.target_dim_set(i).calendar.limit_cube;
1790       end loop;
1791       for j in 1..p_kpi.target_dim_set(i).inc_data_source.count loop
1792         for k in 1..p_kpi.target_dim_set(i).inc_data_source(j).measure.count loop
1793           p_kpi.target_dim_set(i).inc_data_source(j).measure(k).cube:=p_kpi.target_dim_set(i).measure(
1794           l_measure_index(p_kpi.target_dim_set(i).inc_data_source(j).measure(k).measure)).cube;
1795           p_kpi.target_dim_set(i).inc_data_source(j).measure(k).property:=p_kpi.target_dim_set(i).measure(
1796           l_measure_index(p_kpi.target_dim_set(i).inc_data_source(j).measure(k).measure)).property;
1797         end loop;
1798         for k in 1..p_kpi.target_dim_set(i).inc_data_source(j).dim.count loop
1799           p_kpi.target_dim_set(i).inc_data_source(j).dim(k).limit_cube:=
1803           p_kpi.target_dim_set(i).inc_data_source(j).std_dim(k).limit_cube:=
1800           p_kpi.target_dim_set(i).dim(l_dim_index(p_kpi.target_dim_set(i).inc_data_source(j).dim(k).dim_name)).limit_cube;
1801         end loop;
1802         for k in 1..p_kpi.target_dim_set(i).inc_data_source(j).std_dim.count loop
1804           p_kpi.target_dim_set(i).std_dim(l_dim_index(p_kpi.target_dim_set(i).inc_data_source(j).std_dim(k).dim_name)).limit_cube;
1805         end loop;
1806         p_kpi.target_dim_set(i).inc_data_source(j).calendar.limit_cube:=p_kpi.target_dim_set(i).calendar.limit_cube;
1807       end loop;
1808     end if;
1809   end loop;
1810 Exception when others then
1811   log_n('Exception in create_aw_object_names '||sqlerrm);
1812   raise;
1813 End;
1814 
1815 /*
1816 this procedure names the partitions , composites.
1817 p_dimset cane be actual or target  for target, dim_set_name contains .tgt at the end
1818 with the display cube concept, create_PT_comp_names must be called only after compressed composite parameters and partition parameters
1819 are set
1820 */
1821 procedure create_PT_comp_names(p_kpi varchar2,p_dimset in out nocopy dim_set_r) is
1822 l_kpi varchar2(100); --just used to name objects
1823 l_composite_name varchar2(200);
1824 l_countvar_flag boolean;
1825 composite_index bsc_aw_utility.number_table;
1826 Begin
1827   l_kpi:=p_kpi;
1828   if p_dimset.dim_set_type='target' then
1829     l_kpi:=l_kpi||'.tgt';
1830   end if;
1831   --measurename_dim cannot be null
1832   /*
1833   measurename muct be shared by the tgt and actual. otherwise, data is not copied correctly.
1834   so also partition dim
1835   note>>> for measurename, we use p_kpi, not l_kpi
1836   */
1837   p_dimset.measurename_dim:='measurename.'||p_dimset.dim_set||'.'||p_kpi;
1838   l_composite_name:='comp.'||p_dimset.dim_set||'.'||l_kpi;
1839   --
1840   l_countvar_flag:=check_countvar_cube_needed(p_dimset);
1841   if bsc_aw_utility.get_db_version >=10 and nvl(bsc_aw_utility.get_parameter_value('NO DATACUBE'),'N')='N' then
1842     --
1843     p_dimset.cube_design:='datacube';
1844     if p_dimset.number_partitions>0 then
1845       --dimset can have multiple partition templates to support PT for countvar cubes when we have to use compressed composites
1846       /*copy the info from master partition template. master_partition_template(1) is for datacubes */
1847       p_dimset.partition_template(1):=p_dimset.master_partition_template(1);
1848       p_dimset.partition_template(1).template_name:='PT.'||p_dimset.dim_set||'.'||l_kpi;
1849       for i in 1..p_dimset.number_partitions loop --partitions are named P0, P1 etc. name starts with "0"
1850         p_dimset.composite(p_dimset.composite.count+1).composite_name:=l_composite_name||'.'||(i-1);
1851         if p_dimset.compressed='N' then
1852           p_dimset.composite(p_dimset.composite.count).composite_type:='non compressed';
1853         else
1854           p_dimset.composite(p_dimset.composite.count).composite_type:='compressed';
1855         end if;
1856         composite_index('cube'||i):=p_dimset.composite.count;
1857         --we cannot have compressed composites when we have targets at higher levels since we cannot copy data into higher levels
1858         --from targets to the actuals
1859         --
1860         p_dimset.partition_template(1).template_partitions(i).partition_name:='P.'||(i-1);
1861         p_dimset.partition_template(1).template_partitions(i).partition_dim_value:=to_char(i-1);
1862         p_dimset.partition_template(1).template_partitions(i).partition_axis.delete;
1863         p_dimset.partition_template(1).template_partitions(i).partition_axis(1).axis_name:=p_dimset.partition_template(1).template_dim;
1864         p_dimset.partition_template(1).template_partitions(i).partition_axis(1).axis_type:='dimension';
1865         p_dimset.partition_template(1).template_partitions(i).partition_axis(
1866         p_dimset.partition_template(1).template_partitions(i).partition_axis.count+1).axis_name:=p_dimset.measurename_dim;
1867         p_dimset.partition_template(1).template_partitions(i).partition_axis(
1868         p_dimset.partition_template(1).template_partitions(i).partition_axis.count).axis_type:='dimension';
1869         p_dimset.partition_template(1).template_partitions(i).partition_axis(
1870         p_dimset.partition_template(1).template_partitions(i).partition_axis.count+1).axis_name:=
1871         p_dimset.composite(composite_index('cube'||i)).composite_name;
1872         p_dimset.partition_template(1).template_partitions(i).partition_axis(
1873         p_dimset.partition_template(1).template_partitions(i).partition_axis.count).axis_type:='composite';
1874       end loop;
1875       --if there is countvar and compressed composite, we create separate PT for countvar cube . this is not supported now
1876       --by AW. but in case in the future we have it...
1877       if l_countvar_flag and p_dimset.compressed='Y' then
1878         p_dimset.partition_template(2):=p_dimset.master_partition_template(1);
1879         p_dimset.partition_template(2).template_name:='PT.'||p_dimset.dim_set||'.'||l_kpi||'.countvar';
1880         for i in 1..p_dimset.number_partitions loop --partitions are named P0, P1 etc. name starts with "0"
1881           p_dimset.composite(p_dimset.composite.count+1).composite_name:=l_composite_name||'.'||(i-1)||'.countvar';
1882           if p_dimset.compressed='N' then
1883             p_dimset.composite(p_dimset.composite.count).composite_type:='non compressed';
1884           else
1885             p_dimset.composite(p_dimset.composite.count).composite_type:='compressed';
1886           end if;
1887           composite_index('countvar'||i):=p_dimset.composite.count;
1888           p_dimset.partition_template(2).template_partitions(i).partition_name:='P.'||(i-1);
1889           p_dimset.partition_template(2).template_partitions(i).partition_dim_value:=to_char(i-1);
1890           p_dimset.partition_template(2).template_partitions(i).partition_axis.delete;
1891           p_dimset.partition_template(2).template_partitions(i).partition_axis(1).axis_name:=p_dimset.partition_template(2).template_dim;
1892           p_dimset.partition_template(2).template_partitions(i).partition_axis(1).axis_type:='dimension';
1896           p_dimset.partition_template(2).template_partitions(i).partition_axis.count).axis_type:='dimension';
1893           p_dimset.partition_template(2).template_partitions(i).partition_axis(
1894           p_dimset.partition_template(2).template_partitions(i).partition_axis.count+1).axis_name:=p_dimset.measurename_dim;
1895           p_dimset.partition_template(2).template_partitions(i).partition_axis(
1897           p_dimset.partition_template(2).template_partitions(i).partition_axis(
1898           p_dimset.partition_template(2).template_partitions(i).partition_axis.count+1).axis_name:=
1899           p_dimset.composite(composite_index('countvar'||i)).composite_name;
1900           p_dimset.partition_template(2).template_partitions(i).partition_axis(
1901           p_dimset.partition_template(2).template_partitions(i).partition_axis.count).axis_type:='composite';
1902         end loop;
1903       end if;
1904     else --this is 10g, but there are no partitions
1905       --10g will have datacube.
1906       p_dimset.composite(1).composite_name:=l_composite_name;
1907       if p_dimset.compressed='N' then
1908         p_dimset.composite(1).composite_type:='non compressed';
1909       else
1910         p_dimset.composite(1).composite_type:='compressed';
1911       end if;
1912       composite_index('cube'):=1;
1913       if l_countvar_flag and p_dimset.compressed='Y' then
1914         p_dimset.composite(2).composite_name:=l_composite_name||'.countvar';
1915         if p_dimset.compressed='N' then
1916           p_dimset.composite(2).composite_type:='non compressed';
1917         else
1918           p_dimset.composite(2).composite_type:='compressed';
1919         end if;
1920         composite_index('countvar'):=2;
1921       end if;
1922     end if;
1923     --cubes
1924     /*
1925     we need algo to decide the datatype. for now, we go with number
1926     */
1927     p_dimset.cube_set(1).cube_set_name:='cube set.'||p_dimset.dim_set_name||'.1';
1928     p_dimset.cube_set(1).cube_set_type:='datacube';
1929     p_dimset.cube_set(1).cube.cube_name:='datacube.'||p_dimset.dim_set||'.'||l_kpi;
1930     p_dimset.cube_set(1).cube.cube_datatype:='number';
1931     p_dimset.cube_set(1).fcst_cube.cube_name:=p_dimset.cube_set(1).cube.cube_name||'.fcst';
1932     p_dimset.cube_set(1).fcst_cube.cube_datatype:='number';
1933     if l_countvar_flag then
1934       if bsc_aw_utility.get_property(p_dimset.property,'aggcount').property_value='Y' then
1935         null;
1936       else
1937         p_dimset.cube_set(1).countvar_cube.cube_name:=p_dimset.cube_set(1).cube.cube_name||'.countvar'; --countvar not used in targets
1938         p_dimset.cube_set(1).countvar_cube.cube_datatype:='integer';
1939       end if;
1940     end if;
1941     p_dimset.cube_set(1).measurename_dim:=p_dimset.measurename_dim;
1942     for i in 1..p_dimset.measure.count loop
1943       p_dimset.measure(i).cube:=p_dimset.cube_set(1).cube.cube_name;
1944       p_dimset.measure(i).fcst_cube:=p_dimset.cube_set(1).fcst_cube.cube_name;
1945       --if there is one measure with avg, we need countvar for all cubes
1946       if p_dimset.cube_set(1).countvar_cube.cube_name is not null then
1947         p_dimset.measure(i).countvar_cube:=p_dimset.cube_set(1).countvar_cube.cube_name;
1948       end if;
1949       p_dimset.measure(i).aw_formula.formula_name:=p_dimset.measure(i).measure||'.'||p_dimset.dim_set||'.'||l_kpi;
1950       p_dimset.measure(i).aw_formula.formula_expression:=p_dimset.measure(i).cube||'('||p_dimset.measurename_dim||' '''||
1951       p_dimset.measure(i).measure||''')';
1952     end loop;
1953     /*if we have partitions and this is compressed composite, we have a problem when we need to aggregate data on the fly. compressed
1954     composites cannot be limited in dim status and aggregated. this means we will copy the data into a display cube and then aggregate the display
1955     cube. the view runs off the display cube. for now, we have no composites for the display cube. it must have all the dim of the cube including
1956     partition dim. this name must also be added to measuredim for aggregation
1957     display cube axis is set in create_cube. we need to make sure that display cube axis has the same dim in the same order as that of the cube*/
1958     if is_display_cube_required(p_dimset,p_dimset.cube_set(1).cube.cube_name) then
1959       p_dimset.cube_set(1).display_cube.cube_name:=p_dimset.cube_set(1).cube.cube_name||'.disp';
1960       p_dimset.cube_set(1).display_cube.cube_type:=p_dimset.cube_set(1).cube.cube_type;
1961       p_dimset.cube_set(1).display_cube.cube_datatype:=p_dimset.cube_set(1).cube.cube_datatype;
1962       /*display cube will have its composite */
1963       p_dimset.composite(p_dimset.composite.count+1).composite_name:='c.'||p_dimset.cube_set(1).display_cube.cube_name;
1964       p_dimset.composite(p_dimset.composite.count).composite_type:='non compressed';
1965       composite_index('display'):=p_dimset.composite.count;
1966       /*no partition dim for display cube. in the reader,we copy from main cube to display cube. display=main cube
1967       since there is no node duplication across partitions, when data is copied into the display cube, there is no overwriting
1968       so display cube does not need partition dim. this means we can implement avg measure also with display cubes */
1969       p_dimset.cube_set(1).display_cube.cube_axis(1).axis_name:=p_dimset.measurename_dim;
1970       p_dimset.cube_set(1).display_cube.cube_axis(1).axis_type:='dimension';
1971       p_dimset.cube_set(1).display_cube.cube_axis(2).axis_name:=p_dimset.composite(composite_index('display')).composite_name;
1972       p_dimset.cube_set(1).display_cube.cube_axis(2).axis_type:='composite';
1973     end if;
1974     /*set the display cube properties for the measures */
1975     for i in 1..p_dimset.measure.count loop
1976       p_dimset.measure(i).display_cube:=p_dimset.cube_set(1).display_cube.cube_name;
1977       if p_dimset.measure(i).display_cube is not null then /*partitions with CC or avg agg or non-sql-agg formula */
1978         p_dimset.measure(i).aw_formula.formula_expression:=p_dimset.measure(i).display_cube||'('||p_dimset.measurename_dim||' '''||
1979         p_dimset.measure(i).measure||''')';
1980       end if;
1981     end loop;
1982     /* */
1986       p_dimset.cube_set(1).cube.cube_axis(1).axis_type:='partition template';
1983     if p_dimset.number_partitions>0 then
1984       --here countvar cube and regular cube share the partition since the partition is non compressed
1985       p_dimset.cube_set(1).cube.cube_axis(1).axis_name:=p_dimset.partition_template(1).template_name;
1987       if p_dimset.cube_set(1).countvar_cube.cube_name is not null then
1988         if p_dimset.compressed='Y' then
1989           p_dimset.cube_set(1).countvar_cube.cube_axis(1).axis_name:=p_dimset.partition_template(2).template_name;
1990         else
1991           p_dimset.cube_set(1).countvar_cube.cube_axis(1).axis_name:=p_dimset.partition_template(1).template_name;
1992         end if;
1993         p_dimset.cube_set(1).countvar_cube.cube_axis(1).axis_type:='partition template';
1994       end if;
1995       --we dont populate the fcst cubes for now
1996     else --10g but with no partitions
1997       --here countvar cube and regular cube share the partition since the partition is non compressed
1998       p_dimset.cube_set(1).cube.cube_axis(1).axis_name:=p_dimset.measurename_dim;
1999       p_dimset.cube_set(1).cube.cube_axis(1).axis_type:='dimension';
2000       p_dimset.cube_set(1).cube.cube_axis(2).axis_name:=p_dimset.composite(composite_index('cube')).composite_name;
2001       p_dimset.cube_set(1).cube.cube_axis(2).axis_type:='composite';
2002       if p_dimset.cube_set(1).countvar_cube.cube_name is not null then
2003         p_dimset.cube_set(1).countvar_cube.cube_axis(1).axis_name:=p_dimset.measurename_dim;
2004         p_dimset.cube_set(1).countvar_cube.cube_axis(1).axis_type:='dimension';
2005         if p_dimset.compressed='Y' then
2006           p_dimset.cube_set(1).countvar_cube.cube_axis(2).axis_name:=p_dimset.composite(composite_index('countvar')).composite_name;
2007         else
2008           p_dimset.cube_set(1).countvar_cube.cube_axis(2).axis_name:=p_dimset.composite(composite_index('cube')).composite_name;
2009         end if;
2010         p_dimset.cube_set(1).countvar_cube.cube_axis(2).axis_type:='composite';
2011       end if;
2012       --we dont populate the fcst cubes for now
2013     end if;
2014   else --9i no compressed composite in 9i
2015     --no partitions  1 composite , multiple cubes at measure level
2016     p_dimset.composite(1).composite_name:=l_composite_name;
2017     p_dimset.composite(1).composite_type:='non compressed';
2018     composite_index('cube'):=1;
2019     p_dimset.cube_design:='single composite';
2020     p_dimset.compressed:='N';
2021     for i in 1..p_dimset.measure.count loop
2022       p_dimset.cube_set(i).cube_set_name:='cube set.'||p_dimset.dim_set_name||'.'||i;
2023       p_dimset.cube_set(i).cube_set_type:='measurecube';
2024       p_dimset.cube_set(i).cube.cube_name:=p_dimset.measure(i).measure||'.'||p_dimset.dim_set||'.'||l_kpi;
2025       p_dimset.cube_set(i).cube.cube_datatype:=p_dimset.measure(i).data_type;
2026       p_dimset.cube_set(i).fcst_cube.cube_name:=p_dimset.cube_set(i).cube.cube_name||'.fcst';
2027       p_dimset.cube_set(i).fcst_cube.cube_datatype:=p_dimset.measure(i).data_type;
2028       if l_countvar_flag then
2029         p_dimset.cube_set(i).countvar_cube.cube_name:=p_dimset.cube_set(i).cube.cube_name||'.countvar';
2030         p_dimset.cube_set(i).countvar_cube.cube_datatype:='integer';
2031       end if;
2032       --
2033       p_dimset.cube_set(i).measurename_dim:=p_dimset.measurename_dim;
2034       --
2035       p_dimset.cube_set(i).cube.cube_axis(1).axis_name:=p_dimset.composite(composite_index('cube')).composite_name;
2036       p_dimset.cube_set(i).cube.cube_axis(1).axis_type:='composite';
2037       if p_dimset.cube_set(i).countvar_cube.cube_name is not null then
2038         p_dimset.cube_set(i).countvar_cube.cube_axis(1).axis_name:=p_dimset.composite(composite_index('cube')).composite_name;
2039         p_dimset.cube_set(i).countvar_cube.cube_axis(1).axis_type:='composite';
2040       end if;
2041       --dont populate the fcst cube for now
2042       --
2043       p_dimset.measure(i).cube:=p_dimset.cube_set(i).cube.cube_name;
2044       if p_dimset.cube_set(i).countvar_cube.cube_name is not null then
2045         p_dimset.measure(i).countvar_cube:=p_dimset.cube_set(i).countvar_cube.cube_name;
2046       end if;
2047       p_dimset.measure(i).fcst_cube:=p_dimset.cube_set(i).fcst_cube.cube_name;
2048       --
2049     end loop;
2050     /*if there are period cubes and year cubes then create the extra cubes for these objects*/
2051     for i in 1..p_dimset.measure.count loop
2052       for j in 1..p_dimset.measure(i).property.count loop
2053         if p_dimset.measure(i).property(j).property_name='period cube' or p_dimset.measure(i).property(j).property_name='year cube' then
2054           p_dimset.cube_set(p_dimset.cube_set.count+1).cube_set_name:='cube set.'||p_dimset.dim_set_name||'.'||
2055           p_dimset.measure(i).property(j).property_name||'.'||i||'.'||j;
2056           p_dimset.cube_set(p_dimset.cube_set.count).cube_set_type:='measurecube';
2057           p_dimset.cube_set(p_dimset.cube_set.count).cube.cube_name:=p_dimset.measure(i).property(j).property_value||'.'||
2058           p_dimset.dim_set||'.'||l_kpi;
2059           /*set the property name to reflect the correct cube name*/
2060           p_dimset.measure(i).property(j).property_value:=p_dimset.cube_set(p_dimset.cube_set.count).cube.cube_name;
2061           p_dimset.cube_set(p_dimset.cube_set.count).cube.cube_datatype:=p_dimset.measure(i).data_type; /*should be number */
2062           p_dimset.cube_set(p_dimset.cube_set.count).measurename_dim:=p_dimset.measurename_dim;
2063           p_dimset.cube_set(p_dimset.cube_set.count).cube.cube_axis(1).axis_name:=p_dimset.composite(composite_index('cube')).composite_name;
2064           p_dimset.cube_set(p_dimset.cube_set.count).cube.cube_axis(1).axis_type:='composite';
2065           /*no fcst cubes or countvar cubes */
2066         end if;
2067       end loop;
2068     end loop;
2069   end if;
2070 Exception when others then
2071   log_n('Exception in create_PT_comp_names '||sqlerrm);
2072   raise;
2073 End;
2074 
2075 /*
2076 */
2077 procedure create_kpi_objects(p_kpi in out nocopy kpi_r) is
2078 Begin
2079   for i in 1..p_kpi.dim_set.count loop
2083     end if;
2080     create_kpi_objects(p_kpi,p_kpi.dim_set(i));
2081     if p_kpi.dim_set(i).targets_higher_levels='Y' then
2082       create_kpi_objects(p_kpi,p_kpi.target_dim_set(i));
2084   end loop;
2085 Exception when others then
2086   log_n('Exception in create_kpi_objects '||sqlerrm);
2087   raise;
2088 End;
2089 
2090 /*
2091 composite name : comp_dimset_kpi
2092 in the composite, the order of dim is
2093 dim with no agg, no zero code
2094 dim with no agg, zero code
2095 dim with agg
2096 rec dim
2097 time
2098 */
2099 procedure create_kpi_objects(
2100 p_kpi kpi_r,
2101 p_dim_set in out nocopy dim_set_r) is
2102 l_comp varchar2(300);
2103 Begin
2104   create_measure_dim(p_kpi,p_dim_set);
2105   create_composite(p_kpi,p_dim_set);
2106   create_partition_template(p_kpi,p_dim_set);
2107   create_cube(p_kpi,p_dim_set);
2108   create_measure_formula(p_kpi,p_dim_set);
2109   create_aggmap_operators(p_kpi,p_dim_set);
2110   create_agg_map(p_kpi,p_dim_set);
2111 Exception when others then
2112   log_n('Exception in create_kpi_objects '||sqlerrm);
2113   raise;
2114 End;
2115 
2116 procedure create_measure_dim(
2117 p_kpi kpi_r,
2118 p_dim_set in out nocopy dim_set_r) is
2119 l_pt_comp_type varchar2(100);
2120 l_pt_comp varchar2(100);
2121 l_partition_template partition_template_r;
2122 l_stmt varchar2(2000);
2123 Begin
2124   if g_debug then
2125     log_n('create_measure_dim, dimset='||p_dim_set.dim_set_name);
2126   end if;
2127   --if this is targets, we share the measuredim with the actuals. so no need to create it
2128   --actuals are created before targets. see procedure create_kpi_objects(p_kpi in out nocopy kpi_r) is
2129   if p_dim_set.dim_set_type <> 'target' then
2130     l_stmt:='dfn '||p_dim_set.measurename_dim||' dimension TEXT';
2131     bsc_aw_dbms_aw.execute(l_stmt);
2132     for i in 1..p_dim_set.measure.count loop
2133       l_stmt:='mnt '||p_dim_set.measurename_dim||' add '''||p_dim_set.measure(i).measure||'''';
2134       bsc_aw_dbms_aw.execute(l_stmt);
2135       if p_dim_set.measure(i).measure_type=g_balance_last_value_prop then
2136         for j in 1..p_dim_set.measure(i).property.count loop
2137           if p_dim_set.measure(i).property(j).property_name='period cube' or p_dim_set.measure(i).property(j).property_name='year cube' then
2138             l_stmt:='mnt '||p_dim_set.measurename_dim||' add '''||p_dim_set.measure(i).property(j).property_value||'''';
2139             bsc_aw_dbms_aw.execute(l_stmt);
2140           end if;
2141         end loop;
2142       end if;
2143     end loop;
2144   end if;
2145   --
2146   if p_dim_set.aggmap_operator.measure_dim is not null then
2147     l_stmt:='dfn '||p_dim_set.aggmap_operator.measure_dim||' dimension TEXT';
2148     bsc_aw_dbms_aw.execute(l_stmt);
2149     for i in 1..p_dim_set.cube_set.count loop
2150       l_stmt:='mnt '||p_dim_set.aggmap_operator.measure_dim||' add '''||p_dim_set.cube_set(i).cube.cube_name||'''';
2151       bsc_aw_dbms_aw.execute(l_stmt);
2152       if p_dim_set.cube_set(i).display_cube.cube_name is not null then
2153         l_stmt:='mnt '||p_dim_set.aggmap_operator.measure_dim||' add '''||p_dim_set.cube_set(i).display_cube.cube_name||'''';
2154         bsc_aw_dbms_aw.execute(l_stmt);
2155       end if;
2156       /*if the main cube is partitioned, we also add the cube partitions. with this, we can now say
2157       aggregate datacube.4.4014 (partition P.0) using aggmap.4.4014.notime for nonCC composites. earlier we were limiting the
2158       hash partition dim to ensure that only the specified partition got aggregated. but, all partitions ended up getting
2159       aggregated. if we specify datacube.4.4014 (partition P.0) , then only P.0 gets aggregated. but we need an entry for
2160       datacube.4.4014 (partition P.0) in opvar */
2161       l_pt_comp:=get_cube_pt_comp(p_dim_set.cube_set(i).cube.cube_name,p_dim_set,l_pt_comp_type);
2162       if l_pt_comp_type='partition template' then
2163         l_partition_template:=get_partition_template_r(l_pt_comp,p_dim_set);
2164         for j in 1..l_partition_template.template_partitions.count loop
2165           l_stmt:='mnt '||p_dim_set.aggmap_operator.measure_dim||' add '''||p_dim_set.cube_set(i).cube.cube_name||' (PARTITION '||
2166           l_partition_template.template_partitions(j).partition_name||')''';
2167           bsc_aw_dbms_aw.execute(l_stmt);
2168         end loop;
2169       end if;
2170     end loop;
2171   end if;
2172 Exception when others then
2173   log_n('Exception in create_measure_dim '||sqlerrm);
2174   raise;
2175 End;
2176 
2177 function get_comp_dimensions(p_dim_set in out nocopy dim_set_r) return dbms_sql.varchar2_table is
2178 --
2179 l_comp_dimensions dbms_sql.varchar2_table;
2180 Begin
2181   --first we have the dim on which are going to aggregate. confirmed with AW team. best to have the dim on which we are aggregating
2182   --ahead in the index. we will have time first
2183   l_comp_dimensions(l_comp_dimensions.count+1):=p_dim_set.calendar.aw_dim;
2184   --dim on which we aggregate
2185   for i in 1..p_dim_set.dim.count loop
2186     --if p_dim_set.dim(i).levels.count>1 or p_dim_set.dim(i).zero_code='Y' or p_dim_set.dim(i).recursive='Y' then
2187     if is_dim_aggregated(p_dim_set.dim(i)) then
2188       p_dim_set.dim(i).agg_map.created:='Y'; --from now, we will check this flag to see if we need to aggregate on this dim
2189       l_comp_dimensions(l_comp_dimensions.count+1):=p_dim_set.dim(i).dim_name;
2190     end if;
2191   end loop;
2192   --dim on which there is no agg
2193   for i in 1..p_dim_set.dim.count loop
2194     if p_dim_set.dim(i).agg_map.created is null or p_dim_set.dim(i).agg_map.created <> 'Y' then
2195       l_comp_dimensions(l_comp_dimensions.count+1):=p_dim_set.dim(i).dim_name;
2196     end if;
2197   end loop;
2198   --last have the std dim
2199   for i in 1..p_dim_set.std_dim.count loop
2200     l_comp_dimensions(l_comp_dimensions.count+1):=p_dim_set.std_dim(i).dim_name;
2201   end loop;
2202   return l_comp_dimensions;
2206 End;
2203 Exception when others then
2204   log_n('Exception in get_comp_dimensions '||sqlerrm);
2205   raise;
2207 
2208 /*
2209 composite name : comp_dimset_kpi
2210 in the composite, the order of dim is
2211 dim with no agg, no zero code
2212 dim with no agg, zero code
2213 dim with agg
2214 rec dim
2215 time
2216 please note that the procedure set_dim_order has already set the dim in the correct order
2217 */
2218 procedure create_composite(
2219 p_kpi kpi_r,
2220 p_dim_set in out nocopy dim_set_r) is
2221 l_comp_created dbms_sql.varchar2_table;
2222 l_comp_dimensions dbms_sql.varchar2_table;
2223 Begin
2224   l_comp_dimensions:=get_comp_dimensions(p_dim_set);
2225   --first create the composites
2226   for i in 1..p_dim_set.composite.count loop
2227     if bsc_aw_utility.in_array(l_comp_created,p_dim_set.composite(i).composite_name)=false then
2228       p_dim_set.composite(i).composite_dimensions:=l_comp_dimensions;
2229       g_stmt:='dfn '||p_dim_set.composite(i).composite_name||' composite <';
2230       for j in 1..p_dim_set.composite(i).composite_dimensions.count loop
2231         g_stmt:=g_stmt||p_dim_set.composite(i).composite_dimensions(j)||' ';
2232       end loop;
2233       g_stmt:=g_stmt||'>';
2234       if p_dim_set.composite(i).composite_type='compressed' then
2235         g_stmt:=g_stmt||' compressed';
2236       end if;
2237       bsc_aw_dbms_aw.execute(g_stmt);
2238       l_comp_created(l_comp_created.count+1):=p_dim_set.composite(i).composite_name;
2239     end if;
2240   end loop;
2241 Exception when others then
2242   log_n('Exception in create_composite '||sqlerrm);
2243   raise;
2244 End;
2245 
2246 /*
2247 now, we only create list partitions, these list partitions are essentially hash partitions
2248 */
2249 procedure create_partition_template(
2250 p_kpi kpi_r,
2251 p_dim_set in out nocopy dim_set_r) is
2252 Begin
2253   --create the partitions
2254   for i in 1..p_dim_set.partition_template.count loop
2255     create_partition_template(p_kpi,p_dim_set,p_dim_set.partition_template(i));
2256  end loop;
2257 Exception when others then
2258   log_n('Exception in create_partition '||sqlerrm);
2259   raise;
2260 End;
2261 
2262 procedure create_partition_template(
2263 p_kpi kpi_r,
2264 p_dim_set in out nocopy dim_set_r,
2265 p_partition_template in out nocopy partition_template_r
2266 ) is
2267 --
2268 l_comp_dimensions dbms_sql.varchar2_table;
2269 Begin
2270   if p_partition_template.template_name is not null then
2271     l_comp_dimensions:=get_comp_dimensions(p_dim_set);
2272     p_partition_template.template_dimensions(1):=p_partition_template.template_dim;
2273     p_partition_template.template_dimensions(p_partition_template.template_dimensions.count+1):=p_dim_set.measurename_dim;
2274     for i in 1..l_comp_dimensions.count loop
2275       p_partition_template.template_dimensions(p_partition_template.template_dimensions.count+1):=l_comp_dimensions(i);
2276     end loop;
2277     g_stmt:='dfn '||p_partition_template.template_name||' PARTITION TEMPLATE <';
2278     for i in 1..p_partition_template.template_dimensions.count loop
2279       g_stmt:=g_stmt||' '||p_partition_template.template_dimensions(i);
2280     end loop;
2281     g_stmt:=g_stmt||'> -'||bsc_aw_utility.g_newline;
2282     g_stmt:=g_stmt||'partition by '||p_partition_template.template_type||' ('||p_partition_template.template_dim||') -'||bsc_aw_utility.g_newline;
2283     g_stmt:=g_stmt||'( -'||bsc_aw_utility.g_newline;
2284     for i in 1..p_partition_template.template_partitions.count loop
2285       g_stmt:=g_stmt||'PARTITION '||p_partition_template.template_partitions(i).partition_name||' VALUES ('||
2286       p_partition_template.template_partitions(i).partition_dim_value||') <';
2287       for j in 1..p_partition_template.template_partitions(i).partition_axis.count loop
2288         g_stmt:=g_stmt||' '||p_partition_template.template_partitions(i).partition_axis(j).axis_name;
2289         if p_partition_template.template_partitions(i).partition_axis(j).axis_type='composite' then --mention the composite dim also
2290           l_comp_dimensions:=get_composite_r(p_partition_template.template_partitions(i).partition_axis(j).axis_name,p_dim_set).composite_dimensions;
2291           g_stmt:=g_stmt||'<';
2292           for k in 1..l_comp_dimensions.count loop
2293             g_stmt:=g_stmt||' '||l_comp_dimensions(k);
2294           end loop;
2295           g_stmt:=g_stmt||'>';
2296         end if;
2297       end loop;
2298       g_stmt:=g_stmt||'> -'||bsc_aw_utility.g_newline;
2299     end loop;
2300     g_stmt:=g_stmt||')';
2301     bsc_aw_dbms_aw.execute(g_stmt);
2302   end if;
2303 Exception when others then
2304   log_n('Exception in create_partition_template '||sqlerrm);
2305   raise;
2306 End;
2307 
2308 procedure create_cube(
2309 p_kpi kpi_r,
2310 p_dim_set in out nocopy dim_set_r) is
2311 --
2312 l_lc_axis varchar2(400);
2313 Begin
2314   for i in 1..p_dim_set.cube_set.count loop
2315     create_cube(p_kpi,p_dim_set,p_dim_set.cube_set(i).cube);
2316     if p_dim_set.cube_set(i).countvar_cube.cube_name is not null then
2317       create_cube(p_kpi,p_dim_set,p_dim_set.cube_set(i).countvar_cube);
2318     end if;
2319     if p_dim_set.cube_set(i).display_cube.cube_name is not null then
2320       --create_cube(p_kpi,p_dim_set,p_dim_set.cube_set(i).display_cube,make_display_cube_axis(p_dim_set,p_dim_set.cube_set(i).cube));
2321       create_cube(p_kpi,p_dim_set,p_dim_set.cube_set(i).display_cube);
2322     end if;
2323     --we do not create the fcst cube now
2324   end loop;
2325   --create the limit cubes
2326   for i in 1..p_dim_set.dim.count loop
2327     --create the composite
2328     if p_dim_set.dim(i).limit_cube_composite is not null then
2329       g_stmt:='dfn '||p_dim_set.dim(i).limit_cube_composite||' composite <'||p_dim_set.dim(i).dim_name||'>';
2330       bsc_aw_dbms_aw.execute(g_stmt);
2334     end if;
2331       l_lc_axis:=p_dim_set.dim(i).limit_cube_composite||'<'||p_dim_set.dim(i).dim_name||'>';
2332     else
2333       l_lc_axis:=p_dim_set.dim(i).dim_name;
2335     g_stmt:='dfn '||p_dim_set.dim(i).limit_cube||' variable boolean <'||l_lc_axis||'>';
2336     bsc_aw_dbms_aw.execute(g_stmt);
2337     if p_dim_set.dim(i).reset_cube is not null then
2338       g_stmt:='dfn '||p_dim_set.dim(i).reset_cube||' variable boolean <'||l_lc_axis||'>';
2339       bsc_aw_dbms_aw.execute(g_stmt);
2340     end if;
2341     if p_dim_set.dim(i).aggregate_marker is not null then
2342       g_stmt:='dfn '||p_dim_set.dim(i).aggregate_marker||' boolean';
2343       bsc_aw_dbms_aw.execute(g_stmt);
2344       g_stmt:=p_dim_set.dim(i).aggregate_marker||'=false';
2345       bsc_aw_dbms_aw.execute(g_stmt);
2346     end if;
2347   end loop;
2348   --std dim
2349   for i in 1..p_dim_set.std_dim.count loop
2350     if p_dim_set.std_dim(i).limit_cube_composite is not null then
2351       g_stmt:='dfn '||p_dim_set.std_dim(i).limit_cube_composite||' composite <'||p_dim_set.std_dim(i).dim_name||'>';
2352       bsc_aw_dbms_aw.execute(g_stmt);
2353       l_lc_axis:=p_dim_set.std_dim(i).limit_cube_composite||'<'||p_dim_set.std_dim(i).dim_name||'>';
2354     else
2355       l_lc_axis:=p_dim_set.std_dim(i).dim_name;
2356     end if;
2357     g_stmt:='dfn '||p_dim_set.std_dim(i).limit_cube||' variable boolean <'||l_lc_axis||'>';
2358     bsc_aw_dbms_aw.execute(g_stmt);
2359   end loop;
2360   --limit cube for time dim
2361   if p_dim_set.calendar.limit_cube_composite is not null then
2362     g_stmt:='dfn '||p_dim_set.calendar.limit_cube_composite||' composite <'||p_dim_set.calendar.aw_dim||'>';
2363     bsc_aw_dbms_aw.execute(g_stmt);
2364     l_lc_axis:=p_dim_set.calendar.limit_cube_composite||'<'||p_dim_set.calendar.aw_dim||'>';
2365   else
2366     l_lc_axis:=p_dim_set.calendar.aw_dim;
2367   end if;
2368   g_stmt:='dfn '||p_dim_set.calendar.limit_cube||' variable boolean <'||l_lc_axis||'>';
2369   bsc_aw_dbms_aw.execute(g_stmt);
2370   if p_dim_set.calendar.aggregate_marker is not null then
2371     g_stmt:='dfn '||p_dim_set.calendar.aggregate_marker||' boolean';
2372     bsc_aw_dbms_aw.execute(g_stmt);
2373   end if;
2374 Exception when others then
2375   log_n('Exception in create_cube '||sqlerrm);
2376   raise;
2377 End;
2378 
2379 procedure create_cube(
2380 p_kpi kpi_r,
2381 p_dim_set dim_set_r,
2382 p_cube cube_r) is
2383 Begin
2384  create_cube(p_kpi,p_dim_set,p_cube,p_cube.cube_axis);
2385 Exception when others then
2386   log_n('Exception in create_cube '||sqlerrm);
2387   raise;
2388 End;
2389 
2390 procedure create_cube(p_kpi kpi_r,p_dim_set dim_set_r,p_cube cube_r,p_cube_axis axis_tb) is
2391 l_stmt varchar2(4000);
2392 l_dimensions dbms_sql.varchar2_table;
2393 Begin
2394   l_stmt:='dfn '||p_cube.cube_name||' '||p_cube.cube_datatype||'<';
2395   for i in 1..p_cube_axis.count loop
2396     l_stmt:=l_stmt||' '||p_cube_axis(i).axis_name;
2397     l_dimensions.delete;
2398     if p_cube_axis(i).axis_type='partition template' then
2399       l_dimensions:=get_partition_template_r(p_cube_axis(i).axis_name,p_dim_set).template_dimensions;
2400     elsif p_cube_axis(i).axis_type='composite' then
2401       l_dimensions:=get_composite_r(p_cube_axis(i).axis_name,p_dim_set).composite_dimensions;
2402     else --dimension
2403       null; --no action reqd
2404     end if;
2405     if l_dimensions.count>0 then
2406       l_stmt:=l_stmt||' <';
2407       for j in 1..l_dimensions.count loop
2408         l_stmt:=l_stmt||' '||l_dimensions(j);
2409       end loop;
2410       l_stmt:=l_stmt||' >';
2411     end if;
2412   end loop;
2413   l_stmt:=l_stmt||' >';
2414   if bsc_aw_utility.get_property(p_dim_set.property,'aggcount').property_value='Y' then
2415     l_stmt:=l_stmt||' WITH AGGCOUNT';
2416   end if;
2417   bsc_aw_dbms_aw.execute(l_stmt);
2418 Exception when others then
2419   log_n('Exception in create_cube '||sqlerrm);
2420   raise;
2421 End;
2422 
2423 procedure create_measure_formula(
2424 p_kpi kpi_r,
2425 p_dim_set in out nocopy dim_set_r) is
2426 Begin
2427   for i in 1..p_dim_set.measure.count loop
2428     if p_dim_set.measure(i).aw_formula.formula_name is not null then
2429       g_stmt:='dfn '||p_dim_set.measure(i).aw_formula.formula_name||' formula '||p_dim_set.measure(i).aw_formula.formula_expression;
2430       bsc_aw_dbms_aw.execute(g_stmt);
2431     end if;
2432   end loop;
2433 Exception when others then
2434   log_n('Exception in create_measure_formula '||sqlerrm);
2435   raise;
2436 End;
2437 
2438 /*
2439 aggregation is performed if
2440 1. dim.levels.count>1
2441 2. zero code=Y
2442 3. recursive=Y
2443 */
2444 procedure create_agg_map(
2445 p_kpi kpi_r,
2446 p_dim_set in out nocopy dim_set_r) is
2447 --
2448 l_flag boolean;
2449 Begin
2450   if p_dim_set.agg_map.agg_map is not null then
2451     p_dim_set.agg_map.property:='normal';
2452     p_dim_set.agg_map_notime.property:='notime';
2453     create_agg_map(p_dim_set,p_dim_set.agg_map);
2454     create_agg_map(p_dim_set,p_dim_set.agg_map_notime);
2455     ----agg maps for individual dims
2456     --we create agg map for each individual dim for use in on-line agg. we create it with opvar, argvar and measure dim
2457     --if the dimset has 4 cubes and we want to agg only 1, we will limit p_agg_map.measure_dim to just that cube
2458     for i in 1..p_dim_set.dim.count loop
2459       if p_dim_set.dim(i).agg_map.created='Y' then --create_composite has already set this flag
2460         g_commands.delete;
2461         bsc_aw_utility.add_g_commands(g_commands,'dfn '||p_dim_set.dim(i).agg_map.agg_map||' aggmap ');
2462         bsc_aw_utility.add_g_commands(g_commands,'relation '||p_dim_set.dim(i).relation_name||' OPERATOR '||
2463         p_dim_set.dim(i).agg_map.aggmap_operator.opvar||' ARGS '||p_dim_set.dim(i).agg_map.aggmap_operator.argvar);
2467         is set. for us, all dim are in composite. so no need to have this */
2464         bsc_aw_utility.add_g_commands(g_commands,'MEASUREDIM '||p_dim_set.dim(i).agg_map.aggmap_operator.measure_dim);
2465         bsc_aw_utility.exec_aggmap_commands(p_dim_set.dim(i).agg_map.agg_map,g_commands);
2466         /*had aggindex=no. from olap doc, if aggindex=no, then dim outside the composite are aggregated on the fly when natrigger property
2468       end if;
2469     end loop;
2470     /*create aggmap of calendar */
2471     g_commands.delete;
2472     bsc_aw_utility.add_g_commands(g_commands,'dfn '||p_dim_set.calendar.agg_map.agg_map||' aggmap ');
2473     bsc_aw_utility.add_g_commands(g_commands,'relation '||p_dim_set.calendar.relation_name||' OPERATOR '||
2474     p_dim_set.calendar.agg_map.aggmap_operator.opvar||' ARGS '||p_dim_set.calendar.agg_map.aggmap_operator.argvar);
2475     bsc_aw_utility.add_g_commands(g_commands,'MEASUREDIM '||p_dim_set.calendar.agg_map.aggmap_operator.measure_dim);
2476     bsc_aw_utility.exec_aggmap_commands(p_dim_set.calendar.agg_map.agg_map,g_commands);
2477   end if;
2478 Exception when others then
2479   log_n('Exception in create_agg_map '||sqlerrm);
2480   raise;
2481 End;
2482 
2483 /*
2484 the operators for agg maps need not be specific to each aggmap. say aggmap, aggmap_notime
2485 and dim agg maps.
2486 aggmap and aggmap_notime have diff measures. the operator dim will contain all measures
2487 so before firing an aggmap, we must limit the measuredim
2488 tested to make sure that we can have measurename and measuredim that holds the cube name in opvar.
2489 */
2490 procedure create_aggmap_operators(p_kpi kpi_r,p_dim_set dim_set_r) is
2491 l_cube_set cube_set_r;
2492 l_pt_comp_type varchar2(100);
2493 l_pt_comp varchar2(100);
2494 l_partition_template partition_template_r;
2495 Begin
2496   --measure_dim created in create_measure_dim
2497   --opvar makes sense only for std agg. for formulas, it makes no sense. but we just have it here
2498   if p_dim_set.aggmap_operator.opvar is not null then
2499     g_stmt:='dfn '||p_dim_set.aggmap_operator.opvar||' TEXT<'||p_dim_set.measurename_dim||' '||p_dim_set.aggmap_operator.measure_dim||'>';
2500     bsc_aw_dbms_aw.execute(g_stmt);
2501     for i in 1..p_dim_set.measure.count loop
2502       l_cube_set:=get_cube_set_r(p_dim_set.measure(i).cube,p_dim_set);
2503       g_stmt:=p_dim_set.aggmap_operator.opvar||'('||p_dim_set.measurename_dim||' '''||p_dim_set.measure(i).measure||''' '||
2504       p_dim_set.aggmap_operator.measure_dim||' '''||l_cube_set.cube.cube_name||
2505       ''')='''||replace(p_dim_set.measure(i).agg_formula.agg_formula,'''','\''')||'''';
2506       bsc_aw_dbms_aw.execute(g_stmt);
2507       /*we need to add the aggregation function for the partitions */
2508       l_pt_comp:=get_cube_pt_comp(l_cube_set.cube.cube_name,p_dim_set,l_pt_comp_type);
2509       if l_pt_comp_type='partition template' then
2510         l_partition_template:=get_partition_template_r(l_pt_comp,p_dim_set);
2511         for j in 1..l_partition_template.template_partitions.count loop
2512           g_stmt:=p_dim_set.aggmap_operator.opvar||'('||p_dim_set.measurename_dim||' '''||p_dim_set.measure(i).measure||''' '||
2513           p_dim_set.aggmap_operator.measure_dim||' '''||l_cube_set.cube.cube_name||' (PARTITION '||
2514           l_partition_template.template_partitions(j).partition_name||')'')='''||replace(p_dim_set.measure(i).agg_formula.agg_formula,'''','\''')||'''';
2515           bsc_aw_dbms_aw.execute(g_stmt);
2516         end loop;
2517       end if;
2518       if l_cube_set.display_cube.cube_name is not null then
2519         g_stmt:=p_dim_set.aggmap_operator.opvar||'('||p_dim_set.measurename_dim||' '''||p_dim_set.measure(i).measure||''' '||
2520         p_dim_set.aggmap_operator.measure_dim||' '''||l_cube_set.display_cube.cube_name||
2521         ''')='''||replace(p_dim_set.measure(i).agg_formula.agg_formula,'''','\''')||'''';
2522         bsc_aw_dbms_aw.execute(g_stmt);
2523       end if;
2524     end loop;
2525   end if;
2526   if p_dim_set.aggmap_operator.argvar is not null then
2527     g_stmt:='dfn '||p_dim_set.aggmap_operator.argvar||' TEXT<'||p_dim_set.measurename_dim||' '||p_dim_set.aggmap_operator.measure_dim||'>';
2528     bsc_aw_dbms_aw.execute(g_stmt);
2529     for i in 1..p_dim_set.measure.count loop
2530       l_cube_set:=get_cube_set_r(p_dim_set.measure(i).cube,p_dim_set);
2531       g_stmt:=p_dim_set.aggmap_operator.argvar||'('||p_dim_set.measurename_dim||' '''||p_dim_set.measure(i).measure||''' '||
2532       p_dim_set.aggmap_operator.measure_dim||' '''||l_cube_set.cube.cube_name||''')=NA';
2533       bsc_aw_dbms_aw.execute(g_stmt);
2534       if l_cube_set.display_cube.cube_name is not null then
2535         g_stmt:=p_dim_set.aggmap_operator.argvar||'('||p_dim_set.measurename_dim||' '''||p_dim_set.measure(i).measure||''' '||
2536         p_dim_set.aggmap_operator.measure_dim||' '''||l_cube_set.display_cube.cube_name||''')=NA';
2537         bsc_aw_dbms_aw.execute(g_stmt);
2538       end if;
2539     end loop;
2540   end if;
2541 Exception when others then
2542   log_n('Exception in create_aggmap_operators '||sqlerrm);
2543   raise;
2544 End;
2545 
2546 /*
2547 if the aggmap is regular one, time is added
2548 if notime, no time relation is added
2549 */
2550 procedure create_agg_map(p_dim_set dim_set_r,p_agg_map in out nocopy agg_map_r) is
2551 --
2552 l_flag boolean;
2553 agg_formula varchar2(2000);
2554 Begin
2555   --create the agg map
2556   g_commands.delete;
2557   l_flag:=false;
2558   bsc_aw_utility.add_g_commands(g_commands,'dfn '||p_agg_map.agg_map||' aggmap ');
2559   if p_dim_set.compressed='Y' then /* 5236161*/
2560     for i in 1..p_dim_set.measure.count loop
2561       if bsc_aw_utility.is_std_aggregation_function(p_dim_set.measure(i).agg_formula.agg_formula)='Y' then
2562         agg_formula:=p_dim_set.measure(i).agg_formula.agg_formula;
2563         if agg_formula is not null then
2564           exit;
2565         end if;
2566       end if;
2567     end loop;
2568     if agg_formula is null then
2569       log('Could not get an agg formula with std aggregation for CC');
2573   --if regular aggmap, add time relation also
2570       raise bsc_aw_utility.g_exception;
2571     end if;
2572   end if;
2574   if p_agg_map.property='normal' then
2575     if is_calendar_aggregated(p_dim_set.calendar) then
2576       l_flag:=true;
2577       if p_dim_set.compressed='Y' then
2578         --cannot have opvar, argvar or measuredim. so we have restricted implementation. all measures must have the same agg
2579         --formula. if the agg formula is diff, create_PT_comp_names would have set compressed to N
2580         bsc_aw_utility.add_g_commands(g_commands,'relation '||p_dim_set.calendar.relation_name||' OPERATOR '||
2581         agg_formula);
2582       else
2583         bsc_aw_utility.add_g_commands(g_commands,'relation '||p_dim_set.calendar.relation_name||' OPERATOR '||
2584         p_agg_map.aggmap_operator.opvar||' ARGS '||p_agg_map.aggmap_operator.argvar);
2585       end if;
2586     end if;
2587   end if;
2588   for i in 1..p_dim_set.dim.count loop
2589     if p_dim_set.dim(i).agg_map.created='Y' then --create_composite has already set this flag
2590       l_flag:=true;
2591       if p_dim_set.compressed='Y' then
2592         bsc_aw_utility.add_g_commands(g_commands,'relation '||p_dim_set.dim(i).relation_name||' OPERATOR '||
2593         agg_formula);
2594       else
2595         bsc_aw_utility.add_g_commands(g_commands,'relation '||p_dim_set.dim(i).relation_name||' OPERATOR '||
2596         p_agg_map.aggmap_operator.opvar||' ARGS '||p_agg_map.aggmap_operator.argvar);
2597       end if;
2598     end if;
2599   end loop;
2600   if p_dim_set.compressed='Y' then
2601     null;
2602   else
2603     bsc_aw_utility.add_g_commands(g_commands,'MEASUREDIM '||p_agg_map.aggmap_operator.measure_dim);
2604   end if;
2605   if l_flag then
2606     p_agg_map.created:='Y';
2607     bsc_aw_utility.exec_aggmap_commands(p_agg_map.agg_map,g_commands);
2608   else
2609     p_agg_map.created:='N';
2610   end if;
2611 Exception when others then
2612   log_n('Exception in create_agg_map '||sqlerrm);
2613   raise;
2614 End;
2615 
2616 procedure create_kpi_program(p_kpi in out nocopy kpi_r) is
2617 Begin
2618   for i in 1..p_kpi.dim_set.count loop
2619     create_kpi_program(p_kpi,p_kpi.dim_set(i),'initial');
2620     create_kpi_program(p_kpi,p_kpi.dim_set(i),'inc');
2621     create_aggregate_marker_pgm(p_kpi,p_kpi.dim_set(i));
2622   end loop;
2623   --if targets are implemented, create load programs for targets also
2624   for i in 1..p_kpi.target_dim_set.count loop
2625     if p_kpi.target_dim_set(i).dim_set is not null then
2626       create_kpi_program(p_kpi,p_kpi.target_dim_set(i),'initial');
2627       create_kpi_program(p_kpi,p_kpi.target_dim_set(i),'inc');
2628     end if;
2629   end loop;
2630 Exception when others then
2631   log_n('Exception in create_kpi_program 1 '||sqlerrm);
2632   raise;
2633 End;
2634 
2635 /*
2636 only creates load program. no aggregation or forecast
2637 the program has a if findchars check for each data source each data source has base tables
2638 RSG will load base tables, not KPI. so we need to load only those data sources which have the
2639 base tables RSG has specified. also, the load may be for the kpi. so we do the check at each
2640 datasource witl ALL and the base table names
2641 arg(1) will be ALL or BSC_B_1,BSC_B_2, etc. we have a comma at the end and check with the comma to prevent
2642 BSC_B_1 being oked for BSC_B_10
2643 */
2644 procedure create_kpi_program(
2645 p_kpi kpi_r,
2646 p_dim_set in out nocopy dim_set_r,
2647 p_mode varchar2) is
2648 --
2649 l_pgm varchar2(300);
2650 l_stmt varchar2(4000);
2651 Begin
2652   g_commands.delete;
2653   if p_mode='initial' then
2654     set_program_property(p_dim_set.initial_load_program,p_dim_set.data_source);
2655     l_pgm:=p_dim_set.initial_load_program.program_name;
2656     bsc_aw_utility.add_g_commands(g_commands,'dfn '||l_pgm||' program');
2657     for i in 1..p_dim_set.data_source.count loop
2658       create_kpi_program(p_kpi,p_dim_set,p_dim_set.data_source(i));
2659     end loop;
2660   else
2661     set_program_property(p_dim_set.inc_load_program,p_dim_set.inc_data_source);
2662     l_pgm:=p_dim_set.inc_load_program.program_name;
2663     bsc_aw_utility.add_g_commands(g_commands,'dfn '||l_pgm||' program');
2664     for i in 1..p_dim_set.inc_data_source.count loop
2665       create_kpi_program(p_kpi,p_dim_set,p_dim_set.inc_data_source(i));
2666     end loop;
2667   end if;
2668   bsc_aw_utility.exec_program_commands(l_pgm,g_commands);
2669 Exception when others then
2670   log_n('Exception in create_kpi_program 2 '||sqlerrm);
2671   raise;
2672 End;
2673 
2674 /*
2675 given a data source construct the program statements.
2676 this procesure creates the program that will load all measures at the same time. this is done for 9i and 10g.
2677 in 10g, we will also have a program that will load measures in diff sessions for parallelism
2678 this is created so that in case parallelism is disabled, we can launch this process to load all measures at the same
2679 time
2680 for 10g with partitions, we have programs that load on partition basis
2681 we now AND the base tables in a data source. these base tables are ordered according to name
2682 */
2683 procedure create_kpi_program(
2684 p_kpi kpi_r,
2685 p_dim_set dim_set_r,
2686 p_data_source data_source_r) is
2687 l_stmt varchar(4000);
2688 --
2689 l_cube_set cube_set_r;
2690 l_filter varchar2(2000);
2691 l_ordered_b_tables dbms_sql.varchar2_table;
2692 l_balance_loaded_column varchar2(40);
2693 Begin
2694   for i in 1..p_data_source.base_tables.count loop
2695     bsc_aw_utility.merge_value(l_ordered_b_tables,p_data_source.base_tables(i).base_table_name);
2696   end loop;
2697   l_ordered_b_tables:=bsc_aw_utility.order_array(l_ordered_b_tables);
2698   bsc_aw_utility.add_g_commands(g_commands,'if arg(1) EQ \'''||bsc_aw_utility.make_string_from_list(l_ordered_b_tables)||'\'' --');
2702     bsc_aw_utility.add_g_commands(g_commands,l_filter||' --');
2699   --see if there are any additional filter properties defined..used when partitions are involved
2700   l_filter:=bsc_aw_utility.get_property(p_data_source.property,'datasource filter').property_value;
2701   if l_filter is not null then
2703   end if;
2704   bsc_aw_utility.trim_g_commands(g_commands,3,null);
2705   bsc_aw_utility.add_g_commands(g_commands,'then do');
2706   /*temp variables period.temp and year.temp hold the period and year values. they are present in all cube loading programs. they are used when we
2707   have BALANCE LAST VALUE type measure */
2708   create_temp_variables(p_dim_set,p_data_source);
2709   bsc_aw_utility.add_g_commands(g_commands,'allstat');
2710   --if compressed composite, clear the aggregates. if < 10.2
2711   if p_dim_set.compressed='Y' and bsc_aw_utility.get_db_version<10.2 then
2712     bsc_aw_utility.init_is_new_value(1);
2713     for i in 1..p_data_source.measure.count loop
2714       if bsc_aw_utility.is_new_value(p_data_source.measure(i).cube,1) then
2715         bsc_aw_utility.add_g_commands(g_commands,'clear all aggregates from '||p_data_source.measure(i).cube);
2716         /*here we clear all aggregates from the cubes without looking at which measures are involved. if we load only 1
2717         B, we aggregate all measures. this is ok, since cost is not in the arthmetic, but in composite build
2718         */
2719       end if;
2720     end loop;
2721   end if;
2722   for i in 1..p_data_source.data_source_stmt.count loop
2723     bsc_aw_utility.add_g_commands(g_commands,p_data_source.data_source_stmt(i)||' --');
2724   end loop;
2725   bsc_aw_utility.trim_g_commands(g_commands,3,null);
2726   create_dim_match_header(p_data_source);
2727   /*
2728   if the dimset has partitions, data source stmt will have the partition key
2729   if the data source partition dim is not null, it means partitions are implemented in the dimset
2730   */
2731   if p_dim_set.number_partitions>0 and p_data_source.data_source_PT.partition_template.template_dim is not null then
2732     bsc_aw_utility.add_g_commands(g_commands,':match '||p_data_source.data_source_PT.partition_template.template_dim||' --');
2733   end if;
2734   --now the cubes
2735   --every dim has CC dim. we have this so that we can do zero code on any of them.
2736   for i in 1..p_data_source.measure.count loop
2737     l_stmt:=':'||p_data_source.measure(i).cube||'(';
2738     l_cube_set:=get_cube_set_r(p_data_source.measure(i).cube,p_dim_set);
2739     if l_cube_set.cube_set_type='datacube' then --specify the measure name
2740       l_stmt:=l_stmt||l_cube_set.measurename_dim||' \'''||p_data_source.measure(i).measure||'\'' ';
2741     end if;
2742     --time will always be concat
2743     --we dont need to have std dim since they do not have concat dim
2744     --dim. we also need to filter out dim which are standalone and not concat
2745     --note: std dim are automatically filtered since they are not concat
2746     for j in 1..p_data_source.dim.count loop
2747       if p_data_source.dim(j).concat='Y' then
2748         l_stmt:=l_stmt||p_data_source.dim(j).dim_name||' '||p_data_source.dim(j).levels(1).level_name||' ';
2749       end if;
2750     end loop;
2751     --time
2752     l_stmt:=l_stmt||p_data_source.calendar.aw_dim||' '||p_data_source.calendar.periodicity(1).aw_dim||' ';
2753     l_stmt:=l_stmt||') --';
2754     bsc_aw_utility.add_g_commands(g_commands,l_stmt);
2755   end loop;
2756   for i in 1..p_data_source.measure.count loop
2757     if p_data_source.measure(i).measure_type=g_balance_last_value_prop then
2758       /*if this is a BALANCE LAST VALUE column, also grab the loaded Y/N column */
2759       l_balance_loaded_column:=bsc_aw_utility.get_property(p_data_source.measure(i).property,g_balance_loaded_column_prop).property_value;
2760       if l_balance_loaded_column is not null then
2761         bsc_aw_utility.add_g_commands(g_commands,':'||l_balance_loaded_column||' --');
2762       end if;
2763     end if;
2764   end loop;
2765   --markers...limit cubes
2766   create_limit_cube_tail(p_data_source);
2767   /*have a then stmt. if there are balance measures, we need the then */
2768   bsc_aw_utility.add_g_commands(g_commands,'then --');
2769   bsc_aw_utility.add_g_commands(g_commands,'temp_number=NA --');
2770   --if there is balance, add the balance aggregation statements
2771   create_balance_aggregation(p_dim_set,p_data_source,p_data_source.measure);
2772   --
2773   bsc_aw_utility.trim_g_commands(g_commands,3,null);
2774   bsc_aw_utility.add_g_commands(g_commands,'sql close c1');
2775   bsc_aw_utility.add_g_commands(g_commands,'sql cleanup');
2776   bsc_aw_utility.add_g_commands(g_commands,'doend');
2777 Exception when others then
2778   log_n('Exception in create_kpi_program 3 ,dimset='||p_dim_set.dim_set_name||' '||sqlerrm);
2779   raise;
2780 End;
2781 
2782 procedure create_balance_aggregation(p_dim_set dim_set_r, p_data_source data_source_r,p_measures measure_tb) is
2783 l_upper_periodicity dbms_sql.varchar2_table;
2784 l_cube_copy_stmt dbms_sql.varchar2_table;
2785 l_limit_cube_copy_stmt dbms_sql.varchar2_table;
2786 l_stmt varchar2(8000);
2787 l_cube_set cube_set_r;
2788 --
2789 l_balance_loaded_column varchar2(40);
2790 l_year_cube varchar2(80);
2791 l_period_cube varchar2(80);
2792 l_year_cube_stmt varchar2(2000);
2793 l_period_cube_stmt varchar2(2000);
2794 Begin
2795   for i in 1..p_data_source.calendar.parent_child.count loop
2796     if p_data_source.calendar.parent_child(i).parent_dim_name is not null
2797     and p_data_source.calendar.parent_child(i).parent_dim_name<>p_data_source.calendar.periodicity(1).aw_dim then
2798       bsc_aw_utility.merge_value(l_upper_periodicity,p_data_source.calendar.parent_child(i).parent_dim_name);
2799     end if;
2800     if p_data_source.calendar.parent_child(i).child_dim_name is not null
2801     and p_data_source.calendar.parent_child(i).child_dim_name<>p_data_source.calendar.periodicity(1).aw_dim then
2802       bsc_aw_utility.merge_value(l_upper_periodicity,p_data_source.calendar.parent_child(i).child_dim_name);
2803     end if;
2804   end loop;
2808       log(l_upper_periodicity(i));
2805   if g_debug then
2806     log('In create_balance_aggregation dimset '||p_dim_set.dim_set_name||', upper periodicities:-');
2807     for i in 1..l_upper_periodicity.count loop
2809     end loop;
2810   end if;
2811   for i in 1..p_measures.count loop
2812     if g_debug then
2813       log(p_measures(i).measure||' '||p_measures(i).measure_type);
2814     end if;
2815     if p_measures(i).measure_type=g_balance_end_period_prop or p_measures(i).measure_type=g_balance_last_value_prop then
2816       l_cube_set:=get_cube_set_r(p_measures(i).cube,p_dim_set);
2817       for j in 1..l_upper_periodicity.count loop
2818         l_cube_copy_stmt(j):=p_measures(i).cube||'(';
2819         if l_cube_set.cube_set_type='datacube' then --specify the measure name
2820           l_cube_copy_stmt(j):=l_cube_copy_stmt(j)||l_cube_set.measurename_dim||' \'''||p_measures(i).measure||'\'' ';
2821         end if;
2822         for k in 1..p_data_source.dim.count loop
2823           if p_data_source.dim(k).concat='Y' then
2824             l_cube_copy_stmt(j):=l_cube_copy_stmt(j)||p_data_source.dim(k).dim_name||' '||p_data_source.dim(k).levels(1).level_name||' ';
2825           end if;
2826         end loop;
2827         --time
2828         l_cube_copy_stmt(j):=l_cube_copy_stmt(j)||p_data_source.calendar.aw_dim||' '||p_data_source.calendar.denorm_relation_name||'('||
2829         p_data_source.calendar.aw_dim||' '||p_data_source.calendar.periodicity(1).aw_dim||' '||
2830         p_data_source.calendar.end_period_level_name_dim||' \'''||l_upper_periodicity(j)||'\''))=';
2831         l_cube_copy_stmt(j):=l_cube_copy_stmt(j)||p_measures(i).cube||'(';
2832         if l_cube_set.cube_set_type='datacube' then --specify the measure name
2833           l_cube_copy_stmt(j):=l_cube_copy_stmt(j)||l_cube_set.measurename_dim||' \'''||p_measures(i).measure||'\'' ';
2834         end if;
2835         for k in 1..p_data_source.dim.count loop
2836           if p_data_source.dim(k).concat='Y' then
2837             l_cube_copy_stmt(j):=l_cube_copy_stmt(j)||p_data_source.dim(k).dim_name||' '||p_data_source.dim(k).levels(1).level_name||' ';
2838           end if;
2839         end loop;
2840         --time
2841         l_cube_copy_stmt(j):=l_cube_copy_stmt(j)||p_data_source.calendar.aw_dim||' '||p_data_source.calendar.periodicity(1).aw_dim||') --';
2842         /*limit cube stmt */
2843         l_limit_cube_copy_stmt(j):=p_data_source.calendar.limit_cube||'('||p_data_source.calendar.aw_dim||' '||
2844         p_data_source.calendar.denorm_relation_name||'('||p_data_source.calendar.aw_dim||' '||p_data_source.calendar.periodicity(1).aw_dim||' '||
2845         p_data_source.calendar.end_period_level_name_dim||' \'''||l_upper_periodicity(j)||'\''))=TRUE --';
2846       end loop;
2847     end if;
2848     if p_measures(i).measure_type=g_balance_end_period_prop then --default end period balance
2849       /*must have rollup to all upper periodicities */
2850       for j in 1..l_upper_periodicity.count loop
2851         l_stmt:='if '||p_data_source.calendar.aw_dim||'('||p_data_source.calendar.aw_dim||' '||p_data_source.calendar.periodicity(1).aw_dim||') '||
2852         'EQ '||p_data_source.calendar.end_period_relation_name||'('||p_data_source.calendar.aw_dim||' '||
2853         p_data_source.calendar.denorm_relation_name||'('||p_data_source.calendar.aw_dim||' '||p_data_source.calendar.periodicity(1).aw_dim||' '||
2854         p_data_source.calendar.end_period_level_name_dim||' \'''||l_upper_periodicity(j)||'\'') '||
2855         p_data_source.calendar.end_period_level_name_dim||' \'''||p_data_source.calendar.periodicity(1).aw_dim||'\'') --';
2856         bsc_aw_utility.add_g_commands(g_commands,l_stmt);
2857         bsc_aw_utility.add_g_commands(g_commands,'then do --');
2858         bsc_aw_utility.add_g_commands(g_commands,l_cube_copy_stmt(j));
2859         /*set the limit cube of time also to true. this means we are simulating the time agg to come from the B table. this is important
2860         later for aggregation and target copy */
2861         bsc_aw_utility.add_g_commands(g_commands,l_limit_cube_copy_stmt(j));
2862         bsc_aw_utility.add_g_commands(g_commands,'doend --');
2863       end loop;
2864     elsif p_measures(i).measure_type=g_balance_last_value_prop then --last value balance
2865       l_balance_loaded_column:=bsc_aw_utility.get_property(p_measures(i).property,g_balance_loaded_column_prop).property_value;
2866       l_year_cube:=bsc_aw_utility.get_property(p_measures(i).property,'year cube').property_value;
2867       l_period_cube:=bsc_aw_utility.get_property(p_measures(i).property,'period cube').property_value;
2868       /*l_year_cube and l_period_cube cannot be null */
2869       if l_balance_loaded_column is not null then
2870         bsc_aw_utility.add_g_commands(g_commands,'if '||l_balance_loaded_column||' GT 0 --');
2871         bsc_aw_utility.add_g_commands(g_commands,'then do --');
2872       end if;
2873       for j in 1..l_upper_periodicity.count loop
2874         if l_cube_set.cube_set_type='datacube' then
2875           l_year_cube_stmt:=p_measures(i).cube||'('||l_cube_set.measurename_dim||' \'''||l_year_cube||'\'' ';
2876           l_period_cube_stmt:=p_measures(i).cube||'('||l_cube_set.measurename_dim||' \'''||l_period_cube||'\'' ';
2877         else
2878           l_year_cube_stmt:=l_year_cube||'(';
2879           l_period_cube_stmt:=l_period_cube||'(';
2880         end if;
2881         l_stmt:=null;
2882         for k in 1..p_data_source.dim.count loop
2883           if p_data_source.dim(k).concat='Y' then
2884             l_stmt:=l_stmt||p_data_source.dim(k).dim_name||' '||p_data_source.dim(k).levels(1).level_name||' ';
2885           end if;
2886         end loop;
2887         --time
2888         l_stmt:=l_stmt||p_data_source.calendar.aw_dim||' '||p_data_source.calendar.denorm_relation_name||'('||
2889         p_data_source.calendar.aw_dim||' '||p_data_source.calendar.periodicity(1).aw_dim||' '||
2890         p_data_source.calendar.end_period_level_name_dim||' \'''||l_upper_periodicity(j)||'\''))';
2891         l_year_cube_stmt:=l_year_cube_stmt||l_stmt;
2892         l_period_cube_stmt:=l_period_cube_stmt||l_stmt;
2893         bsc_aw_utility.add_g_commands(g_commands,'if '||l_year_cube_stmt||' EQ NA OR --');
2897         bsc_aw_utility.add_g_commands(g_commands,'then do --');
2894         bsc_aw_utility.add_g_commands(g_commands,g_year_temp||' GT '||l_year_cube_stmt||' OR --');
2895         bsc_aw_utility.add_g_commands(g_commands,'('||g_year_temp||' EQ '||l_year_cube_stmt||' AND --');
2896         bsc_aw_utility.add_g_commands(g_commands,g_period_temp||' GT '||l_period_cube_stmt||') --');
2898         bsc_aw_utility.add_g_commands(g_commands,l_cube_copy_stmt(j));
2899         bsc_aw_utility.add_g_commands(g_commands,l_limit_cube_copy_stmt(j));
2900         /*we must set the upper year and period values also */
2901         bsc_aw_utility.add_g_commands(g_commands,l_year_cube_stmt||'='||g_year_temp||' --');
2902         bsc_aw_utility.add_g_commands(g_commands,l_period_cube_stmt||'='||g_period_temp||' --');
2903         bsc_aw_utility.add_g_commands(g_commands,'doend --');
2904       end loop;
2905       if l_balance_loaded_column is not null then
2906         bsc_aw_utility.add_g_commands(g_commands,'doend --');
2907       end if;
2908     end if;
2909   end loop;
2910 Exception when others then
2911   log_n('Exception in create_balance_aggregation,dimset='||p_dim_set.dim_set_name||' '||sqlerrm);
2912   raise;
2913 End;
2914 
2915 /*
2916 this procedure will create the :match header. we have this procesure in place because the following will need it.
2917 creation of generic load program for all measures
2918 creation of load program per measure (10g)
2919 creation of limit cube program (10g)
2920 we have this so we can avoid repeating the code
2921 */
2922 procedure create_dim_match_header(p_data_source data_source_r) is
2923 Begin
2924   bsc_aw_utility.add_g_commands(g_commands,'sql open c1');
2925   --even after arun changed the filter to be like (select code from dim_view), import does not work. this means
2926   --if there is filter, we have to have fetch loop...
2927   if bsc_aw_utility.get_property(p_data_source.property,'dimension filter').property_value='Y'
2928   or bsc_aw_utility.get_property(p_data_source.property,g_balance_last_value_prop).property_value='Y' then
2929     bsc_aw_utility.add_g_commands(g_commands,'sql fetch c1 loop into --');
2930   else
2931     bsc_aw_utility.add_g_commands(g_commands,'sql import c1 into --');
2932   end if;
2933   for i in 1..p_data_source.dim.count loop
2934     bsc_aw_utility.add_g_commands(g_commands,':match '||p_data_source.dim(i).levels(1).level_name||' --');
2935   end loop;
2936   --std dim
2937   for i in 1..p_data_source.std_dim.count loop
2938     bsc_aw_utility.add_g_commands(g_commands,':match '||p_data_source.std_dim(i).levels(1).level_name||' --');
2939   end loop;
2940   --time dim. data source will only have 1 periodicity, the periodicity of the base table
2941   bsc_aw_utility.add_g_commands(g_commands,':match '||p_data_source.calendar.periodicity(1).aw_dim||' --');
2942   if bsc_aw_utility.get_property(p_data_source.property,g_balance_last_value_prop).property_value='Y' then
2943     /*we need to place period and year values into the temp variables */
2944     bsc_aw_utility.add_g_commands(g_commands,':'||g_period_temp||' --');
2945     bsc_aw_utility.add_g_commands(g_commands,':'||g_year_temp||' --');
2946   end if;
2947 Exception when others then
2948   log_n('Exception in create_dim_match_header '||sqlerrm);
2949   raise;
2950 End;
2951 
2952 /*
2953 creates the trailing :limit cube stmt. here in place to avoid duplicating code
2954 needed by generic program for all measures and the program for individual measures and limit cubes
2955 */
2956 procedure create_limit_cube_tail(p_data_source data_source_r) is
2957 Begin
2958   for i in 1..p_data_source.dim.count loop
2959     if p_data_source.dim(i).concat='Y' then
2960       bsc_aw_utility.add_g_commands(g_commands,':'||p_data_source.dim(i).limit_cube||'('||
2961       p_data_source.dim(i).dim_name||' '||p_data_source.dim(i).levels(1).level_name||') --');
2962     else
2963       bsc_aw_utility.add_g_commands(g_commands,':'||p_data_source.dim(i).limit_cube||' --');
2964     end if;
2965   end loop;
2966   --limit cubes for std dim...std dim are not concat
2967   for i in 1..p_data_source.std_dim.count loop
2968     bsc_aw_utility.add_g_commands(g_commands,':'||p_data_source.std_dim(i).limit_cube||' --');
2969   end loop;
2970   --we dont need to have std dim since they do not have concat dim
2971   --time dim
2972   bsc_aw_utility.add_g_commands(g_commands,':'||p_data_source.calendar.limit_cube||'('||
2973   p_data_source.calendar.aw_dim||' '||p_data_source.calendar.periodicity(1).aw_dim||') --');
2974 Exception when others then
2975   log_n('Exception in create_limit_cube_tail '||sqlerrm);
2976   raise;
2977 End;
2978 
2979 /*
2980 this procedure creates the program that can load in parallel the dim limit cubes and the measures
2981 the program will look as
2982 --data source 1
2983 if findchars(MEASURE1) GT 0
2984 then do
2985   select dim1,dim2,measure1 from B1 where ...
2986   sql import into :match dim1 :match dim2 :cube1(..)
2987 doend
2988 if findchars(MEASURE2) GT 0
2989 then do
2990   select dim1,dim2,measure2 from B1 where ...
2991   sql import into :match dim1 :match dim2 :cube1(..)
2992 doend
2993 if findchars(LIMIT CUBE) GT 0
2994 then do
2995   select dim1,dim2,1,1,1.. from B1 where ...
2996   sql import into :match dim1 :match dim2 :limitcube1,limitcube2...(..)
2997 doend
2998 --data source 2
2999 if findchars(MEASURE1) GT 0
3000 then do
3001   select dim1,dim2,measure1 from B2 where ...
3002   sql import into :match dim1 :match dim2 :cube1(..)
3003 doend
3004 if findchars(LIMIT CUBE) GT 0
3005 then do
3006   select dim1,dim2,1,1,1.. from B2 where ...
3007   sql import into :match dim1 :match dim2 :limitcube1,limitcube2...(..)
3008 doend
3009 */
3010 procedure create_kpi_program_parallel(p_kpi in out nocopy kpi_r) is
3011 Begin
3012   for i in 1..p_kpi.dim_set.count loop
3013     if p_kpi.dim_set(i).number_partitions>0 then
3014       create_kpi_program_LB_resync(p_kpi,p_kpi.dim_set(i));
3018       create_kpi_program_cube(p_kpi,p_kpi.dim_set(i),'initial');
3015       create_kpi_program_partition(p_kpi,p_kpi.dim_set(i),'initial');
3016       create_kpi_program_partition(p_kpi,p_kpi.dim_set(i),'inc');
3017     else
3019       create_kpi_program_cube(p_kpi,p_kpi.dim_set(i),'inc');
3020     end if;
3021   end loop;
3022   --if targets are implemented, create load programs for targets also
3023   for i in 1..p_kpi.target_dim_set.count loop
3024     if p_kpi.target_dim_set(i).dim_set is not null then
3025       if p_kpi.target_dim_set(i).number_partitions>0 then
3026         create_kpi_program_LB_resync(p_kpi,p_kpi.target_dim_set(i));
3027         create_kpi_program_partition(p_kpi,p_kpi.target_dim_set(i),'initial');
3028         create_kpi_program_partition(p_kpi,p_kpi.target_dim_set(i),'inc');
3029       else
3030         create_kpi_program_cube(p_kpi,p_kpi.target_dim_set(i),'initial');
3031         create_kpi_program_cube(p_kpi,p_kpi.target_dim_set(i),'inc');
3032       end if;
3033     end if;
3034   end loop;
3035 Exception when others then
3036   log_n('Exception in create_kpi_program_parallel '||sqlerrm);
3037   raise;
3038 End;
3039 
3040 /*
3041 this procedure creates the program that can load in parallel the dim limit cubes and the measures
3042 */
3043 procedure create_kpi_program_cube(
3044 p_kpi kpi_r,
3045 p_dim_set in out nocopy dim_set_r,
3046 p_mode varchar2) is
3047 --
3048 l_data_source data_source_tb;
3049 l_pgm varchar2(300);
3050 l_cube_measures measure_tb;
3051 l_cube_considered dbms_sql.varchar2_table;
3052 Begin
3053   g_commands.delete;
3054   if p_mode='initial' then
3055     set_program_property(p_dim_set.initial_load_program_parallel,p_dim_set.data_source);
3056     l_pgm:=p_dim_set.initial_load_program_parallel.program_name;
3057     l_data_source:=p_dim_set.data_source;
3058   else
3059     set_program_property(p_dim_set.inc_load_program_parallel,p_dim_set.inc_data_source);
3060     l_pgm:=p_dim_set.inc_load_program_parallel.program_name;
3061     l_data_source:=p_dim_set.inc_data_source;
3062   end if;
3063   bsc_aw_utility.add_g_commands(g_commands,'dfn '||l_pgm||' program');
3064   for i in 1..l_data_source.count loop
3065     l_cube_considered.delete;
3066     for j in 1..l_data_source(i).measure.count loop
3067       if bsc_aw_utility.in_array(l_cube_considered,l_data_source(i).measure(j).cube)=false then
3068         l_cube_considered(l_cube_considered.count+1):=l_data_source(i).measure(j).cube;
3069       end if;
3070     end loop;
3071     for j in 1..l_cube_considered.count loop
3072       l_cube_measures.delete;
3073       for k in 1..l_data_source(i).measure.count loop
3074         if l_data_source(i).measure(k).cube=l_cube_considered(j) then
3075           l_cube_measures(l_cube_measures.count+1):=l_data_source(i).measure(k);
3076         end if;
3077       end loop;
3078       create_kpi_program_cube(p_kpi,p_dim_set,get_cube_set_r(l_cube_considered(j),p_dim_set),l_cube_measures,l_data_source(i));
3079     end loop;
3080     --limit cubes
3081     create_kpi_program_limit_cube(p_kpi,p_dim_set,l_data_source(i));
3082   end loop;
3083   bsc_aw_utility.exec_program_commands(l_pgm,g_commands);
3084 Exception when others then
3085   log_n('Exception in create_kpi_program_cube 2 '||sqlerrm);
3086   raise;
3087 End;
3088 
3089 /*
3090 this procedure adds to the program that loads measures in parallel. input is a measure and a data source. if the datasource
3091 has the measure, then create the program stmt
3092 */
3093 procedure create_kpi_program_cube(
3094 p_kpi kpi_r,
3095 p_dim_set dim_set_r,
3096 p_cube_set cube_set_r,
3097 p_measures measure_tb,
3098 p_data_source data_source_r) is
3099 --
3100 l_measure_index number;
3101 l_stmt varchar(4000);
3102 l_measures dbms_sql.varchar2_table;
3103 l_ordered_b_tables dbms_sql.varchar2_table;
3104 l_balance_loaded_column varchar2(40);
3105 Begin
3106   for i in 1..p_measures.count loop
3107     l_measures(i):=p_measures(i).measure;
3108   end loop;
3109   for i in 1..p_data_source.base_tables.count loop
3110     bsc_aw_utility.merge_value(l_ordered_b_tables,p_data_source.base_tables(i).base_table_name);
3111   end loop;
3112   l_ordered_b_tables:=bsc_aw_utility.order_array(l_ordered_b_tables);
3113   bsc_aw_utility.add_g_commands(g_commands,'if arg(1) EQ \'''||bsc_aw_utility.make_string_from_list(l_ordered_b_tables)||'\'' --');
3114   bsc_aw_utility.add_g_commands(g_commands,' AND arg(2) EQ \'''||upper(p_cube_set.cube.cube_name)||',\'' ');
3115   bsc_aw_utility.add_g_commands(g_commands,'then do');
3116   /*temp variables period.temp and year.temp hold the period and year values. they are present in all cube loading programs. they are used when we
3117   have BALANCE LAST VALUE type measure */
3118   create_temp_variables(p_dim_set,p_data_source);
3119   --if compressed composite, clear the aggregates. if < 10.2
3120   if p_dim_set.compressed='Y' and bsc_aw_utility.get_db_version<10.2 then
3121     bsc_aw_utility.add_g_commands(g_commands,'clear all aggregates from '||p_cube_set.cube.cube_name);
3122   end if;
3123   --we do not have limit cubes. only the sql, dim and the measure we are looking at
3124   for i in 1..p_data_source.data_source_stmt.count loop
3125     if substr(p_data_source.data_source_stmt_type(i),1,3)='sql' or substr(p_data_source.data_source_stmt_type(i),1,10)='dimension=' or
3126     substr(p_data_source.data_source_stmt_type(i),1,10)='temp time=' then
3127       if p_data_source.data_source_stmt_type(i)='sql from' then
3128         if substr(bsc_aw_utility.get_g_commands(g_commands,null),-4)=', --' then
3129           bsc_aw_utility.trim_g_commands(g_commands,4,' --'); --remove the trailing ,
3130         end if;
3131       end if;
3132       bsc_aw_utility.add_g_commands(g_commands,p_data_source.data_source_stmt(i)||' --');
3133     elsif substr(p_data_source.data_source_stmt_type(i),1,8)='measure=' then
3134       if bsc_aw_utility.in_array(l_measures,substr(p_data_source.data_source_stmt_type(i),9,length(p_data_source.data_source_stmt_type(i)))) then
3138       if bsc_aw_utility.in_array(l_measures,substr(p_data_source.data_source_stmt_type(i),28,length(p_data_source.data_source_stmt_type(i)))) then
3135         bsc_aw_utility.add_g_commands(g_commands,p_data_source.data_source_stmt(i)||' --');
3136       end if;
3137     elsif substr(p_data_source.data_source_stmt_type(i),1,27)='temp balance loaded column=' then /*temp balance loaded column=measure name */
3139         bsc_aw_utility.add_g_commands(g_commands,p_data_source.data_source_stmt(i)||' --');
3140       end if;
3141     end if;
3142   end loop;
3143   bsc_aw_utility.trim_g_commands(g_commands,3,null);
3144   create_dim_match_header(p_data_source);
3145   --now the cube for the measures
3146   for i in 1..p_measures.count loop
3147     l_stmt:=':'||p_cube_set.cube.cube_name||'('; --time will always be concat
3148     if p_cube_set.cube_set_type='datacube' then
3149       l_stmt:=l_stmt||p_cube_set.measurename_dim||' \'''||p_measures(i).measure||'\'' ';
3150     end if;
3151     for j in 1..p_data_source.dim.count loop
3152       if p_data_source.dim(j).concat='Y' then
3153         l_stmt:=l_stmt||p_data_source.dim(j).dim_name||' '||p_data_source.dim(j).levels(1).level_name||' ';
3154       end if;
3155     end loop;
3156     --time
3157     l_stmt:=l_stmt||p_data_source.calendar.aw_dim||' '||p_data_source.calendar.periodicity(1).aw_dim||' ';
3158     l_stmt:=l_stmt||') --';
3159     bsc_aw_utility.add_g_commands(g_commands,l_stmt);
3160   end loop;
3161   for i in 1..p_measures.count loop
3162     if p_measures(i).measure_type=g_balance_last_value_prop then
3163       /*if this is a BALANCE LAST VALUE column, also grab the loaded Y/N column */
3164       l_balance_loaded_column:=bsc_aw_utility.get_property(p_measures(i).property,g_balance_loaded_column_prop).property_value;
3165       if l_balance_loaded_column is not null then
3166         bsc_aw_utility.add_g_commands(g_commands,':'||l_balance_loaded_column||' --');
3167       end if;
3168     end if;
3169   end loop;
3170   /*have a then stmt. if there are balance measures, we need the then */
3171   bsc_aw_utility.add_g_commands(g_commands,'then --');
3172   bsc_aw_utility.add_g_commands(g_commands,'temp_number=NA --');
3173   --if there is balance, add the balance aggregation statements
3174   create_balance_aggregation(p_dim_set,p_data_source,p_measures);
3175   --
3176   bsc_aw_utility.trim_g_commands(g_commands,3,null);
3177   bsc_aw_utility.add_g_commands(g_commands,'sql close c1');
3178   bsc_aw_utility.add_g_commands(g_commands,'sql cleanup');
3179   bsc_aw_utility.add_g_commands(g_commands,'doend');
3180 Exception when others then
3181   log_n('Exception in create_kpi_program_cube 3 '||sqlerrm);
3182   raise;
3183 End;
3184 
3185 /*
3186 this program is reqd when we have partitions. the dim LB is the same across partition loads. we need to acquire lock with
3187 resync at the end on the LB. resync discards private data changes. so before getting the lock, we save the state to session
3188 variables, get the lock, then merge the status from session variables into LB and then save it back. so the program has a
3189 pre and post part
3190 */
3191 procedure create_kpi_program_LB_resync(
3192 p_kpi kpi_r,
3193 p_dim_set in out nocopy dim_set_r
3194 ) is
3195 --
3196 l_kpi varchar2(200);
3197 l_name varchar2(200);
3198 Begin
3199   l_kpi:=p_kpi.kpi;
3200   if p_dim_set.dim_set_type='target' then
3201     l_kpi:=l_kpi||'.tgt';
3202   end if;
3203   p_dim_set.LB_resync_program:='LB.resync.'||p_dim_set.dim_set||'.'||l_kpi;
3204   g_commands.delete;
3205   bsc_aw_utility.add_g_commands(g_commands,'dfn '||p_dim_set.LB_resync_program||' program');
3206   --all LB of the dimset
3207   bsc_aw_utility.add_g_commands(g_commands,'if arg(1) EQ \''PRE\'' ');
3208   bsc_aw_utility.add_g_commands(g_commands,'then do');
3209   for i in 1..p_dim_set.dim.count loop
3210     l_name:=p_dim_set.dim(i).limit_cube||'.S';
3211     bsc_aw_utility.add_g_commands(g_commands,'if exists(\'''||l_name||'\'') eq false');
3212     bsc_aw_utility.add_g_commands(g_commands,'then do');
3213     bsc_aw_utility.add_g_commands(g_commands,'dfn '||l_name||' boolean <'||p_dim_set.dim(i).dim_name||'> session');
3214     bsc_aw_utility.add_g_commands(g_commands,'doend');
3215   end loop;
3216   for i in 1..p_dim_set.std_dim.count loop
3217     l_name:=p_dim_set.std_dim(i).limit_cube||'.S';
3218     bsc_aw_utility.add_g_commands(g_commands,'if exists(\'''||l_name||'\'') eq false');
3219     bsc_aw_utility.add_g_commands(g_commands,'then do');
3220     bsc_aw_utility.add_g_commands(g_commands,'dfn '||l_name||' boolean <'||p_dim_set.std_dim(i).dim_name||'> session');
3221     bsc_aw_utility.add_g_commands(g_commands,'doend');
3222   end loop;
3223   l_name:=p_dim_set.calendar.limit_cube||'.S';
3224   bsc_aw_utility.add_g_commands(g_commands,'if exists(\'''||l_name||'\'') eq false');
3225   bsc_aw_utility.add_g_commands(g_commands,'then do');
3226   bsc_aw_utility.add_g_commands(g_commands,'dfn '||l_name||' boolean <'||p_dim_set.calendar.aw_dim||'> session');
3227   bsc_aw_utility.add_g_commands(g_commands,'doend');
3228   --
3229   for i in 1..p_dim_set.dim.count loop
3230     bsc_aw_utility.add_g_commands(g_commands,'push '||p_dim_set.dim(i).dim_name);
3231     bsc_aw_utility.add_g_commands(g_commands,'limit '||p_dim_set.dim(i).dim_name||' to '||p_dim_set.dim(i).limit_cube);
3232     bsc_aw_utility.add_g_commands(g_commands,p_dim_set.dim(i).limit_cube||'.S=true');
3233     bsc_aw_utility.add_g_commands(g_commands,'pop '||p_dim_set.dim(i).dim_name);
3234   end loop;
3235   for i in 1..p_dim_set.std_dim.count loop
3236     bsc_aw_utility.add_g_commands(g_commands,'push '||p_dim_set.std_dim(i).dim_name);
3237     bsc_aw_utility.add_g_commands(g_commands,'limit '||p_dim_set.std_dim(i).dim_name||' to '||p_dim_set.std_dim(i).limit_cube);
3238     bsc_aw_utility.add_g_commands(g_commands,p_dim_set.std_dim(i).limit_cube||'.S=true');
3239     bsc_aw_utility.add_g_commands(g_commands,'pop '||p_dim_set.std_dim(i).dim_name);
3240   end loop;
3241   bsc_aw_utility.add_g_commands(g_commands,'push '||p_dim_set.calendar.aw_dim);
3245   --
3242   bsc_aw_utility.add_g_commands(g_commands,'limit '||p_dim_set.calendar.aw_dim||' to '||p_dim_set.calendar.limit_cube);
3243   bsc_aw_utility.add_g_commands(g_commands,p_dim_set.calendar.limit_cube||'.S=true');
3244   bsc_aw_utility.add_g_commands(g_commands,'pop '||p_dim_set.calendar.aw_dim);
3246   bsc_aw_utility.add_g_commands(g_commands,'doend');
3247   --
3248   bsc_aw_utility.add_g_commands(g_commands,'if arg(1) EQ \''POST\'' ');
3249   bsc_aw_utility.add_g_commands(g_commands,'then do');
3250   for i in 1..p_dim_set.dim.count loop
3251     bsc_aw_utility.add_g_commands(g_commands,'push '||p_dim_set.dim(i).dim_name);
3252     bsc_aw_utility.add_g_commands(g_commands,'limit '||p_dim_set.dim(i).dim_name||' to '||p_dim_set.dim(i).limit_cube||'.S');
3253     bsc_aw_utility.add_g_commands(g_commands,p_dim_set.dim(i).limit_cube||'=true');
3254     bsc_aw_utility.add_g_commands(g_commands,'pop '||p_dim_set.dim(i).dim_name);
3255   end loop;
3256   for i in 1..p_dim_set.std_dim.count loop
3257     bsc_aw_utility.add_g_commands(g_commands,'push '||p_dim_set.std_dim(i).dim_name);
3258     bsc_aw_utility.add_g_commands(g_commands,'limit '||p_dim_set.std_dim(i).dim_name||' to '||p_dim_set.std_dim(i).limit_cube||'.S');
3259     bsc_aw_utility.add_g_commands(g_commands,p_dim_set.std_dim(i).limit_cube||'=true');
3260     bsc_aw_utility.add_g_commands(g_commands,'pop '||p_dim_set.std_dim(i).dim_name);
3261   end loop;
3262   bsc_aw_utility.add_g_commands(g_commands,'push '||p_dim_set.calendar.aw_dim);
3263   bsc_aw_utility.add_g_commands(g_commands,'limit '||p_dim_set.calendar.aw_dim||' to '||p_dim_set.calendar.limit_cube||'.S');
3264   bsc_aw_utility.add_g_commands(g_commands,p_dim_set.calendar.limit_cube||'=true');
3265   bsc_aw_utility.add_g_commands(g_commands,'pop '||p_dim_set.calendar.aw_dim);
3266   bsc_aw_utility.add_g_commands(g_commands,'doend');
3267   --
3268   bsc_aw_utility.exec_program_commands(p_dim_set.LB_resync_program,g_commands);
3269 Exception when others then
3270   log_n('Exception in create_kpi_program_LB_resync '||sqlerrm);
3271   raise;
3272 End;
3273 
3274 procedure create_kpi_program_partition(
3275 p_kpi kpi_r,
3276 p_dim_set in out nocopy dim_set_r,
3277 p_mode varchar2) is
3278 --
3279 l_pgm varchar2(300);
3280 l_data_source data_source_tb;
3281 l_partition_template partition_template_r;
3282 l_pt_name varchar2(200);
3283 Begin
3284   g_commands.delete;
3285   if p_mode='initial' then
3286     set_program_property(p_dim_set.initial_load_program_parallel,p_dim_set.data_source);
3287     l_pgm:=p_dim_set.initial_load_program_parallel.program_name;
3288     l_data_source:=p_dim_set.data_source;
3289   else
3290     set_program_property(p_dim_set.inc_load_program_parallel,p_dim_set.inc_data_source);
3291     l_pgm:=p_dim_set.inc_load_program_parallel.program_name;
3292     l_data_source:=p_dim_set.inc_data_source;
3293   end if;
3294   bsc_aw_utility.add_g_commands(g_commands,'dfn '||l_pgm||' program');
3295   --
3296   for i in 1..l_data_source.count loop
3297     l_pt_name:=get_cube_axis(l_data_source(i).measure(1).cube,p_dim_set,'partition template');
3298     --note>>> all measures of a data source share a PT. a cube can have at most 1 PT
3299     l_partition_template:=get_partition_template_r(l_pt_name,p_dim_set);
3300     for j in 1..l_partition_template.template_partitions.count loop
3301       create_kpi_program_partition(p_kpi,l_partition_template.template_partitions(j),p_dim_set,l_data_source(i),j);
3302     end loop;
3303   end loop;
3304   bsc_aw_utility.exec_program_commands(l_pgm,g_commands);
3305 Exception when others then
3306   log_n('Exception in create_kpi_program_partition '||sqlerrm);
3307   raise;
3308 End;
3309 
3310 /*
3311 we loop through the data source and fix the where clause to add the 'where partition_dim=partition_dim_value'
3312 */
3313 procedure create_kpi_program_partition(
3314 p_kpi kpi_r,
3315 template_partition partition_r,
3316 p_dim_set in out nocopy dim_set_r,
3317 p_data_source data_source_r,
3318 partition_index number --1,2,3,4 etc
3319 ) is
3320 --
3321 l_data_source data_source_r;
3322 i integer;
3323 l_partition_stmt varchar2(4000);
3324 l_partition_type varchar2(40);
3325 l_cubes dbms_sql.varchar2_table;
3326 l_property_value varchar2(4000);
3327 Begin
3328   l_data_source:=p_data_source;
3329   i:=1;
3330   loop
3331     if l_data_source.data_source_stmt_type(i)='partition dim list' then
3332       l_partition_type:='list';
3333     elsif l_data_source.data_source_stmt_type(i)='partition dim hash' then
3334       /*l_partition_stmt will look like
3335       dbms_utility.get_hash_value(RELEASE_CODE||'-'||COMPO_CODE||'-'||CITY_CODE||'-'||PER_CODE||'-'||TYPE||'-'||PROJECTION||'-'||
3336       period||'.'||year,0,4) hash_partition_dim,
3337       so we need to substr this to remove the hash_partition_dim,   look for the last )
3338       */
3339       l_partition_stmt:=l_data_source.data_source_stmt(i);
3340       l_partition_stmt:=substr(l_partition_stmt,1,instr(l_partition_stmt,')',-1));
3341       l_partition_type:='hash';
3342     end if;
3343     if l_partition_type='hash' and l_data_source.data_source_stmt_type(i)='sql where' and l_data_source.data_source_stmt(i)=' where 1=1 ' then
3344       --we add partition filter to the DS stmt
3345       l_data_source.data_source_stmt(i):=l_data_source.data_source_stmt(i)||'and '||template_partition.partition_dim_value||'='||
3346       l_partition_stmt;
3347     end if;
3348     if l_partition_type='list' and l_data_source.data_source_stmt_type(i)='sql from table' and l_data_source.data_source_stmt(i)=' where 1=1 ' then
3349       --we add partition filter to the B table stmt
3350       if l_data_source.base_tables(1).table_partition.main_partition.partition_column_data_type='NUMBER' then
3351         l_data_source.data_source_stmt(i):=l_data_source.data_source_stmt(i)||'and '||
3352         l_data_source.base_tables(1).table_partition.main_partition.partitions(partition_index).partition_value||'='||
3353         l_data_source.base_tables(1).table_partition.main_partition.partition_column;
3354       else
3358       end if;
3355         l_data_source.data_source_stmt(i):=l_data_source.data_source_stmt(i)||'and '||
3356         '\'''||l_data_source.base_tables(1).table_partition.main_partition.partitions(partition_index).partition_value||'\''='||
3357         l_data_source.base_tables(1).table_partition.main_partition.partition_column;
3359     end if;
3360     i:=i+1;
3361     if i>l_data_source.data_source_stmt.count then
3362       exit;
3363     end if;
3364   end loop;
3365   --
3366   for i in 1..l_data_source.measure.count loop
3367     if bsc_aw_utility.in_array(l_cubes,l_data_source.measure(i).cube)=false then
3368       l_cubes(l_cubes.count+1):=l_data_source.measure(i).cube;
3369     end if;
3370   end loop;
3371   l_property_value:='AND (';
3372   for i in 1..l_cubes.count loop
3373     l_property_value:=l_property_value||'arg(2) EQ \'''||l_cubes(i)||',\'' OR ';
3374   end loop;
3375   l_property_value:=substr(l_property_value,1,length(l_property_value)-3);
3376   l_property_value:=l_property_value||') AND arg(3) EQ \''partition='||template_partition.partition_name||',\'' ';
3377   bsc_aw_utility.merge_property(l_data_source.property,'datasource filter',null,l_property_value);
3378   bsc_aw_utility.merge_property(l_data_source.property,'partition',null,template_partition.partition_name);
3379   --
3380   create_kpi_program(p_kpi,p_dim_set,l_data_source);
3381 Exception when others then
3382   log_n('Exception in create_kpi_program_partition '||sqlerrm);
3383   raise;
3384 End;
3385 
3386 /*
3387 used to create the program where measures and limit cubes run in parallel
3388 */
3389 procedure create_kpi_program_limit_cube(
3390 p_kpi kpi_r,
3391 p_dim_set dim_set_r,
3392 p_data_source data_source_r) is
3393 l_ordered_b_tables dbms_sql.varchar2_table;
3394 Begin
3395   for i in 1..p_data_source.base_tables.count loop
3396     bsc_aw_utility.merge_value(l_ordered_b_tables,p_data_source.base_tables(i).base_table_name);
3397   end loop;
3398   l_ordered_b_tables:=bsc_aw_utility.order_array(l_ordered_b_tables);
3399   bsc_aw_utility.add_g_commands(g_commands,'if arg(1) EQ \'''||bsc_aw_utility.make_string_from_list(l_ordered_b_tables)||'\'' --');
3400   bsc_aw_utility.add_g_commands(g_commands,' AND arg(2) EQ \''LIMIT CUBE\'' ');
3401   bsc_aw_utility.add_g_commands(g_commands,'then do');
3402   create_temp_variables(p_dim_set,p_data_source);
3403   for i in 1..p_data_source.data_source_stmt.count loop
3404     if p_data_source.data_source_stmt_type(i)='sql from' then
3405       if substr(bsc_aw_utility.get_g_commands(g_commands,null),-4)=', --' then
3406         bsc_aw_utility.trim_g_commands(g_commands,4,' --'); --remove the trailing ,
3407       end if;
3408     end if;
3409     if substr(p_data_source.data_source_stmt_type(i),1,3)='sql' or
3410     substr(p_data_source.data_source_stmt_type(i),1,10)='dimension=' or
3411     substr(p_data_source.data_source_stmt_type(i),1,10)='temp time=' or
3412     substr(p_data_source.data_source_stmt_type(i),1,11)='limit cube=' then
3413       bsc_aw_utility.add_g_commands(g_commands,p_data_source.data_source_stmt(i)||' --');
3414     end if;
3415   end loop;
3416   bsc_aw_utility.trim_g_commands(g_commands,3,null);
3417   create_dim_match_header(p_data_source);
3418   create_limit_cube_tail(p_data_source);
3419   bsc_aw_utility.trim_g_commands(g_commands,3,null);
3420   bsc_aw_utility.add_g_commands(g_commands,'sql close c1');
3421   bsc_aw_utility.add_g_commands(g_commands,'sql cleanup');
3422   bsc_aw_utility.add_g_commands(g_commands,'doend');
3423 Exception when others then
3424   log_n('Exception in create_kpi_program_limit_cube '||sqlerrm);
3425   raise;
3426 End;
3427 
3428 /*
3429 used in create_kpi_program to see if we need to use sql fetch c1 loop into or import
3430 import is faster but filter has hardcoded numbers that import does not allow.
3431 */
3432 function is_filter_in_data_source(
3433 p_data_source data_source_r
3434 )return varchar2 is
3435 Begin
3436   for i in 1..p_data_source.dim.count loop
3437     if p_data_source.dim(i).levels(1).filter.count > 0 then
3438       return 'Y';
3439     end if;
3440   end loop;
3441   return 'N';
3442 Exception when others then
3443   log_n('Exception in is_filter_in_data_source '||sqlerrm);
3444   raise;
3445 End;
3446 
3447 function is_balance_last_value_in_DS(p_data_source data_source_r) return varchar2 is
3448 Begin
3449   for i in 1..p_data_source.measure.count loop
3450     if p_data_source.measure(i).measure_type=g_balance_last_value_prop then
3451       return 'Y';
3452     end if;
3453   end loop;
3454   return 'N';
3455 Exception when others then
3456   log_n('Exception in is_balance_last_value_in_DS '||sqlerrm);
3457   raise;
3458 End;
3459 
3460 /*
3461 creates the S views. we dont create the SB views since they are never queried directly
3462 we do have SB cubes though
3463 
3464 create kpi view and create type must be autonomous transactions. otherwise, they result in
3465 implicit commit
3466 */
3467 procedure create_kpi_view(p_kpi in out nocopy kpi_r) is
3468 PRAGMA AUTONOMOUS_TRANSACTION;
3469 Begin
3470   for i in 1..p_kpi.dim_set.count loop
3471     create_kpi_view(p_kpi,p_kpi.dim_set(i));
3472   end loop;
3473 Exception when others then
3474   log_n('Exception in create_kpi_view '||sqlerrm);
3475   raise;
3476 End;
3477 
3478 procedure create_kpi_view(p_kpi kpi_r,p_dim_set in out nocopy dim_set_r) is
3479 PRAGMA AUTONOMOUS_TRANSACTION;
3480 Begin
3481   create_db_type(p_kpi,p_dim_set);
3482   --std S MV
3483   for i in 1..p_dim_set.s_view.count loop
3484     create_kpi_view(p_kpi,p_dim_set,p_dim_set.s_view(i),'mv');
3485   end loop;
3486   --
3487   --Zero code MV
3488   for i in 1..p_dim_set.z_s_view.count loop
3489     create_kpi_view(p_kpi,p_dim_set,p_dim_set.z_s_view(i),'zmv');
3490   end loop;
3491 Exception when others then
3495 
3492   log_n('Exception in create_kpi_view '||sqlerrm);
3493   raise;
3494 End;
3496 /*s view dim have 1 level
3497 */
3498 procedure create_kpi_view(p_kpi kpi_r,p_dim_set dim_set_r,p_s_view s_view_r,p_type varchar2) is
3499 PRAGMA AUTONOMOUS_TRANSACTION;
3500 --
3501 l_dimensions dbms_sql.varchar2_table;
3502 l_outer_measures dbms_sql.varchar2_table;
3503 l_outer_measure_agg_types dbms_sql.varchar2_table;
3504 l_outer_measure_aggregations dbms_sql.varchar2_table;/*holds the agg formula */
3505 l_inner_measures dbms_sql.varchar2_table;
3506 l_inner_select_columns dbms_sql.varchar2_table;
3507 l_inner_select_column_types dbms_sql.varchar2_table;/*fk or measure */
3508 l_name varchar2(30);
3509 l_inner_stmt varchar2(32000);
3510 l_sql_agg_stmt varchar2(32000);
3511 sql_aggregation boolean;
3512 Begin
3513   sql_aggregation:=false;
3514   l_inner_stmt:=' from table (
3515   olap_table('''||bsc_aw_management.get_aw_workspace_name||' duration session'','''||p_s_view.type_table_name||''','''',
3516   ''';
3517   for i in 1..p_s_view.dim.count loop
3518     if p_s_view.dim(i).levels(1).level_type='normal' then
3519       if p_s_view.dim(i).base_value_cube is not null then
3520         --use get_hash to make sure we are within 30 chars
3521         l_name:='D_'||bsc_aw_utility.get_hash_value(p_s_view.dim(i).dim_name||'.'||p_s_view.dim(i).levels(1).level_name||'.'||i,
3522         100,1073741824);
3523         l_inner_stmt:=l_inner_stmt||' dimension '||l_name||' from '||p_s_view.dim(i).dim_name||bsc_aw_utility.g_newline;
3524         l_dimensions(l_dimensions.count+1):=l_name;
3525         l_inner_stmt:=l_inner_stmt||' with attribute '||p_s_view.dim(i).levels(1).fk||' from '||p_s_view.dim(i).base_value_cube||
3526         bsc_aw_utility.g_newline;
3527         l_inner_measures(l_inner_measures.count+1):=p_s_view.dim(i).levels(1).fk;
3528         l_inner_select_columns(l_inner_select_columns.count+1):=p_s_view.dim(i).levels(1).fk;
3529         l_inner_select_column_types(l_inner_select_column_types.count+1):='fk';
3530       else
3531         --if a rec dim, we must be referncing  the parent level
3532         if p_s_view.dim(i).levels(1).rec_parent_level is not null then
3533           l_inner_stmt:=l_inner_stmt||' dimension '||p_s_view.dim(i).levels(1).fk||' from '||p_s_view.dim(i).levels(1).rec_parent_level||'
3534           ';
3535           /*elsif p_type='zmv' and p_s_view.dim(i).levels(1).zero_code_level is not null then
3536           l_inner_stmt:=l_inner_stmt||' dimension '||p_s_view.dim(i).levels(1).fk||' from '||p_s_view.dim(i).levels(1).zero_code_level||'
3537           ';
3538           cannot have this...the zero code mv must be based on regular levels. if we base it on zero code level
3539           how can we limit dim to any other value? zero code mv has 0 and other values.
3540           so we need to limit zero code levelto 0, limit dim to zero code level, then limit level to 0
3541           so when we query from the mv, we will see the level value as 0 and also see the measure value for "all"
3542           */
3543         else
3544           l_inner_stmt:=l_inner_stmt||' dimension '||p_s_view.dim(i).levels(1).fk||' from '||p_s_view.dim(i).levels(1).level_name||'
3545           ';
3546         end if;
3547         l_inner_measures(l_inner_measures.count+1):=p_s_view.dim(i).levels(1).fk;
3548         l_inner_select_columns(l_inner_select_columns.count+1):=p_s_view.dim(i).levels(1).fk;
3549         l_inner_select_column_types(l_inner_select_column_types.count+1):='fk';
3550       end if;
3551     end if;
3552   end loop;
3553   --std dim
3554   for i in 1..p_dim_set.std_dim.count loop
3555     l_inner_stmt:=l_inner_stmt||' dimension '||p_dim_set.std_dim(i).levels(1).fk||' from '||p_dim_set.std_dim(i).levels(1).level_name||'
3556     ';
3557     l_dimensions(l_dimensions.count+1):=p_dim_set.std_dim(i).levels(1).fk;
3558     l_inner_select_columns(l_inner_select_columns.count+1):=p_dim_set.std_dim(i).levels(1).fk;
3559     l_inner_select_column_types(l_inner_select_column_types.count+1):='fk';
3560     --assume std dim are non concat?
3561   end loop;
3562   --time
3563   --all s views have period and year and periodicity
3564   l_inner_stmt:=l_inner_stmt||' measure period from period_cal_'||p_kpi.calendar||'
3565   measure year from year_cal_'||p_kpi.calendar||'
3566   measure periodicity_id from periodicity_cal_'||p_kpi.calendar||'
3567   ';
3568   l_inner_measures(l_inner_measures.count+1):='period';
3569   l_inner_measures(l_inner_measures.count+1):='year';
3570   l_inner_measures(l_inner_measures.count+1):='periodicity_id';
3571   l_inner_select_columns(l_inner_select_columns.count+1):='period';
3572   l_inner_select_column_types(l_inner_select_column_types.count+1):='fk';
3573   l_inner_select_columns(l_inner_select_columns.count+1):='year';
3574   l_inner_select_column_types(l_inner_select_column_types.count+1):='fk';
3575   l_inner_select_columns(l_inner_select_columns.count+1):='periodicity_id';
3576   l_inner_select_column_types(l_inner_select_column_types.count+1):='fk';
3577   for i in 1..p_dim_set.measure.count loop
3578     l_outer_measures(l_outer_measures.count+1):=p_dim_set.measure(i).measure;
3579     l_outer_measure_aggregations(l_outer_measure_aggregations.count+1):=p_dim_set.measure(i).agg_formula.sql_agg_formula;
3580     if p_dim_set.measure(i).sql_aggregated='N' then
3581       l_outer_measure_agg_types(l_outer_measure_agg_types.count+1):='std';
3582       l_inner_stmt:=l_inner_stmt||' measure '||p_dim_set.measure(i).measure||' from ';
3583       if p_dim_set.measure(i).aw_formula.formula_name is not null then
3584         l_inner_stmt:=l_inner_stmt||p_dim_set.measure(i).aw_formula.formula_name;
3585       else
3586         l_inner_stmt:=l_inner_stmt||p_dim_set.measure(i).cube;
3587       end if;
3588       l_inner_stmt:=l_inner_stmt||'
3589       ';
3590       l_inner_measures(l_inner_measures.count+1):=p_dim_set.measure(i).measure;
3591       l_inner_select_columns(l_inner_select_columns.count+1):=p_dim_set.measure(i).measure;
3592       l_inner_select_column_types(l_inner_select_column_types.count+1):='measure';
3593     else
3594       sql_aggregation:=true;
3598   l_inner_stmt:=l_inner_stmt||'''))';
3595       l_outer_measure_agg_types(l_outer_measure_agg_types.count+1):='non std';
3596     end if;
3597   end loop;
3599   if bsc_aw_utility.get_db_version>10.1 and l_dimensions.count>0 and l_inner_measures.count>0 then
3600     l_inner_stmt:=l_inner_stmt||bsc_aw_utility.g_newline;
3601     l_inner_stmt:=l_inner_stmt||'model'||bsc_aw_utility.g_newline;
3602     l_inner_stmt:=l_inner_stmt||'UNIQUE SINGLE REFERENCE'||bsc_aw_utility.g_newline;
3603     l_inner_stmt:=l_inner_stmt||'dimension by('||bsc_aw_utility.g_newline;
3604     for i in 1..l_dimensions.count loop
3605       if i=1 then
3606         l_inner_stmt:=l_inner_stmt||l_dimensions(i)||bsc_aw_utility.g_newline;
3607       else
3608         l_inner_stmt:=l_inner_stmt||','||l_dimensions(i)||bsc_aw_utility.g_newline;
3609       end if;
3610     end loop;
3611     l_inner_stmt:=l_inner_stmt||')'||bsc_aw_utility.g_newline;
3612     l_inner_stmt:=l_inner_stmt||'measures('||bsc_aw_utility.g_newline;
3613     for i in 1..l_inner_measures.count loop
3614       if i=1 then
3615         l_inner_stmt:=l_inner_stmt||l_inner_measures(i)||bsc_aw_utility.g_newline;
3616       else
3617         l_inner_stmt:=l_inner_stmt||','||l_inner_measures(i)||bsc_aw_utility.g_newline;
3618       end if;
3619     end loop;
3620     l_inner_stmt:=l_inner_stmt||')'||bsc_aw_utility.g_newline;
3621     l_inner_stmt:=l_inner_stmt||'rules update sequential order()';
3622   end if;
3623   /*if there is sql agg for non std measures (when there are non std agg and partitions), we need to create the stmt as (AVGBUG is the formula)
3624   create or replace view testv as
3625   select PER_CODE,COUNTRY_CODE,TYPE,PROJECTION,period,year,periodicity_id,BUGLOG,BUGLOG/BUGOPEN AVGBUG
3626   from(
3627   select PER_CODE,COUNTRY_CODE,TYPE,PROJECTION,period,year,periodicity_id,sum(BUGLOG) BUGLOG,sum(BUGOPEN) BUGOPEN
3628   from
3629   (select PER_CODE,COUNTRY_CODE,TYPE,PROJECTION,period,year,periodicity_id,BUGLOG,BUGOPEN
3630   from table (  olap_table( ...
3631   ...
3632   rules update sequential order())
3633   group by PER_CODE,COUNTRY_CODE,TYPE,PROJECTION,period,year,periodicity_id)
3634   */
3635   g_stmt:='create or replace view '||p_s_view.s_view||' as select ';
3636   if sql_aggregation then
3637     for i in 1..l_inner_select_columns.count loop
3638       if l_inner_select_column_types(i)='fk' then
3639         g_stmt:=g_stmt||l_inner_select_columns(i)||',';
3640       end if;
3641     end loop;
3642     /*now the measures */
3643     for i in 1..l_outer_measures.count loop
3644       if l_outer_measure_agg_types(i)='std' then
3645         g_stmt:=g_stmt||l_outer_measures(i)||',';
3646       else/*non std */
3647         g_stmt:=g_stmt||'('||l_outer_measure_aggregations(i)||') '||l_outer_measures(i)||',';
3648       end if;
3649     end loop;
3650     /*now the second part */
3651     g_stmt:=substr(g_stmt,1,length(g_stmt)-1);
3652     g_stmt:=g_stmt||bsc_aw_utility.g_newline;
3653     g_stmt:=g_stmt||'from (select ';
3654     for i in 1..l_inner_select_columns.count loop
3655       if l_inner_select_column_types(i)='fk' then
3656         g_stmt:=g_stmt||l_inner_select_columns(i)||',';
3657       end if;
3658     end loop;
3659     for i in 1..l_outer_measures.count loop
3660       if l_outer_measure_agg_types(i)='std' then
3661         g_stmt:=g_stmt||l_outer_measure_aggregations(i)||'('||l_outer_measures(i)||') '||l_outer_measures(i)||',';
3662       end if;
3663     end loop;
3664     g_stmt:=substr(g_stmt,1,length(g_stmt)-1);
3665     g_stmt:=g_stmt||bsc_aw_utility.g_newline;
3666     g_stmt:=g_stmt||'from (select ';
3667   end if;
3668   for i in 1..l_inner_select_columns.count loop
3669     g_stmt:=g_stmt||l_inner_select_columns(i)||',';
3670   end loop;
3671   g_stmt:=substr(g_stmt,1,length(g_stmt)-1);
3672   g_stmt:=g_stmt||l_inner_stmt;
3673   if sql_aggregation then
3674     g_stmt:=g_stmt||')'||bsc_aw_utility.g_newline;
3675     g_stmt:=g_stmt||'group by ';
3676     for i in 1..l_inner_select_columns.count loop
3677       if l_inner_select_column_types(i)='fk' then
3678         g_stmt:=g_stmt||l_inner_select_columns(i)||',';
3679       end if;
3680     end loop;
3681     g_stmt:=substr(g_stmt,1,length(g_stmt)-1);
3682     g_stmt:=g_stmt||')';
3683   end if;
3684   bsc_aw_utility.execute_ddl(g_stmt);
3685 Exception when others then
3686   log_n('Exception in create_kpi_view '||sqlerrm);
3687   raise;
3688 End;
3689 
3690 /*
3691 this procedure creates the database type and table of type so that we can build the olap table
3692 function on top of this
3693 we have to create a type for each s view since the column names have to match if we are going to go
3694 with the model of having 2 views , the second view doing to_number(), then we only need one type
3695 per dim set. for now, we create a type per s view
3696 
3697 we can create one type object for all the views in a dims set,. this would mean that all upper levels
3698 of a dim also share the same data type. can we assume this?
3699 if City is varchar2 and State is number, then we have a problem. in our implementation, all dim are TEXT. so
3700 we can assume this.
3701 this will not work because if we have one type with col names FK_1, FK_2 etc, then the views created will also
3702 have these column names. this will not do. so each s view must have its own type
3703 */
3704 procedure create_db_type(p_kpi kpi_r,p_dim_set in out nocopy dim_set_r) is
3705 PRAGMA AUTONOMOUS_TRANSACTION;
3706 Begin
3707   for i in 1..p_dim_set.s_view.count loop
3708     create_db_type(p_kpi.kpi,p_dim_set,p_dim_set.s_view(i));
3709   end loop;
3710   for i in 1..p_dim_set.z_s_view.count loop
3711     create_db_type(p_kpi.kpi,p_dim_set,p_dim_set.z_s_view(i));
3712   end loop;
3713 Exception when others then
3714   log_n('Exception in create_db_type '||sqlerrm);
3715   raise;
3716 End;
3717 
3718 procedure create_db_type(p_kpi varchar2,p_dim_set dim_set_r,p_s_view in out nocopy s_view_r) is
3719 PRAGMA AUTONOMOUS_TRANSACTION;
3723   p_s_view.type_name:='type_'||p_kpi||'_'||p_dim_set.dim_set||'_'||p_s_view.id;
3720 --
3721 l_name varchar2(30);
3722 Begin
3724   p_s_view.type_table_name:=p_s_view.type_name||'_tab';
3725   g_stmt:='drop type '||p_s_view.type_table_name;
3726   bsc_aw_utility.execute_ddl_ne(g_stmt);
3727   g_stmt:='drop type '||p_s_view.type_name;
3728   bsc_aw_utility.execute_ddl_ne(g_stmt);
3729   g_stmt:='create or replace type '||p_s_view.type_name||' as object (';
3730   for i in 1..p_s_view.dim.count loop
3731     if p_s_view.dim(i).levels(1).level_type='normal' then
3732       if p_s_view.dim(i).base_value_cube is not null then
3733         l_name:='D_'||bsc_aw_utility.get_hash_value(p_s_view.dim(i).dim_name||'.'||p_s_view.dim(i).levels(1).level_name||'.'||i,
3734         100,1073741824);
3735         g_stmt:=g_stmt||l_name||' varchar2(800),';
3736       end if;
3737       g_stmt:=g_stmt||p_s_view.dim(i).levels(1).fk||' '||p_s_view.dim(i).levels(1).data_type||',';
3738     end if;
3739   end loop;
3740   --std dim
3741   for j in 1..p_dim_set.std_dim.count loop
3742     g_stmt:=g_stmt||p_dim_set.std_dim(j).levels(1).fk||' '||p_dim_set.std_dim(j).levels(1).data_type||',';
3743   end loop;
3744   --time
3745   g_stmt:=g_stmt||'period number,year number,periodicity_id number,';
3746   for j in 1..p_dim_set.measure.count loop
3747     g_stmt:=g_stmt||p_dim_set.measure(j).measure||' '||p_dim_set.measure(j).data_type||',';
3748   end loop;
3749   g_stmt:=substr(g_stmt,1,length(g_stmt)-1)||')';
3750   bsc_aw_utility.execute_ddl(g_stmt);
3751   --create the table of type
3752   g_stmt:='create or replace type '||p_s_view.type_table_name||' as table of '||p_s_view.type_name;
3753   bsc_aw_utility.execute_ddl(g_stmt);
3754 Exception when others then
3755   log_n('Exception in create_db_type '||sqlerrm);
3756   raise;
3757 End;
3758 
3759 /*
3760 dmp the kpi record and all its properties
3761 */
3762 procedure dmp_kpi(p_kpi kpi_r) is
3763 Begin
3764   log_n('KPI Dmp');
3765   log('---------------------------------');
3766   log('KPI '||p_kpi.kpi);
3767   log('Dim Sets');
3768   for i in 1..p_kpi.dim_set.count loop
3769     log(p_kpi.dim_set(i).dim_set);
3770   end loop;
3771   log('Calendar');
3772   log(p_kpi.calendar);
3773   log('KPI Dim Set Parameters =');
3774   for i in 1..p_kpi.dim_set.count loop
3775     dmp_dimset(p_kpi.dim_set(i));
3776   end loop;
3777   log('================================================');
3778   log('================================================');
3779   log('KPI Target Dim Set Parameters =');
3780   for i in 1..p_kpi.target_dim_set.count loop
3781     dmp_dimset(p_kpi.target_dim_set(i));
3782   end loop;
3783 Exception when others then
3784   log_n('Exception in dmp_kpi '||sqlerrm);
3785   raise;
3786 End;
3787 
3788 procedure dmp_dimset(p_dim_set dim_set_r) is
3789 Begin
3790   if p_dim_set.dim_set is null then
3791     return;
3792   end if;
3793   log('----------------------------------------');
3794   log('Dmp Dim Set ='||p_dim_set.dim_set||', Dim Set Name ='||p_dim_set.dim_set_name);
3795   log('Dim Set Type='||p_dim_set.dim_set_type);
3796   log('Dim Set Aggmap Operators shared across Agg Maps');
3797   dmp_agg_map_operator(p_dim_set.aggmap_operator);
3798   dmp_agg_map(p_dim_set.agg_map);
3799   dmp_agg_map(p_dim_set.agg_map_notime);
3800   log('Initial Load Program='||p_dim_set.initial_load_program.program_name||', Inc Load Program='||p_dim_set.inc_load_program.program_name);
3801   dmp_calendar(p_dim_set.calendar);
3802   log('Dimensions =('||p_dim_set.dim.count||')');
3803   for i in 1..p_dim_set.dim.count loop
3804     dmp_dim(p_dim_set.dim(i));
3805   end loop;
3806   log('Std Dimensions =('||p_dim_set.std_dim.count||')');
3807   for i in 1..p_dim_set.std_dim.count loop
3808     dmp_dim(p_dim_set.std_dim(i));
3809   end loop;
3810   log('Targets at higher level? '||p_dim_set.targets_higher_levels);
3811   log('Measures =');
3812   for i in 1..p_dim_set.measure.count loop
3813     dmp_measure(p_dim_set.measure(i));
3814   end loop;
3815   log('Dimset Properties');
3816   log('Measurename Dim='||p_dim_set.measurename_dim);
3817   log('Partition Dim='||p_dim_set.partition_dim);
3818   log('Cube design='||p_dim_set.cube_design);
3819   log('Number partitions='||p_dim_set.number_partitions);
3820   log('Compressed='||p_dim_set.compressed);
3821   log('Partition Template');
3822   for i in 1..p_dim_set.partition_template.count loop
3823     dmp_partition_template(p_dim_set.partition_template(i));
3824   end loop;
3825   for i in 1..p_dim_set.composite.count loop
3826     dmp_composite(p_dim_set.composite(i));
3827   end loop;
3828   for i in 1..p_dim_set.cube_set.count loop
3829     dmp_cube_set(p_dim_set.cube_set(i));
3830   end loop;
3831   --
3832   log('Initial Data Source=');
3833   dmp_data_source(p_dim_set.data_source);
3834   log('Inc Data Source=');
3835   dmp_data_source(p_dim_set.inc_data_source);
3836   --
3837   log('S Views=');
3838   for i in 1..p_dim_set.s_view.count loop
3839     log('S View '||p_dim_set.s_view(i).s_view||', ID='||p_dim_set.s_view(i).id);
3840     log('S view levels ');
3841     for j in 1..p_dim_set.s_view(i).dim.count loop
3842       log('Dim '||p_dim_set.s_view(i).dim(j).dim_name);
3843       log('Levels');
3844       for k in 1..p_dim_set.s_view(i).dim(j).levels.count loop
3845         log(p_dim_set.s_view(i).dim(j).levels(k).level_name);
3846       end loop;
3847     end loop;
3848   end loop;
3849   --
3850   log('Z S Views=');
3851   for i in 1..p_dim_set.z_s_view.count loop
3852     log('S View '||p_dim_set.z_s_view(i).s_view||', ID='||p_dim_set.z_s_view(i).id);
3853     log('S view levels ');
3854     for j in 1..p_dim_set.z_s_view(i).dim.count loop
3855       log('Dim '||p_dim_set.z_s_view(i).dim(j).dim_name);
3856       log('Levels');
3857       for k in 1..p_dim_set.z_s_view(i).dim(j).levels.count loop
3861   end loop;
3858         log(p_dim_set.z_s_view(i).dim(j).levels(k).level_name);
3859       end loop;
3860     end loop;
3862   log('--------------------');
3863 Exception when others then
3864   log_n('Exception in dmp_dimset '||sqlerrm);
3865   raise;
3866 End;
3867 
3868 procedure dmp_measure(p_measure measure_r) is
3869 Begin
3870   log(p_measure.measure||' type='||p_measure.measure_type||' data type='||p_measure.data_type);
3871   log('formula='||p_measure.formula||' agg formula='||p_measure.agg_formula.agg_formula||', std agg='||
3872   p_measure.agg_formula.std_aggregation);
3873   log('forecast='||p_measure.forecast||', forecast method='||p_measure.forecast_method);
3874   log('cube='||p_measure.cube||', countvar cube='||p_measure.countvar_cube||', fcst cube='||p_measure.fcst_cube);
3875   if p_measure.agg_formula.std_aggregation='N' then
3876     log('Agg formula cubes');
3877     for i in 1..p_measure.agg_formula.cubes.count loop
3878       log(p_measure.agg_formula.cubes(i));
3879     end loop;
3880   end if;
3881 Exception when others then
3882   log_n('Exception in dmp_measure '||sqlerrm);
3883   raise;
3884 End;
3885 
3886 procedure dmp_agg_map(p_agg_map agg_map_r) is
3887 Begin
3888   log('Agg Map ='||p_agg_map.agg_map);
3889   log('  Property='||p_agg_map.property);
3890   dmp_agg_map_operator(p_agg_map.aggmap_operator);
3891 Exception when others then
3892   log_n('Exception in dmp_agg_map '||sqlerrm);
3893   raise;
3894 End;
3895 
3896 procedure dmp_agg_map_operator(p_agg_map_operator aggmap_operator_r) is
3897 Begin
3898   log('Agg Map.Measure_dim='||p_agg_map_operator.measure_dim);
3899   log('Agg Map.Opvar='||p_agg_map_operator.opvar);
3900   log('Agg Map.Argvar='||p_agg_map_operator.argvar);
3901 Exception when others then
3902   log_n('Exception in dmp_agg_map_operator '||sqlerrm);
3903   raise;
3904 End;
3905 
3906 procedure dmp_dim(p_dim dim_r) is
3907 Begin
3908   log('Dim '||p_dim.dim_name||' prop='||p_dim.property||' rec='||
3909   p_dim.recursive||' multi-level='||p_dim.multi_level||' zero code='||
3910   p_dim.zero_code||', concat='||p_dim.concat);
3911   log('limit cube='||p_dim.limit_cube||', limit cube composite='||p_dim.limit_cube_composite||
3912   ',reset cube='||p_dim.reset_cube||',aggregate marker='||p_dim.aggregate_marker||',agg map='||
3913   p_dim.agg_map.agg_map||', agg level='||p_dim.agg_level);
3914   log('Dim Levels =');
3915   for i in 1..p_dim.levels.count loop
3916     log(p_dim.levels(i).level_name||' type='||p_dim.levels(i).level_type||' pk='||
3917     p_dim.levels(i).pk||' fk='||p_dim.levels(i).fk||' data type='||
3918     p_dim.levels(i).data_type||' zero code='||p_dim.levels(i).zero_code||', zero code level='||p_dim.levels(i).zero_code_level||
3919     ', position='||p_dim.levels(i).position||',property='||p_dim.levels(i).property);
3920     log('filter=');
3921     for j in 1..p_dim.levels(i).filter.count loop
3922       log(p_dim.levels(i).filter(j));
3923     end loop;
3924   end loop;
3925   log('Dim Level Relations =');
3926   for i in 1..p_dim.parent_child.count loop
3927     log('Parent='||p_dim.parent_child(i).parent_level||', pk='||p_dim.parent_child(i).parent_pk||','||
3928     'Child='||p_dim.parent_child(i).child_level||',fk='||p_dim.parent_child(i).child_fk);
3929   end loop;
3930 Exception when others then
3931   log_n('Exception in dmp_dim '||sqlerrm);
3932   raise;
3933 End;
3934 
3935 procedure dmp_data_source(p_data_source data_source_tb) is
3936 Begin
3937   for i in 1..p_data_source.count loop
3938     log('Data Source -> '||i);
3939     dmp_data_source(p_data_source(i));
3940   end loop;
3941 Exception when others then
3942   log_n('Exception in dmp_data_source '||sqlerrm);
3943   raise;
3944 End;
3945 
3946 procedure dmp_data_source(p_data_source data_source_r) is
3947 Begin
3948   log('DS type='||p_data_source.ds_type);
3949   log('partition_dim='||p_data_source.data_source_PT.partition_template.template_dim);
3950   log('DS properties');
3951   for i in 1..p_data_source.property.count loop
3952     log(p_data_source.property(i).property_name||' '||p_data_source.property(i).property_type||' '||
3953     p_data_source.property(i).property_value);
3954   end loop;
3955   log('Data Source Dimensions=');
3956   for i in 1..p_data_source.dim.count loop
3957     dmp_dim(p_data_source.dim(i));
3958   end loop;
3959   log('Data Source Std dimensions=');
3960   for i in 1..p_data_source.std_dim.count loop
3961     dmp_dim(p_data_source.std_dim(i));
3962   end loop;
3963   dmp_calendar(p_data_source.calendar);
3964   log('Data Source Measures=');
3965   for i in 1..p_data_source.measure.count loop
3966     log(p_data_source.measure(i).measure||' cube='||p_data_source.measure(i).cube);
3967   end loop;
3968   log('Base Tables=');
3969   for i in 1..p_data_source.base_tables.count loop
3970     log(p_data_source.base_tables(i).base_table_name);
3971     log('Base Table periodicity >'||p_data_source.base_tables(i).periodicity.periodicity);
3972     log('Current period>'||p_data_source.base_tables(i).current_period);
3973     log('Base Table Levels');
3974     for j in 1..p_data_source.base_tables(i).levels.count loop
3975       log(p_data_source.base_tables(i).levels(j).level_name||', feed='||p_data_source.base_tables(i).feed_levels(j));
3976     end loop;
3977     dmp_table_partition(p_data_source.base_tables(i).table_partition);
3978   end loop;
3979   log('Data Source Stmt =');
3980   for i in 1..p_data_source.data_source_stmt.count loop
3981     log(p_data_source.data_source_stmt(i));
3982   end loop;
3983 Exception when others then
3984   log_n('Exception in dmp_data_source '||sqlerrm);
3985   raise;
3986 End;
3987 
3988 procedure dmp_table_partition(p_partition bsc_aw_utility.object_partition_r) is
3989 Begin
3990   log('Table partitions');
3991   log('Main partition:-');
3992   dmp_partition_set(p_partition.main_partition);
3996   log_n('Exception in dmp_table_partition '||sqlerrm);
3993   log('Sub partition:-');
3994   dmp_partition_set(p_partition.sub_partition);
3995 Exception when others then
3997   raise;
3998 End;
3999 
4000 procedure dmp_partition_set(p_partition_set bsc_aw_utility.partition_set_r) is
4001 Begin
4002   log('Partition set '||p_partition_set.set_name);
4003   if p_partition_set.set_name is not null then
4004     log('Partition type '||p_partition_set.partition_type);
4005     log('Partition Column '||p_partition_set.partition_column);
4006     log('Partition Column Data Type '||p_partition_set.partition_column_data_type);
4007     for i in 1..p_partition_set.partitions.count loop
4008       log('Partition Name '||p_partition_set.partitions(i).partition_name);
4009       log('Partition Value '||p_partition_set.partitions(i).partition_value);
4010       log('Partition Position '||p_partition_set.partitions(i).partition_position);
4011     end loop;
4012   end if;
4013 Exception when others then
4014   log_n('Exception in dmp_partition_set '||sqlerrm);
4015   raise;
4016 End;
4017 
4018 procedure dmp_calendar(p_calendar calendar_r) is
4019 Begin
4020   log('Calendar '||p_calendar.calendar||' dim='||p_calendar.aw_dim||' relation='||
4021   p_calendar.relation_name||', denorm relation='||p_calendar.denorm_relation_name);
4022   log('Limit cube='||p_calendar.limit_cube||', Limit cube composite='||p_calendar.limit_cube_composite||
4023   ', aggregate marker='||p_calendar.aggregate_marker);
4024   log('Periodicities');
4025   for i in 1..p_calendar.periodicity.count loop
4026     log('Periodicity='||p_calendar.periodicity(i).periodicity||' dim='||p_calendar.periodicity(i).aw_dim||
4027     ', property='||p_calendar.periodicity(i).property||', lowest level='||p_calendar.periodicity(i).lowest_level||', missing level='||
4028     p_calendar.periodicity(i).missing_level);
4029   end loop;
4030   log('Periodicitie Relations');
4031   for i in 1..p_calendar.parent_child.count loop
4032     log('Parent='||p_calendar.parent_child(i).parent_dim_name||', Parent periodicity='||
4033     p_calendar.parent_child(i).parent||',Child='||p_calendar.parent_child(i).child_dim_name||',Child periodicity='||
4034     p_calendar.parent_child(i).child);
4035   end loop;
4036 Exception when others then
4037   log_n('Exception in dmp_calendar '||sqlerrm);
4038   raise;
4039 End;
4040 
4041 procedure dmp_partition_template(p_partition_template partition_template_r) is
4042 Begin
4043   log('Partition Template:-');
4044   log('Template name='||p_partition_template.template_name);
4045   log('Template type='||p_partition_template.template_type);
4046   log('Template use='||p_partition_template.template_use);
4047   log('Template dim='||p_partition_template.template_dim);
4048   log('hpt data');
4049   dmp_hpt_data(p_partition_template.hpt_data);
4050   log('Template dimensions');
4051   for i in 1..p_partition_template.template_dimensions.count loop
4052     log(p_partition_template.template_dimensions(i));
4053   end loop;
4054   log('Partitions:-');
4055   for i in 1..p_partition_template.template_partitions.count loop
4056     dmp_partition(p_partition_template.template_partitions(i));
4057   end loop;
4058 Exception when others then
4059   log_n('Exception in dmp_partition_template '||sqlerrm);
4060   raise;
4061 End;
4062 
4063 procedure dmp_partition(p_partition partition_r) is
4064 Begin
4065   log('Partition name='||p_partition.partition_name);
4066   log('Partition Dim Value='||p_partition.partition_dim_value);
4067   for i in 1..p_partition.partition_axis.count loop
4068     dmp_axis(p_partition.partition_axis(i));
4069   end loop;
4070 Exception when others then
4071   log_n('Exception in dmp_partition '||sqlerrm);
4072   raise;
4073 End;
4074 
4075 procedure dmp_axis(p_axis axis_r) is
4076 Begin
4077   log('Axis name='||p_axis.axis_name||', Axis type='||p_axis.axis_type);
4078 Exception when others then
4079   log_n('Exception in dmp_axis '||sqlerrm);
4080   raise;
4081 End;
4082 
4083 procedure dmp_composite(p_composite composite_r) is
4084 Begin
4085   log('Composite name='||p_composite.composite_name);
4086   log('Composite type='||p_composite.composite_type);
4087   log('Composite dimensions');
4088   for i in 1..p_composite.composite_dimensions.count loop
4089     log(p_composite.composite_dimensions(i));
4090   end loop;
4091 Exception when others then
4092   log_n('Exception in dmp_composite '||sqlerrm);
4093   raise;
4094 End;
4095 
4096 procedure dmp_cube_set(p_cube_set cube_set_r) is
4097 Begin
4098   log('Cube set name='||p_cube_set.cube_set_name||', Cube set type='||p_cube_set.cube_set_type);
4099   log('Measurename Dim='||p_cube_set.measurename_dim);
4100   log('Cube:-');
4101   dmp_cube(p_cube_set.cube);
4102   log('Fcst Cube:-');
4103   dmp_cube(p_cube_set.fcst_cube);
4104   log('Countvar Cube:-');
4105   dmp_cube(p_cube_set.countvar_cube);
4106 Exception when others then
4107   log_n('Exception in dmp_cube_set '||sqlerrm);
4108   raise;
4109 End;
4110 
4111 procedure dmp_cube(p_cube cube_r) is
4112 Begin
4113   log('Cube name='||p_cube.cube_name);
4114   log('Cube type='||p_cube.cube_type);
4115   log('Cube datatype='||p_cube.cube_datatype);
4116   for i in 1..p_cube.cube_axis.count loop
4117     dmp_axis(p_cube.cube_axis(i));
4118   end loop;
4119 Exception when others then
4120   log_n('Exception in dmp_cube '||sqlerrm);
4121   raise;
4122 End;
4123 
4124 /*
4125 every kpi has the type and projection dim attached to it. this api adds these std dimensions
4126 to the kpi dimset
4127 */
4128 procedure get_dim_set_std_dims(
4129 p_kpi varchar2,
4130 p_dim_set in out nocopy dim_set_r) is
4131 --
4132 Begin
4133   p_dim_set.std_dim(1):=null;
4134   p_dim_set.std_dim(2):=null;
4135   get_dim_set_std_dim_type(p_kpi,p_dim_set.std_dim(1));
4139   raise;
4136   get_dim_set_std_dim_projection(p_kpi,p_dim_set.std_dim(2));
4137 Exception when others then
4138   log_n('Exception in get_dim_set_std_dims '||sqlerrm);
4140 End;
4141 
4142 --adds TYPE dim to the dim of the dimset
4143 procedure get_dim_set_std_dim_type(
4144 p_kpi varchar2,
4145 p_dim in out nocopy dim_r) is
4146 --
4147 l_dim varchar2(300);
4148 Begin
4149   bsc_aw_md_api.get_dim_for_level('TYPE',l_dim);
4150   p_dim.dim_name:=l_dim;
4151   p_dim.zero_code:='N';
4152   p_dim.relation_name:=null;
4153   p_dim.property:='normal';
4154   p_dim.recursive:='N';
4155   p_dim.multi_level:='N';
4156   p_dim.zero_code:='N';
4157   p_dim.agg_level:=0;
4158   p_dim.levels(1).level_name:='TYPE';
4159   p_dim.levels(1).level_type:='normal';
4160   p_dim.levels(1).pk:='TYPE';
4161   p_dim.levels(1).fk:='TYPE';
4162   p_dim.levels(1).data_type:='varchar2(100)';
4163   p_dim.levels(1).zero_code:='N';
4164   p_dim.levels(1).position:=1;
4165 Exception when others then
4166   log_n('Exception in get_dim_set_std_dim_type '||sqlerrm);
4167   raise;
4168 End;
4169 
4170 --adds TYPE dim to the dim of the dimset
4171 procedure get_dim_set_std_dim_projection(
4172 p_kpi varchar2,
4173 p_dim in out nocopy dim_r) is
4174 --
4175 l_dim varchar2(300);
4176 Begin
4177   bsc_aw_md_api.get_dim_for_level('PROJECTION',l_dim);
4178   p_dim.dim_name:=l_dim;
4179   p_dim.zero_code:='N';
4180   p_dim.relation_name:=null;
4181   p_dim.property:='normal';
4182   p_dim.recursive:='N';
4183   p_dim.multi_level:='N';
4184   p_dim.zero_code:='N';
4185   p_dim.agg_level:=0;
4186   p_dim.levels(1).level_name:='PROJECTION';
4187   p_dim.levels(1).level_type:='normal';
4188   p_dim.levels(1).pk:='PROJECTION';
4189   p_dim.levels(1).fk:='PROJECTION';
4190   p_dim.levels(1).data_type:='varchar2(100)';
4191   p_dim.levels(1).zero_code:='N';
4192   p_dim.levels(1).position:=1;
4193 Exception when others then
4194   log_n('Exception in get_dim_set_std_dim_projection '||sqlerrm);
4195   raise;
4196 End;
4197 
4198 /*
4199 this procedure takes in an agg formula based on measures and then substitutes the cube names. once the cube names are in, we
4200 can simply execute the formula
4201 
4202 note: this changes the agg formula. it substitutes the cube names in the place of measure names
4203 
4204 the formula is ALL CAPS
4205 */
4206 procedure make_agg_formula(
4207 p_kpi in out nocopy kpi_r
4208 ) is
4209 Begin
4210   for i in 1..p_kpi.dim_set.count loop
4211     make_agg_formula(p_kpi.dim_set(i));
4212     --no need for targets since they have no agg
4213   end loop;
4214 Exception when others then
4215   log_n('Exception in make_agg_formula '||sqlerrm);
4216   raise;
4217 End;
4218 
4219 procedure make_agg_formula(
4220 p_dim_set in out nocopy dim_set_r
4221 ) is
4222 Begin
4223   for i in 1..p_dim_set.measure.count loop
4224     if p_dim_set.measure(i).agg_formula.std_aggregation='N' then
4225       make_agg_formula(p_dim_set.measure(i),p_dim_set.measure,p_dim_set);
4226     end if;
4227   end loop;
4228 Exception when others then
4229   log_n('Exception in make_agg_formula '||sqlerrm);
4230   raise;
4231 End;
4232 
4233 procedure make_agg_formula(
4234 p_measure in out nocopy measure_r,
4235 p_all_measures measure_tb,
4236 p_dim_set dim_set_r
4237 ) is
4238 --
4239 l_agg_formula varchar2(1000);
4240 l_start_array dbms_sql.number_table; --contains the start address of a measure in a formula
4241 l_cube varchar2(200);
4242 l_cube_set cube_set_r;
4243 Begin
4244   l_agg_formula:=p_measure.agg_formula.agg_formula;
4245   if g_debug then
4246     log_n('In make_agg_formula, old agg formula='||l_agg_formula);
4247   end if;
4248   --search for each measure and substitute it
4249   for i in 1..p_all_measures.count loop
4250     l_start_array.delete;
4251     if bsc_aw_utility.is_string_present(l_agg_formula,p_all_measures(i).measure,l_start_array) then
4252       if l_start_array.count>0 then
4253         l_cube_set:=get_cube_set_r(p_all_measures(i).cube,p_dim_set);
4254         if l_cube_set.cube_set_type='datacube' then
4255           l_cube:=p_all_measures(i).cube||'('||l_cube_set.measurename_dim||' '''||p_all_measures(i).measure||''')';
4256         else
4257           l_cube:=p_all_measures(i).cube;
4258         end if;
4259         --we leave the agg_formula.cubes as the original name of the cube
4260         bsc_aw_utility.merge_value(p_measure.agg_formula.cubes,p_all_measures(i).cube);
4261         bsc_aw_utility.merge_value(p_measure.agg_formula.measures,p_all_measures(i).measure);
4262         bsc_aw_utility.replace_string(l_agg_formula,p_all_measures(i).measure,l_cube,l_start_array);
4263       end if;
4264     end if;
4265   end loop;
4266   if g_debug then
4267     log('New agg formula='||l_agg_formula);
4268     log('--');
4269   end if;
4270   --now change the record to reflect the agg formula with the cube
4271   p_measure.agg_formula.agg_formula:=l_agg_formula;
4272   /*agg_formula.sql_agg_formula retains the original agg formula from metadata */
4273 Exception when others then
4274   log_n('Exception in make_agg_formula '||sqlerrm);
4275   raise;
4276 End;
4277 
4278 /*
4279 this procedure decides what the agg level should be for each dim in the dim sets
4280 the first choise is adv sum profile. it gets complicated if targets at higher levels are involved.
4281 say adv sum profile is to state. if targets come to country level, then we have to aggregate to
4282 country. its too complicated to handle this on-line.
4283 
4284 since we set the agg level at the creation time, when adv sum profile changes, we have to drop the
4285 cubes, recreate them and reload them,
4286 this is better for aw. sotherwise, when adv sum profile is dropped from 3 to 2, how do we reclaim space
4290 l_flag dbms_sql.varchar2_table;--to track if we do change the agg level in a target dim set
4287 from the cubes? it gets complicated
4288 */
4289 procedure set_dim_agg_level(p_kpi in out nocopy kpi_r) is
4291 Begin
4292   --
4293   for i in 1..p_kpi.dim_set.count loop
4294     init_agg_level(p_kpi.dim_set(i));
4295   end loop;
4296   for i in 1..p_kpi.target_dim_set.count loop
4297     init_agg_level(p_kpi.target_dim_set(i));
4298   end loop;
4299   --
4300   for i in 1..p_kpi.target_dim_set.count loop
4301     l_flag(i):='N';
4302     --for each dim, see if the first level > adv sum profile
4303     for j in 1..p_kpi.target_dim_set(i).dim.count loop
4304       if p_kpi.target_dim_set(i).dim(j).recursive='N' then
4305         if p_kpi.target_dim_set(i).dim(j).levels(1).position > p_kpi.target_dim_set(i).dim(j).agg_level then
4306           l_flag(i):='Y';
4307           p_kpi.target_dim_set(i).dim(j).agg_level:=p_kpi.target_dim_set(i).dim(j).levels(1).position;
4308         end if;
4309       end if;
4310     end loop;
4311   end loop;
4312   --also set the agg level for the corresponding actual dimset
4313   for i in 1..p_kpi.target_dim_set.count loop
4314     if l_flag(i)='Y' then
4315       --get the corresponding actual dimset
4316       for j in 1..p_kpi.dim_set.count loop
4317         if p_kpi.target_dim_set(i).base_dim_set=p_kpi.dim_set(j).dim_set_name then
4318           for k in 1..p_kpi.target_dim_set(i).dim.count loop
4319             for m in 1..p_kpi.dim_set(j).dim.count loop
4320               if p_kpi.target_dim_set(i).dim(k).dim_name=p_kpi.dim_set(j).dim(m).dim_name then
4321                 if p_kpi.dim_set(j).dim(m).agg_level < p_kpi.target_dim_set(i).dim(k).agg_level then
4322                   p_kpi.dim_set(j).dim(m).agg_level:=p_kpi.target_dim_set(i).dim(k).agg_level;
4323                 end if;
4324                 exit;
4325               end if;
4326             end loop;
4327           end loop;
4328           exit;
4329         end if;
4330       end loop;
4331     end if;
4332   end loop;
4333   for i in 1..p_kpi.dim_set.count loop
4334     set_dim_agg_level(p_kpi.dim_set(i));
4335   end loop;
4336   for i in 1..p_kpi.target_dim_set.count loop
4337     set_dim_agg_level(p_kpi.target_dim_set(i));
4338   end loop;
4339 Exception when others then
4340   log_n('Exception in set_dim_agg_level '||sqlerrm);
4341   raise;
4342 End;
4343 
4344 /*level positions are read from bsc_olap_object. level positions are set when the dim metadata is created. so the lowest level for a kpi
4345 need not have level position of 1 */
4346 procedure set_dim_agg_level(p_dim_set in out nocopy dim_set_r) is
4347 Begin
4348   for i in 1..p_dim_set.dim.count loop
4349     set_dim_agg_level(p_dim_set.dim(i));
4350   end loop;
4351 Exception when others then
4352   log_n('Exception in set_dim_agg_level '||sqlerrm);
4353   raise;
4354 End;
4355 
4356 procedure set_dim_agg_level(p_dim in out nocopy dim_r) is
4357 Begin
4358   for i in 1..p_dim.levels.count loop
4359     p_dim.levels(i).aggregated:='Y';
4360     p_dim.levels(i).zero_aggregated:=nvl(p_dim.levels(i).zero_code,'N');
4361     if p_dim.levels(i).position>p_dim.agg_level then
4362       p_dim.levels(i).aggregated:='N';
4363       p_dim.levels(i).zero_aggregated:='N';
4364     end if;
4365   end loop;
4366 Exception when others then
4367   log_n('Exception in set_dim_agg_level '||sqlerrm);
4368   raise;
4369 End;
4370 
4371 /*set the aggregated flag for each periodicity */
4372 procedure set_calendar_agg_level(p_kpi in out nocopy kpi_r) is
4373 Begin
4374   for i in 1..p_kpi.dim_set.count loop
4375     set_calendar_agg_level(p_kpi.dim_set(i),p_kpi.target_dim_set(i));
4376   end loop;
4377   for i in 1..p_kpi.target_dim_set.count loop
4378     set_calendar_agg_level(p_kpi.target_dim_set(i));
4379   end loop;
4380 Exception when others then
4381   log_n('Exception in set_calendar_agg_level '||sqlerrm);
4382   raise;
4383 End;
4384 
4385 /*by default, we will not aggregate on time, unless explicitly specified */
4386 procedure set_calendar_agg_level(p_dim_set in out nocopy dim_set_r) is
4387 aggregated boolean;
4388 Begin
4389   if bsc_aw_utility.get_parameter_value('AGGREGATE TIME')='Y' then
4390     aggregated:=true;
4391   else
4392     aggregated:=false;
4393   end if;
4394   for i in 1..p_dim_set.calendar.periodicity.count loop
4395     if p_dim_set.calendar.periodicity(i).lowest_level='Y' then
4396       p_dim_set.calendar.periodicity(i).aggregated:='Y';
4397     else
4398       if aggregated then
4399         p_dim_set.calendar.periodicity(i).aggregated:='Y';
4400       else
4401         p_dim_set.calendar.periodicity(i).aggregated:='N';
4402       end if;
4403     end if;
4404   end loop;
4405 Exception when others then
4406   log_n('Exception in set_calendar_agg_level '||sqlerrm);
4407   raise;
4408 End;
4409 
4410 /*if there are targets, we need to make sure that the level at the target is aggregated. if target is at month, we cannot just agg to
4411 day level */
4412 procedure set_calendar_agg_level(p_dim_set in out nocopy dim_set_r,p_target_dim_set dim_set_r) is
4413 l_pc bsc_aw_utility.parent_child_tb;
4414 l_child_levels dbms_sql.varchar2_table;
4415 Begin
4416   set_calendar_agg_level(p_dim_set);
4417   if p_dim_set.targets_higher_levels='Y' then
4418     for i in 1..p_dim_set.calendar.parent_child.count loop
4419       if p_dim_set.calendar.parent_child(i).parent_dim_name is not null and p_dim_set.calendar.parent_child(i).child_dim_name is not null then
4420         l_pc(l_pc.count+1).parent:=p_dim_set.calendar.parent_child(i).parent_dim_name;
4421         l_pc(l_pc.count).child:=p_dim_set.calendar.parent_child(i).child_dim_name;
4422       end if;
4423     end loop;
4424     for i in 1..p_target_dim_set.calendar.periodicity.count loop
4425       if p_target_dim_set.calendar.periodicity(i).lowest_level='Y' then
4429             p_dim_set.calendar.periodicity(j).aggregated:='Y';
4426         /*set the actual per corresponding to targets as aggregated */
4427         for j in 1..p_dim_set.calendar.periodicity.count loop
4428           if p_dim_set.calendar.periodicity(j).aw_dim=p_target_dim_set.calendar.periodicity(i).aw_dim then
4430             if g_debug then
4431               log('Due to targets('||p_dim_set.dim_set_name||'), setting '||p_dim_set.calendar.periodicity(j).aw_dim||' aggregated flag to ''Y''');
4432             end if;
4433             --
4434             exit;
4435           end if;
4436         end loop;
4437         l_child_levels.delete;
4438         bsc_aw_utility.get_all_children(l_pc,p_target_dim_set.calendar.periodicity(i).aw_dim,l_child_levels);
4439         if l_child_levels.count>0 then
4440           for j in 1..p_dim_set.calendar.periodicity.count loop
4441             if bsc_aw_utility.in_array(l_child_levels,p_dim_set.calendar.periodicity(j).aw_dim) then
4442               p_dim_set.calendar.periodicity(j).aggregated:='Y';
4443               if g_debug then
4444                 log('Due to targets('||p_dim_set.dim_set_name||'), setting '||p_dim_set.calendar.periodicity(j).aw_dim||' aggregated flag to ''Y''');
4445               end if;
4446             end if;
4447           end loop;
4448         end if;
4449       end if;
4450     end loop;
4451   end if;
4452 Exception when others then
4453   log_n('Exception in set_calendar_agg_level '||sqlerrm);
4454   raise;
4455 End;
4456 
4457 procedure init_agg_level(p_dim_set in out nocopy dim_set_r) is
4458 --
4459 l_adv_sum_profile number;
4460 Begin
4461   l_adv_sum_profile:=bsc_aw_utility.get_adv_sum_profile;
4462   --init the agg level to adv sum profile first
4463   for i in 1..p_dim_set.dim.count loop
4464     if p_dim_set.dim(i).recursive='Y' then
4465       p_dim_set.dim(i).agg_level:=1000000; --hard coded. agg all levels for rec dim
4466     else
4467       p_dim_set.dim(i).agg_level:=l_adv_sum_profile;
4468     end if;
4469   end loop;
4470   for i in 1..p_dim_set.std_dim.count loop
4471     p_dim_set.std_dim(i).agg_level:=l_adv_sum_profile;
4472   end loop;
4473 Exception when others then
4474   log_n('Exception in init_agg_level '||sqlerrm);
4475   raise;
4476 End;
4477 
4478 /*
4479 open: we have an issue where user can have missing levels for a kpi. they can have city and country. right now, in BSC, this is
4480 treated as independent dimensions.
4481 in aw, we will find out the missing levels. we will optimize to get the shortest path between the levels.
4482 then we will make sure that the agg level for this dim is set to the max of the levels specified for the kpi. so wven if
4483 agg level is 2, we will make it 3 since country is an independent level for the kpi
4484 in the s views, we will have both the city and country keys. we query the s view levels. so the MO api is going to come back with
4485 city and country. so we will end up with city and country levels and fk. also the read api must handle multiple level values being
4486 specified for the same dim.
4487 
4488 when this procedure is called, targets are not yet in the picture. so we do not have to think about propagating
4489 the missing levels to targets
4490 
4491 NOTE!!! get_dim_set_dims will return the missing levels. so we really do not need an api to create the missing levels.
4492 now, the issue will be this. say city and country are the levels. get_dim_set_dims returns city,state and country.
4493 if the adv sum profile is 2, then we only aggregate to state. when country is specified, we have to agg on the fly. in bsc, when
4494 city and country are specified, both are level 1.
4495 
4496 Other issue : what about zero code? when city and country are specified, there is zero code for both. get_zero_code_levels will
4497 say there is zero code for both city and country.
4498 we now have zero code in dim at all levels.
4499 */
4500 procedure create_missing_dim_levels(p_kpi varchar2,p_dim_set in out nocopy dim_set_r) is
4501 Begin
4502   null;
4503 Exception when others then
4504   log_n('Exception in create_missing_dim_levels '||sqlerrm);
4505   raise;
4506 End;
4507 
4508 /*
4509 user can specify city and country with no relation between each other. they become independent levels. so the cube must have
4510 city and country as the dim, not geog.
4511 we do this:
4512 lets say in a dim we see levels with diff MO dim groups. this means they are independent. say
4513 geog :
4514 city  mo : 1
4515 state  mo : 1
4516 country mo : 2
4517 region mo : 2
4518 
4519 we group all levels associated with the lowest level into the geog dim.
4520 all others become independent levels.
4521 
4522 This is not possible. this is because if we dim with the concat dim, then we cannot dim by any otger level
4523 we get this error
4524 ORA-33376: (DUPCLCHK03) BSC_AW!BSC_D_STATE_AW and BSC_AW!BSC_CCDIM_400_401_402 cannot both appear in a dimension list because they
4525 this means if there are more than 1 MO dim groups, we have to have all levels as snow flake.
4526 also we need to skip missing levels.
4527 
4528 note>>> how will we ever support multiple references to the same dim in BSC?
4529 do we create diff copies of the dim?
4530 */
4531 procedure identify_standalone_levels(
4532 p_kpi varchar2,
4533 p_dim_set in out nocopy dim_set_r) is
4534 --
4535 l_distict_mo_dim_groups dbms_sql.varchar2_table;
4536 l_levels level_tb;
4537 l_levels_for_new_dim level_tb;
4538 l_dim_to_split dim_tb;
4539 l_dim_copy dim_tb;
4540 l_flag bsc_aw_utility.boolean_table;
4541 l_skip_flag varchar2(40);
4542 Begin
4543   --for each dim, get a list of distinct mo
4544   for i in 1..p_dim_set.dim.count loop
4545     l_flag(i):=false;
4546     l_distict_mo_dim_groups.delete;
4547     get_dim_mo_dim_groups(p_dim_set.dim(i),l_distict_mo_dim_groups);
4548     if l_distict_mo_dim_groups.count>1 then
4549       --we have to remove this dim from the dimset
4550       l_dim_to_split(l_dim_to_split.count+1):=p_dim_set.dim(i);
4551       l_flag(i):=true;
4552       if g_debug then
4553         log_n('identify_standalone_levels: Remove Dim '||p_dim_set.dim(i).dim_name||', replace with levels');
4554       end if;
4555     end if;
4556   end loop;
4557   if l_dim_to_split.count>0 then
4558     --remove the split dim from the dimset
4559     l_dim_copy:=p_dim_set.dim;
4560     p_dim_set.dim.delete;
4561     for i in 1..l_dim_copy.count loop
4562       if l_flag(i)=false then
4563         p_dim_set.dim(p_dim_set.dim.count+1):=l_dim_copy(i);
4564       end if;
4565     end loop;
4566     --now split the dim
4567     l_levels_for_new_dim.delete;
4568     for i in 1..l_dim_to_split.count loop
4569       for j in 1..l_dim_to_split(i).levels.count loop
4570         l_skip_flag:=bsc_aw_utility.get_parameter_value(l_dim_to_split(i).levels(j).property,'skip level',',');
4571         --ignore the levels to skip
4572         if l_skip_flag='N' then
4573           l_levels_for_new_dim(l_levels_for_new_dim.count+1):=l_dim_to_split(i).levels(j);
4574         end if;
4575       end loop;
4576     end loop;
4577   end if;
4578   if g_debug then
4579     if l_levels_for_new_dim.count>0 then
4580       log_n('identify_standalone_levels : Create new dim for these levels');
4581       for i in 1..l_levels_for_new_dim.count loop
4582         log(l_levels_for_new_dim(i).level_name);
4583       end loop;
4584     end if;
4585   end if;
4586   --create the new dim
4587   --dim with name=level name are seeded in bsc olap metadata. this is the snowflake implementation.
4588   --this metadata is created when the dim is created
4589   if l_levels_for_new_dim.count>0 then
4590     for i in 1..l_levels_for_new_dim.count loop
4591       p_dim_set.dim(p_dim_set.dim.count+1).dim_name:=l_levels_for_new_dim(i).level_name;
4592       p_dim_set.dim(p_dim_set.dim.count).levels(p_dim_set.dim(p_dim_set.dim.count).levels.count+1):=l_levels_for_new_dim(i);
4593     end loop;
4594   end if;
4595   --
4596 Exception when others then
4597   log_n('Exception in identify_standalone_levels '||sqlerrm);
4598   raise;
4599 End;
4600 
4601 --level mo dim group is held in level.property
4602 procedure get_dim_mo_dim_groups(
4603 p_dim dim_r,
4604 p_distict_mo_dim_groups out nocopy dbms_sql.varchar2_table) is
4605 --
4606 l_mo_dim_group varchar2(200);
4607 Begin
4608   for i in 1..p_dim.levels.count loop
4609     l_mo_dim_group:=bsc_aw_utility.get_parameter_value(p_dim.levels(i).property,'mo dim group',',');
4610     if bsc_aw_utility.in_array(p_distict_mo_dim_groups,l_mo_dim_group)=false then
4611       p_distict_mo_dim_groups(p_distict_mo_dim_groups.count+1):=l_mo_dim_group;
4612     end if;
4613   end loop;
4614 Exception when others then
4615   log_n('Exception in get_dim_mo_dim_groups '||sqlerrm);
4616   raise;
4617 End;
4618 
4619 /*
4620 used to dmp cube data into a table.
4621 dmps all cubes of the dimset
4622 p_table_name is dropped and recreated
4623 p_dimset will be 0 or 1 etc
4624 */
4625 procedure create_dmp_program(
4626 p_kpi varchar2,
4627 p_dimset varchar2,
4628 p_dim_levels dbms_sql.varchar2_table,
4629 p_name varchar2,
4630 p_table_name varchar2) is
4631 --
4632 l_oo_object bsc_aw_md_wrapper.bsc_olap_object_tb;
4633 l_oo_relation bsc_aw_md_wrapper.bsc_olap_object_relation_tb;
4634 l_dimset varchar2(100);
4635 l_dim_level_dims dbms_sql.varchar2_table;
4636 l_measures dbms_sql.varchar2_table;
4637 l_cubes dbms_sql.varchar2_table;
4638 l_cube_formula dbms_sql.varchar2_table;
4639 l_cube_composites dbms_sql.varchar2_table;
4640 l_stmt varchar2(8000);
4641 l_calendar_id number;
4642 l_dim_levels dbms_sql.varchar2_table;
4643 l_axis_type varchar2(100);
4644 Begin
4645   l_dim_levels:=p_dim_levels;
4646   bsc_aw_md_api.get_kpi_dimset(p_kpi,l_oo_object);
4647   for i in 1..l_oo_object.count loop
4648     if bsc_aw_utility.get_parameter_value(l_oo_object(i).property1,'dim set',',')=p_dimset then
4649       if bsc_aw_utility.get_parameter_value(l_oo_object(i).property1,'dim set type',',')='actual' then
4650         l_dimset:=l_oo_object(i).object;
4651         exit;
4652       end if;
4653     end if;
4654   end loop;
4655   if l_dimset is not null then
4656     bsc_aw_md_api.get_bsc_olap_object_relation(null,null,null,p_kpi,'kpi',l_oo_relation);
4657     for i in 1..l_dim_levels.count loop
4658       l_dim_level_dims(i):=null;
4659       for j in 1..l_oo_relation.count loop
4660         if l_oo_relation(j).relation_object=l_dim_levels(i) and l_oo_relation(j).relation_type='dim set dim level' and
4661         instr(l_oo_relation(j).object,'+'||l_dimset)>0 and instr(l_oo_relation(j).object,'+'||l_dimset||'.')=0 then
4662           log(l_oo_relation(j).object);
4663           l_dim_level_dims(i):=substr(l_oo_relation(j).object,1,instr(l_oo_relation(j).object,'+')-1);
4664           exit;
4665         end if;
4666       end loop;
4667       --is this rec dim, then get the parent level
4668       l_oo_object.delete;
4669       bsc_aw_md_api.get_bsc_olap_object(l_dim_level_dims(i),'dimension',l_dim_level_dims(i),'dimension',l_oo_object);
4670       if bsc_aw_utility.get_parameter_value(l_oo_object(1).property1,'recursive',',')='Y' then
4671         l_oo_object.delete;
4672         bsc_aw_md_api.get_bsc_olap_object(null,'recursive level',l_dim_level_dims(i),'dimension',l_oo_object);
4673         l_dim_levels(i):=l_oo_object(1).object;--store the parent rec level
4674       end if;
4675     end loop;
4676     --calendar
4677     for i in 1..l_oo_relation.count loop
4678       if l_oo_relation(i).object=l_dimset and l_oo_relation(i).relation_type='dim set calendar' then
4679         l_calendar_id:=to_number(bsc_aw_utility.get_parameter_value(l_oo_relation(i).property1,'calendar',','));
4680         exit;
4681       end if;
4682     end loop;
4683     --get the measures and cubes
4684     for i in 1..l_oo_relation.count loop
4685       if l_oo_relation(i).object=l_dimset and l_oo_relation(i).relation_type='dim set measure' then
4686         l_measures(l_measures.count+1):=l_oo_relation(i).relation_object;
4687         l_cubes(l_cubes.count+1):=bsc_aw_utility.get_parameter_value(l_oo_relation(i).property1,'cube',',');
4688         l_cube_formula(l_cube_formula.count+1):=bsc_aw_utility.get_parameter_value(l_oo_relation(i).property1,'aw formula',',');
4689         for j in 1..l_oo_relation.count loop
4690           if l_oo_relation(j).object=l_cubes(l_cubes.count) and l_oo_relation(j).relation_type='cube axis' then
4691             l_axis_type:=bsc_aw_utility.get_parameter_value(l_oo_relation(j).property1,'axis type',',');
4692             if l_axis_type='partition template' or l_axis_type='composite' then
4693               l_cube_composites(l_cubes.count):=l_oo_relation(j).relation_object;
4694               exit;
4695             end if;
4696           end if;
4697         end loop;
4698       end if;
4699     end loop;
4700     --create the table first
4701     bsc_aw_utility.execute_ddl_ne('drop table '||p_table_name);
4702     l_stmt:='create table '||p_table_name||'(
4703     ';
4704     for i in 1..l_dim_levels.count loop
4705       l_stmt:=l_stmt||l_dim_levels(i)||' varchar2(300),
4706       ';
4707     end loop;
4708     for i in 1..l_measures.count loop
4709       l_stmt:=l_stmt||l_measures(i)||' number,
4710       ';
4711     end loop;
4712     l_stmt:=l_stmt||'period number,year number,periodicity_id number)';
4713     bsc_aw_utility.execute_ddl(l_stmt);
4714     --create the program
4715     g_commands.delete;
4716     bsc_aw_utility.add_g_commands(g_commands,'dfn '||p_name||' program');
4717     bsc_aw_utility.add_g_commands(g_commands,'sql prepare c1 from --');
4718     bsc_aw_utility.add_g_commands(g_commands,'insert into '||p_table_name||' values ( --');
4719     for i in 1..l_dim_levels.count loop
4720       if l_dim_level_dims(i) <> l_dim_levels(i) then
4721         bsc_aw_utility.add_g_commands(g_commands,':key('||l_dim_level_dims(i)||' '||l_dim_levels(i)||'), --');
4722       else
4723         bsc_aw_utility.add_g_commands(g_commands,':'||l_dim_levels(i)||', --');
4724       end if;
4725     end loop;
4726     for i in 1..l_measures.count loop
4727       if l_cube_formula(i) is not null then
4728         bsc_aw_utility.add_g_commands(g_commands,':'||l_cube_formula(i)||', --');
4729       else
4730         bsc_aw_utility.add_g_commands(g_commands,':'||l_cubes(i)||', --');
4731       end if;
4732     end loop;
4733     bsc_aw_utility.add_g_commands(g_commands,':period_cal_'||l_calendar_id||',:year_cal_'||l_calendar_id||',:periodicity_cal_'||l_calendar_id||')');
4734     bsc_aw_utility.add_g_commands(g_commands,'for '||l_cube_composites(1));
4735     bsc_aw_utility.add_g_commands(g_commands,'do');
4736     bsc_aw_utility.add_g_commands(g_commands,'sql execute c1');
4737     bsc_aw_utility.add_g_commands(g_commands,'if sqlcode ne 0');
4738     bsc_aw_utility.add_g_commands(g_commands,'then break');
4739     bsc_aw_utility.add_g_commands(g_commands,'doend');
4740     bsc_aw_utility.exec_program_commands(p_name,g_commands);
4741     --limit the dimensions
4742     for i in 1..l_dim_levels.count loop
4743       if l_dim_level_dims(i) <> l_dim_levels(i) then
4744         bsc_aw_dbms_aw.execute('limit '||l_dim_level_dims(i)||' to '||l_dim_levels(i));
4745       end if;
4746     end loop;
4747   end if;
4748 Exception when others then
4749   log_n('Exception in create_dmp_program '||sqlerrm);
4750   raise;
4751 End;
4752 
4753 procedure get_missing_periodicity(p_kpi kpi_r,p_dim_set in out nocopy dim_set_r) is
4754 --
4755 l_periodicity_dim dbms_sql.varchar2_table;
4756 l_lowest_level dbms_sql.varchar2_table;
4757 l_initial_count number;
4758 l_flag boolean;
4759 Begin
4760   l_initial_count:=p_dim_set.calendar.periodicity.count;
4761   for i in 1..p_dim_set.calendar.periodicity.count loop
4762     l_periodicity_dim(l_periodicity_dim.count+1):=p_dim_set.calendar.periodicity(i).aw_dim;
4763   end loop;
4764   --
4765   bsc_aw_calendar.get_missing_periodicity(p_dim_set.calendar.aw_dim,l_periodicity_dim,l_lowest_level);
4766   --
4767   for i in 1..l_periodicity_dim.count loop
4768     l_flag:=false;
4769     for j in 1..p_dim_set.calendar.periodicity.count loop
4773         l_flag:=true;
4770       if p_dim_set.calendar.periodicity(j).aw_dim=l_periodicity_dim(i) then
4771         p_dim_set.calendar.periodicity(j).lowest_level:=l_lowest_level(i);
4772         p_dim_set.calendar.periodicity(j).missing_level:='N';
4774         exit;
4775       end if;
4776     end loop;
4777     if l_flag=false then
4778       p_dim_set.calendar.periodicity(p_dim_set.calendar.periodicity.count+1).aw_dim:=l_periodicity_dim(i);
4779       p_dim_set.calendar.periodicity(p_dim_set.calendar.periodicity.count).lowest_level:=l_lowest_level(i);
4780       p_dim_set.calendar.periodicity(p_dim_set.calendar.periodicity.count).missing_level:='Y';
4781     end if;
4782   end loop;
4783   if l_initial_count < p_dim_set.calendar.periodicity.count then --we need to add periodicity id to the new dim..this is re-read cal info
4784     bsc_aw_md_api.get_dim_set_calendar(p_kpi,p_dim_set);
4785   end if;
4786 Exception when others then
4787   log_n('Exception in get_missing_periodicity '||sqlerrm);
4788   raise;
4789 End;
4790 
4791 function get_periodicity_r(p_periodicity periodicity_tb,p_periodicity_dim varchar2) return periodicity_r is
4792 Begin
4793   for i in 1..p_periodicity.count loop
4794     if p_periodicity(i).aw_dim=p_periodicity_dim then
4795       return p_periodicity(i);
4796     end if;
4797   end loop;
4798   return null;
4799 Exception when others then
4800   log_n('Exception in get_periodicity_r '||sqlerrm);
4801   raise;
4802 End;
4803 
4804 function get_periodicity_r(p_periodicity periodicity_tb,p_periodicity_id number) return periodicity_r is
4805 Begin
4806   for i in 1..p_periodicity.count loop
4807     if p_periodicity(i).periodicity=p_periodicity_id then
4808       return p_periodicity(i);
4809     end if;
4810   end loop;
4811   return null;
4812 Exception when others then
4813   log_n('Exception in get_periodicity_r '||sqlerrm);
4814   raise;
4815 End;
4816 
4817 /*
4818 we have to handle re-agg of cubes when dim hier change. we do inc aggregations. this means we do limit dim to limit.cube
4819 this has an issue. if dim A needs re-agg, then we cannot limit dim B to limit cube. if we do, we re-agg only a portion
4820 of the data in the cube. if A has re-agg, we have to limit the limit cube to the composite of the cubes.
4821 we limit it to the composite of the cube for efficiency. we want to re-agg only those data that has to be re-aggregated. so we
4822 do not want to limit B to all values.
4823 this program must be called before calling the load of the dimset. the reason is that we want to do this
4824 only to those values of dim that have undergone hier change. if we load data, limit cubes capture inc data also
4825 */
4826 procedure create_aggregate_marker_pgm(
4827 p_kpi kpi_r,
4828 p_dim_set dim_set_r
4829 )is
4830 --
4831 l_composite_name dbms_sql.varchar2_table;
4832 l_flag boolean;
4833 l_cube cube_tb;
4834 Begin
4835   --note>>> we dont do this for std dim since they are single level dim
4836   for i in 1..p_dim_set.measure.count loop
4837     l_cube(i):=get_cube_set_r(p_dim_set.measure(i).cube,p_dim_set).cube;
4838     for j in 1..l_cube(i).cube_axis.count loop
4839       if l_cube(i).cube_axis(j).axis_type='partition template' or l_cube(i).cube_axis(j).axis_type='composite' then
4840         if bsc_aw_utility.in_array(l_composite_name,l_cube(i).cube_axis(j).axis_name)=false then
4841           l_composite_name(l_composite_name.count+1):=l_cube(i).cube_axis(j).axis_name;
4842         end if;
4843       end if;
4844     end loop;
4845   end loop;
4846   --there must be 1 entry only for l_composite_name, either a PT or composite
4847   l_flag:=false;
4848   g_commands.delete;
4849   bsc_aw_utility.add_g_commands(g_commands,'dfn '||p_dim_set.aggregate_marker_program||' program');
4850   l_flag:=true;
4851   for i in 1..p_dim_set.dim.count loop
4852     if p_dim_set.dim(i).aggregate_marker is not null then --there is a aggregate marker
4853       bsc_aw_utility.add_g_commands(g_commands,'allstat');
4854       bsc_aw_utility.add_g_commands(g_commands,'if '||p_dim_set.dim(i).aggregate_marker||' EQ true');
4855       bsc_aw_utility.add_g_commands(g_commands,'then do');
4856       bsc_aw_utility.add_g_commands(g_commands,'limit '||p_dim_set.dim(i).dim_name||' to '||p_dim_set.dim(i).limit_cube);
4857       bsc_aw_utility.add_g_commands(g_commands,'limit '||p_dim_set.dim(i).dim_name||' add ancestors using '||p_dim_set.dim(i).relation_name);
4858       for j in 1..p_dim_set.dim.count loop
4859         if i<>j then
4860           for k in 1..l_composite_name.count loop
4861             bsc_aw_utility.add_g_commands(g_commands,p_dim_set.dim(j).limit_cube||'=true across '||l_composite_name(k));
4862           end loop;
4863         end if;
4864       end loop;
4865       for j in 1..p_dim_set.std_dim.count loop
4866         for k in 1..l_composite_name.count loop
4867           bsc_aw_utility.add_g_commands(g_commands,p_dim_set.std_dim(j).limit_cube||'=true across '||l_composite_name(k));
4868         end loop;
4869       end loop;
4870       for j in 1..l_composite_name.count loop
4871         bsc_aw_utility.add_g_commands(g_commands,p_dim_set.calendar.limit_cube||'=true across '||l_composite_name(j));
4872       end loop;
4873       bsc_aw_utility.add_g_commands(g_commands,'doend');
4874     end if;
4875   end loop;
4876   --for the reset cubes. loop across each dim and if each dim has a situation where a parent now no longer has any child nodes,
4877   --set the value of the cube to na
4878   for i in 1..p_dim_set.dim.count loop
4879     if p_dim_set.dim(i).reset_cube is not null and p_dim_set.dim(i).aggregate_marker is not null then --there is a aggregate marker and reset cube
4880       bsc_aw_utility.add_g_commands(g_commands,'if '||p_dim_set.dim(i).aggregate_marker||' EQ true');
4881       bsc_aw_utility.add_g_commands(g_commands,'then do');
4882       bsc_aw_utility.add_g_commands(g_commands,'allstat');
4883       bsc_aw_utility.add_g_commands(g_commands,'limit '||p_dim_set.dim(i).dim_name||' to '||p_dim_set.dim(i).reset_cube);
4887       for j in 1..p_dim_set.measure.count loop
4884       bsc_aw_utility.add_g_commands(g_commands,'if statlen('||p_dim_set.dim(i).dim_name||') GT 0');
4885       bsc_aw_utility.add_g_commands(g_commands,'then do');
4886       bsc_aw_utility.init_is_new_value(1);
4888         for k in 1..l_cube(j).cube_axis.count loop
4889           if l_cube(j).cube_axis(k).axis_type='partition template' or l_cube(j).cube_axis(k).axis_type='composite' then
4890             if bsc_aw_utility.is_new_value(p_dim_set.measure(j).cube,1) then
4891               bsc_aw_utility.add_g_commands(g_commands,p_dim_set.measure(j).cube||'=NA across '||l_cube(j).cube_axis(k).axis_name);
4892             end if;
4893           end if;
4894         end loop;
4895       end loop;
4896       bsc_aw_utility.add_g_commands(g_commands,'doend');
4897       bsc_aw_utility.add_g_commands(g_commands,'doend');
4898     end if;
4899   end loop;
4900   --reset values
4901   bsc_aw_utility.add_g_commands(g_commands,'allstat');
4902   for i in 1..p_dim_set.dim.count loop
4903     if p_dim_set.dim(i).aggregate_marker is not null then
4904       bsc_aw_utility.add_g_commands(g_commands,p_dim_set.dim(i).aggregate_marker||'=false');
4905     end if;
4906     if p_dim_set.dim(i).reset_cube is not null then
4907       if p_dim_set.dim(i).limit_cube_composite is not null then
4908         bsc_aw_utility.add_g_commands(g_commands,p_dim_set.dim(i).reset_cube||'=false across '||p_dim_set.dim(i).limit_cube_composite);
4909       else
4910         bsc_aw_utility.add_g_commands(g_commands,p_dim_set.dim(i).reset_cube||'=false');
4911       end if;
4912     end if;
4913   end loop;
4914   if l_flag then
4915     bsc_aw_utility.exec_program_commands(p_dim_set.aggregate_marker_program,g_commands);
4916   end if;
4917 Exception when others then
4918   log_n('Exception in create_aggregate_marker_pgm '||sqlerrm);
4919   raise;
4920 End;
4921 
4922 /*this procedure will load the master partition template pattern. then the dimset PT can make copies from this.
4923 this is the main procedure that will set the partition aspects of the dimset*/
4924 procedure load_master_PT(p_actual_dim_set in out nocopy dim_set_r,p_target_dim_set in out nocopy dim_set_r) is
4925 Begin
4926   if g_debug then
4927     log('load_master_PT '||p_actual_dim_set.dim_set_name);
4928   end if;
4929   if check_partition_possible(p_actual_dim_set,p_target_dim_set) then
4930     set_pt_type_count(p_actual_dim_set);
4931     if p_actual_dim_set.targets_higher_levels='Y' then
4932       set_pt_type_count(p_target_dim_set);
4933     end if;
4934     if p_actual_dim_set.number_partitions>0 then
4935       set_master_PT(p_actual_dim_set);
4936       /*this sets the hash dim to partition on if pt type=hash for example. may also turn off partitions if partitions cannot be implemented
4937       for the type specified */
4938       if p_actual_dim_set.number_partitions>0 then
4939         if p_actual_dim_set.targets_higher_levels='Y' then
4940           if p_target_dim_set.number_partitions>0 then
4941             set_master_PT(p_target_dim_set);
4942           end if;
4943         end if;
4944       else
4945         p_target_dim_set.number_partitions:=0;
4946       end if;
4947     end if;
4948   else
4949     p_actual_dim_set.number_partitions:=0;
4950     p_target_dim_set.number_partitions:=0;
4951   end if;
4952   if g_debug then
4953     if p_actual_dim_set.number_partitions>0 then
4954       log('Finally, Master Partition Template for Actuals');
4955       dmp_partition_template(p_actual_dim_set.master_partition_template(1));
4956       if p_actual_dim_set.targets_higher_levels='Y' then
4957         log('Finally, Master Partition Template for Targets');
4958         dmp_partition_template(p_target_dim_set.master_partition_template(1));
4959       end if;
4960     else
4961       log('Finally, No partitions');
4962     end if;
4963   end if;
4964 Exception when others then
4965   log_n('Exception in load_master_PT  '||sqlerrm);
4966   raise;
4967 End;
4968 
4969 /*right now, partitions are checked at dimset level. this means all cubes of a dimset have partitions or none have */
4970 function check_partition_possible(p_actual_dim_set in out nocopy dim_set_r,p_target_dim_set in out nocopy dim_set_r) return boolean is
4971 l_partition_count number;
4972 display_cube_flag boolean;
4973 actual_periodicity periodicity_tb;
4974 target_periodicity periodicity_tb;
4975 flag boolean;
4976 Begin
4977   if g_debug then
4978     log('check_partition_possible dimset '||p_actual_dim_set.dim_set_name||', with target '||p_target_dim_set.dim_set_name);
4979   end if;
4980   if bsc_aw_utility.get_db_version<10.2 then
4981     if g_debug then
4982       log('DB < 10.2. No partitions');
4983     end if;
4984     return false;
4985   end if;
4986   --
4987   if p_actual_dim_set.dim.count=0 then
4988     if g_debug then
4989       log('Only std dim and time, No other dimensions. No partitions');
4990     end if;
4991     return false;
4992   end if;
4993   --
4994   if nvl(bsc_aw_utility.get_parameter_value('NO PARTITION'),'N')='Y' then
4995     if g_debug then
4996       log('No partition specified.');
4997     end if;
4998     return false;
4999   end if;
5000   /*we have an issue with compressed composite and partitions in 10.104. clear all from aggregates does not work when we have cc
5001   and pt. 10.2, it should be resolved. if cc is specified, gets priority over pt specification
5002   we have partitions only when db is 10.2 and greater
5003   */
5004   --
5005   l_partition_count:=get_partition_count;
5006   if l_partition_count is null or l_partition_count<2 then
5007     if g_debug then
5008       log('Max possible partition count<2. No partitions');
5009     end if;
5010     return false;
5011   end if;
5012   /* */
5013   display_cube_flag:=is_display_cube_possible(p_actual_dim_set);
5014   if display_cube_flag=false then
5018       end if;
5015     if check_countvar_cube_needed(p_actual_dim_set) then
5016       if g_debug then
5017         log('Countvar cube needed. Partitions not possible');
5019       return false;
5020     end if;
5021     /*if sql aggregations are enabled, we can go for partitions. the view has the formula in it */
5022     for i in 1..p_actual_dim_set.measure.count loop
5023       if p_actual_dim_set.measure(i).sql_aggregated='N' then
5024         if p_actual_dim_set.measure(i).agg_formula.std_aggregation='N' then
5025           if g_debug then
5026             log('Non std agg in dimset '||p_actual_dim_set.dim_set||', partitions not possible');
5027           end if;
5028           return false;
5029         end if;
5030         /*for now, if thereis AVERAGE or COUNT aggregation, we disable partitions */
5031         if bsc_aw_utility.is_PT_aggregation_function(p_actual_dim_set.measure(i).agg_formula.agg_formula)='N' then
5032           if g_debug then
5033             log('Non partitionable aggregation function '||p_actual_dim_set.measure(i).agg_formula.agg_formula);
5034           end if;
5035           return false;
5036         end if;
5037       end if;
5038     end loop;
5039   else
5040     if g_debug then
5041       log('Display cube is possible. This means we can have partitions when there is AVERAGE or Non Std Aggregations');
5042     end if;
5043   end if;
5044   /*if there are targets at higher levels, we disable partitions
5045   targets can be partitioned if actuals are partitioned or not. however, actuals cannot be partitioned if there are targets.
5046   for targets we can introduce year based partitions. question is : is it really worth it. year based partitions (still list) will help
5047   parallelize initial aggregations. on an inc basis, there is no help. if a dbi style kpi is brought into bsc, it will not have targets at higher
5048   levels mostly. even without partitions, aw aggregations are fast. so not worth it to introduce year based aggregations
5049   --
5050   with hash partitions on time and agg on time on the fly, we can partition targets at higher levels as long as targets and actuals are at the
5051   same periodicity level. if actuals are at day and targets at month, no partitions. if at the same periodicity level, we enable only hash
5052   partitions on time. must make sure we have only hash and only on time. targets do not have rollups. so the system must not select list partitions
5053   for it. we can partition when there are targets as long as actuals and targets have the same number of partitions and a given period is guaranteed
5054   to be in P.x of actuals and P.x of targets
5055   */
5056   if p_actual_dim_set.targets_higher_levels='Y' then
5057     if nvl(bsc_aw_utility.get_parameter_value('NO TARGET PARTITION'),'N')='Y' then
5058       if g_debug then
5059         log('Targets at higher level and NO TARGET PARTITION specified. No partitions');
5060       end if;
5061       return false;
5062     end if;
5063     if g_debug then
5064       log('Targets at higher level. Partitions are possible only if targets and actuals have the same periodicity');
5065     end if;
5066     actual_periodicity:=get_dim_set_lowest_periodicity(p_actual_dim_set);
5067     target_periodicity:=get_dim_set_lowest_periodicity(p_target_dim_set);
5068     for i in 1..target_periodicity.count loop
5069       flag:=false;
5070       for j in 1..actual_periodicity.count loop
5071         if actual_periodicity(j).aw_dim=target_periodicity(i).aw_dim then
5072           flag:=true;
5073           exit;
5074         end if;
5075       end loop;
5076       if flag=false then
5077         if g_debug then
5078           log('Targets and Actuals do not have the same periodicity. Partitions not possible');
5079         end if;
5080         return false;
5081       end if;
5082     end loop;
5083     if g_debug then
5084       log('Partitions are possible. Only HASH partitions on Time Dimension');
5085     end if;
5086     bsc_aw_utility.merge_property(p_actual_dim_set.property,'hash partition',null,'Y');
5087     bsc_aw_utility.merge_property(p_actual_dim_set.property,'hash partition only time',null,'Y');
5088     /* */
5089     bsc_aw_utility.merge_property(p_target_dim_set.property,'hash partition',null,'Y');
5090     bsc_aw_utility.merge_property(p_target_dim_set.property,'hash partition only time',null,'Y');
5091   end if;
5092   /*partition possible*/
5093   return true;
5094 Exception when others then
5095   log_n('Exception in check_partition_possible  '||sqlerrm);
5096   raise;
5097 End;
5098 
5099 /*check to see if list partition is possible or we need hash partition the number of partitions are set here*/
5100 procedure set_pt_type_count(p_dim_set in out nocopy dim_set_r) is
5101 l_bt_pt_type varchar2(40);
5102 l_bt_pt_count number;
5103 l_bt_levels dbms_sql.varchar2_table;
5104 l_reason varchar2(8000);
5105 l_partition_count number;
5106 Begin
5107   if bsc_aw_utility.get_property(p_dim_set.property,'hash partition').property_value='Y' then
5108     p_dim_set.partition_type:='hash';
5109   else
5110     p_dim_set.partition_type:='list';--default
5111   end if;
5112   l_bt_levels.delete;
5113   for i in 1..p_dim_set.data_source(1).base_tables(1).levels.count loop
5114     l_bt_levels(l_bt_levels.count+1):=p_dim_set.data_source(1).base_tables(1).levels(i).level_name;
5115   end loop;
5116   /*list partitions are possible if this dimset has no aggregation in it and the dimset has the same number of keys at the same level
5117   as the B tables. also the periodicity must match */
5118   if p_dim_set.partition_type='list' then
5119     for i in 1..p_dim_set.dim.count loop
5120       if p_dim_set.dim(i).levels.count>1 then /*there is rollup */
5121         p_dim_set.partition_type:='hash';
5122         l_reason:='Dim '||p_dim_set.dim(i).dim_name||' has rollup. List partitions not possible';
5123         exit;
5124       end if;
5125     end loop;
5126     if p_dim_set.partition_type='list' then /*see if there is time rollup */
5127       for i in 1..p_dim_set.calendar.periodicity.count loop
5131         end if;
5128         if p_dim_set.calendar.periodicity(i).lowest_level<>'Y' then
5129           p_dim_set.partition_type:='hash';
5130           l_reason:='Dimset calendar has rollup. List partitions not possible';
5132       end loop;
5133     end if;
5134     if p_dim_set.partition_type='list' then
5135       if p_dim_set.dim.count<>l_bt_levels.count then
5136         p_dim_set.partition_type:='hash';
5137         l_reason:='Dimset has diff number of dimension keys than B table. Only hash partition possible';
5138       end if;
5139     end if;
5140     if p_dim_set.partition_type='list' then
5141       for i in 1..p_dim_set.dim.count loop
5142         if bsc_aw_utility.in_array(l_bt_levels,p_dim_set.dim(i).levels(1).level_name)=false then
5143           p_dim_set.partition_type:='hash';
5144           l_reason:='Dimset has diff dim levels than B table. Only hash partition possible';
5145           exit;
5146         end if;
5147       end loop;
5148     end if;
5149   end if;
5150   if p_dim_set.partition_type='list' then
5151     for i in 1..p_dim_set.data_source.count loop
5152       for j in 1..p_dim_set.data_source(i).base_tables.count loop
5153         if p_dim_set.data_source(i).base_tables(j).levels.count<>l_bt_levels.count then
5154           l_reason:='B table '||p_dim_set.data_source(i).base_tables(j).base_table_name||' has '||p_dim_set.data_source(i).base_tables(j).levels.count||
5155           ' number of levels while the first B table has '||l_bt_levels.count||' levels. List partitions not possible';
5156           p_dim_set.partition_type:='hash';
5157           exit;
5158         end if;
5159         /*check that each levels match */
5160         for k in 1..p_dim_set.data_source(i).base_tables(j).levels.count loop
5161           if bsc_aw_utility.in_array(l_bt_levels,p_dim_set.data_source(i).base_tables(j).levels(k).level_name)=false then
5162             l_reason:='B table '||p_dim_set.data_source(i).base_tables(j).base_table_name||' has level '||
5163             p_dim_set.data_source(i).base_tables(j).levels(k).level_name||' that is not in the first B table. List partitions not possible';
5164             p_dim_set.partition_type:='hash';
5165             exit;
5166           end if;
5167         end loop;
5168       end loop;
5169       /*check that there is no periodicity rollup reqd from any B table */
5170       if p_dim_set.data_source(i).calendar.periodicity(1).periodicity<>p_dim_set.data_source(i).base_tables(1).periodicity.periodicity then
5171         p_dim_set.partition_type:='hash';
5172         l_reason:='B table '||p_dim_set.data_source(i).base_tables(1).base_table_name||' needs rollup in periodicity. List partitions not possible';
5173       end if;
5174       if p_dim_set.partition_type='hash' then /*list partitions not possible */
5175         exit;
5176       end if;
5177     end loop;
5178   end if;
5179   /*if we can go for list partitions, now make sure that all B tables have the same list partitions */
5180   if p_dim_set.partition_type='list' then
5181     l_bt_pt_type:=nvl(p_dim_set.data_source(1).base_tables(1).table_partition.main_partition.partition_type,'none');
5182     l_bt_pt_count:=p_dim_set.data_source(1).base_tables(1).table_partition.main_partition.partitions.count;
5183     if l_bt_pt_type='LIST' and l_bt_pt_count>0 then
5184       for i in 1..p_dim_set.data_source.count loop
5185         for j in 1..p_dim_set.data_source(i).base_tables.count loop
5186           if nvl(p_dim_set.data_source(i).base_tables(j).table_partition.main_partition.partition_type,'none')<>l_bt_pt_type
5187           or p_dim_set.data_source(i).base_tables(j).table_partition.main_partition.partitions.count<>l_bt_pt_count then
5188             l_reason:='B table '||p_dim_set.data_source(i).base_tables(j).base_table_name||' has diff partition parameters.'||
5189             'List partitions on dimset not possible';
5190             p_dim_set.partition_type:='hash';
5191             exit;
5192           end if;
5193         end loop;
5194         if p_dim_set.partition_type='hash' then /*list partitions not possible */
5195           exit;
5196         end if;
5197       end loop;
5198     else
5199       l_reason:='B table does not have LIST partitions. So we can only attempt hash partitions';
5200       p_dim_set.partition_type:='hash';
5201     end if;
5202   end if;
5203   --
5204   if p_dim_set.partition_type='hash' then
5205     if g_debug then
5206       log('We can only try hash partitions for dimset '||p_dim_set.dim_set_name||'. Reason: '||l_reason);
5207     end if;
5208   end if;
5209   --
5210   l_reason:=null;
5211   l_partition_count:=get_partition_count;
5212   if p_dim_set.partition_type='list' then
5213     if l_bt_pt_count>l_partition_count then
5214       l_partition_count:=0;
5215       l_reason:='B tables have number of partitions='||l_bt_pt_count||' while max allowed partitions are '||l_partition_count||
5216       '. Cannot have partitions';
5217     elsif l_bt_pt_count<l_partition_count then
5218       l_partition_count:=l_bt_pt_count;
5219       l_reason:='B tables have number of partitions='||l_bt_pt_count||' while max allowed partitions are '||l_partition_count||
5220       '. Reducing number of partition to '||l_bt_pt_count;
5221     end if;
5222   end if;
5223   if l_partition_count is null then
5224     l_partition_count:=0;
5225   end if;
5226   p_dim_set.number_partitions:=l_partition_count;
5227   if g_debug then
5228     log('Finally, Dimset '||p_dim_set.dim_set||', partition type='||p_dim_set.partition_type||', number partitions='||
5229     p_dim_set.number_partitions||' and any reason(null if nothing)='||l_reason);
5230   end if;
5231 Exception when others then
5232   log_n('Exception in set_pt_type_count  '||sqlerrm);
5233   raise;
5234 End;
5235 
5236 /*here, we set the master PT template for list or hash or range partitions
5237 master PT only contains the logical metadata. will not contain axis info. this is loaded in create_pt_comp_names*/
5238 procedure set_master_PT(p_dim_set in out nocopy dim_set_r) is
5239 Begin
5243   p_dim_set.master_partition_template(1).template_use:='datacube';/*this pt is meant for cubes */
5240   p_dim_set.partition_dim:='hash_partition_dim';
5241   p_dim_set.master_partition_template(1).template_name:='master PT';
5242   p_dim_set.master_partition_template(1).template_type:='list'; /*hash and list are AW list partitions */
5244   p_dim_set.master_partition_template(1).template_dim:=p_dim_set.partition_dim;
5245   if p_dim_set.partition_type='hash' then
5246     if set_PT_hash_dimensions(p_dim_set,p_dim_set.master_partition_template(1)) then
5247       set_PT_dim_aggregated(p_dim_set,p_dim_set.master_partition_template(1));/*sets the aggregated flag */
5248       set_PT_calendar_aggregated(p_dim_set,p_dim_set.master_partition_template(1));/*sets the aggregated flag */
5249     else
5250      p_dim_set.number_partitions:=0;
5251      p_dim_set.partition_dim:=null;
5252      reset_PT_template(p_dim_set.master_partition_template(1));
5253      if g_debug then
5254        log('No Hash Partitions possible for '||p_dim_set.dim_set_name);
5255      end if;
5256     end if;
5257   end if;
5258 Exception when others then
5259   log_n('Exception in set_master_PT  '||sqlerrm);
5260   raise;
5261 End;
5262 
5263 /*this api must set the hash partition dim. what dim this sets has implication on what levels will get aggregated.
5264 if this sets partition at lowest calendar level (day) there is no aggrgation in time except at runtime
5265 if this is set at state, there is aggregation upto state. we will change the agg level per dim to reflect this
5266 have to account for targets. there are no partitions when there are targets. but still, must make sure that we do not include dim that have
5267 targets coming at diff levels
5268 if balance measures are involved and we partition on time, they are still aggregated to top levels in time since this is done in the
5269 load program itself. aggregation online is for non bal measures only
5270 if we have multiple lowest levels in a dim like
5271 city>-state>-country
5272 county>-state>-country, if we decide to partition on city, we must also partition on county because otherwise, data coming at county level
5273 has no partition to go to
5274 if the return flag=false, it means this api could not find dim suitable to hash partition on
5275 */
5276 function set_PT_hash_dimensions(p_dim_set dim_set_r,p_partition_template in out nocopy partition_template_r) return boolean is
5277 partition_time boolean;
5278 partition_dim boolean;
5279 Begin
5280   p_partition_template.hpt_data.hpt_dimensions.delete;
5281   p_partition_template.hpt_data.hpt_calendar.dim_name:=null;
5282   /*for now, we hash on time only. must handle kpi that only have year level.for now, if there is year only kpi, no hash partitions possible */
5283   /*if we have yearly kpi or balance last value measure, we cannot hash on time. if we just have balance measure (based on period end), we
5284   can hash on time. upper time nodes will not be duplicated across partitions in this case */
5285   if p_dim_set.calendar.periodicity.count=1 then
5286     if p_dim_set.calendar.periodicity(1).periodicity_type='1' then
5287       if g_debug then
5288         log('HASH Partitions not possible on time as the KPI is YEARLY kpi');
5289       end if;
5290       return false;
5291     end if;
5292   end if;
5293   /*check for balance last value */
5294   for i in 1..p_dim_set.measure.count loop
5295     if p_dim_set.measure(i).measure_type=g_balance_last_value_prop then
5296       if g_debug then
5297         log('HASH Partitions not possible on time as the KPI has measure of type '||g_balance_last_value_prop);
5298       end if;
5299       return false;
5300     end if;
5301   end loop;
5302   partition_dim:=false; /*for now, no dim involved in hash partitions */
5303   partition_time:=true;
5304   if bsc_aw_utility.get_property(p_dim_set.property,'hash partition only time').property_value='Y' then
5305     partition_dim:=false;/*this will be the case for targets at higher levels */
5306   end if;
5307   if partition_time then
5308     p_partition_template.hpt_data.hpt_calendar.dim_name:=p_dim_set.calendar.aw_dim;
5309     p_partition_template.hpt_data.hpt_calendar.dim_type:='time';
5310     p_partition_template.hpt_data.hpt_calendar.level_names.delete;
5311     p_partition_template.hpt_data.hpt_calendar.level_keys.delete;
5312     for i in 1..p_dim_set.calendar.periodicity.count loop
5313       if p_dim_set.calendar.periodicity(i).lowest_level='Y' then
5314         p_partition_template.hpt_data.hpt_calendar.level_names(
5315         p_partition_template.hpt_data.hpt_calendar.level_names.count+1):=
5316         p_dim_set.calendar.periodicity(i).aw_dim;
5317         p_partition_template.hpt_data.hpt_calendar.level_keys(
5318         p_partition_template.hpt_data.hpt_calendar.level_keys.count+1):='period';
5319       end if;
5320     end loop;
5321   end if;
5322   /*if we needed to partition on time, we can do so here. but for now, there are partitions only on time */
5323   if partition_dim then
5324     null;
5325   end if;
5326   if g_debug then
5327     log('set_PT_hash_dimensions for template '||p_partition_template.template_name);
5328     dmp_hpt_data(p_partition_template.hpt_data);
5329   end if;
5330   return true;
5331 Exception when others then
5332   log_n('Exception in set_PT_hash_dimensions '||sqlerrm);
5333   raise;
5334 End;
5335 
5336 /*sets the aggregated flag */
5337 procedure set_PT_dim_aggregated(p_dim_set in out nocopy dim_set_r,p_partition_template partition_template_r) is
5338 Begin
5339   for i in 1..p_dim_set.dim.count loop
5340     for j in 1..p_partition_template.hpt_data.hpt_dimensions.count loop
5341       if p_dim_set.dim(i).dim_name=p_partition_template.hpt_data.hpt_dimensions(j).dim_name then
5342         set_PT_dim_aggregated(p_dim_set.dim(i),p_dim_set,p_partition_template.hpt_data.hpt_dimensions(j).level_names);
5343         --
5344         exit;
5345       end if;
5346     end loop;
5347   end loop;
5348 Exception when others then
5349   log_n('Exception in set_PT_dim_aggregated '||sqlerrm);
5350   raise;
5351 End;
5352 
5356 l_child_levels dbms_sql.varchar2_table;
5353 procedure set_PT_dim_aggregated(p_dim in out nocopy dim_r,p_dim_set dim_set_r,p_levels dbms_sql.varchar2_table) is
5354 l_parent_child bsc_aw_adapter_dim.dim_parent_child_tb;
5355 l_pc bsc_aw_utility.parent_child_tb;
5357 zero_aggregated dbms_sql.varchar2_table;
5358 aggregated dbms_sql.varchar2_table;
5359 Begin
5360   bsc_aw_md_api.get_dim_parent_child(p_dim.dim_name,l_parent_child);
5361   for i in 1..l_parent_child.count loop
5362     if l_parent_child(i).parent_level is not null and l_parent_child(i).child_level is not null then
5363       l_pc(l_pc.count+1).parent:=l_parent_child(i).parent_level;
5364       l_pc(l_pc.count).child:=l_parent_child(i).child_level;
5365     end if;
5366   end loop;
5367   /*if there is partition at country say, we can rollup to country but not perform zero code */
5368   for i in 1..p_dim.levels.count loop
5369     if bsc_aw_utility.in_array(p_levels,p_dim.levels(i).level_name) then
5370       /*p_dim.levels(i).aggregated is left unchanged*/
5371       p_dim.levels(i).zero_aggregated:='N';/*there cannot be zero code aggregation at this level */
5372       aggregated(i):=p_dim.levels(i).aggregated;
5373       zero_aggregated(i):=p_dim.levels(i).zero_aggregated;
5374       if g_debug then
5375         log('Dimension '||p_dim.dim_name||', Partition Level '||p_dim.levels(i).level_name||' aggregated='''||p_dim.levels(i).aggregated||
5376         ''', zero_aggregated='''||p_dim.levels(i).zero_aggregated||'''');
5377       end if;
5378     else
5379       aggregated(i):=p_dim.levels(i).aggregated;
5380       zero_aggregated(i):=p_dim.levels(i).zero_aggregated;/*capture the prev setting for zero_aggregated */
5381       p_dim.levels(i).aggregated:='N';
5382       p_dim.levels(i).zero_aggregated:='N';
5383     end if;
5384   end loop;
5385   if l_pc.count>0 then
5386     for i in 1..p_levels.count loop
5387       l_child_levels.delete;
5388       bsc_aw_utility.get_all_children(l_pc,p_levels(i),l_child_levels);
5389       if l_child_levels.count>0 then
5390         for j in 1..p_dim.levels.count loop
5391           if bsc_aw_utility.in_array(l_child_levels,p_dim.levels(j).level_name) then
5392             p_dim.levels(j).aggregated:=aggregated(j);
5393             p_dim.levels(j).zero_aggregated:=zero_aggregated(j);
5394             if g_debug then
5395               log('Dimension '||p_dim.dim_name||', Child Level '||p_dim.levels(j).level_name||' aggregated='''||p_dim.levels(j).aggregated||
5396               ''', zero_aggregated='''||p_dim.levels(j).zero_aggregated||'''');
5397             end if;
5398           end if;
5399         end loop;
5400       end if;
5401     end loop;
5402   end if;
5403 Exception when others then
5404   log_n('Exception in set_PT_dim_aggregated '||sqlerrm);
5405   raise;
5406 End;
5407 
5408 /*sets the aggregated flag */
5409 procedure set_PT_calendar_aggregated(p_dim_set in out nocopy dim_set_r,p_partition_template partition_template_r) is
5410 Begin
5411   if p_partition_template.hpt_data.hpt_calendar.dim_name is not null then /*There is partitioning on Calendar */
5412     set_PT_calendar_aggregated(p_dim_set.calendar,p_dim_set,p_partition_template.hpt_data.hpt_calendar.level_names);
5413   end if;
5414 Exception when others then
5415   log_n('Exception in set_PT_calendar_aggregated '||sqlerrm);
5416   raise;
5417 End;
5418 
5419 procedure set_PT_calendar_aggregated(p_calendar in out nocopy calendar_r,p_dim_set dim_set_r,p_levels dbms_sql.varchar2_table) is
5420 l_pc bsc_aw_utility.parent_child_tb;
5421 l_child_levels dbms_sql.varchar2_table;
5422 aggregated dbms_sql.varchar2_table;
5423 Begin
5424   for i in 1..p_calendar.parent_child.count loop
5425     if p_calendar.parent_child(i).parent_dim_name is not null and p_calendar.parent_child(i).child_dim_name is not null then
5426       l_pc(l_pc.count+1).parent:=p_calendar.parent_child(i).parent_dim_name;
5427       l_pc(l_pc.count).child:=p_calendar.parent_child(i).child_dim_name;
5428     end if;
5429   end loop;
5430   for i in 1..p_calendar.periodicity.count loop
5431     if bsc_aw_utility.in_array(p_levels,p_calendar.periodicity(i).aw_dim) then
5432       /*p_calendar.periodicity(i).aggregated is left unchanged */
5433       aggregated(i):=p_calendar.periodicity(i).aggregated;/*could be Y or N */
5434     else
5435       aggregated(i):=p_calendar.periodicity(i).aggregated;
5436       p_calendar.periodicity(i).aggregated:='N';/*init all to N. then from the PT levels, drill down and mark as Y */
5437     end if;
5438   end loop;
5439   if l_pc.count>0 then
5440     for i in 1..p_levels.count loop
5441       l_child_levels.delete;
5442       bsc_aw_utility.get_all_children(l_pc,p_levels(i),l_child_levels);
5443       if l_child_levels.count>0 then
5444         for j in 1..p_calendar.periodicity.count loop
5445           if bsc_aw_utility.in_array(l_child_levels,p_calendar.periodicity(j).aw_dim) then
5446             p_calendar.periodicity(j).aggregated:=aggregated(j);
5447             if g_debug then
5448               log('Calendar '||p_calendar.aw_dim||', Child Periodicity '||p_calendar.periodicity(j).aw_dim||' aggregated='''||
5449               p_calendar.periodicity(j).aggregated||'''');
5450             end if;
5451           end if;
5452         end loop;
5453       end if;
5454     end loop;
5455   end if;
5456 Exception when others then
5457   log_n('Exception in set_PT_calendar_aggregated '||sqlerrm);
5458   raise;
5459 End;
5460 
5461 function get_partition_count return number is
5462 l_cpu_count number;
5463 l_partition_count number;
5464 Begin
5465   l_cpu_count:=bsc_aw_utility.get_cpu_count;
5466   l_partition_count:=to_number(bsc_aw_utility.get_parameter_value('NUMBER PARTITION'));--most of the time null
5467   if l_partition_count is null or l_partition_count=0 then
5468     l_partition_count:=bsc_aw_utility.get_min(bsc_aw_utility.get_closest_2_power_number(l_cpu_count),bsc_aw_utility.g_max_partitions);
5469   else
5470     if l_partition_count>l_cpu_count then
5474   if l_partition_count>bsc_aw_utility.g_max_partitions then
5471       l_partition_count:=l_cpu_count; /*max partitions possible is cpu count */
5472     end if;
5473   end if;
5475     l_partition_count:=bsc_aw_utility.g_max_partitions;
5476   end if;
5477   return l_partition_count;
5478 Exception when others then
5479   log_n('Exception in get_partition_count '||sqlerrm);
5480   raise;
5481 End;
5482 
5483 function get_cube_set_r(p_cube_name varchar2,p_dimset dim_set_r) return cube_set_r is
5484 Begin
5485   for i in 1..p_dimset.cube_set.count loop
5486     if p_dimset.cube_set(i).cube.cube_name=p_cube_name then
5487       return p_dimset.cube_set(i);
5488     end if;
5489   end loop;
5490   /*check countvar cube */
5491   for i in 1..p_dimset.cube_set.count loop
5492     if p_dimset.cube_set(i).countvar_cube.cube_name=p_cube_name then
5493       return p_dimset.cube_set(i);
5494     end if;
5495   end loop;
5496   /*check display cube */
5497   for i in 1..p_dimset.cube_set.count loop
5498     if p_dimset.cube_set(i).display_cube.cube_name=p_cube_name then
5499       return p_dimset.cube_set(i);
5500     end if;
5501   end loop;
5502   /* */
5503   return null;
5504 Exception when others then
5505   log_n('Exception in get_cube_set_r '||sqlerrm);
5506   raise;
5507 End;
5508 
5509 function get_composite_r(p_composite_name varchar2,p_dimset dim_set_r) return composite_r is
5510 Begin
5511   for i in 1..p_dimset.composite.count loop
5512     if p_dimset.composite(i).composite_name=p_composite_name then
5513       return p_dimset.composite(i);
5514     end if;
5515   end loop;
5516   return null;
5517 Exception when others then
5518   log_n('Exception in get_composite_r '||sqlerrm);
5519   raise;
5520 End;
5521 
5522 function get_partition_template_r(p_partition_template varchar2,p_dimset dim_set_r) return partition_template_r is
5523 Begin
5524   for i in 1..p_dimset.partition_template.count loop
5525     if p_dimset.partition_template(i).template_name=p_partition_template then
5526       return p_dimset.partition_template(i);
5527     end if;
5528   end loop;
5529   return null;
5530 Exception when others then
5531   log_n('Exception in get_partition_template_r '||sqlerrm);
5532   raise;
5533 End;
5534 
5535 /*
5536 right now, we support p_axis_type of partition template or composite
5537 */
5538 function get_cube_axis(p_cube_name varchar2,p_dimset dim_set_r,p_axis_type varchar2) return varchar2 is
5539 cube_set cube_set_r;
5540 l_cube cube_r;
5541 Begin
5542   cube_set:=get_cube_set_r(p_cube_name,p_dimset);
5543   if cube_set.cube.cube_name=p_cube_name then
5544     l_cube:=cube_set.cube;
5545   elsif cube_set.countvar_cube.cube_name=p_cube_name then
5546     l_cube:=cube_set.countvar_cube;
5547   elsif cube_set.display_cube.cube_name=p_cube_name then
5548     l_cube:=cube_set.display_cube;
5549   end if;
5550   if l_cube.cube_name is not null then
5551     for i in 1..l_cube.cube_axis.count loop
5552       if l_cube.cube_axis(i).axis_type=p_axis_type then
5553         return l_cube.cube_axis(i).axis_name;
5554       end if;
5555     end loop;
5556   end if;
5557   return null;
5558 Exception when others then
5559   log_n('Exception in get_cube_axis '||sqlerrm);
5560   raise;
5561 End;
5562 
5563 /*
5564 let us assume a cube has 1 PT or 1 composite. this function returns either PT or if not found, composite name
5565 */
5566 function get_cube_pt_comp(p_cube_name varchar2,p_dimset dim_set_r,p_type out nocopy varchar2) return varchar2 is
5567 l_pt_name varchar2(200);
5568 Begin
5569   p_type:=null;
5570   l_pt_name:=get_cube_axis(p_cube_name,p_dimset,'partition template');
5571   if l_pt_name is null then
5572     l_pt_name:=get_cube_axis(p_cube_name,p_dimset,'composite');
5573     if l_pt_name is not null then
5574       p_type:='composite';
5575     end if;
5576   else
5577     p_type:='partition template';
5578   end if;
5579   return l_pt_name;
5580 Exception when others then
5581   log_n('Exception in get_cube_pt_comp '||sqlerrm);
5582   raise;
5583 End;
5584 
5585 procedure get_measures_for_cube(
5586 p_cube varchar2,
5587 p_dim_set dim_set_r,
5588 p_measures out nocopy measure_tb) is
5589 Begin
5590   for i in 1..p_dim_set.measure.count loop
5591     if p_dim_set.measure(i).cube=p_cube then
5592       p_measures(p_measures.count+1):=p_dim_set.measure(i);
5593     end if;
5594   end loop;
5595 Exception when others then
5596   log_n('Exception in get_measures_for_cube '||sqlerrm);
5597   raise;
5598 End;
5599 
5600 function get_cube_set_for_measure(p_measure varchar2,p_dim_set dim_set_r) return cube_set_r is
5601 Begin
5602   for i in 1..p_dim_set.measure.count loop
5603     if p_dim_set.measure(i).measure=p_measure then
5604       return get_cube_set_r(p_dim_set.measure(i).cube,p_dim_set);
5605     end if;
5606   end loop;
5607   return null;
5608 Exception when others then
5609   log_n('Exception in get_measures_for_cube '||sqlerrm);
5610   raise;
5611 End;
5612 
5613 /*
5614 this is to register the B table combinations used in the load program. when we load the B tables, we see which one of these combinations
5615 to use
5616 */
5617 procedure set_program_property(p_load_program in out nocopy load_program_r,p_data_source data_source_tb) is
5618 l_ordered_bt dbms_sql.varchar2_table;
5619 Begin
5620   p_load_program.ds_base_tables:=null;
5621   for i in 1..p_data_source.count loop
5622     l_ordered_bt.delete;
5623     for j in 1..p_data_source(i).base_tables.count loop
5624       l_ordered_bt(l_ordered_bt.count+1):=upper(p_data_source(i).base_tables(j).base_table_name);
5625     end loop;
5626     l_ordered_bt:=bsc_aw_utility.order_array(l_ordered_bt);
5630     log('Program name '||p_load_program.program_name||', DS Tables '||p_load_program.ds_base_tables);
5627     p_load_program.ds_base_tables:=p_load_program.ds_base_tables||bsc_aw_utility.make_string_from_list(l_ordered_bt,'^')||'+';
5628   end loop;
5629   if g_debug then
5631   end if;
5632 Exception when others then
5633   log_n('Exception in set_program_property '||sqlerrm);
5634   raise;
5635 End;
5636 
5637 /*
5638 if we know the level name, this api will loop over the dim set dim and their levels and return the
5639 dim structure
5640 */
5641 function get_kpi_level_dim_r(
5642 p_dim_set dim_set_r,
5643 p_level varchar2) return dim_r is
5644 Begin
5645   for i in 1..p_dim_set.dim.count loop
5646     for j in 1..p_dim_set.dim(i).levels.count loop
5647       if p_dim_set.dim(i).levels(j).level_name=p_level then
5648         return p_dim_set.dim(i);
5649       end if;
5650     end loop;
5651   end loop;
5652   return null;
5653 Exception when others then
5654   log_n('Exception in get_kpi_level_dim_r '||sqlerrm);
5655   raise;
5656 End;
5657 
5658 function get_dim_level_r(
5659 p_dim dim_r,
5660 p_level varchar2) return level_r is
5661 Begin
5662   for i in 1..p_dim.levels.count loop
5663     if p_dim.levels(i).level_name=p_level then
5664       return p_dim.levels(i);
5665     end if;
5666   end loop;
5667   return null;
5668 Exception when others then
5669   log_n('Exception in get_dim_level_r '||sqlerrm);
5670   raise;
5671 End;
5672 
5673 procedure check_compressed_composite(p_actual_dim_set in out nocopy dim_set_r,p_target_dim_set in out nocopy dim_set_r) is
5674 l_reason varchar2(4000);
5675 l_countvar_flag boolean;
5676 l_agg_formula varchar2(4000);
5677 l_cal_aggregated boolean;
5678 Begin
5679   p_actual_dim_set.compressed:='N';--default
5680   p_target_dim_set.compressed:='N';--default
5681   l_countvar_flag:=check_countvar_cube_needed(p_actual_dim_set);
5682   if nvl(bsc_aw_utility.get_parameter_value('NO COMPRESSED COMPOSITE'),'N')='Y' then
5683     if g_debug then
5684       log('Non compressed composite specified');
5685     end if;
5686     return;
5687   end if;
5688   if bsc_aw_utility.get_db_version>=10.2 or nvl(bsc_aw_utility.get_parameter_value('COMPRESSED COMPOSITE'),'N')='Y' then
5689     /*if we have average in aggregation, we need countvar. countvar cannot share the same composite as main cube. if we have
5690     diff composite, we cannot aggregate. aw throws error
5691     ORA-36168: COUNTVAR variable BSC_AW!DATACUBE.1.4014.COUNTVAR must have the same dimensionality as AGGMAP object
5692     BSC_AW!DATACUBE.1.4014. so we have to disable compressed composite
5693     */
5694     p_actual_dim_set.compressed:='Y'; --default
5695     if p_actual_dim_set.targets_higher_levels='Y' then
5696       p_actual_dim_set.compressed:='N';
5697       l_reason:='Target at higher level';
5698     end if;
5699     /*if l_countvar_flag then
5700       bsc_aw_utility.merge_property(p_actual_dim_set.property,'aggcount',null,'Y');
5701     end if;*/
5702     /*even with aggcount set in the cube, aw still complains that we need countvar cube when we have aggregate cube using aggmap. so for now,
5703     no CC for avg */
5704     if l_countvar_flag then
5705       p_actual_dim_set.compressed:='N';
5706       l_reason:='countvar cube needed';
5707     end if;
5708     if p_actual_dim_set.compressed='Y' then --check to make sure all measures have the same agg formula
5709       --we cannot use opvar and argvar and measuredim in the aggmap with cc
5710       --now we have this restricted implementation. future,can create cubes by grouping according to agg formula
5711       l_agg_formula:=null;
5712       for i in 1..p_actual_dim_set.measure.count loop
5713         if p_actual_dim_set.measure(i).sql_aggregated='N' then
5714           l_agg_formula:=p_actual_dim_set.measure(i).agg_formula.agg_formula;
5715           exit;
5716         end if;
5717       end loop;
5718       if l_agg_formula is not null then
5719         if bsc_aw_utility.is_CC_aggregation_function(l_agg_formula)='N' then
5720           p_actual_dim_set.compressed:='N';
5721           l_reason:='Agg Formula '||l_agg_formula||' cannot have compressed composite';
5722         end if;
5723       end if;
5724       if p_actual_dim_set.compressed='Y' then
5725         for i in 1..p_actual_dim_set.measure.count loop
5726           if p_actual_dim_set.measure(i).sql_aggregated='N' then
5727             if p_actual_dim_set.measure(i).agg_formula.agg_formula<>l_agg_formula then
5728               p_actual_dim_set.compressed:='N';
5729               l_reason:='agg formula not the same across measures';
5730               exit;
5731             end if;
5732           end if;
5733         end loop;
5734       end if;
5735     end if;
5736     /*we have to consider ORA-37133: Cannot write into an aggregated VARIABLE dimensioned by a COMPRESSED COMPOSITE.
5737     this means we cannot have balance measures or formula measures or projection measures in compressed composite
5738     */
5739     if p_actual_dim_set.compressed='Y' then
5740       l_cal_aggregated:=is_calendar_aggregated(p_actual_dim_set.calendar);
5741       for i in 1..p_actual_dim_set.measure.count loop
5742         if p_actual_dim_set.measure(i).agg_formula.std_aggregation='N' and p_actual_dim_set.measure(i).sql_aggregated='N' then
5743           p_actual_dim_set.compressed:='N';
5744           l_reason:='non std agg (formula)';
5745           exit;
5746         elsif p_actual_dim_set.measure(i).measure_type=g_balance_end_period_prop or p_actual_dim_set.measure(i).measure_type=g_balance_last_value_prop then
5747           p_actual_dim_set.compressed:='N';
5748           l_reason:='balance measure';
5749           exit;
5750         elsif p_actual_dim_set.measure(i).forecast='Y' and l_cal_aggregated then
5751           /*its very important that set_calendar_agg_level be done before this is executed. if we do not have agg on calendar at load time,
5755           l_reason:='Measure has projection';
5752           we do not have to correct forecast. for CC, forecast correction done online is on the display cube. projection is on by default in BSC
5753           so we want to have CC even when there are forecasts */
5754           p_actual_dim_set.compressed:='N';
5756           exit;
5757         end if;
5758       end loop;
5759     end if;
5760     /*if we have B table loading at higher periodicity or dim level, cannot have compressed composite */
5761     if p_actual_dim_set.compressed='Y' then
5762       if is_higher_level_preloaded(p_actual_dim_set) then
5763         p_actual_dim_set.compressed:='N';
5764         l_reason:='Higher levels preloaded from Base Tables';
5765       end if;
5766     end if;
5767     if p_actual_dim_set.compressed='Y' then
5768       if is_higher_period_preloaded(p_actual_dim_set) then
5769         p_actual_dim_set.compressed:='N';
5770         l_reason:='Higher periodicity preloaded from Base Tables';
5771       end if;
5772     end if;
5773     /* */
5774     if p_actual_dim_set.compressed='N' then
5775       if g_debug then
5776         log('Could not implement compressed composite. dimset='||p_actual_dim_set.dim_set||', Reason '||l_reason);
5777       end if;
5778     end if;
5779   else
5780     p_actual_dim_set.compressed:='N'; --default, no compressed composite
5781   end if;
5782   if p_actual_dim_set.targets_higher_levels='Y' and p_actual_dim_set.compressed='Y' then /*not possible scenario for now */
5783     p_target_dim_set.compressed:='Y';
5784   end if;
5785 Exception when others then
5786   log_n('Exception in check_compressed_composite '||sqlerrm);
5787   raise;
5788 End;
5789 
5790 function check_countvar_cube_needed(p_dimset dim_set_r) return boolean is
5791 l_countvar_flag boolean;
5792 Begin
5793   l_countvar_flag:=false;
5794   if p_dimset.dim_set_type<>'target' then --if target, no countvar cube
5795     for i in 1..p_dimset.measure.count loop --create countvar only if needed
5796       if p_dimset.measure(i).agg_formula.avg_aggregation='Y' then
5797         l_countvar_flag:=true;
5798         exit;
5799       end if;
5800     end loop;
5801   end if;
5802   return l_countvar_flag;
5803 Exception when others then
5804   log_n('Exception in check_countvar_cube_needed '||sqlerrm);
5805   raise;
5806 End;
5807 
5808 /*set dimset properties like pre-calc etc. only actuals?
5809 */
5810 procedure set_dim_set_properties(p_kpi in out nocopy kpi_r) is
5811 Begin
5812   for i in 1..p_kpi.dim_set.count loop
5813     set_dim_set_properties(p_kpi.dim_set(i));
5814   end loop;
5815 Exception when others then
5816   log_n('Exception in set_dim_set_properties '||sqlerrm);
5817   raise;
5818 End;
5819 
5820 procedure set_dim_set_properties(p_dim_set in out nocopy dim_set_r) is
5821 Begin
5822   --pre-calc
5823   if is_dimset_precalculated(p_dim_set) then
5824     p_dim_set.pre_calculated:='Y';
5825   else
5826     p_dim_set.pre_calculated:='N';
5827   end if;
5828 Exception when others then
5829   log_n('Exception in set_dim_set_properties '||sqlerrm);
5830   raise;
5831 End;
5832 
5833 /*for now, see if there is any DS feeding at higher level and if so, its pre-calculated. ideally, pre-calc means all higher levels are
5834 provided by DS. Q is : what if we have a case where some higher levels are from DS and the remaining higher levels have to be done by AW?
5835 this can be quite complicated. user provides city and country. AW aggregates to state and then from country to region?
5836 we do not consider this case. if DS provides any higher level or periodicity, its pre-calc */
5837 function is_dimset_precalculated(p_dim_set dim_set_r) return boolean is
5838 Begin
5839   return is_higher_level_preloaded(p_dim_set);
5840   /*later, also check is_higher_period_preloaded */
5841 Exception when others then
5842   log_n('Exception in is_dimset_precalculated '||sqlerrm);
5843   raise;
5844 End;
5845 
5846 /* this looks at the cal hier and looks at the periodicities in the dimset and trims the parent child relation to have only the relevant
5847 parent child relations*/
5848 procedure get_relevant_cal_hier(p_periodicity periodicity_tb,p_pc cal_parent_child_tb,p_relevant_pc out nocopy cal_parent_child_tb) is
5849 l_periodicity dbms_sql.varchar2_table;
5850 Begin
5851   for i in 1..p_periodicity.count loop
5852     l_periodicity(l_periodicity.count+1):=p_periodicity(i).aw_dim;
5853   end loop;
5854   for i in 1..p_pc.count loop
5855     if (p_pc(i).parent_dim_name is null or bsc_aw_utility.in_array(l_periodicity,p_pc(i).parent_dim_name))
5856     and (p_pc(i).child_dim_name is null or bsc_aw_utility.in_array(l_periodicity,p_pc(i).child_dim_name)) then
5857       p_relevant_pc(p_relevant_pc.count+1):=p_pc(i);
5858     end if;
5859   end loop;
5860 Exception when others then
5861   log_n('Exception in get_relevant_cal_hier '||sqlerrm);
5862   raise;
5863 End;
5864 
5865 /*given a hier and a start value, it finds the upper hier */
5866 procedure get_upper_cal_hier(p_pc cal_parent_child_tb,p_child varchar2,p_upper_hier out nocopy cal_parent_child_tb) is
5867 l_pc bsc_aw_utility.parent_child_tb;
5868 l_trim_pc bsc_aw_utility.parent_child_tb;
5869 Begin
5870   for i in 1..p_pc.count loop
5871     l_pc(l_pc.count+1).parent:=p_pc(i).parent_dim_name;
5872     l_pc(l_pc.count).child:=p_pc(i).child_dim_name;
5873   end loop;
5874   bsc_aw_utility.get_upper_trim_hier(l_pc,p_child,l_trim_pc);
5875   --
5876   for i in 1..l_trim_pc.count loop
5877     for j in 1..p_pc.count loop
5878       if nvl(p_pc(j).parent_dim_name,'^^^')=nvl(l_trim_pc(i).parent,'^^^')
5879       and nvl(p_pc(j).child_dim_name,'^^^')=nvl(l_trim_pc(i).child,'^^^') then
5880         p_upper_hier(p_upper_hier.count+1):=p_pc(j);
5881         exit;
5882       end if;
5883     end loop;
5884   end loop;
5885 Exception when others then
5886   log_n('Exception in get_upper_cal_hier '||sqlerrm);
5890 /*temp variables period.temp and year.temp hold the period and year values. they are present in all cube loading programs. they are used when we
5887   raise;
5888 End;
5889 
5891 have BALANCE LAST VALUE type measure */
5892 procedure create_temp_variables(p_dim_set dim_set_r,p_data_source data_source_r) is
5893 l_balance_loaded_column varchar2(40);
5894 Begin
5895   if bsc_aw_utility.get_property(p_data_source.property,g_balance_last_value_prop).property_value='Y' then
5896     bsc_aw_utility.add_g_commands(g_commands,'if exists(\'''||g_period_temp||'\'') eq false');
5897     bsc_aw_utility.add_g_commands(g_commands,'then do');
5898     bsc_aw_utility.add_g_commands(g_commands,'dfn '||g_period_temp||' NUMBER session');
5899     bsc_aw_utility.add_g_commands(g_commands,'doend');
5900     bsc_aw_utility.add_g_commands(g_commands,'if exists(\'''||g_year_temp||'\'') eq false');
5901     bsc_aw_utility.add_g_commands(g_commands,'then do');
5902     bsc_aw_utility.add_g_commands(g_commands,'dfn '||g_year_temp||' NUMBER session');
5903     bsc_aw_utility.add_g_commands(g_commands,'doend');
5904     /*columns to hold balance loaded are also temp . balance loaded column will hold number. see create_base_table_sql decodes this
5905     to number*/
5906     for i in 1..p_data_source.measure.count loop
5907       if p_data_source.measure(i).measure_type=g_balance_last_value_prop then
5908         l_balance_loaded_column:=bsc_aw_utility.get_property(p_data_source.measure(i).property,g_balance_loaded_column_prop).property_value;
5909         if l_balance_loaded_column is not null then
5910           bsc_aw_utility.add_g_commands(g_commands,'if exists(\'''||l_balance_loaded_column||'\'') eq false');
5911           bsc_aw_utility.add_g_commands(g_commands,'then do');
5912           bsc_aw_utility.add_g_commands(g_commands,'dfn '||l_balance_loaded_column||' NUMBER session');
5913           bsc_aw_utility.add_g_commands(g_commands,'doend');
5914         end if;
5915       end if;
5916     end loop;
5917   end if;
5918 Exception when others then
5919   log_n('Exception in create_temp_variables '||sqlerrm);
5920   raise;
5921 End;
5922 
5923 procedure upgrade(p_new_version number,p_old_version number) is
5924 Begin
5925   null;
5926 Exception when others then
5927   log_n('Exception in upgrade '||sqlerrm);
5928   raise;
5929 End;
5930 
5931 function is_higher_level_preloaded(p_dim_set dim_set_r) return boolean is
5932 Begin
5933   for i in 1..p_dim_set.dim.count loop
5934     for j in 1..p_dim_set.data_source.count loop
5935       for k in 1..p_dim_set.data_source(j).dim.count loop
5936         if p_dim_set.dim(i).dim_name=p_dim_set.data_source(j).dim(k).dim_name then
5937           if p_dim_set.dim(i).levels(1).level_name <> p_dim_set.data_source(j).dim(k).levels(1).level_name then
5938             if g_debug then
5939               log('Dimset dim '||p_dim_set.dim(i).dim_name||' has Lowest Level='||p_dim_set.dim(i).levels(1).level_name||', while DS has '||
5940               p_dim_set.data_source(j).dim(k).levels(1).level_name||'. Higher Level preloaded');
5941             end if;
5942             return true;
5943           end if;
5944           exit;
5945         end if;
5946       end loop;
5947     end loop;
5948   end loop;
5949   return false;
5950 Exception when others then
5951   log_n('Exception in is_higher_level_preloaded '||sqlerrm);
5952   raise;
5953 End;
5954 
5955 function is_higher_period_preloaded(p_dim_set dim_set_r) return boolean is
5956 Begin
5957   for i in 1..p_dim_set.data_source.count loop
5958     for j in 1..p_dim_set.calendar.periodicity.count loop
5959       if p_dim_set.calendar.periodicity(j).periodicity=p_dim_set.data_source(i).calendar.periodicity(1).periodicity then
5960         if p_dim_set.calendar.periodicity(j).lowest_level<>'Y' then
5961           if g_debug then
5962             log('Datasource has periodicity '||p_dim_set.data_source(i).calendar.periodicity(1).periodicity||' and this is not the lowest '||
5963             'periodicity in dimset ');
5964           end if;
5965           return true;
5966         end if;
5967         exit;
5968       end if;
5969     end loop;
5970   end loop;
5971   return false;
5972 Exception when others then
5973   log_n('Exception in is_higher_period_preloaded '||sqlerrm);
5974   raise;
5975 End;
5976 
5977 procedure dmp_hpt_data(p_hpt_data hpt_data_r) is
5978 Begin
5979   log('hpt dimensions');
5980   for i in 1..p_hpt_data.hpt_dimensions.count loop
5981     log(p_hpt_data.hpt_dimensions(i).dim_name||' '||p_hpt_data.hpt_dimensions(i).dim_type);
5982     for j in 1..p_hpt_data.hpt_dimensions(i).level_names.count loop
5983       log('  '||p_hpt_data.hpt_dimensions(i).level_names(j)||' ('||p_hpt_data.hpt_dimensions(i).level_keys(j)||')');
5984     end loop;
5985   end loop;
5986   log('hpt calendar');
5987   log(p_hpt_data.hpt_calendar.dim_name||' '||p_hpt_data.hpt_calendar.dim_type);
5988   for i in 1..p_hpt_data.hpt_calendar.level_names.count loop
5989     log('  '||p_hpt_data.hpt_calendar.level_names(i)||' ('||p_hpt_data.hpt_calendar.level_keys(i)||')');
5990   end loop;
5991 Exception when others then
5992   log_n('Exception in dmp_hpt_data '||sqlerrm);
5993   raise;
5994 End;
5995 
5996 /*PT belong to dimsets. cubes point to the PT they want to use. DS has measures that its loading. from this, we find the cubes and find
5997 the PT. from PT we can get all info like partition dim, hpt_data etc. we assume that all the cubes a DS is loading has a similar PT
5998 so each DS deals with one PT*/
5999 function get_DS_partition_template(p_dim_set dim_set_r,p_data_source data_source_r) return partition_template_r is
6000 l_cube_set cube_set_r;
6001 l_axis axis_tb;
6002 l_pt partition_template_r;
6003 Begin
6004   l_cube_set:=get_cube_set_for_measure(p_data_source.measure(1).measure,p_dim_set);
6005   l_axis:=l_cube_set.cube.cube_axis;
6006   for i in 1..l_axis.count loop
6007     if l_axis(i).axis_type='partition template' then
6008       l_pt.template_name:=l_axis(i).axis_name;
6012   if l_pt.template_name is not null then
6009       exit;
6010     end if;
6011   end loop;
6013     l_pt:=get_partition_template_r(l_pt.template_name,p_dim_set);
6014   end if;
6015   return l_pt;
6016 Exception when others then
6017   log_n('Exception in get_DS_partition_template '||sqlerrm);
6018   raise;
6019 End;
6020 
6021 /*PT belong to dimsets. cubes point to the PT they want to use. DS has measures that its loading. from this, we find the cubes and find
6022 the PT. from PT we can get all info like partition dim, hpt_data etc. we assume that all the cubes a DS is loading has similar PT
6023 so each DS deals with one PT
6024 because cube axis info is set in create_pt_comp_names, which comes after set_data_source_sql, for now, lets go with the assumption
6025 that a dimset has cubes all of which share the PT characteristics*/
6026 procedure set_data_source_PT(p_kpi kpi_r,p_dim_set in out nocopy dim_set_r) is
6027 Begin
6028   if p_dim_set.number_partitions>0 then
6029     for i in 1..p_dim_set.data_source.count loop
6030       set_data_source_PT(p_dim_set,p_dim_set.data_source(i));
6031     end loop;
6032     for i in 1..p_dim_set.inc_data_source.count loop
6033       set_data_source_PT(p_dim_set,p_dim_set.inc_data_source(i));
6034     end loop;
6035   end if;
6036 Exception when others then
6037   log_n('Exception in set_data_source_PT '||sqlerrm);
6038   raise;
6039 End;
6040 
6041 procedure set_data_source_PT(p_dim_set dim_set_r,p_data_source in out nocopy data_source_r) is
6042 Begin
6043   p_data_source.data_source_PT.partition_template:=p_dim_set.master_partition_template(1);/*master_partition_template(1) is for datacubes */
6044   if p_data_source.data_source_PT.partition_template.template_name is not null then
6045     if p_dim_set.partition_type='hash' then
6046       /*we need info on hpt dimensions, rollups reqd if partition is at state level and DS is at city level */
6047       set_DS_hpt_rollup_data(p_dim_set,p_data_source);
6048     end if;
6049   end if;
6050 Exception when others then
6051   log_n('Exception in set_data_source_PT '||sqlerrm);
6052   raise;
6053 End;
6054 
6055 /*given a DS and a dimset, this goes through the hpt data of the PT in the dimset, then assigns corrected hpt data to data source data_source_PT
6056 it also loads data_source_pt.dim_parent_child and data_source_pt.cal_parent_child if rollups are reqd */
6057 procedure set_DS_hpt_rollup_data(p_dim_set dim_set_r,p_data_source in out nocopy data_source_r) is
6058 l_hpt_data hpt_data_r;
6059 Begin
6060   l_hpt_data:=p_data_source.data_source_PT.partition_template.hpt_data;
6061   /*reset DS.partition.hpt_data info. we do so because we need to set only those levels that the DS is responsible for */
6062   p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions.delete;
6063   set_DS_hpt_rollup_data(p_data_source.dim,l_hpt_data,p_data_source);
6064   set_DS_hpt_rollup_data(p_data_source.std_dim,l_hpt_data,p_data_source);
6065   set_DS_hpt_rollup_data(p_dim_set.calendar,p_data_source.calendar,l_hpt_data,p_data_source);
6066   /*we have to pass dimset cal because DS cal does not have all periodicities */
6067   if g_debug then
6068     log('Datasource Partition Template dmp for '||p_dim_set.dim_set_name||' '||p_data_source.ds_type);
6069     dmp_partition_template(p_data_source.data_source_PT.partition_template);
6070   end if;
6071 Exception when others then
6072   log_n('Exception in set_DS_hpt_rollup_data '||sqlerrm);
6073   raise;
6074 End;
6075 
6076 /*p_dim can be normal or std dim */
6077 procedure set_DS_hpt_rollup_data(p_DS_dim dim_tb,p_hpt_data hpt_data_r,p_data_source in out nocopy data_source_r) is
6078 l_dim_parent_child parent_child_tb;/*for initialization */
6079 l_index number;
6080 l_parent_child bsc_aw_adapter_dim.dim_parent_child_tb;
6081 l_pc_subset bsc_aw_adapter_dim.dim_parent_child_tb;
6082 l_child_levels dbms_sql.varchar2_table;
6083 Begin
6084   for i in 1..p_DS_dim.count loop
6085     for j in 1..p_hpt_data.hpt_dimensions.count loop /*hpt_dimension does not include time */
6086       if p_DS_dim(i).dim_name=p_hpt_data.hpt_dimensions(j).dim_name then
6087         p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions(
6088         p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions.count+1).dim_name:=p_hpt_data.hpt_dimensions(j).dim_name;
6089         p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions(
6093         l_index:=bsc_aw_utility.get_array_index(p_hpt_data.hpt_dimensions(j).level_names,p_DS_dim(i).levels(1).level_name);
6090         p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions.count).dim_type:=p_hpt_data.hpt_dimensions(j).dim_type;
6091         l_dim_parent_child.delete;
6092         p_data_source.data_source_PT.dim_parent_child(p_hpt_data.hpt_dimensions(j).dim_name):=l_dim_parent_child;/*empty parent child info */
6094         if l_index is not null then
6095           p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions(
6096           p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions.count).level_names(
6097           p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions(
6098           p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions.count).level_names.count+1):=
6099           p_hpt_data.hpt_dimensions(j).level_names(l_index);
6100           p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions(
6101           p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions.count).level_keys(
6102           p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions(
6103           p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions.count).level_keys.count+1):=
6104           p_hpt_data.hpt_dimensions(j).level_keys(l_index);
6105           /*level keys is initially set to dim(i).levels(j).fk */
6106         else
6107           /*there is rollup reqd . for std dim, this part should not be executed*/
6108           /*we will have to find the rollup info for each level that is partitioned and merge the parent child relations. example, we can have hier
6109           like comp>-prod>-prod fam, comp>-prod>-manager. we can have partition at prod fam and manager. then we find the rollup from comp->prodfam
6110           and comp->manager and then merge the 2 pc together */
6111           l_parent_child.delete;
6112           l_pc_subset.delete;
6113           l_child_levels.delete;
6114           bsc_aw_md_api.get_dim_parent_child(p_DS_dim(i).dim_name,l_parent_child);
6115           l_child_levels(l_child_levels.count+1):=p_DS_dim(i).levels(1).level_name;
6116           l_pc_subset:=bsc_aw_adapter_dim.get_hier_subset(l_parent_child,p_hpt_data.hpt_dimensions(j).level_names,l_child_levels);
6117           if l_pc_subset.count=0 then
6118             log('Could not rollup from '||p_DS_dim(i).levels(1).level_name||' to higher levels like '||p_hpt_data.hpt_dimensions(j).level_names(1));
6119             log('This means we cannot rollup from the dim level of the DS to the dim level at which the partition is defined. This is not allowed');
6120             raise bsc_aw_utility.g_exception;
6121           end if;
6122           l_dim_parent_child.delete;
6123           for k in 1..l_pc_subset.count loop
6124             l_dim_parent_child(l_dim_parent_child.count+1).parent_level:=l_pc_subset(k).parent_level;
6125             l_dim_parent_child(l_dim_parent_child.count).child_level:=l_pc_subset(k).child_level;
6126             l_dim_parent_child(l_dim_parent_child.count).parent_pk:=l_pc_subset(k).parent_pk;
6127             l_dim_parent_child(l_dim_parent_child.count).child_fk:=l_pc_subset(k).child_fk;
6128           end loop;
6129           p_data_source.data_source_PT.dim_parent_child(p_hpt_data.hpt_dimensions(j).dim_name):=l_dim_parent_child;
6130           /*from l_pc_subset, we need to find levels that match p_hpt_data.hpt_dimensions(j).level_names. these levels are then loaded
6131           into hpt_dimensions */
6132           for k in 1..p_hpt_data.hpt_dimensions(j).level_names.count loop
6133             for m in 1..l_pc_subset.count loop
6134               if p_hpt_data.hpt_dimensions(j).level_names(k)=l_pc_subset(m).parent_level then
6135                 p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions(
6136                 p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions.count).level_names(
6140                 p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions(
6137                 p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions(
6138                 p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions.count).level_names.count+1):=
6139                 l_pc_subset(m).child_level;
6141                 p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions.count).level_keys(
6142                 p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions(
6143                 p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions.count).level_keys.count+1):=
6144                 l_pc_subset(m).child_level||'.'||l_pc_subset(m).child_fk;
6145                 /*we modify the level key to pick the child.fk example bsc_d_city.state_code when partition is at state
6146                 its initially set to dim(i).levels(j).fk . we use this column to hash on
6147                 if PT is at DS dim level,level_key will be simply city_code etc. if there is rollup, then it will be bsc_d_city.state_code etc */
6148                 --
6149                 exit;
6150               end if;
6151             end loop;
6152           end loop;
6153         end if;
6154         --
6155         exit;
6156       end if;
6157     end loop;
6158   end loop;
6159 Exception when others then
6160   log_n('Exception in set_DS_hpt_rollup_data '||sqlerrm);
6161   raise;
6162 End;
6163 
6164 /*we can have multiple levels at which partitons are defined. example month and week
6165 each DS can be at one periodicity only*/
6166 procedure set_DS_hpt_rollup_data(p_calendar calendar_r,p_DS_calendar calendar_r,p_hpt_data hpt_data_r,p_data_source in out nocopy data_source_r) is
6167 l_index number;
6168 l_calendar bsc_aw_calendar.calendar_r;
6169 l_ds_periodicity bsc_aw_calendar.periodicity_r;
6170 l_upper_periodicities bsc_aw_calendar.periodicity_tb;
6171 Begin
6172   p_data_source.data_source_PT.partition_template.hpt_data.hpt_calendar.dim_name:=null;
6173   p_data_source.data_source_PT.partition_template.hpt_data.hpt_calendar.level_names.delete;
6174   p_data_source.data_source_PT.partition_template.hpt_data.hpt_calendar.level_keys.delete;
6175   if p_hpt_data.hpt_calendar.dim_name is not null and p_hpt_data.hpt_calendar.dim_name=p_DS_calendar.aw_dim then
6176     p_data_source.data_source_PT.partition_template.hpt_data.hpt_calendar.dim_name:=p_hpt_data.hpt_calendar.dim_name;
6177     p_data_source.data_source_PT.partition_template.hpt_data.hpt_calendar.dim_type:=p_hpt_data.hpt_calendar.dim_type;
6178     l_index:=bsc_aw_utility.get_array_index(p_hpt_data.hpt_calendar.level_names,p_DS_calendar.periodicity(1).aw_dim);
6179     if l_index is not null then
6180       p_data_source.data_source_PT.partition_template.hpt_data.hpt_calendar.level_names(
6181       p_data_source.data_source_PT.partition_template.hpt_data.hpt_calendar.level_names.count+1):=
6182       p_hpt_data.hpt_calendar.level_names(l_index);
6183       p_data_source.data_source_PT.partition_template.hpt_data.hpt_calendar.level_keys(
6184       p_data_source.data_source_PT.partition_template.hpt_data.hpt_calendar.level_keys.count+1):=
6185       p_hpt_data.hpt_calendar.level_keys(l_index);
6186     else /*rollup required */
6187       /*find out the upper periodicities that DS periodicity touches */
6188       /*upgrade(to level 3) must reimplement all calendars so db_column_name is populated in bsc olap metadata */
6189       bsc_aw_calendar.get_calendar(p_DS_calendar.aw_dim,l_calendar);
6190       l_ds_periodicity:=bsc_aw_calendar.get_periodicity_r(p_DS_calendar.periodicity(1).periodicity,l_calendar.periodicity);
6191       bsc_aw_calendar.get_all_upper_periodicities(l_ds_periodicity,l_calendar,l_upper_periodicities);
6192       for j in 1..p_hpt_data.hpt_calendar.level_names.count loop
6193         for k in 1..l_upper_periodicities.count loop
6194           if p_hpt_data.hpt_calendar.level_names(j)=l_upper_periodicities(k).dim_name then
6195             p_data_source.data_source_PT.cal_parent_child(p_data_source.data_source_PT.cal_parent_child.count+1).parent:=
6196             l_upper_periodicities(k).periodicity_id;
6197             p_data_source.data_source_PT.cal_parent_child(p_data_source.data_source_PT.cal_parent_child.count).parent_dim_name:=
6198             l_upper_periodicities(k).db_column_name;
6199             p_data_source.data_source_PT.cal_parent_child(p_data_source.data_source_PT.cal_parent_child.count).child:=
6200             l_ds_periodicity.periodicity_id;
6201             p_data_source.data_source_PT.cal_parent_child(p_data_source.data_source_PT.cal_parent_child.count).child_dim_name:=
6202             l_ds_periodicity.db_column_name;
6203             --
6204             p_data_source.data_source_PT.partition_template.hpt_data.hpt_calendar.level_names(
6205             p_data_source.data_source_PT.partition_template.hpt_data.hpt_calendar.level_names.count+1):=l_upper_periodicities(k).dim_name;
6206             p_data_source.data_source_PT.partition_template.hpt_data.hpt_calendar.level_keys(
6207             p_data_source.data_source_PT.partition_template.hpt_data.hpt_calendar.level_keys.count+1):='bsc_db_calendar.'||
6208             l_upper_periodicities(k).db_column_name;
6209             --
6210             exit;
6211           end if;
6212         end loop;
6213       end loop;
6214     end if;
6215   end if;
6216 Exception when others then
6217   log_n('Exception in set_DS_hpt_rollup_data '||sqlerrm);
6218   raise;
6219 End;
6220 
6221 function get_DS_PT_hash_stmt(p_dim_set dim_set_r,p_data_source data_source_r)return varchar2 is
6222 pt_stmt varchar2(4000);
6223 Begin
6224   pt_stmt:='dbms_utility.get_hash_value(\''H\''';
6225   for i in 1..p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions.count loop /*loop through dim (Not time)*/
6226     for j in 1..p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions(i).level_names.count loop
6227       pt_stmt:=pt_stmt||'||\''-\''||'||p_data_source.data_source_PT.partition_template.hpt_data.hpt_dimensions(i).level_keys(j);
6228     end loop;
6229   end loop;
6230   if p_data_source.data_source_PT.partition_template.hpt_data.hpt_calendar.dim_name is not null then
6234       pt_ is appended to the columns selected from calendar to prevent clash with columns selected from the DS*/
6231     for i in 1..p_data_source.data_source_PT.partition_template.hpt_data.hpt_calendar.level_names.count loop
6232       pt_stmt:=pt_stmt||'||\''-\''||'||p_data_source.data_source_PT.partition_template.hpt_data.hpt_calendar.level_keys(i)||'||\''.\''||year';
6233       /*append year also as part of the calendar key
6235     end loop;
6236   end if;
6237   pt_stmt:=pt_stmt||',0,'||p_dim_set.number_partitions||') ';
6238   return pt_stmt;
6239 Exception when others then
6240   log_n('Exception in get_DS_PT_hash_stmt '||sqlerrm);
6241   raise;
6242 End;
6243 
6244 function is_dim_aggregated(p_dim dim_r) return boolean is
6245 Begin
6246   /*if p_dim_set.dim(i).levels.count>1 or p_dim_set.dim(i).zero_code='Y' or p_dim_set.dim(i).recursive='Y' then */
6247   if p_dim.recursive='Y' then
6248     return true;
6249   else
6250     for i in 1..p_dim.levels.count loop
6251       if p_dim.levels(i).aggregated='Y' then
6252         if i=1 then /*lowest level */
6253           if p_dim.levels(i).zero_aggregated='Y' then /*lowest level and there is zero code */
6254             return true;
6255           end if;
6256         else
6257           return true;
6258         end if;
6259       end if;
6260     end loop;
6261   end if;
6262   return false;
6263 Exception when others then
6264   log_n('Exception in is_dim_aggregated '||sqlerrm);
6265   raise;
6266 End;
6267 
6268 function is_calendar_aggregated(p_calendar calendar_r) return boolean is
6269 Begin
6270   for i in 1..p_calendar.periodicity.count loop
6271     if p_calendar.periodicity(i).aggregated='Y'
6272     and (p_calendar.periodicity(i).lowest_level is null or p_calendar.periodicity(i).lowest_level<>'Y') then
6273       return true;
6274     end if;
6275   end loop;
6276   return false;
6277 Exception when others then
6278   log_n('Exception in is_calendar_aggregated '||sqlerrm);
6279   raise;
6280 End;
6281 
6282 function get_projection_dim(p_dim_set dim_set_r) return varchar2 is
6283 Begin
6284   for i in 1..p_dim_set.std_dim.count loop
6285     if p_dim_set.std_dim(i).dim_name='PROJECTION' then
6286       return p_dim_set.std_dim(i).dim_name;
6287     end if;
6288   end loop;
6289   return null;
6290 Exception when others then
6291   log_n('Exception in get_projection_dim '||sqlerrm);
6292   raise;
6293 End;
6294 
6295 function make_display_cube_axis(p_dim_set dim_set_r,p_cube cube_r) return axis_tb is
6296 l_axis axis_tb;
6297 l_dimensions dbms_sql.varchar2_table;
6298 Begin
6299   for i in 1..p_cube.cube_axis.count loop
6300     l_dimensions.delete;
6301     if p_cube.cube_axis(i).axis_type='partition template' then
6302       l_dimensions:=get_partition_template_r(p_cube.cube_axis(i).axis_name,p_dim_set).template_dimensions;
6303     elsif p_cube.cube_axis(i).axis_type='composite' then
6304       l_dimensions:=get_composite_r(p_cube.cube_axis(i).axis_name,p_dim_set).composite_dimensions;
6305     end if;
6306     if l_dimensions.count>0 then
6307       for j in 1..l_dimensions.count loop
6308         l_axis(l_axis.count+1).axis_name:=l_dimensions(j);
6309         l_axis(l_axis.count).axis_type:='dimension';
6310       end loop;
6311     else
6312       l_axis(l_axis.count+1):=p_cube.cube_axis(i);
6313     end if;
6314   end loop;
6315   return l_axis;
6316 Exception when others then
6317   log_n('Exception in get_display_cube_axis '||sqlerrm);
6318   raise;
6319 End;
6320 
6321 /*sets the sql_aggregation flag for the measures to Y or N
6322 unset is done only if the dimset is not partitioned
6323 if we have a situation where the agg_formula looks like sum(m1/m2), we have to set this as sql_aggregated=Y. for aw, if this is a formula, we want
6324 the formula to be like m1/m2. I guess this is how the metadata reader api will return the formula. we cannot have sum(m1/m2) specified. because the
6325 formula is applied as it is. like cube3=cube1/cube2.
6326 */
6327 procedure set_sql_aggregations(p_kpi in out nocopy kpi_r,p_action varchar2) is
6328 Begin
6329   for i in 1..p_kpi.dim_set.count loop
6330     if (p_action='set' and bsc_aw_utility.get_db_version>=10.2 and p_kpi.dim_set(i).targets_higher_levels<>'Y')
6331     or (p_action='unset' and p_kpi.dim_set(i).number_partitions=0 and p_kpi.dim_set(i).compressed<>'Y') then
6332       set_sql_aggregations(p_kpi,p_kpi.dim_set(i),p_action);
6333     end if;
6334   end loop;
6335 Exception when others then
6336   log_n('Exception in set_sql_aggregations '||sqlerrm);
6337   raise;
6338 End;
6339 
6340 /*if action=set
6341 if there are targets, we do not set sql_aggregated to Y. we need to aggregate the measure and copy the targets
6342  */
6343 procedure set_sql_aggregations(p_kpi kpi_r,p_dim_set in out nocopy dim_set_r,p_action varchar2) is
6344 l_agg_flag varchar2(10);
6345 Begin
6346   if p_action='set' then
6347     l_agg_flag:='Y';
6348   else
6349     l_agg_flag:='N';
6350   end if;
6351   for i in 1..p_dim_set.measure.count loop
6352     if p_dim_set.measure(i).agg_formula.std_aggregation='N' then
6353       p_dim_set.measure(i).sql_aggregated:=l_agg_flag;
6354     end if;
6355   end loop;
6356 Exception when others then
6357   log_n('Exception in set_sql_aggregations '||sqlerrm);
6358   raise;
6359 End;
6360 
6361 procedure reset_PT_template(p_partition_template in out nocopy partition_template_r) is
6362 Begin
6363   p_partition_template.template_name:=null;
6364   p_partition_template.template_type:=null;
6365   p_partition_template.template_use:=null;
6366   p_partition_template.template_dim:=null;
6367   p_partition_template.template_dimensions.delete;
6368   p_partition_template.template_partitions.delete;
6369   p_partition_template.hpt_data.hpt_dimensions.delete;
6370   p_partition_template.hpt_data.hpt_calendar.dim_name:=null;
6371 Exception when others then
6372   log_n('Exception in reset_PT_template '||sqlerrm);
6373   raise;
6374 End;
6375 
6376 /*used in partitions to see if we can get partitions done with display cubes. data is copied into display cubes for
6377 aggregations at viewer time */
6378 function is_display_cube_required(p_dim_set dim_set_r,p_cube varchar2) return boolean is
6379 measures measure_tb;
6380 flag boolean;
6381 Begin
6382   flag:=false;
6383   if p_dim_set.number_partitions>0 then
6384     if p_dim_set.compressed='Y' then
6385       if g_debug then
6386         log('Compressed composite. partitions possible only with display cube');
6387       end if;
6388       flag:=true;
6389     end if;
6390     if flag=false then
6391       measures.delete;
6392       get_measures_for_cube(p_cube,p_dim_set,measures);
6393       for i in 1..measures.count loop
6394         if measures(i).agg_formula.std_aggregation='N' and measures(i).sql_aggregated='N' then
6395           if g_debug then
6396             log('Non std agg in dimset '||p_dim_set.dim_set||', partitions possible only with display cube');
6397           end if;
6398           flag:=true;
6399           exit;
6400         end if;
6401         if bsc_aw_utility.is_PT_aggregation_function(measures(i).agg_formula.agg_formula)='N' then
6402           if g_debug then
6403             log('Non partitionable aggregation function '||measures(i).agg_formula.agg_formula||'. Partitions possible only with '||
6404            'display cubes');
6405           end if;
6406           flag:=true;
6407           exit;
6408         end if;
6409       end loop;
6410     end if;
6411   end if;
6412   return flag;
6413 Exception when others then
6414   log_n('Exception in is_display_cube_required '||sqlerrm);
6415   raise;
6416 End;
6417 
6418 function is_display_cube_possible(p_dim_set dim_set_r) return boolean is
6419 Begin
6420   if nvl(bsc_aw_utility.get_parameter_value('NO DISPLAY CUBE'),'N')='Y' then
6421     return false;
6422   end if;
6423   return true;
6424 Exception when others then
6425   log_n('Exception in is_display_cube_possible '||sqlerrm);
6426   raise;
6427 End;
6428 
6429 function get_dim_set_lowest_periodicity(p_dim_set dim_set_r) return periodicity_tb is
6430 periodicity periodicity_tb;
6431 Begin
6432   for i in 1..p_dim_set.calendar.periodicity.count loop
6433     if p_dim_set.calendar.periodicity(i).lowest_level='Y' then
6434       periodicity(periodicity.count+1):=p_dim_set.calendar.periodicity(i);
6435     end if;
6436   end loop;
6437   return periodicity;
6438 Exception when others then
6439   log_n('Exception in get_dim_set_lowest_periodicity '||sqlerrm);
6440   raise;
6441 End;
6442 
6443 ------------------
6444 procedure init_all is
6445 Begin
6446   g_debug:=bsc_aw_utility.g_debug;
6447 Exception when others then
6448   null;
6449 End;
6450 
6451 procedure log(p_message varchar2) is
6452 Begin
6453   bsc_aw_utility.log(p_message);
6454 Exception when others then
6455   null;
6456 End;
6457 
6458 procedure log_n(p_message varchar2) is
6459 Begin
6460   log('  ');
6461   log(p_message);
6462 Exception when others then
6463   null;
6464 End;
6465 
6466 END BSC_AW_ADAPTER_KPI;