1 package body BSC_AW_LOAD_DIM AS
2 /*$Header: BSCAWLDB.pls 120.11 2006/04/20 11:39 vsurendr noship $*/
3
4 /*
5 the top procedure is called with a list of dim levels. from RSG, a list of dim levels affecting a kpi or base table
6 are passed in. we will resolve into aw dim and call procedure and pass in aw dim
7 this procedure must then resolve all info and load. in 10g, these procedures will be launched in parallel as jobs
8 */
9 procedure load_dim(p_dim_level_list dbms_sql.varchar2_table) is
10 Begin
11 --p_dim_level_list is an assorted list.can contain city,product, state etc
12 if g_debug then
13 log_n('Load Dim');
14 log('Levels to load ');
15 for i in 1..p_dim_level_list.count loop
16 log(p_dim_level_list(i));
17 end loop;
18 end if;
19 --get the dimensions for the levels
20 load_dim_levels(p_dim_level_list);
21 Exception when others then
22 log_n('Exception in load_dim '||sqlerrm);
23 raise;
24 End;
25
26 procedure load_dim_levels(p_dim_level_list dbms_sql.varchar2_table) is
27 l_dim_list dbms_sql.varchar2_table;
28 l_dim varchar2(300);
29 --
30 Begin
31 for i in 1..p_dim_level_list.count loop
32 bsc_aw_md_api.get_dim_for_level(p_dim_level_list(i),l_dim);
33 if bsc_aw_utility.in_array(l_dim_list,l_dim)=false then
34 l_dim_list(l_dim_list.count+1):=l_dim;
35 end if;
36 end loop;
37 if g_debug then
38 log_n('Load the following AW Dim');
39 for i in 1..l_dim_list.count loop
40 log(l_dim_list(i));
41 end loop;
42 end if;
43 --
44 load_dimensions(l_dim_list);
45 Exception when others then
46 log_n('Exception in load_dim_levels '||sqlerrm);
47 raise;
48 End;
49
50 procedure load_dimensions(p_dim_list dbms_sql.varchar2_table) is
51 l_parallel boolean;
52 Begin
53 --if 10g, we can launcg parallel jobs.
54 l_parallel:=false;
55 if bsc_aw_utility.can_launch_jobs(p_dim_list.count)='Y' then
56 l_parallel:=true;
57 end if;
58 if l_parallel=false then
59 for i in 1..p_dim_list.count loop
60 load_aw_dim(p_dim_list(i),null,null,null);
61 end loop;
62 else --launch jobs and wait
63 load_aw_dim_jobs(p_dim_list);
64 end if;
65 Exception when others then
66 log_n('Exception in load_dimensions '||sqlerrm);
67 raise;
68 End;
69
70 procedure load_dim_if_needed(p_dim dbms_sql.varchar2_table) is
71 --
72 l_load_dim dbms_sql.varchar2_table;
73 l_dim_lock dbms_sql.varchar2_table;
74 Begin
75 if g_debug then
76 log('load_dim_if_needed, the dimensions to check for load are');
77 for i in 1..p_dim.count loop
78 log(p_dim(i));
79 end loop;
80 end if;
81 l_load_dim.delete;
82 l_dim_lock.delete;
83 for i in 1..p_dim.count loop
84 l_dim_lock(l_dim_lock.count+1):='lock_aw_dim_'||p_dim(i);
85 bsc_aw_utility.get_db_lock(l_dim_lock(l_dim_lock.count));
86 if check_dim_loaded(p_dim(i))='N' or bsc_aw_adapter_dim.check_dim_view_based(p_dim(i))='Y' then
87 l_load_dim(l_load_dim.count+1):=p_dim(i);
88 else
89 bsc_aw_utility.release_db_lock(l_dim_lock(l_dim_lock.count));
90 l_dim_lock.delete(l_dim_lock.count);
91 end if;
92 end loop;
93 if g_debug then
94 log('Dimensions to load');
95 for i in 1..l_load_dim.count loop
96 log(l_load_dim(i));
97 end loop;
98 end if;
99 --
100 load_dimensions(l_load_dim);--will parallelize if needed
101 --
102 for i in 1..l_dim_lock.count loop
103 bsc_aw_utility.release_db_lock(l_dim_lock(i));
104 end loop;
105 Exception when others then
106 for i in 1..l_dim_lock.count loop
107 bsc_aw_utility.release_db_lock(l_dim_lock(i));
108 end loop;
109 log_n('Exception in load_dim_if_needed '||sqlerrm);
110 raise;
111 End;
112
113 procedure load_aw_dim_jobs(p_dim_list dbms_sql.varchar2_table) is
114 --
115 l_job_name varchar2(100);
116 l_process varchar2(8000);
117 l_job_status bsc_aw_utility.parallel_job_tb;
118 l_exception exception;
119 pragma exception_init(l_exception,-20000);
120 --
121 Begin
122 bsc_aw_utility.clean_up_jobs('all');
123 for i in 1..p_dim_list.count loop
124 l_job_name:='bsc_aw_job_dim_'||bsc_aw_utility.get_session_id||'_'||i;
125 l_process:='bsc_aw_load_dim.load_aw_dim('''||p_dim_list(i)||''','||i||','''||l_job_name||''','''||bsc_aw_utility.get_option_string||''');';
126 bsc_aw_utility.start_job(l_job_name,i,l_process,null);
127 end loop;
128 --wait (this will lock and wait)
129 bsc_aw_utility.wait_on_jobs(null,l_job_status);
130 --check the status
131 for i in 1..l_job_status.count loop
132 if l_job_status(i).status='error' then
133 --raise error
134 raise l_exception;
135 end if;
136 end loop;
137 Exception when others then
138 log_n('Exception in load_aw_dim_jobs '||sqlerrm);
139 raise;
140 End;
141
142 /*
143 this procedure is the atomic unit, given the aw dim, loads it.
144 it decides inc vs full etc. in 10g jobs also, this is the procedure that is called in the job
145
146 for now, lets start with full refresh all the time. otherwise we need to check the aw dim to see if there are
147 values in it. or we may need to check the temp table for the levels and see if there is data in the temp table
148 if there is data, assume inc refresh. else full
149 we commit after each dim load. if these are dbms jobs, there needs to be a commit after each dim load
150 (lets do this as part of 10g enhancements)
151 p_options: to support parallel jobs
152 */
153 procedure load_aw_dim(p_dim varchar2,p_run_id number,p_job_name varchar2,p_options varchar2) is
154 l_initial_load_pgm varchar2(300);
155 l_inc_load_pgm varchar2(300);
156 l_dim_property varchar2(4000);
157 l_oo bsc_aw_md_wrapper.bsc_olap_object_tb;
158 l_denorm_src varchar2(4000);
159 l_dim_level_delete dim_level_delete_tv;
160 l_dim_delete_flag boolean;
161 Begin
162 --for the dim, get the program name,
163 --get the lock on the dim objects
164 if p_run_id is not null then
165 --this is a dbms job. we have to do the initializations since this is a new session
166 bsc_aw_utility.g_options.delete;
167 bsc_aw_utility.parse_parameter_values(p_options,',',bsc_aw_utility.g_options);
168 bsc_aw_utility.open_file(p_dim||'_'||p_run_id);
169 bsc_aw_utility.dmp_g_options(bsc_aw_utility.g_options);
170 bsc_aw_utility.init_all_procedures;
171 end if;
172 log_n('load_aw_dim, p_dim='||p_dim||', p_run_id='||p_run_id||', p_job_name='||p_job_name||
173 ', p_options='||p_options);
174 l_oo.delete;
175 bsc_aw_md_api.get_bsc_olap_object(null,null,p_dim,'dimension',l_oo);
176 for i in 1..l_oo.count loop
177 if l_oo(i).object_type='dml program' then
178 if l_oo(i).olap_object_type='dml program initial load' then
179 l_initial_load_pgm:=l_oo(i).object;
180 elsif l_oo(i).olap_object_type='dml program inc load' then
181 l_inc_load_pgm:=l_oo(i).object;
182 end if;
183 end if;
184 end loop;
185 for i in 1..l_oo.count loop
186 if l_oo(i).object_type='dimension' then
187 l_dim_property:=l_oo(i).property1;
188 exit;
189 end if;
190 end loop;
191 /*we cannot get multi locks if there are deletes. so we first pre-load delete values into memory. if deletes are involved, we get full lock */
192 load_dim_delete(p_dim,l_dim_property,l_dim_level_delete,l_dim_delete_flag);
193 lock_dim_objects(p_dim,l_dim_delete_flag);
194 if l_dim_delete_flag then
195 merge_delete_values_to_levels(l_dim_level_delete);
196 end if;
197 l_oo.delete;
198 /*if this is a rec dim and implemented with normal hier, we need to populate bsc_aw_temp_pc */
199 if nvl(bsc_aw_utility.get_parameter_value(l_dim_property,'recursive',','),'N')='Y' and
200 nvl(bsc_aw_utility.get_parameter_value(l_dim_property,'normal hier',','),'N')='Y' then
201 l_denorm_src:=bsc_aw_utility.get_parameter_value(l_dim_property,'denorm source',',');
202 if l_denorm_src is not null then --dbi rec dim
203 load_recursive_norm_hier(replace(l_denorm_src,'*^',','),
204 bsc_aw_utility.get_parameter_value(l_dim_property,'child col',','),
205 bsc_aw_utility.get_parameter_value(l_dim_property,'parent col',','));
206 end if;
207 end if;
208 /*4646329 for some reason, the dim levels were missing the value 0. maybe the dim was purged. we need a way to get the std values back into the dim
209 we do this for std and custom dim for now. projection dim is not loaded via program. now we assume text datatype. later we can have property as
210 pk data type in oo for dim level. for rec dim, 0 is never all
211 */
212 for i in 1..l_oo.count loop
213 if l_oo(i).object_type='dimension level' then
214 if l_oo(i).olap_object is not null then
215 bsc_aw_dbms_aw.execute('maintain '||l_oo(i).olap_object||' merge ''0''');
216 end if;
217 end if;
218 end loop;
219 --launch the aw program
220 if g_debug then
221 log_n('Going to load '||p_dim);
222 end if;
223 if check_initial_load(p_dim) then
224 bsc_aw_dbms_aw.execute('call '||l_initial_load_pgm);
225 else
226 bsc_aw_dbms_aw.execute('call '||l_inc_load_pgm);
227 end if;
228 if g_debug then
229 log_n('Finished load '||p_dim);
230 end if;
231 /*we now need to handle any deletes*/
232 if l_dim_delete_flag then
233 execute_dim_delete(l_dim_level_delete);
234 clean_bsc_aw_dim_delete(l_dim_level_delete);
235 end if;
236 --
237 set_kpi_limit_variables(p_dim);
238 bsc_aw_management.commit_aw;--will release the locks on the dim objects in 10g
239 bsc_aw_management.detach_workspace;
240 --if this is a job, send success message to pipe...update bsc_olap_object saying operation_flag='loaded'
241 mark_dim_loaded(p_dim);
242 --
243 if p_run_id is not null then
244 bsc_aw_utility.send_pipe_message(p_job_name,'status=success');
245 end if;
246 commit;
247 Exception when others then
248 log_n('Exception in load_aw_dim '||sqlerrm);
249 if p_run_id is not null then
250 bsc_aw_utility.send_pipe_message(p_job_name,'status=error,sqlcode='||sqlcode||',message='||sqlerrm);
251 rollback;
252 bsc_aw_management.detach_workspace;
253 else
254 raise;
255 end if;
256 End;
257
258 /*
259 delete are handled in the following way
260 delete table has 2 columns. dim_level and delete_value. say we have geog dim. city,state,country
261 we want to delete all cities in ca and ca
262 the table has
263 'city' 'SF'
264 'city' 'LA'
265 'state' 'CA'
266 the program already has support for marking limit cubes. once the program runs, this already has happened.
267 we now need to clean up the values from the dim.
268 Q:if we clean up CA and we still retail some cities in ca, what will happen to the relation. for example, sacramento
269 will say parent=ca while ca is gone. will agg on this relation error out? No. did a prototype to verify this. if CA is gone,
270 AW will take care of removing CA from the relation or at-least not considering it anymore
271 */
272 procedure load_dim_delete(
273 p_dim varchar2,
274 p_dim_property varchar2,
275 p_dim_level_delete in out nocopy dim_level_delete_tv,
276 p_delete_flag out nocopy boolean) is
277 --
278 l_level varchar2(300);
279 l_oo bsc_aw_md_wrapper.bsc_olap_object_tb;
280 Begin
281 p_delete_flag:=false;
282 p_dim_level_delete('ALL').delete_name:='ALL';
283 p_dim_level_delete('ALL').delete_values.delete;
284 --get the dim levels
285 l_oo.delete;
286 bsc_aw_md_api.get_bsc_olap_object(null,'dimension level',p_dim,'dimension',l_oo);
287 --
288 if l_oo.count>0 then
289 for i in 1..l_oo.count loop
290 bsc_aw_utility.merge_value(p_dim_level_delete('ALL').delete_values,l_oo(i).object);--ALL will hold the levels involved
291 load_delete_dim_level_value(l_oo(i).object,upper(l_oo(i).object),p_dim_level_delete);
292 if p_dim_level_delete(l_oo(i).object).delete_values.count>0 then
293 p_delete_flag:=true;
294 end if;
295 end loop;
296 --
297 if nvl(bsc_aw_utility.get_parameter_value(p_dim_property,'recursive',','),'N')='Y' then
298 l_level:=l_oo(1).object;
299 l_oo.delete;
300 bsc_aw_md_api.get_bsc_olap_object(null,'recursive level',p_dim,'dimension',l_oo);
301 for i in 1..l_oo.count loop
302 bsc_aw_utility.merge_value(p_dim_level_delete('ALL').delete_values,l_oo(i).object);--ALL will hold the levels involved
303 load_delete_dim_level_value(l_oo(i).object,upper(l_level),p_dim_level_delete);
304 end loop;
305 end if;
306 end if;
307 Exception when others then
308 log_n('Exception in load_dim_delete '||sqlerrm);
309 raise;
310 End;
311
312 /*5064802. cannot delete in multi mode. pre-load deletes into memory. if there are any deletes, then get rw lock */
313 procedure load_delete_dim_level_value(
314 p_dim_level varchar2,
315 p_select_level varchar2,--useful in case of rec dim. we need to delete the virtual parent level also
316 p_dim_level_delete in out nocopy dim_level_delete_tv) is
317 l_stmt varchar2(4000);
318 TYPE CurTyp IS REF CURSOR;
319 cv CurTyp;
320 Begin
321 l_stmt:='select distinct delete_value from bsc_aw_dim_delete where dim_level=:1';
322 if g_debug then
323 log(l_stmt||' '||p_select_level||bsc_aw_utility.get_time);
324 end if;
325 p_dim_level_delete(p_dim_level).delete_name:=p_dim_level;
326 p_dim_level_delete(p_dim_level).delete_values.delete;
327 open cv for l_stmt using p_select_level;
328 loop
329 fetch cv bulk collect into p_dim_level_delete(p_dim_level).delete_values;
330 exit when cv%notfound;
331 end loop;
332 if g_debug then
333 log('Fetched '||p_dim_level_delete(p_dim_level).delete_values.count||' rows'||bsc_aw_utility.get_time);
334 end if;
335 close cv;
336 Exception when others then
337 log_n('Exception in load_delete_dim_level_value '||sqlerrm);
338 raise;
339 End;
340
341 procedure execute_dim_delete(p_dim_level_delete dim_level_delete_tv) is
342 l_levels dbms_sql.varchar2_table;
343 Begin
344 l_levels:=p_dim_level_delete('ALL').delete_values; --levels also include virtual rec dim parent level
345 for i in 1..l_levels.count loop
346 delete_dim_level_value(l_levels(i),p_dim_level_delete(l_levels(i)).delete_values);
347 end loop;
348 Exception when others then
349 log_n('Exception in execute_dim_delete '||sqlerrm);
350 raise;
351 End;
352
353 /*bsc_aw_dim_delete is created by loader. so keep the sql dynamic
354 5064802: when we delete values, we cannot be in multi attach mode. must get full rw lock
355 lock_dim_objects will lock the dim in full mode if there are deletes reqd*/
356 procedure delete_dim_level_value(p_dim_level varchar2,p_delete_values dbms_sql.varchar2_table) is
357 Begin
358 for i in 1..p_delete_values.count loop
359 bsc_aw_dbms_aw.execute('mnt '||p_dim_level||' delete '''||p_delete_values(i)||'''');
360 end loop;
361 Exception when others then
362 log_n('Exception in delete_dim_level_value '||sqlerrm);
363 raise;
364 End;
365
366 procedure clean_bsc_aw_dim_delete(p_dim_level_delete dim_level_delete_tv) is
367 l_levels dbms_sql.varchar2_table;
368 l_stmt varchar2(4000);
369 Begin
370 l_levels:=p_dim_level_delete('ALL').delete_values;
371 for i in 1..l_levels.count loop
372 l_stmt:='delete bsc_aw_dim_delete where dim_level=:1';
373 if g_debug then
374 log(l_stmt||' '||l_levels(i)||bsc_aw_utility.get_time);
375 end if;
376 execute immediate l_stmt using l_levels(i);
377 if g_debug then
378 log('Deleted '||sql%rowcount||' rows '||bsc_aw_utility.get_time);
379 end if;
380 end loop;
381 Exception when others then
382 log_n('Exception in clean_bsc_aw_dim_delete '||sqlerrm);
383 raise;
384 End;
385
386 /*
387 to check initial vs inc laod, check the temp table.
388 */
389 function check_initial_load(p_dim varchar2) return boolean is
390 Begin
391 --for now, full refresh
392 return true;
393 Exception when others then
394 log_n('Exception in check_initial_load '||sqlerrm);
395 raise;
396 End;
397
398 /*
399 purge a dim completely from the given list of levels
400 */
401 procedure purge_dim(p_dim_level_list dbms_sql.varchar2_table) is
402 l_dim_list dbms_sql.varchar2_table;
403 l_dim varchar2(300);
404 Begin
405 for i in 1..p_dim_level_list.count loop
406 bsc_aw_md_api.get_dim_for_level(p_dim_level_list(i),l_dim);
407 if bsc_aw_utility.in_array(l_dim_list,l_dim)=false then
408 l_dim_list(l_dim_list.count+1):=l_dim;
409 end if;
410 end loop;
411 for i in 1..l_dim_list.count loop
412 purge_dim(l_dim_list(i));
413 end loop;
414 Exception when others then
415 log_n('Exception in purge_dim '||sqlerrm);
416 raise;
417 End;
418
419 /*purge a dim
420 logic:
421 purge all related kpi
422 purge dim related data objects
423 purge dim levels
424 */
425 procedure purge_dim(p_dim varchar2) is
426 --
427 l_olap_object bsc_aw_md_wrapper.bsc_olap_object_tb;
428 l_kpi_list dbms_sql.varchar2_table;
429 Begin
430 if g_debug then
431 log_n('Purge dim '||p_dim);
432 end if;
433 --get lock, for purge, we need exclusive locks. otherwise we cannot delete dimensions
434 bsc_aw_management.get_workspace_lock('rw',null);
435 --purge kpi
436 bsc_aw_md_api.get_kpi_for_dim(p_dim,l_kpi_list);
437 for i in 1..l_kpi_list.count loop
438 bsc_aw_load_kpi.purge_kpi(l_kpi_list(i));
439 end loop;
440 --
441 bsc_aw_md_api.get_bsc_olap_object(null,null,p_dim,'dimension',l_olap_object);
442 --purge variables
443 for i in 1..l_olap_object.count loop
444 if l_olap_object(i).object_type='limit cube' or l_olap_object(i).object_type='filter cube' then
445 bsc_aw_dbms_aw.execute('clear all from '||l_olap_object(i).olap_object);
446 end if;
447 end loop;
448 --
449 for i in 1..l_olap_object.count loop
450 if l_olap_object(i).object_type='dimension level' then
451 bsc_aw_dbms_aw.execute('mnt '||l_olap_object(i).olap_object||' delete all');
452 end if;
453 end loop;
454 --
455 bsc_aw_management.commit_aw;
456 commit;
457 Exception when others then
458 log_n('Exception in purge_dim '||sqlerrm);
459 raise;
460 End;
461
462 /*
463 this procedure will dmp the dim level data into table bsc_aw_dim_data
464 used for bis dimensions that are not materialized. bsc loader needs the dim values
465 to know which values have got deleted
466
467 this creates the program on the fly, executes it and drops the program
468 NO COMMIT!!!
469 remember: multiple dim loads can be happening. so we cannot have just one program for all
470 dim levels. the same level cannot be loaded in 2 sessions
471 */
472 procedure dmp_dim_level_into_table(p_dim_level_list dbms_sql.varchar2_table) is
473 Begin
474 for i in 1..p_dim_level_list.count loop
475 dmp_dim_level_into_table(upper(p_dim_level_list(i)));
476 end loop;
477 Exception when others then
478 log_n('Exception in dmp_dim_level_into_table '||sqlerrm);
479 raise;
480 End;
481 --
482 procedure dmp_dim_level_into_table(p_dim_level varchar2) is
483 --
484 l_name varchar2(300);
485 Begin
486 l_name:='dmp_'||p_dim_level;
487 bsc_aw_dbms_aw.execute_ne('delete '||l_name);
488 bsc_aw_adapter_dim.create_dmp_program(p_dim_level,l_name);
489 bsc_aw_dbms_aw.execute('call '||l_name);
490 bsc_aw_dbms_aw.execute('delete '||l_name);
491 Exception when others then
492 log_n('Exception in dmp_dim_level_into_table '||sqlerrm);
493 raise;
494 End;
495
496 /*
497 say there are hier changes. we need to make sure we mark the kpi limit variables accordingly.
498 example:
499 if any(BSC_CCDIM_100_101_102_103.limit.bool) --limit bool now represented as .LB to reduce length of name
500 then do
501 limit BSC_CCDIM_100_101_102_103 to BSC_CCDIM_100_101_102_103.limit.bool
502 kpi_3014_1.BSC_CCDIM_100_101_102_103.limit.bool=TRUE
503 doend
504 earlier this was in the dim program. but there is an issue here. when creating the dim programs, we cannot
505 know which kpi are implemented. if we assume that all kpi marked for aw are implemented, we can run into an
506 issue if a kpi ends up not implemented. so better do this at runtime, after reading the olap metadata
507
508 here we will limit the dim to whatever hier changed. then we will set the kpi.dim.limit.bool to these values
509 at this time, the levels for which the hier changed maynot even be a level of the kpi. this is ok. at the time
510 when we are about to aggregate the kpi, we will eliminate all the levels that are not involved
511 we also set the aggregate marker for the kpi dimset to true
512 */
513 procedure set_kpi_limit_variables(p_dim varchar2) is
514 --
515 l_olap_object_relation bsc_aw_md_wrapper.bsc_olap_object_relation_tb;
516 l_olap_object bsc_aw_md_wrapper.bsc_olap_object_tb;
517 l_dim_limit_cube varchar2(300);
518 l_kpi_limit_cubes dbms_sql.varchar2_table;
519 l_kpi_aggregate_markers dbms_sql.varchar2_table;
520 l_kpi_reset_cubes dbms_sql.varchar2_table;
521 l_statlen varchar2(200);
522 l_relation varchar2(200);
523 Begin
524 bsc_aw_md_api.get_bsc_olap_object_relation(null,null,'dim limit cube',p_dim,'dimension',l_olap_object_relation);
525 bsc_aw_md_api.get_bsc_olap_object(null,'relation',p_dim,'dimension',l_olap_object);
526 if l_olap_object.count>0 then
527 l_relation:=l_olap_object(1).olap_object;
528 else
529 if g_debug then
530 log_n('No relation found for dim '||p_dim);
531 end if;
532 end if;
533 --there must be only 1 limit cube
534 --see which kpi and which dim sets have this dim. get the kpi limit cube from the property
535 if l_olap_object_relation.count > 0 then
536 l_dim_limit_cube:=l_olap_object_relation(1).relation_object;
537 --get the cube limit cubes
538 --see if we need to set the aggregate marker
539 --the output comes in formats like 321,667...so do not want to use to_number(...)
540 bsc_aw_dbms_aw.execute('push '||p_dim);
541 bsc_aw_dbms_aw.execute('limit '||p_dim||' to '||l_dim_limit_cube);
542 l_statlen:=bsc_aw_dbms_aw.interp('show statlen('||p_dim||')');
543 if l_statlen <> '0' then
544 if l_relation is not null then
545 bsc_aw_dbms_aw.execute('limit '||p_dim||' to children using '||l_relation);
546 end if;
547 l_statlen:=bsc_aw_dbms_aw.interp('show statlen('||p_dim||')');
548 if l_statlen <> '0' then
549 l_kpi_limit_cubes.delete;
550 l_kpi_aggregate_markers.delete;
551 bsc_aw_adapter_dim.get_dim_kpi_limit_cubes(p_dim,l_kpi_limit_cubes,l_kpi_aggregate_markers,l_kpi_reset_cubes);
552 for i in 1..l_kpi_limit_cubes.count loop
553 bsc_aw_dbms_aw.execute(l_kpi_limit_cubes(i)||'=TRUE');
554 end loop;
555 for i in 1..l_kpi_aggregate_markers.count loop
556 bsc_aw_dbms_aw.execute(l_kpi_aggregate_markers(i)||'=TRUE');
557 end loop;
558 end if;
559 --handle setting reset cubes
560 /*
561 we cannot have this part inside if l_statlen <> '0' (after drill down to children). imagine we have A >- B.
562 now, A does not have a manager. so we have A and B. in this case, l_statlen will be 0. but we need to set the
563 reset cubes to 0 for B.
564 reset cubes are reqd because a parent node can be left with no children in which case, we need to set the values for
565 the node to NA in the cube
566 example: A C changes to A C
567 a b d a b d
568 in this case, we need to set the aggregated value for A to na in the cubes. AW will not re-agg A. it will re-agg only if
569 A has at-least another child node, even if this child node is not a part of the cube
570 */
571 if l_relation is not null then
572 bsc_aw_dbms_aw.execute('limit '||p_dim||' to parents using '||l_relation);
573 bsc_aw_dbms_aw.execute(l_dim_limit_cube||'=false');
574 bsc_aw_dbms_aw.execute('limit '||p_dim||' to '||l_dim_limit_cube);--only hanging nodes left
575 l_statlen:=bsc_aw_dbms_aw.interp('show statlen('||p_dim||')');
576 if l_statlen <> '0' then
577 for i in 1..l_kpi_reset_cubes.count loop
578 bsc_aw_dbms_aw.execute(l_kpi_reset_cubes(i)||'=TRUE');
579 end loop;
580 end if;
581 end if;
582 --dim limit cube will be set to false at the start of the dim load
583 end if;
584 bsc_aw_dbms_aw.execute('pop '||p_dim);
585 end if;
586 Exception when others then
587 log_n('Exception in set_kpi_limit_variables '||sqlerrm);
588 raise;
589 End;
590
591 procedure lock_dim_objects(p_dim varchar2,p_dim_delete boolean) is
592 --
593 l_lock_objects dbms_sql.varchar2_table;
594 Begin
595 if p_dim_delete then --full rw lock
596 bsc_aw_management.get_workspace_lock('rw',null);
597 else
598 get_dim_objects_to_lock(p_dim,l_lock_objects);
599 bsc_aw_management.get_workspace_lock(l_lock_objects,null);
600 end if;
601 Exception when others then
602 log_n('Exception in lock_dim_objects '||sqlerrm);
603 raise;
604 End;
605
606 /*
607 we cannot lock concat dim. got error
608 acquire BSC_CCDIM_100_101_102_103 (S: 04/13/2005 17:34:10
609 Exception in execute acquire BSC_CCDIM_100_101_102_103 ORA-37018:Multiwriter operations are not supported for object BSC_AW!BSC_CCDIM_100_101_102_103.
610 --
611 we have to acquire locks and update in a certain order . else we get
612 ORA-37023: (XSMLTUPD01) Object workspace object cannot be updated without dimension workspace object.
613 we cannot update a relation before a dim. so when we get locks, we first get dim, then relations, then variables
614 */
615 procedure get_dim_objects_to_lock(p_dim varchar2,p_lock_objects out nocopy dbms_sql.varchar2_table) is
616 --
617 l_bsc_olap_object bsc_aw_md_wrapper.bsc_olap_object_tb;
618 l_kpi_limit_cubes dbms_sql.varchar2_table;
619 l_kpi_reset_cubes dbms_sql.varchar2_table;
620 l_kpi_aggregate_markers dbms_sql.varchar2_table;
621 l_objects dbms_sql.varchar2_table;
622 Begin
623 l_bsc_olap_object.delete;
624 bsc_aw_md_api.get_bsc_olap_object(null,null,p_dim,'dimension',l_bsc_olap_object);
625 for i in 1..l_bsc_olap_object.count loop
626 if l_bsc_olap_object(i).olap_object_type is not null and l_bsc_olap_object(i).olap_object_type='dimension' then
627 l_objects(l_objects.count+1):=l_bsc_olap_object(i).olap_object;
628 end if;
629 end loop;
630 for i in 1..l_bsc_olap_object.count loop
631 if l_bsc_olap_object(i).olap_object_type is not null and l_bsc_olap_object(i).olap_object_type='relation' then
632 l_objects(l_objects.count+1):=l_bsc_olap_object(i).olap_object;
633 end if;
634 end loop;
635 for i in 1..l_bsc_olap_object.count loop
636 if l_bsc_olap_object(i).olap_object_type is not null and l_bsc_olap_object(i).olap_object_type='variable' then
637 l_objects(l_objects.count+1):=l_bsc_olap_object(i).olap_object;
638 end if;
639 end loop;
640 --also, we have to lock the kpi limit cubes
641 bsc_aw_adapter_dim.get_dim_kpi_limit_cubes(p_dim,l_kpi_limit_cubes,l_kpi_aggregate_markers,l_kpi_reset_cubes);
642 for i in 1..l_kpi_limit_cubes.count loop
643 l_objects(l_objects.count+1):=l_kpi_limit_cubes(i);
644 end loop;
645 for i in 1..l_kpi_aggregate_markers.count loop
646 l_objects(l_objects.count+1):=l_kpi_aggregate_markers(i);
647 end loop;
648 --
649 for i in 1..l_objects.count loop
650 if bsc_aw_utility.in_array(p_lock_objects,l_objects(i))=false then
651 p_lock_objects(p_lock_objects.count+1):=l_objects(i);
652 end if;
653 end loop;
654 Exception when others then
655 log_n('Exception in get_dim_objects_to_lock '||sqlerrm);
656 raise;
657 End;
658
659 /*
660 this is called only for rec dim implemented with normal hier. in this case, we take the data from denorm
661 table and normalize it into a temp table bsc_aw_temp_pc. the dim load program for the rec dim will
662 pick up data from here
663 to support multiple parents, we use the rank fn. if a child has 2 parents (example 3), we will see
664 C P RANK()OVER(PARTITIONBYCORDERBYROWNUM)
665 ---------- ---------- -------------------------------------
666 2 1 1
667 3 1 1
668 3 6 2
669 order by parent col is imp. it makes the result repeatable
670 this api is only fired for dbi based rec dim
671 */
672 procedure load_recursive_norm_hier(p_denorm_source varchar2,p_child_col varchar2,p_parent_col varchar2) is
673 --
674 l_stmt varchar2(8000);
675 Begin
676 if p_denorm_source is not null then
677 bsc_aw_utility.execute_stmt('delete bsc_aw_temp_pc');
678 bsc_aw_utility.execute_stmt('delete bsc_aw_temp_vn');
679 --
680 l_stmt:='insert into bsc_aw_temp_vn(name,id) select '||p_child_col||',count(*) from '||p_denorm_source||' group by '||p_child_col;
681 bsc_aw_utility.execute_stmt(l_stmt);
682 --
683 l_stmt:='insert into bsc_aw_temp_pc(parent,child,id) select '||p_parent_col||','||p_child_col||',rank() over(partition by '||
684 p_child_col||' order by '||p_parent_col||') from (select denorm.'||p_parent_col||',denorm.'||p_child_col||' from '||
685 p_denorm_source||' denorm,bsc_aw_temp_vn t1,bsc_aw_temp_vn t2 where denorm.'||p_parent_col||'=t1.name(+) and '||
686 'denorm.'||p_child_col||'=t2.name and t2.id=nvl(t1.id,0)+1)';
687 bsc_aw_utility.execute_stmt(l_stmt);
688 end if;
689 Exception when others then
690 log_n('Exception in load_recursive_norm_hier '||sqlerrm);
691 raise;
692 End;
693
694 function check_dim_loaded(p_dim varchar2) return varchar2 is
695 l_oo bsc_aw_md_wrapper.bsc_olap_object_tb;
696 Begin
697 if bsc_aw_utility.in_array(bsc_aw_adapter_dim.get_preloaded_dim_list,p_dim)=false then
698 bsc_aw_md_api.get_bsc_olap_object(p_dim,'dimension',p_dim,'dimension',l_oo);
699 if l_oo(1).operation_flag is not null and l_oo(1).operation_flag='loaded' then
700 return 'Y';
701 else
702 return 'N';
703 end if;
704 else
705 return 'Y';
706 end if;
707 Exception when others then
708 log_n('Exception in check_dim_loaded '||sqlerrm);
709 raise;
710 End;
711
712 procedure mark_dim_loaded(p_dim varchar2) is
713 l_oo bsc_aw_md_wrapper.bsc_olap_object_tb;
714 Begin
715 bsc_aw_md_api.update_olap_object(p_dim,'dimension',p_dim,'dimension',null,null,'operation_flag','loaded');
716 bsc_aw_md_api.get_bsc_olap_object(null,'dimension level',p_dim,'dimension',l_oo);
717 for i in 1..l_oo.count loop --mark snowflake impl as loaded
718 bsc_aw_md_api.update_olap_object(l_oo(i).object,'dimension',l_oo(i).object,'dimension',null,null,'operation_flag','loaded');
719 end loop;
720 Exception when others then
721 log_n('Exception in mark_dim_loaded '||sqlerrm);
722 raise;
723 End;
724
725 /* 5064802 cannot recreate dim programs. do this: load all dim once again and also load the values from bsc_aw_dim_delete table
726 from now on, hopefully, there will not be attempt to delete values that do not exist in dimensions. newly created dim will have robust strategy
727 to handle cases where dim delete values are not yet in aw dim*/
728 procedure upgrade_load_sync_all_dim is
729 l_oo bsc_aw_md_wrapper.bsc_olap_object_tb;
730 l_dim varchar2(200);
731 l_dim_list dbms_sql.varchar2_table;
732 Begin
733 bsc_aw_md_api.get_bsc_olap_object(null,'dimension level',null,'dimension',l_oo);
734 for i in 1..l_oo.count loop
735 if bsc_aw_utility.get_parameter_value(l_oo(i).property1,'periodicity',',') is null then --this is not a calendar dim level
736 bsc_aw_md_api.get_dim_for_level(l_oo(i).object,l_dim);
737 bsc_aw_utility.merge_value(l_dim_list,l_dim);
738 end if;
739 end loop;
740 --
741 for i in 1..l_dim_list.count loop
742 upgrade_load_sync_all_dim(l_dim_list(i));
743 end loop;
744 Exception when others then
745 log_n('Exception in upgrade_load_sync_all_dim '||sqlerrm);
746 raise;
747 End;
748
749 procedure upgrade_load_sync_all_dim(p_dim varchar2) is
750 l_oo bsc_aw_md_wrapper.bsc_olap_object_tb;
751 l_dim_level_delete dim_level_delete_tv;
752 l_delete_flag boolean;
753 Begin
754 if g_debug then
755 log('upgrade_load_sync_all_dim '||p_dim);
756 end if;
757 /*add delete values into the dim levels */
758 bsc_aw_md_api.get_bsc_olap_object(p_dim,'dimension',p_dim,'dimension',l_oo);
759 if l_oo.count>0 then
760 load_dim_delete(p_dim,l_oo(1).property1,l_dim_level_delete,l_delete_flag);
761 if l_delete_flag then
762 merge_delete_values_to_levels(l_dim_level_delete);
763 end if;
764 end if;
765 /*refresh the dim */
766 l_oo.delete;
767 bsc_aw_md_api.get_bsc_olap_object(null,'dml program',p_dim,'dimension',l_oo);
768 for i in 1..l_oo.count loop
769 if l_oo(i).olap_object_type='dml program initial load' then
770 begin
771 bsc_aw_dbms_aw.execute('call '||l_oo(i).object);
772 exception when others then
773 null;
774 end;
775 exit;
776 end if;
777 end loop;
778 Exception when others then
779 log_n('Exception in upgrade_load_sync_all_dim '||sqlerrm);
780 raise;
781 End;
782
783 /*5074869 in the load programs, the delete values are handled only when the dim levels have parents. if this is the top level and
784 bsc_aw_dim_delete has values not in the dim, we can run into the issue of value not valid error
785 best way is to merge these delete values into the dim levels anyway */
786 procedure merge_delete_values_to_levels(p_dim_level_delete dim_level_delete_tv) is
787 l_levels dbms_sql.varchar2_table;
788 Begin
789 l_levels:=p_dim_level_delete('ALL').delete_values;
790 for i in 1..l_levels.count loop
791 for j in 1..p_dim_level_delete(l_levels(i)).delete_values.count loop
792 bsc_aw_dbms_aw.execute('mnt '||l_levels(i)||' merge '''||p_dim_level_delete(l_levels(i)).delete_values(j)||'''');
793 end loop;
794 end loop;
795 Exception when others then
796 log_n('Exception in merge_delete_values_to_levels '||sqlerrm);
797 raise;
798 End;
799
800 ------------------------------------------
801 procedure init_all is
802 Begin
803 g_debug:=bsc_aw_utility.g_debug;
804 Exception when others then
805 log_n('Exception in init_all '||sqlerrm);
806 raise;
807 End;
808
809 procedure log(p_message varchar2) is
810 Begin
811 bsc_aw_utility.log(p_message);
812 Exception when others then
813 null;
814 End;
815
816 procedure log_n(p_message varchar2) is
817 Begin
818 log(' ');
819 log(p_message);
820 Exception when others then
821 null;
822 End;
823
824 END BSC_AW_LOAD_DIM;