DBA Data[Home] [Help]

PACKAGE BODY: APPS.QLTVCREB

Source


1 PACKAGE BODY QLTVCREB AS
2 /* $Header: qltvcreb.plb 120.6.12010000.2 2008/09/15 09:37:29 ntungare ship $ */
3 
4 -- executes a sql statement dynamically
5 
6 -- A constant to fool GSCC.  See bug 3554899
7 -- bso Wed Apr  7 22:27:11 PDT 2004
8     g_period CONSTANT VARCHAR2(1) := '.';
9 
10 --
11 -- The following set functions is an effort to extend the capability
12 -- of the global_view procedure, so it can handle view definitions
13 -- longer than 32K, the previous hard limit (because of PL/SQL varchar2
14 -- string limit). Now, the DBMS_SQL.Varchar2s type is used for storing
15 -- the view definition.  This is a table and is the data type used by
16 -- AD_DDL.DO_ARRAY_DDL.
17 --
18 -- April 22, 1998.  bso
19 --
20 
21     --
22     -- Apps schema info
23     --
24     g_dummy           BOOLEAN;
25     g_fnd             CONSTANT VARCHAR2(3) := 'FND';
26     g_status          VARCHAR2(1);
27     g_industry        VARCHAR2(10);
28     g_schema          VARCHAR2(30);
29 
30 /*
31 PROCEDURE table_print(A in DBMS_SQL.varchar2s) IS
32 -- Debug procedure, not used in production.
33 -- bso
34     i binary_integer;
35 BEGIN
36     --FOR i IN 1..A.count LOOP
37     --    DBMS_OUTPUT.put_line(A(i));
38     --END LOOP;
39       FOR i IN 1..A.count LOOP
40           insert into bso(l1, n1) values(A(i), i);
41       END LOOP;
42     commit;
43 END;
44 */
45 
46 --
47 -- bug 7409976
48 -- New type to hold the privileges granted on a view
49 -- ntungare
50 --
51 TYPE grants_tab_typ IS TABLE OF VARCHAR2(32767) INDEX BY binary_integer;
52 
53 PROCEDURE create_clause(s in out NOCOPY DBMS_SQL.varchar2s, f in DBMS_SQL.varchar2s,
54     keyword varchar2) IS
55 --
56 -- Add to s the content of f to make f the FROM or WHERE clause of s.
57 -- This procedure replaces the QLTSTORB.Create_From/Where_Clause procedures
58 -- because that one does not allow a clause that's > 32k.
59 --
60 -- s is the sql string in dbms_sql.varchar2s
61 -- f is the list of from or where clauses
62 -- keyword is either 'FROM' or 'WHERE'
63 --
64 -- bso
65 --
66     i binary_integer;
67     sep varchar2(10);
68 BEGIN
69     IF f.count > 0 THEN
70         IF keyword = 'FROM' THEN
71             sep := ', ';
72         ELSE
73             sep := ' AND ';
74         END IF;
75         i := s.count + 1;
76         s(i) := ' ' || keyword || ' ' || f(1);
77 
78         FOR j IN 2..f.count LOOP
79             i := i + 1;
80             s(i) :=  sep || f(j);
81         END LOOP;
82     END IF;
83 END;
84 
85 
86 PROCEDURE exec_ddl_table(schema in varchar2, shortname in varchar2,
87     cmd in integer, statement in DBMS_SQL.varchar2s, name in varchar2) IS
88 -- Execute a data definition statement by using the AD_DDL.DO_ARRAY_DDL
89 -- function.  See Bug 574078.  Release 10.7 requires this patch to work.
90 -- bso
91 
92     --
93     -- Bug 3756235
94     -- This is a performance fix.  A global view usually has tens of
95     -- thousands of "statements" because each statement(i) is a short
96     -- string.  Thus, we have been calling ad_ddl.build_statement a
97     -- lot.  The no. of calls can be reduced 10-fold if we concat the
98     -- shorter strings into a long one before invoking the API.
99     --
100     -- 255 is the current max size of build_statement's input param.
101     -- If this limit is lifted, this constant and the variable can
102     -- be changed accordingly and the code will adapt to use the
103     -- larger buffer for even better performance.  See AD's bug or
104     -- enhancement 3754657.
105     --
106     -- bso Sat Jul 24 16:17:15 PDT 2004
107     --
108     max_size CONSTANT NUMBER := 255;
109     s VARCHAR2(255);
110     n INTEGER;
111 
112 BEGIN
113     --table_print(statement);
114 
115     n := 0;
116     FOR i IN 1..statement.count LOOP
117         --
118         -- check if we have enough room in s to take in more statements
119         -- if not, we should call build_statement to process the previous
120         -- concatenated string.
121         -- bso Sat Jul 24 16:17:15 PDT 2004
122         --
123         -- check the size of the statement using lengthb function instead of
124         -- length, to handle NLS characters.
125         -- vvs BUG 4129987 Wed Mar  2 04:48:07 PST 2005
126         --
127         IF nvl(lengthb(s), 0) + nvl(lengthb(statement(i)), 0) + 1 > max_size THEN
128             n := n + 1;
129             AD_DDL.build_statement(s, n);
130             s := '';
131         END IF;
132 
133         s := s || statement(i) || ' ';
134     END LOOP;
135 
136     --
137     -- Because the last command in the loop is a string concatenation,
138     -- we will always have a final "s" to process here.
139     -- bso Sat Jul 24 16:17:15 PDT 2004
140     --
141     n := n + 1;
142     AD_DDL.build_statement(s, n);
143 
144     AD_DDL.do_array_ddl(schema, shortname, cmd, 1, n, name);
145 END;
146 
147 
148 FUNCTION trans(name VARCHAR2) RETURN VARCHAR2 IS
149 --
150 -- The translate is there for NLS fix and pseudo-trans fix.
151 -- Problem is, we allow user to enter single quote in NLS fix.
152 -- Pseudo-trans will also translate element names into names
153 -- with asterisks and braces.  All these will cause error in
154 -- Discoverer Work Book (although they actually won't cause
155 -- problem in our view generation code).  Therefore, translate
156 -- them into underscores to help Discoverer out.
157 --
158 BEGIN
159     RETURN upper(translate(name, ' ''"*{}', '______'));
160 END trans;
161 
162 
163 PROCEDURE drop_view(x VARCHAR2) IS
164 BEGIN
165     ad_ddl.do_ddl(g_schema, 'QA', ad_ddl.drop_view,
166         'DROP VIEW "' || upper(x) || '"', x);
167     EXCEPTION WHEN OTHERS THEN
168         NULL;
169 END drop_view;
170 
171 
172 FUNCTION contains(a dbms_sql.number_table, x NUMBER) RETURN NUMBER IS
173 BEGIN
174     FOR i IN a.first .. a.last LOOP
175         IF a(i) = x THEN
176             RETURN i;
177         END IF;
178     END LOOP;
179     RETURN -1;
180 END contains;
181 
182 
183 PROCEDURE global_view(x_view_name IN VARCHAR2) IS
184 
185     --
186     -- Complete rewrite on Thu Dec  7 14:08:03 PST 2000
187     -- bso
188     --
189 
190     --
191     -- Used to construct the final dynamic sql.
192     --
193     v_sql_table     dbms_sql.varchar2s;
194     v_from_table    dbms_sql.varchar2s;
195     v_where_table   dbms_sql.varchar2s;
196 
197 
198     --
199     -- Maximum no. of columns allowed in a view.
200     --
201     max_columns CONSTANT NUMBER := 1000;
202 
203     --
204     -- No. of fixed, seeded columns to be included in the beginning of the view
205     --
206     fixed_columns CONSTANT NUMBER := 14;
207     column_count NUMBER;
208 
209     --
210     -- Bug 1357601.  The decode statement used to "straighten" softcoded
211     -- elements into a single column has a sever limit of 255 parameters.
212     -- These variables are added to resolve the limit.  When the limit is
213     -- up, we use the very last parameter of the decode statement to
214     -- start a new decode, which can have another 255 params.  This is
215     -- repeated as necessary.
216     --
217     -- decode_count keeps the no. of decodes being used so far.
218     -- decode_param keeps the no. of parameters in the current decode.
219     -- decode_limit is the server limit.  This should be updated if
220     --    the server is enhanced in the future.
221     --
222     -- bso Thu Sep 21 13:11:19 PDT 2000
223     --
224     decode_count NUMBER;
225     decode_param NUMBER;
226     decode_limit CONSTANT NUMBER := 255;
227 
228     --
229     -- Bug 4958779
230     -- This cursor is not performing.  Removed and fetch element
231     -- info on-the-fly.
232     -- bso Tue Jan 31 14:57:53 PST 2006
233     --
234     -- CURSOR elements_cursor IS
235     --    SELECT   qc.char_id, qc.name, qc.hardcoded_column, qc.datatype
236     --    FROM     qa_chars qc
237     --    WHERE    qc.enabled_flag = 1 and
238     --             rownum < (max_columns - fixed_columns)
239     --    ORDER BY qc.hardcoded_column, qc.name;
240     --
241     -- The elements to be included in the final view.
242     --
243     -- element_ids               dbms_sql.number_table;
244     -- element_names             dbms_sql.varchar2s;
245     -- element_hardcoded_columns dbms_sql.varchar2s;
246     -- element_datatypes         dbms_sql.number_table;
247     --
248     l_element_id NUMBER;
249     l_element_name qa_chars.name%TYPE;
250     l_element_hardcoded_column qa_chars.hardcoded_column%TYPE;
251     l_element_datatype NUMBER;
252 
253     --
254     -- This cursor is used to fetch foreign key info for hardcoded,
255     -- normalized elements.
256     --
257     CURSOR fk_cursor(x NUMBER) IS
258         SELECT qc.fk_table_name,
259                qc.fk_table_short_name,
260                qc.fk_lookup_type,
261                qc.pk_id,
262                qc.fk_id,
263                qc.pk_id2,
264                qc.fk_id2,
265                qc.pk_id3,
266                qc.fk_id3,
267                qc.fk_meaning,
268                qc.fk_description,
269                qc.fk_add_where
270         FROM   qa_chars qc
271         WHERE  qc.char_id = x;
272 
273     fk fk_cursor%ROWTYPE;
274 
275     --
276     -- This cursor loops through qa_plan_chars to find all
277     -- plan_id and result_column_name for each collection element.
278     --
279     -- The decode() function and distinct are there to cleverly
280     -- eliminate all but one row of hardcoded elements.  We only
281     -- need one row for each hardcoded ones.
282     --
283     CURSOR plan_cursor IS
284         SELECT
285         /*
286            This is a batch program that needs to loop through
287            all collection plans to generate a global view.
288            Full table scan is expected.  Bryan So 1/31/2006
289         */
290                  distinct qpc.char_id,
291                  decode(qc.hardcoded_column, null, qpc.plan_id, 0) plan_id,
292                  upper(qpc.result_column_name) result_column_name,
293                  qc.name,
294                  qc.hardcoded_column
295         FROM     qa_plan_chars qpc, qa_chars qc
296         WHERE    qc.char_id = qpc.char_id AND
297                  qpc.enabled_flag = 1 AND
298                  qc.enabled_flag = 1
299         ORDER BY qc.hardcoded_column, qc.name;
300 
301     pc plan_cursor%ROWTYPE;
302 
303     current_element NUMBER;
304     temp            VARCHAR2(255);
305     n               INTEGER;
306 
307     i               INTEGER;   -- I used these as counters for the
308     j               INTEGER;   -- following lists: select list (v_sql_table),
309     k               INTEGER;   -- from list, where list
310     --
311     -- I have used generic function such as table_add to an element
312     -- to a PL/SQL table... it is way too slow.  3 times difference
313     -- than using simple variable counters.
314     --
315 
316 BEGIN
317 
318     --
319     -- This is the beginning of the global view.
320     --
321 
322     v_sql_table(1) := 'CREATE OR REPLACE FORCE VIEW ' || x_view_name;
323     v_sql_table(2) := ' AS SELECT ';
324     v_sql_table(3) := ' qr.rowid row_id,';                         -- 1
325     v_sql_table(4) := ' qr.plan_id,';                              -- 2
326     v_sql_table(5) := ' qp'||g_period||'name plan_name,';          -- 3 see bug 3554899
327     v_sql_table(6) := ' qr.organization_id,';                      -- 4
328     v_sql_table(7) := ' hou.name organization_name,';              -- 5
329     v_sql_table(8) := ' qr.collection_id,';                        -- 6
330     v_sql_table(9) := ' qr.occurrence,';                           -- 7
331     v_sql_table(10) := ' qr.qa_last_update_date last_update_date,'; -- 8
332     v_sql_table(11) := ' qr.qa_last_updated_by last_update_by_id,'; -- 9
333     v_sql_table(12) := ' fu2.user_name last_updated_by,';           -- 10
334     v_sql_table(13) := ' qr.qa_creation_date creation_date,';       -- 11
335     v_sql_table(14) := ' qr.qa_created_by created_by_id,';          -- 12
336     v_sql_table(15) := ' fu.user_name created_by,';                 -- 13
337     v_sql_table(16) := ' qr.last_update_login';                     -- 14
338     i := 17;
339     column_count := fixed_columns;  -- 14
340 
341     -- Then add the necessary where and froms
342     v_from_table(1) := 'qa_results qr';
343     v_from_table(2) := 'qa_plans qp';
344     v_from_table(3) := 'fnd_user_view fu';
345     v_from_table(4) := 'fnd_user_view fu2';
346     v_from_table(5) := 'hr_organization_units hou';
347     j := 6;
348 
349     v_where_table(1) := 'qp'||g_period||'plan_id = qr.plan_id'; -- see bug 3554899
350     v_where_table(2) := 'qr.qa_created_by = fu.user_id';
351     v_where_table(3) := 'qr.qa_last_updated_by = fu2.user_id';
352     v_where_table(4) := 'qr.organization_id = hou.organization_id';
353     v_where_table(5) := '(qr.status IS NULL OR qr.status = 2)';
354     k := 6;
355 
356     --
357     -- Bug 4958779
358     -- This cursor is not performing.  Removed and fetch element
359     -- info on-the-fly.
360     -- bso Tue Jan 31 14:57:53 PST 2006
361     --
362     -- -- Collection all elements to be included in the view.
363     -- --
364     -- OPEN elements_cursor;
365     --
366     -- FETCH elements_cursor BULK COLLECT INTO element_ids, element_names,
367     --    element_hardcoded_columns, element_datatypes;
368     --
369     -- CLOSE elements_cursor;
370     --
371 
372     --
373     -- One option is to go through each element, but it is slightly
374     -- more efficient to go through qa_plan_chars to avoid performing
375     -- too many database parses.
376     --
377     -- FOR element IN elements_cursor LOOP
378     --
379     OPEN plan_cursor;
380     FETCH plan_cursor INTO pc;
381 
382     LOOP
383       EXIT WHEN column_count > (max_columns-2);  -- reserve 2 columns
384 
385       EXIT WHEN plan_cursor%NOTFOUND;
386 
387       --
388       -- We will do the following only if element appears in the given
389       -- element ID list.
390       --
391       current_element := pc.char_id;
392 
393       SELECT char_id, name, hardcoded_column, datatype
394       INTO   l_element_id, l_element_name, l_element_hardcoded_column,
395              l_element_datatype
396       FROM   qa_chars
397       WHERE  char_id = current_element;
398 
399         -- There are several conditions.
400 
401         --
402         -- If the element has a specially-coded stored function, then
403         -- use the stored function...
404         --
405         IF current_element = qa_ss_const.sales_order THEN
406           v_sql_table(i) := ', qr.' || l_element_hardcoded_column;
407           i := i + 1;
408           v_sql_table(i) := ', qa_flex_util.sales_order(qr.so_header_id) "'
409               || trans(l_element_name) || '"';
410           i := i + 1;
411           column_count := column_count + 2;
412 
413         ELSIF current_element = qa_ss_const.rma_number THEN
414           v_sql_table(i) := ', qr.' || l_element_hardcoded_column;
415           i := i + 1;
416           v_sql_table(i) := ', qa_flex_util.rma_number(qr.rma_header_id) "'
417               || trans(l_element_name) || '"';
418           i := i + 1;
419           column_count := column_count + 2;
420 
421         ELSIF current_element = qa_ss_const.project_number THEN
425               || trans(l_element_name) || '"';
422           v_sql_table(i) := ', qr.' || l_element_hardcoded_column;
423           i := i + 1;
424           v_sql_table(i) := ', qa_flex_util.project_number(qr.project_id) "'
426           i := i + 1;
427           column_count := column_count + 2;
428 
429         --
430         -- If the element is hardcoded, then simply use the hardcoded column.
431         --
432         ELSIF l_element_hardcoded_column IS NOT NULL THEN
433 
434           --
435           -- a small complication is if the element is a foreign key,
436           -- such as ITEM_ID, then outer join to the foreign table.
437           --
438           OPEN fk_cursor(current_element);
439           FETCH fk_cursor INTO fk;
440 
441           IF fk.fk_lookup_type IN (0, 1)
442               --
443               -- Safety check to make sure foreign key reference is
444               -- there.  Otherwise, we will have a cross product with
445               -- no join condition!
446               --
447               AND fk.fk_id IS NOT NULL
448               AND fk.pk_id IS NOT NULL THEN
449               --
450               -- Here is where there is a foreign table.  First add
451               -- the hardcoded column as is, so the ID column is present.
452               --
453               v_sql_table(i) := ', qr.' || l_element_hardcoded_column;
454               i := i + 1;
455 
456               --
457               -- Then add the foreign select as a separate column.
458               --
459               v_sql_table(i) := ', ' || fk.fk_table_short_name || '.' ||
460                   fk.fk_meaning || ' "' || trans(l_element_name) || '"';
461               i := i + 1;
462 
463               -- Then the foreign table in the from clause
464               -- and finally the outer join in where clause.
465               --
466               v_from_table(j) :=
467                   fk.fk_table_name || ' ' || fk.fk_table_short_name;
468               j := j + 1;
469 
470               IF fk.pk_id IS NOT NULL AND fk.fk_id IS NOT NULL THEN
471                   v_where_table(k) := 'qr.' || fk.fk_id || ' = ' ||
472                       fk.fk_table_short_name || '.' || fk.pk_id || ' (+)';
473                   k := k + 1;
474               END IF;
475 
476               IF fk.pk_id2 IS NOT NULL AND fk.fk_id2 IS NOT NULL THEN
477                   v_where_table(k) := 'qr.' || fk.fk_id2 || ' = ' ||
478                       fk.fk_table_short_name || '.' || fk.pk_id2 || ' (+)';
479                   k := k + 1;
480               END IF;
481 
482               IF fk.pk_id3 IS NOT NULL AND fk.fk_id3 IS NOT NULL THEN
483                   v_where_table(k) := 'qr.' || fk.fk_id3 || ' = ' ||
484                       fk.fk_table_short_name || '.' || fk.pk_id3 || ' (+)';
485                   k := k + 1;
486               END IF;
487 
488               IF fk.fk_add_where IS NOT NULL THEN
489                   v_where_table(k) := fk.fk_add_where;
490                   k := k + 1;
491               END IF;
492 
493               column_count := column_count + 2;
494 
495             ELSE
496               --
497               -- Not foreign key ... great, simply add the hardcoded
498               -- column name, examples are LOT_NUMBER, QUANTITY...
499               --
500               v_sql_table(i) := ', qr.' || l_element_hardcoded_column ||
501                   ' "' || trans(l_element_name) || '"';
502               i := i + 1;
503 
504               column_count := column_count + 1;
505             END IF;
506 
507             CLOSE fk_cursor;
508 
509         ELSE -- Here, hardcoded_column IS NULL
510 
511           --
512           -- Here the element must be softcoded.  This is most interesting.
513           -- Need to use a bunch of decode statement and also correct the
514           -- canonical datatype to real datatype format.
515           --
516           -- For example, if defect code is assigned to CHARACTER2 in
517           -- plan 101 and assigned to CHARACTER5 in plan 103, the decode
518           -- statement will look like this:
519           --
520           -- decode(qr.plan_id, 101, character2, 103, character5) defect_code
521           --
522 
523           decode_count := 0;     -- see comments in variable declaration.
524           decode_param := decode_limit;
525 
526           WHILE pc.char_id = current_element LOOP
527               --
528               -- If maximum no. of arguments to the "decode" function is
529               -- close to the server allowed 'decode_limit', then we want
530               -- to start a new tail-end decode statement.
531               --
532               IF decode_param >= (decode_limit - 2) THEN
533                   v_sql_table(i) := ', decode(qr.plan_id';
534                   i := i + 1;
535                   decode_count := decode_count + 1;
536                   decode_param := 1;
537               END IF;
538 
539               --
540               -- CHARACTER column data are stored in canonical format.
541               -- Convert to real number/real date if appropriate.
542               --
543               IF l_element_datatype = 2 THEN
544 
545               --
546               -- Need to create views with 12 decimal places
547               -- for number type elements. See Bug 2624112
551               --       ', ''9999999999999999999999999999999.999999'')';
548               -- rkunchal Wed Oct 16 05:32:33 PDT 2002
549               --
550               --    temp := 'to_number(qr.' || pc.result_column_name ||
552 
553                     temp := 'qltdate.any_to_number(qr.' || pc.result_column_name || ')';
554 
555               ELSIF l_element_datatype = 3 THEN
556                   temp := 'to_date(qr.' || pc.result_column_name ||
557                       ', ''YYYY/MM/DD'')';
558               --
559               -- Bug 3179845. Added to iinclude datetime type for Timezone.
560               -- saugupta Tue Oct 14 05:08:00 PDT 2003
561               --
562               ELSIF l_element_datatype = 6 THEN
563                   temp := 'to_date(qr.' || pc.result_column_name ||
564                       ', ''YYYY/MM/DD HH24:MI:SS'')';
565               ELSE
566                   temp := 'qr.' || pc.result_column_name;
567               END IF;
568 
569               v_sql_table(i) := ', ' || pc.plan_id || ', ' || temp;
570               i := i + 1;
571               decode_param := decode_param + 2;
572 
573               FETCH plan_cursor INTO pc;
574 
575               EXIT WHEN plan_cursor%NOTFOUND;
576 
577           END LOOP;
578 
579           --
580           -- Close all decode() parenthesis
581           --
582           temp := '';
583           FOR x IN 1 .. decode_count LOOP
584               temp := temp || ')';
585           END LOOP;
586 
587           v_sql_table(i) := temp || ' "' || trans(l_element_name) || '"';
588           i := i + 1;
589           column_count := column_count + 1;
590 
591         END IF;
592 
593       WHILE pc.char_id = current_element LOOP
594         FETCH plan_cursor INTO pc;
595         EXIT WHEN plan_cursor%NOTFOUND;
596       END LOOP;
597 
598     END LOOP;
599 
600     CLOSE plan_cursor;
601 
602     -- create the from and where clause
603     create_clause(v_sql_table, v_from_table, 'FROM');
604     create_clause(v_sql_table, v_where_table, 'WHERE');
605 
606     --
607     -- Find apps schema info.  To be used in ad_ddl calls.
608     --
609     exec_ddl_table(g_schema, 'QA', AD_DDL.create_view, v_sql_table, x_view_name);
610 
611 END global_view;
612 
613 --
614 -- bug 7409976
615 -- New procedure to create a stack of
616 -- all the grants present on the views
617 -- ntungare
618 --
619 PROCEDURE create_grant_sql(p_view_name  IN VARCHAR2,
620                            x_grants_tab OUT NOCOPY grants_tab_typ) AS
621 
622     TYPE privs_rec IS RECORD(grantee   VARCHAR2(200),
623                              obj_priv  VARCHAR2(200),
624                              grantable VARCHAR2(200));
625     TYPE privs_rec_tab_type IS TABLE OF privs_rec INDEX BY BINARY_INTEGER;
626     privs_rec_tab  privs_rec_tab_type ;
627 
628     grant_option VARCHAR2(2000):= ' WITH GRANT OPTION ';
629 
630     grant_stmt  VARCHAR2(4000);
631 BEGIN
632     SELECT grantee, privilege, grantable
633       BULK COLLECT INTO privs_rec_tab
634     FROM User_TAB_PRIVS
635       WHERE table_name = p_view_name
636     ORDER BY grantee;
637 
638     FOR cntr in 1..privs_rec_tab.COUNT
639       LOOP
640          grant_stmt := 'GRANT '|| privs_rec_tab(cntr).obj_priv ||' ON '||p_view_name ||
641                        ' TO '  || privs_rec_tab(cntr).grantee;
642 
643          IF (privs_rec_tab(cntr).grantable = 'YES') THEN
644             grant_stmt := grant_stmt ||grant_option;
645          END IF;
646 
647          x_grants_tab(cntr) := grant_stmt;
648       END LOOP;
649 END create_grant_sql;
650 
651 --  Plan View creates a view of QA_RESULTS using the user defined names
652 --  for the Character fields found there
653 
654 --  Kevin Wiggen  September 22 1994
655 
656 
657 PROCEDURE plan_view(x_view_name IN VARCHAR2, x_old_view_name IN VARCHAR2,
658     x_plan_id IN NUMBER) IS
659 
660     v_select VARCHAR2(20000);
661     v_from   VARCHAR2(20000);
662     v_where  VARCHAR2(20000);
663     v_final  VARCHAR2(32000);
664 
665     temp     VARCHAR2(255);
666 
667     CURSOR pcursor is
668         --
669         -- See comments in global_view
670         --
671         SELECT   qc.char_id,
672                  upper(translate(qc.name,' ''*{}','_____')) name,
673                  qpc.result_column_name,
674                  qc.hardcoded_column,
675                  qc.FK_LOOKUP_TYPE,
676                  qc.FK_TABLE_NAME,
677                  qc.FK_TABLE_SHORT_NAME,
678                  qc.PK_ID,
679                  qc.FK_ID,
680                  qc.PK_ID2,
681                  qc.FK_ID2,
682                  qc.PK_ID3,
683                  qc.FK_ID3,
684                  qc.FK_MEANING,
685                  qc.FK_DESCRIPTION,
686                  qc.FK_ADD_WHERE,
687                  qc.DATATYPE
688         FROM     qa_chars qc,
689                  qa_plan_chars qpc
690         WHERE    qc.char_id = qpc.char_id
691         AND      qpc.plan_id = x_plan_id
692         ORDER BY qpc.prompt_sequence;
693 
694      --
695      -- bug 6350575
696      -- 12.1 QWB Usability Improvements Project
697      --
701      v_deref_view_where  VARCHAR2(20000);
698      v_plan_view_create  VARCHAR2(2000);
699      v_deref_view_create VARCHAR2(2000);
700      v_deref_view_final  VARCHAR2(32000);
702      v_deref_view_name   VARCHAR2(30);
703 
704      --
705      -- bug 7409976
706      -- ntungare
707      --
708      x_pv_grants_tab  grants_tab_typ; -- Collection for grants on Plan  View
709      x_dv_grants_tab  grants_tab_typ; -- Collection for grants on Deref View
710 BEGIN
711    --
712    -- bug 6350575
713    -- 12. QWB Usability Improvements Project
714    -- Deriving the Deref view name
715    --
716    SELECT substr(import_view_name, 1, length(import_view_name)-2)||'DV'
717      INTO v_deref_view_name FROM qa_plans
718    WHERE plan_id = x_plan_id;
719 
720    --
721    -- When QLTPLMDF deletes a plan, it calls this proc with
722    -- null x_view_name and with x_old_view_name populated.
723    -- Need to drop the old view name and return.
724    --
725    IF x_old_view_name IS NOT NULL THEN
726        --
727        -- bug 7409976
728        -- Getting a list of all the grants on the plan view
729        -- before dropping it
730        -- ntungare
731        --
732        create_grant_sql(p_view_name  => x_old_view_name,
733                         x_grants_tab => x_pv_grants_tab);
734 
735        drop_view(x_old_view_name);
736 
737        --
738        -- bug 7409976
739        -- Getting a list of all the grants on the deref view
740        -- before dropping it
741        -- ntungare
742        --
743        create_grant_sql(p_view_name  => v_deref_view_name,
744                         x_grants_tab => x_dv_grants_tab);
745 
746        drop_view(v_deref_view_name);
747    END IF;
748 
749    IF x_view_name IS NULL THEN
750        RETURN;
751    END IF;
752 
753    --
754    -- bug 6350575
755    -- 12.1 QWB Usability Improvements Project
756    -- building the create clause for the plan view
757    --
758    v_plan_view_create := 'CREATE OR REPLACE FORCE VIEW "' || upper(x_view_name) || '" AS ';
759 
760    --
761    -- bug 6350575
762    -- 12.1 QWB Usability Improvements Project
763    -- building the create clause for the plan view
764    --
765    v_deref_view_create := 'CREATE OR REPLACE FORCE VIEW "' || upper(v_deref_view_name) || '" AS ';
766 
767    v_select := ' SELECT
768        qr.rowid row_id,
769        qr.plan_id,
770        qp'||g_period||'name plan_name,
771        qr.organization_id,
772        hou.name organization_name,
773        qr.collection_id,
774        qr.occurrence,
775        qr.qa_last_update_date last_update_date,
776        qr.qa_last_updated_by last_updated_by_id,
777        fu2.user_name last_updated_by,
778        qr.qa_creation_date creation_date,
779        qr.qa_created_by created_by_id,
780        fu.user_name created_by,
781        qr.last_update_login';
782 
783     v_from := ' FROM qa_results qr,
784        qa_plans qp,
785        fnd_user_view fu,
786        fnd_user_view fu2,
787        hr_organization_units hou';
788 
789     v_where := ' WHERE qp'||g_period||'plan_id = ' || x_plan_id || ' AND '||
790        --
791        -- bug 6044832
792        -- Added an additional where clause, so that
793        -- the index on QA_RESULTS is looked at, while
794        -- querying the view, even with high volume of
795        -- data
796        -- ntungare Mon Jul 16 03:02:23 PDT 2007
797        --
798        -- bug 6350575
799        -- 12.1 QWB USABILITY IMPROVEMENTS PROJECT
800        -- removed the status where caluse since it would be
801        -- added at the end
802        --
803        'qr'||g_period||'plan_id = '|| x_plan_id || ' AND
804        qp'||g_period||'plan_id = qr.plan_id AND
805        qr.qa_created_by = fu.user_id AND
806        qr.qa_last_updated_by = fu2.user_id AND
807        qr.organization_id = hou.organization_id';
808        --AND
809        --(qr.status IS NULL OR qr.status = 2)';
810 
811     FOR fk in pcursor LOOP
812 
813         IF fk.char_id = qa_ss_const.sales_order THEN
814           v_select := v_select || ', qr.' || fk.hardcoded_column;
815           v_select := v_select ||
816             ', qa_flex_util.sales_order(qr.so_header_id) "' || fk.name || '"';
817 
818         ELSIF fk.char_id = qa_ss_const.rma_number THEN
819           v_select := v_select || ', qr.' || fk.hardcoded_column;
820           v_select := v_select ||
821             ', qa_flex_util.rma_number(qr.rma_header_id) "' || fk.name || '"';
822 
823         ELSIF fk.char_id = qa_ss_const.project_number THEN
824           v_select := v_select || ', qr.' || fk.hardcoded_column;
825           v_select := v_select ||
826             ', qa_flex_util.project_number(qr.project_id) "' || fk.name || '"';
827 
828         --
829         -- If the element is hardcoded, then simply use the hardcoded column.
830         --
831         ELSIF fk.hardcoded_column IS NOT NULL THEN
832 
833           --
834           -- a small complication is if the element is a foreign key,
835           -- such as ITEM_ID, then outer join to the foreign table.
836           --
837           IF fk.fk_lookup_type IN (0, 1)
838               --
842               --
839               -- Safety check to make sure foreign key reference is
840               -- there.  Otherwise, we will have a cross product with
841               -- no join condition!
843               AND fk.fk_id IS NOT NULL
844               AND fk.pk_id IS NOT NULL THEN
845 
846               --
847               -- Here is where there is a foreign table.  First add
848               -- the hardcoded column as is, so the ID column is present.
849               --
850               v_select := v_select || ', qr.' || fk.hardcoded_column;
851 
852               --
853               -- Then add the foreign select as a separate column.
854               --
855               v_select := v_select || ', ' || fk.fk_table_short_name || '.' ||
856                   fk.fk_meaning || ' "' || fk.name || '"';
857 
858               -- Then the foreign table in the from clause
859               -- and finally the outer join in where clause.
860               --
861               v_from := v_from || ', ' || fk.fk_table_name || ' ' ||
862                   fk.fk_table_short_name;
863 
864               IF fk.pk_id IS NOT NULL AND fk.fk_id IS NOT NULL THEN
865                   v_where := v_where || ' AND qr.' || fk.fk_id || ' = ' ||
866                       fk.fk_table_short_name || '.' || fk.pk_id || ' (+)';
867               END IF;
868 
869               IF fk.pk_id2 IS NOT NULL AND fk.fk_id2 IS NOT NULL THEN
870                   v_where := v_where || ' AND qr.' || fk.fk_id2 || ' = ' ||
871                       fk.fk_table_short_name || '.' || fk.pk_id2 || ' (+)';
872               END IF;
873 
874               IF fk.pk_id3 IS NOT NULL AND fk.fk_id3 IS NOT NULL THEN
875                   v_where := v_where || ' AND qr.' || fk.fk_id3 || ' = ' ||
876                       fk.fk_table_short_name || '.' || fk.pk_id3 || ' (+)';
877               END IF;
878 
879               IF fk.fk_add_where IS NOT NULL THEN
880                   v_where := v_where || ' AND ' || fk.fk_add_where;
881               END IF;
882 
883             ELSE
884               --
885               -- Not foreign key ... great, simply add the hardcoded
886               -- column name, examples are LOT_NUMBER, QUANTITY...
887               --
888               v_select := v_select || ', qr.' || fk.hardcoded_column ||
889                   ' "' || fk.name || '"';
890             END IF;
891         ELSE
892             --
893             -- Element is softcoded.  Use result_column name.
894             --
895             -- CHARACTER column data are stored in canonical format.
896             -- Convert to real number/real date if appropriate.
897             --
898             IF fk.datatype = 2 THEN
899 
900               --
901               -- Need to create views with 12 decimal places
902               -- for number type elements. See Bug 2624112
903               -- rkunchal Wed Oct 16 05:32:33 PDT 2002
904               --
905               --  temp := 'to_number(qr.' || fk.result_column_name ||
906               --       ', ''9999999999999999999999999999999.999999'')';
907 
908                 temp := 'qltdate.any_to_number(qr.' || fk.result_column_name || ')';
909 
910             ELSIF fk.datatype = 3 THEN
911                 temp := 'to_date(qr.' || fk.result_column_name ||
912                       ', ''YYYY/MM/DD'')';
913            --
914            -- Bug 3179845. Added to include datetime type in plan_view
915            -- saugupta Tue Oct 14 05:29:19 PDT 2003
916            --
917            ELSIF fk.datatype = 6  THEN
918                 temp := 'to_date(qr.' || fk.result_column_name ||
919                       ', ''YYYY/MM/DD HH24:MI:SS'')';
920             ELSE
921                 temp := 'qr.' || fk.result_column_name;
922             END IF;
923 
924             v_select := v_select || ', ' || temp || ' "' || fk.name || '"';
925         END IF;
926 
927     END LOOP;
928 
929     -- create a dynamic call to do_ddl for either the 10.6 or 10.7 api
930     -- bug 6350575
931     -- 12.1 QWB Usability Improvements Project
932     -- Adding the status clause to the plan view
933     -- The Deref view does not contain the status
934     -- where clause
935     --
936     v_deref_view_where := v_where;
937     v_where :=  v_where || ' AND (qr.status IS NULL OR qr.status = 2)';
938 
939     --
940     -- bug 6350575
941     -- 12.1 QWB Usability Improvements
942     -- Appending the create clause to the Plan view
943     --
944     v_final := v_plan_view_create || v_select || v_from || v_where;
945 
946     --
947     -- bug 6350575
948     -- 12.1 QWB Usability Improvements
949     -- Building the final query for the deref view
950     --
951     v_deref_view_final := v_deref_view_create || v_select || v_from || v_deref_view_where;
952 
953     ad_ddl.do_ddl(g_schema, 'QA', ad_ddl.create_view, v_final,
954         x_view_name);
955 
956     --
957     -- bug 6350575
958     -- 12.1 QWB Usability Improvements
959     -- Creating the deref view
960     --
961     ad_ddl.do_ddl(g_schema, 'QA', ad_ddl.create_view, v_deref_view_final,
962         v_deref_view_name);
963 
964     --
965     -- bug 6350575
966     -- 12.1 QWB Usability Improvements
967     -- Updating the deref view name in the qa_plans table
968     --
969     UPDATE qa_plans set deref_view_name = v_deref_view_name
970       WHERE plan_id = x_plan_id;
971 
972     --
973     -- bug 7409976
974     -- Regranting the privileges on the plan view and
975     -- deref view
976     -- ntungare
977     --
978     FOR Cntr in 1..x_pv_grants_tab.COUNT
979        LOOP
980           EXECUTE IMMEDIATE x_pv_grants_tab(cntr);
981        END LOOP; -- End of loop for plan view
982 
983     FOR Cntr in 1..x_dv_grants_tab.COUNT
984        LOOP
985           EXECUTE IMMEDIATE x_dv_grants_tab(cntr);
986        END LOOP; -- End of loop for deref view
987 END plan_view;
988 
989 
990 PROCEDURE import_plan_view(x_view_name IN VARCHAR2, x_old_view_name IN VARCHAR2,
991     x_plan_id IN NUMBER) IS
992 --
993 -- import view creation for QA_RESULTS_INTERFACE and collection import
994 --
995 
996     v_select VARCHAR2(20000);
997 
998     --
999     -- See comments in global_view about translate()
1000     --
1001     CURSOR pcursor is
1002         SELECT   qpc.result_column_name,
1003                  upper(translate(qc.name,' ''*{}','_____')) name,
1004                  qc.hardcoded_column,
1005                  qc.developer_name
1006         FROM     qa_plan_chars qpc, qa_chars qc
1007         WHERE    qpc.char_id = qc.char_id AND qpc.plan_id = x_plan_id
1008         ORDER BY prompt_sequence;
1009 
1010     --
1011     -- bug 7409976
1012     -- ntungare
1013     --
1014     x_grants_tab  grants_tab_typ;
1015 BEGIN
1016 
1017     --
1018     -- When QLTPLMDF deletes a plan, it calls this proc with
1019     -- null x_view_name and with x_old_view_name populated.
1020     -- Need to drop the old view name and return.
1021     --
1022     IF x_old_view_name IS NOT NULL THEN
1023         --
1024         -- bug 7409976
1025         -- Getting a list of all the grants on the view
1026         -- before dropping it
1027         -- ntungare
1028         --
1029         create_grant_sql(p_view_name  => x_old_view_name,
1030                          x_grants_tab => x_grants_tab);
1031 
1032         drop_view(x_old_view_name);
1033     END IF;
1034 
1035     IF x_view_name IS NULL THEN
1036         RETURN;
1037     END IF;
1038 
1039     --
1040     -- R12 Project MOAC 4637896
1041     -- Added operating_unit and operating_unit_id as columns in an
1042     -- import view.  These are now needed because according to MOAC
1043     -- PO Number is no longer unique across OUs.  Thus user has to
1044     -- specify OU name in order to resolve PO Number uniquely in
1045     -- the worst case.
1046     -- bso Sun Oct  2 11:41:00 PDT 2005
1047     --
1048     v_select := 'CREATE OR REPLACE FORCE VIEW "' || upper(x_view_name) ||
1049       '" AS SELECT
1050         transaction_interface_id,
1051         qa_last_updated_by_name,
1052         qa_created_by_name,
1053         collection_id,
1054         source_code,
1055         source_line_id,
1056         process_status,
1057         organization_code,
1058         operating_unit_id,
1059         operating_unit,
1060         plan_name,
1061         insert_type,
1062         matching_elements,
1063         spec_name';
1064 
1065     FOR prec in pcursor LOOP
1066 
1067     -- If the column is hardcoded column access the developer name and leave
1068     -- the developer name as the actual name for it in the view
1069     -- Otherwise, use the result column name to get the correct column but
1070     -- use the characteristic name as the column name in the view.
1071 
1072         --
1073         -- Added the following IF condition for ASO project
1074         -- To uniquely identify a Maintenance_Requirement it takes
1075         -- two fields, namely, Title and Version_Number.
1076         -- rkunchal Thu Jul 25 01:43:48 PDT 2002
1077         --
1078 
1079         IF prec.developer_name = 'MAINTENANCE_REQUIREMENT' THEN
1080            v_select := v_select || ', VERSION_NUMBER';
1081         END IF;
1082 
1083         IF prec.hardcoded_column IS NOT NULL THEN
1084            v_select := v_select || ', ' || prec.developer_name;
1085         ELSE
1086 
1087            -- originally we were going to change the datatype to number or
1088            -- date here if that was the datatype of the element.  when we
1089            -- did this, however, it was no longer possible to insert into
1090            -- this column of the view (it became a virtual column).
1091 
1092            v_select := v_select || ', ' || prec.result_column_name ||
1093                ' "' || prec.name || '"';
1094         END IF;
1095     END LOOP;
1096 
1097     v_select := v_select || ' FROM QA_RESULTS_INTERFACE';
1098 
1099     ad_ddl.do_ddl(g_schema, 'QA', ad_ddl.create_view, v_select,
1100         x_view_name);
1101 
1102     --
1103     -- bug 7409976
1104     -- Regranting the privileges
1105     -- ntungare
1106     --
1107     FOR Cntr in 1..x_grants_tab.COUNT
1108        LOOP
1109           EXECUTE IMMEDIATE x_grants_tab(cntr);
1110        END LOOP;
1111 END import_plan_view;
1112 
1113 BEGIN
1114 
1115     g_dummy := fnd_installation.get_app_info(g_fnd, g_status,
1116         g_industry, g_schema);
1117 
1118 END  QLTVCREB ;