DBA Data[Home] [Help]

PACKAGE BODY: APPS.FND_FLEX_SERVER1

Source


1 PACKAGE BODY fnd_flex_server1 AS
2 /* $Header: AFFFSV1B.pls 120.22.12010000.2 2008/08/11 17:47:58 hgeorgi ship $ */
3 
4 --------
5 -- PRIVATE TYPES
6 --
7 --
8 --  Segment array is 1-based containing entries for i <= i <= nsegs
9 
10 TYPE SqlStringArray IS TABLE OF VARCHAR2(10000) INDEX BY BINARY_INTEGER;
11 TYPE VsNameArray IS TABLE OF VARCHAR2(60) INDEX BY BINARY_INTEGER;
12 TYPE SegNameArray IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;
13 
14 -- Stored value is value stored in the database.
15 -- Displayed value is value displayed to the user.  This depends on the
16 -- users NLS parameters at runtime.
17 --
18 TYPE FlexValue IS RECORD
19    (displayed_value        VARCHAR2(1000),
20     stored_value           VARCHAR2(1000),
21     hidden_id              VARCHAR2(1000),
22     description            VARCHAR2(1000),
23     format                 VARCHAR2(4),
24     compiled_attributes    VARCHAR2(2000),
25     summary_flag           VARCHAR2(1),
26     enabled_flag           VARCHAR2(1),
27     start_valid            DATE,
28     end_valid              DATE);
29 
30 TYPE SegmentInfo IS RECORD
31    (segname                   fnd_id_flex_segments.segment_name%TYPE,
32     colname                   fnd_id_flex_segments.application_column_name%TYPE,
33     coltype                   fnd_columns.column_type%TYPE,
34     collen                    fnd_columns.width%TYPE,
35     required                  fnd_id_flex_segments.required_flag%TYPE,
36     segsecure                 fnd_id_flex_segments.security_enabled_flag%TYPE,
37     catdesclen                fnd_id_flex_segments.concatenation_description_len%TYPE,
38     dflt_type                 fnd_id_flex_segments.default_type%TYPE,
39     dflt_val                  fnd_id_flex_segments.default_value%TYPE,
40     vsid                      fnd_id_flex_segments.flex_value_set_id%TYPE,
41     runtime_property_function fnd_id_flex_segments.runtime_property_function%TYPE,
42     additional_where_clause   fnd_id_flex_segments.additional_where_clause%TYPE);
43 
44 TYPE ValueSetInfo IS RECORD
45     (vsid           fnd_flex_value_sets.flex_value_set_id%TYPE,
46      parent_vsid    fnd_flex_value_sets.parent_flex_value_set_id%TYPE,
47      valsecure      fnd_flex_value_sets.security_enabled_flag%TYPE,
48      valtype        fnd_flex_value_sets.validation_type%TYPE,
49      vsformat       fnd_flex_value_sets.format_type%TYPE,
50      maxsize        fnd_flex_value_sets.maximum_size%TYPE,
51      lettersok      fnd_flex_value_sets.alphanumeric_allowed_flag%TYPE,
52      capsonly       fnd_flex_value_sets.uppercase_only_flag%TYPE,
53      zfill          fnd_flex_value_sets.numeric_mode_enabled_flag%TYPE,
54      precis         fnd_flex_value_sets.number_precision%TYPE,
55      minval         fnd_flex_value_sets.minimum_value%TYPE,
56      maxval         fnd_flex_value_sets.maximum_value%TYPE,
57      vsname         fnd_flex_value_sets.flex_value_set_name%TYPE);
58 
59 ------------
60 -- PRIVATE CONSTANTS
61 
62 --
63 -- Character-set independent NEWLINE, TAB and WHITESPACE
64 --
65 NEWLINE     VARCHAR2(4);
66 TAB         VARCHAR2(4);
67 WHITESPACE  VARCHAR2(12);
68 
69 DATE_STORAGE_FMT      CONSTANT VARCHAR2(21) := 'YYYY/MM/DD HH24:MI:SS';
70 TIME_STORAGE_FMT      CONSTANT VARCHAR2(10) := 'HH24:MI:SS';
71 TIME_DISPLAY_FMT      CONSTANT VARCHAR2(10) := 'HH24:MI:SS';
72 FLEX_DELIMITER_ESCAPE CONSTANT VARCHAR2(1) := '\';
73 
74 -- Characters allowed in segment, value set profile and :block.field names
75 -- for interpreting $FLEX$, $PROFILE$, and :BLOCK.FIELD references
76 --
77 FLEX_BIND_CHARS       CONSTANT VARCHAR2(150) := 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$#.:';
78 
79 
80 --
81 -- SQL String Parser: Constants
82 --
83 SSP_QUOTE      constant varchar2(1)   := '''';
84 SSP_QUOTE2     constant varchar2(2)   := SSP_QUOTE || SSP_QUOTE;
85 SSP_COLON      constant varchar2(1)   := ':';
86 SSP_BIND_CHARS constant varchar2(150) := FLEX_BIND_CHARS;
87 
88 --
89 -- SQL String Parser: Piece Types
90 --
91 SSP_PIECE_TYPE_QUOTED    constant varchar2(1) := 'Q';
92 SSP_PIECE_TYPE_BIND      constant varchar2(1) := 'B';
93 SSP_PIECE_TYPE_SQL       constant varchar2(1) := 'S';
94 
95 TYPE sql_piece_rec_type IS RECORD
96   (piece_type varchar2(1),
97    piece_text varchar2(32000),
98 
99    bind_value varchar2(32000));
100 
101 TYPE sql_pieces_tab_type IS TABLE OF
102   sql_piece_rec_type INDEX BY binary_integer;
103 
104 security_begin CONSTANT VARCHAR2(180) :=
105   'select M.ERROR_MESSAGE ' ||
106   '  from FND_FLEX_VALUE_RULE_USAGES U, FND_FLEX_VALUE_RULES_VL M ' ||
107   ' where U.FLEX_VALUE_RULE_ID = M.FLEX_VALUE_RULE_ID ';
108 
109 security_mid CONSTANT VARCHAR2(180) :=
110   'exists (select null ' ||
111   '          from FND_FLEX_VALUE_RULE_LINES L ' ||
112   '         where 1 = 1 ';
113 
114 security_end CONSTANT VARCHAR2(180) :=
115   'and L.FLEX_VALUE_RULE_ID = U.FLEX_VALUE_RULE_ID ' ||
116   'and L.INCLUDE_EXCLUDE_INDICATOR = ';
117 
118 
119 -------------
120 -- GLOBAL VARIABLES
121 --
122 chr_newline VARCHAR2(8);
123 
124 n_sqlstrings  BINARY_INTEGER;
125 sqlstrings    SqlStringArray;
126 
127 -- Canonical, Display, and Database decimal separators.
128 tmp_varchar2 VARCHAR2(1000);
129 m_nc         VARCHAR2(1);
130 m_nd         VARCHAR2(1);
131 m_nb         VARCHAR2(1);
132 
133 --  Debugging information
134 TYPE debug_array_type IS TABLE OF VARCHAR2(1500)
135   INDEX BY BINARY_INTEGER;
136 
137 MAX_RETSTR_LEN      CONSTANT NUMBER := 1500;
138 g_debug_array       debug_array_type;
139 g_debug_array_size  NUMBER := 0;
140 g_debug_text        VARCHAR2(2000);
141 
142 -- Error message information for value error message handling.
143 -- Value errors are generated by incorrect user input.
144 -- Only set first value error message in FND_MESSAGE
145 -- All other error messages override value errors.
146 value_error_set       BOOLEAN;
147 entering_new_message  BOOLEAN;
148 
149 /* -------------------------------------------------------------------- */
150 /*               Private definitions for value validation               */
151 /* -------------------------------------------------------------------- */
152 
153 FUNCTION string_clause(char_string IN VARCHAR2) RETURN VARCHAR2;
154 
155 FUNCTION validate_seg(seg_in          IN      VARCHAR2,
156                       displayed       IN      BOOLEAN,
157                       kseg            IN      SegmentInfo,
158                       vsinf           IN      ValueSetInfo,
159                       vflags          IN      ValueValidationFlags,
160                       fstruct         IN      FlexStructId,
161                       v_date          IN      DATE,
162                       v_ruls          IN      Vrules,
163                       uappid          IN      NUMBER,
164                       respid          IN      NUMBER,
165                       nprev           IN      NUMBER,
166                       prev_dispvals   IN      ValueArray,
167                       prev_vals       IN      ValueArray,
168                       prev_ids        IN      ValueIdArray,
169                       prev_descs      IN      ValueDescArray,
170                       prev_vsids      IN      NumberArray,
171                       prev_segnames   IN      SegNameArray,
172                       prev_vsnames    IN      VsNameArray,
173                       x_flexvalue     OUT     nocopy FlexValue,
174                       squals          OUT     nocopy Qualifiers) RETURN VARCHAR2;
175 
176 FUNCTION coerce_format(user_value IN     VARCHAR2,
177                        p_is_displayed IN BOOLEAN,
178                        vs_format  IN     VARCHAR2,
179                        vs_name    IN     VARCHAR2,
180                        max_length IN     NUMBER,
181                        letters_ok IN     VARCHAR2,
182                        caps_only  IN     VARCHAR2,
183                        zero_fill  IN     VARCHAR2,
184                        precision  IN     VARCHAR2,
185                        min_value  IN     VARCHAR2,
186                        max_value  IN     VARCHAR2,
187                        x_storage_value OUT nocopy VARCHAR2,
188                        x_display_value OUT nocopy VARCHAR2) RETURN VARCHAR2;
189 
190 FUNCTION find_value(p_str_info          IN  FlexStructId,
191                     p_seg_info          IN  SegmentInfo,
192                     p_vs_info           IN  ValueSetInfo,
193                     p_vdate             IN  DATE,
194                     p_char_val          IN  VARCHAR2,
195                     p_is_value          IN  BOOLEAN,
196                     p_orphans_ok        IN  BOOLEAN,
197                     p_this_segname      IN  VARCHAR2,
198                     p_n_prev            IN  NUMBER,
199                     p_prev_vsids        IN  NumberArray,
200                     p_prev_dispvals     IN  ValueArray,
201                     p_prev_vals         IN  ValueArray,
202                     p_prev_ids          IN  ValueIdArray,
203                     p_prev_descs        IN  ValueDescArray,
204                     p_prev_segnames     IN  SegNameArray,
205                     p_prev_vsnames      IN  VsNameArray,
206                     p_parent_val        IN  VARCHAR2,
207                     x_this_val_out      OUT nocopy FlexValue) RETURN VARCHAR2;
208 
209 FUNCTION table_validate(p_str_info            IN  FlexStructId,
210                         p_seg_info            IN  SegmentInfo,
211                         p_vs_info             IN  ValueSetInfo,
212                         p_vdate               IN  DATE,
213                         p_parent_value        IN  VARCHAR2,
214                         p_charval             IN  VARCHAR2,
215                         p_is_value            IN  BOOLEAN,
216                         p_nprev               IN  NUMBER,
217                         p_prev_dispvals       IN  ValueArray,
218                         p_prev_vals           IN  ValueArray,
219                         p_prev_ids            IN  ValueIdArray,
220                         p_prev_descs          IN  ValueDescArray,
221                         p_prev_segnames       IN  SegNameArray,
222                         p_prev_vsnames        IN  VsNameArray,
223                         x_check_valtab        OUT nocopy BOOLEAN,
224                         x_found_value         OUT nocopy FlexValue)
225   RETURN VARCHAR2;
226 
227  FUNCTION default_val(def_type        IN  VARCHAR2,
228                       def_text        IN  VARCHAR2,
229                       valset_fmt      IN  VARCHAR2,
230                       valset_len      IN  NUMBER,
231                       valset_precis   IN  NUMBER,
232                       valset_lettersok IN VARCHAR2,
233                       seg_name        IN  VARCHAR2,
234                       nprev           IN  NUMBER,
235                       prev_dispvals   IN  ValueArray,
236                       prev_vals       IN  ValueArray,
237                       prev_ids        IN  ValueIdArray,
238                       prev_descs      IN  ValueDescArray,
239                       prev_segnames   IN  SegNameArray,
240                       prev_vsnames    IN  VsNameArray,
241                       displayed_val   OUT nocopy VARCHAR2) RETURN VARCHAR2;
242 
243 PROCEDURE parse_sql_string(p_sql_string  in varchar2,
244                            px_sql_pieces in out nocopy sql_pieces_tab_type);
245 
246 FUNCTION substitute_flex_binds3(p_string_in     IN VARCHAR2,
247                                 p_nprev         IN NUMBER,
248                                 p_prev_dispvals IN ValueArray,
249                                 p_prev_vals     IN ValueArray,
250                                 p_prev_ids      IN ValueIdArray,
251                                 p_prev_descs    IN ValueDescArray,
252                                 p_prev_segnames IN SegNameArray,
253                                 p_prev_vsnames  IN VsNameArray,
254                                 px_sql_pieces   in out nocopy sql_pieces_tab_type)
255   RETURN VARCHAR2;
256 
257 FUNCTION substitute_flex_binds5(p_string_in     IN VARCHAR2,
258                                 p_str_info      IN FlexStructId,
259                                 p_seg_info      IN SegmentInfo,
260                                 p_vdate         IN DATE,
261                                 p_parent_value  IN VARCHAR2,
262                                 p_nprev         IN NUMBER,
263                                 p_prev_dispvals IN ValueArray,
264                                 p_prev_vals     IN ValueArray,
265                                 p_prev_ids      IN ValueIdArray,
266                                 p_prev_descs    IN ValueDescArray,
267                                 p_prev_segnames IN SegNameArray,
268                                 p_prev_vsnames  IN VsNameArray,
269                                 px_sql_pieces   in out nocopy sql_pieces_tab_type)
270   RETURN VARCHAR2;
271 
272 FUNCTION convert_bind_token(bind_token    IN  VARCHAR2,
273                             nprev         IN  NUMBER,
274                             prev_dispvals IN  ValueArray,
275                             prev_vals     IN  ValueArray,
276                             prev_ids      IN  ValueIdArray,
277                             prev_descs    IN  ValueDescArray,
278                             prev_segnames IN  SegNameArray,
279                             prev_vsnames  IN  VsNameArray,
280                             bind_value    OUT nocopy VARCHAR2) RETURN VARCHAR2;
281 
282 FUNCTION convert_bind_token2(p_bind_token    IN  VARCHAR2,
283                              p_str_info      IN  FlexStructId,
284                              p_seg_info      IN  SegmentInfo,
285                              p_vdate         IN  DATE,
286                              p_parent_value  IN  VARCHAR2,
287                              p_nprev         IN  NUMBER,
288                              p_prev_dispvals IN  ValueArray,
289                              p_prev_vals     IN  ValueArray,
290                              p_prev_ids      IN  ValueIdArray,
291                              p_prev_descs    IN  ValueDescArray,
292                              p_prev_segnames IN  SegNameArray,
293                              p_prev_vsnames  IN  VsNameArray,
294                              x_bind_value    OUT nocopy VARCHAR2) RETURN VARCHAR2;
295 
296 FUNCTION get_value_set(value_set_id   IN  NUMBER,
297                        segment_name   IN  VARCHAR2,
298                        vs_info        OUT nocopy ValueSetInfo) RETURN BOOLEAN;
299 
300 FUNCTION virtual_value_set(column_type  IN  VARCHAR2,
301                            column_width IN  NUMBER,
302                            segment_name IN  VARCHAR2,
303                            vs_info      OUT nocopy ValueSetInfo) RETURN BOOLEAN;
304 
305 FUNCTION get_qualifiers(ffstruct      IN  FlexStructId,
306                         seg_colname   IN  VARCHAR2,
307                         seg_quals     OUT nocopy Qualifiers) RETURN NUMBER;
308 
309 
310 FUNCTION qualifier_values(ffstruct       IN  FlexStructId,
311                           valset_id      IN  NUMBER,
312                           cvas           IN  VARCHAR2,
313                           nqualifs       IN  NUMBER,
314                           fqnames        IN  QualNameArray,
315                           sqnames        IN  QualNameArray,
316                           sqvals         IN OUT nocopy ValAttribArray) RETURN NUMBER;
317 
318 FUNCTION derive_values(new_dvals      IN      DerivedVals,
319                        new_quals      IN      Qualifiers,
320                        drv_dvals      IN OUT  nocopy DerivedVals,
321                        drv_quals      IN OUT  nocopy Qualifiers) RETURN BOOLEAN;
322 
323 FUNCTION check_security(val          IN VARCHAR2,
324                         valfmt       IN VARCHAR2,
325                         parentval    IN VARCHAR2,
326                         user_apid    IN NUMBER,
327                         user_respid  IN NUMBER,
328                         vsinfo       IN ValueSetInfo,
329                         set_message  IN BOOLEAN) RETURN VARCHAR2;
333                       sumflg  IN VARCHAR2) RETURN VARCHAR2;
330 
331 FUNCTION check_vrules(vrs     IN Vrules,
332                       sqs     IN Qualifiers,
334 
335 FUNCTION check_displayed(segindex     IN  NUMBER,
336                          disp_tokmap  IN  DisplayedSegs,
337                          d_flag       OUT nocopy BOOLEAN) RETURN BOOLEAN;
338 
339 PROCEDURE value_error_init;
340 
341 PROCEDURE value_error_name(appl_sname      IN  VARCHAR2,
342                            errmsg_name     IN  VARCHAR2);
343 
344 PROCEDURE value_error_token(token_name   IN  VARCHAR2,
345                             token_value  IN  VARCHAR2);
346 
347 FUNCTION msg_val(valset_fmt  IN  VARCHAR2,
348                  valset_len  IN  NUMBER,
349                  valset_prec IN  NUMBER,
350                  valset_lettersok IN VARCHAR2,
351                  stored_val  IN  VARCHAR2) RETURN VARCHAR2;
352 
353 FUNCTION stored_to_displayed(valset_fmt  IN  VARCHAR2,
354                              valset_len  IN  NUMBER,
355                              valset_prec IN  NUMBER,
356                              valset_lettersok IN VARCHAR2,
357                              stored_val  IN  VARCHAR2,
358                              disp_val    OUT nocopy VARCHAR2) RETURN VARCHAR2;
359 
360 FUNCTION isa_stored_date(teststr IN VARCHAR2,
361                          flexfmt IN VARCHAR2,
362                          outdate OUT nocopy DATE) RETURN BOOLEAN;
363 
364 FUNCTION isa_displayed_date(teststr IN VARCHAR2,
365                             flexfmt IN VARCHAR2,
366                             outdate OUT nocopy DATE) RETURN BOOLEAN;
367 
368 FUNCTION isa_date(teststr IN VARCHAR2,
369                   datefmt IN VARCHAR2,
370                   outdate OUT nocopy DATE) RETURN BOOLEAN;
371 
372 FUNCTION displayed_date_format(flex_data_type IN VARCHAR2,
373                                string_length  IN NUMBER) RETURN VARCHAR2;
374 
375 -- ======================================================================
376 -- Caching.
377 -- ======================================================================
378 g_cache_return_code   VARCHAR2(30);
379 g_cache_key           VARCHAR2(2000);
380 g_cache_value         fnd_plsql_cache.generic_cache_value_type;
381 g_cache_values        fnd_plsql_cache.generic_cache_values_type;
382 g_cache_indexes       fnd_plsql_cache.custom_cache_indexes_type;
383 g_cache_numof_indexes NUMBER;
384 g_cache_numof_values  NUMBER;
385 
386 -- ======================================================================
387 -- Value Set Cache : VST
388 --
389 -- PK: <flex_value_set_id>
390 --
391 -- ======================================================================
392 vst_cache_controller      fnd_plsql_cache.cache_1to1_controller_type;
393 vst_cache_storage         fnd_plsql_cache.generic_cache_values_type;
394 
395 -- ======================================================================
396 -- Value Security Cache : VSC
397 --
398 -- PK: <application_id> || NEWLINE || <responsibility_id> || NEWLINE ||
399 --     <value_set_id>   || NEWLINE || <parent_value> || NEWLINE ||
400 --     <value>
401 --
402 -- ======================================================================
403 vsc_cache_controller      fnd_plsql_cache.cache_1to1_controller_type;
404 vsc_cache_storage         fnd_plsql_cache.generic_cache_values_type;
405 
406 -- ======================================================================
407 -- Flex Value Cache : FVC
408 --
409 -- PK: <value_set_id> || NEWLINE || <parent_value> || NEWLINE || <value>
410 --
411 -- ======================================================================
412 fvc_cache_controller      fnd_plsql_cache.cache_1to1_controller_type;
413 fvc_cache_storage         fnd_plsql_cache.generic_cache_values_type;
414 
415 -- ======================================================================
416 -- Flex Segment Qualifiers Cache : FSQ
417 --
418 -- PK: <application_id> || NEWLINE || <id_flex_code> || NEWLINE ||
419 --     <id_flex_num> || NEWLINE || <application_column_name>
420 --
421 -- ======================================================================
422 fsq_cache_controller      fnd_plsql_cache.cache_1tom_controller_type;
423 fsq_cache_storage         fnd_plsql_cache.generic_cache_values_type;
424 
425 -- ======================================================================
426 -- Value Set Qualifiers Cache : VSQ
427 --
428 -- PK: <flex_value_set_id>
429 --
430 -- ======================================================================
431 vsq_cache_controller      fnd_plsql_cache.cache_1tom_controller_type;
432 vsq_cache_storage         fnd_plsql_cache.generic_cache_values_type;
433 
434 -- ======================================================================
435 -- Validate Structue Segments Cache : str
436 -- ======================================================================
437 TYPE str_cache_storage_type IS TABLE OF segmentinfo
438   INDEX BY BINARY_INTEGER;
439 
440 str_cache_controller      fnd_plsql_cache.cache_1tom_controller_type;
441 str_cache_storage         str_cache_storage_type;
442 
443 -- ======================================================================
444 -- Local Cache Functions
445 -- ======================================================================
446 FUNCTION check_vsc(p_application_id    IN NUMBER,
450                    p_value             IN VARCHAR2,
447                    p_responsibility_id IN NUMBER,
448                    p_value_set_id      IN NUMBER,
449                    p_parent_value      IN VARCHAR2,
451                    px_error_code       IN OUT nocopy VARCHAR2)
452   RETURN VARCHAR2
453   IS
454 BEGIN
455    --
456    -- seperate p_parent_value and p_value to get rid of ambiguity.
457    --
458    g_cache_key := (p_parent_value || '.' ||
459                    p_application_id || '.' ||
460                    p_responsibility_id || '.' ||
461                    p_value_set_id || '.' ||
462                    p_value);
463 
464    fnd_plsql_cache.generic_1to1_get_value(vsc_cache_controller,
465                                           vsc_cache_storage,
466                                           g_cache_key,
467                                           g_cache_value,
468                                           g_cache_return_code);
469 
470    IF (g_cache_return_code = fnd_plsql_cache.CACHE_FOUND) THEN
471       px_error_code := g_cache_value.varchar2_1;
472       IF (px_error_code = FF_VVALID) THEN
473          RETURN(fnd_plsql_cache.CACHE_VALID);
474        ELSE
475          fnd_message.set_encoded(g_cache_value.varchar2_2);
476          RETURN(fnd_plsql_cache.CACHE_INVALID);
477       END IF;
478     ELSE
479       RETURN(g_cache_return_code);
480    END IF;
481 EXCEPTION
482    WHEN OTHERS THEN
483       RETURN(fnd_plsql_cache.CACHE_NOTFOUND);
484 END check_vsc;
485 
486 PROCEDURE update_vsc(p_application_id    IN NUMBER,
487                      p_responsibility_id IN NUMBER,
488                      p_value_set_id      IN NUMBER,
489                      p_parent_value      IN VARCHAR2,
490                      p_value             IN VARCHAR2,
491                      p_error_code        IN VARCHAR2)
492   IS
493      l_enc_err_msg VARCHAR2(2000) := NULL;
494 BEGIN
495    --
496    -- seperate p_parent_value and p_value to get rid of ambiguity.
497    --
498    g_cache_key := (p_parent_value || '.' ||
499                    p_application_id || '.' ||
500                    p_responsibility_id || '.' ||
501                    p_value_set_id || '.' ||
502                    p_value);
503 
504    IF (p_error_code <> FF_VVALID) THEN
505       l_enc_err_msg := fnd_message.get_encoded;
506       fnd_message.set_encoded(l_enc_err_msg);
507    END IF;
508 
509    fnd_plsql_cache.generic_cache_new_value
510      (x_value      => g_cache_value,
511       p_varchar2_1 => p_error_code,
512       p_varchar2_2 => l_enc_err_msg);
513 
514    fnd_plsql_cache.generic_1to1_put_value(vsc_cache_controller,
515                                           vsc_cache_storage,
516                                           g_cache_key,
517                                           g_cache_value);
518 EXCEPTION
519    WHEN OTHERS THEN
520       RETURN;
521 END update_vsc;
522 
523 -- ----------------------------------------------------------------------
524 FUNCTION check_fvc(p_value_set_id      IN NUMBER,
525                    p_parent_value      IN VARCHAR2,
526                    p_value             IN VARCHAR2,
527                    px_flexvalue        IN OUT nocopy flexvalue)
528 
529   RETURN VARCHAR2
530   IS
531 BEGIN
532    --
533    -- seperate p_parent_value and p_value to get rid of ambiguity.
534    --
535    g_cache_key := (p_parent_value || '.' ||
536                    p_value_set_id || '.' ||
537                    p_value);
538 
539    fnd_plsql_cache.generic_1to1_get_value(fvc_cache_controller,
540                                           fvc_cache_storage,
541                                           g_cache_key,
542                                           g_cache_value,
543                                           g_cache_return_code);
544 
545    IF (g_cache_return_code = fnd_plsql_cache.CACHE_FOUND) THEN
546       px_flexvalue.displayed_value     := g_cache_value.varchar2_1;
547       px_flexvalue.stored_value        := g_cache_value.varchar2_2;
548       px_flexvalue.hidden_id           := g_cache_value.varchar2_3;
549       px_flexvalue.description         := g_cache_value.varchar2_4;
550       px_flexvalue.format              := g_cache_value.varchar2_5;
551       px_flexvalue.compiled_attributes := g_cache_value.varchar2_6;
552       px_flexvalue.summary_flag        := g_cache_value.varchar2_7;
553       px_flexvalue.enabled_flag        := g_cache_value.varchar2_8;
554       px_flexvalue.start_valid         := g_cache_value.date_1;
555       px_flexvalue.end_valid           := g_cache_value.date_2;
556    END IF;
557    RETURN(g_cache_return_code);
558 EXCEPTION
559    WHEN OTHERS THEN
560       RETURN(fnd_plsql_cache.CACHE_NOTFOUND);
561 END check_fvc;
562 
563 PROCEDURE update_fvc(p_value_set_id    IN NUMBER,
564                      p_parent_value    IN VARCHAR2,
565                      p_value           IN VARCHAR2,
566                      p_flexvalue       IN flexvalue)
567   IS
568 BEGIN
569    --
570    -- seperate p_parent_value and p_value to get rid of ambiguity.
571    --
572    g_cache_key := (p_parent_value || '.' ||
573                    p_value_set_id || '.' ||
574                    p_value);
575 
576    fnd_plsql_cache.generic_cache_new_value
580       p_varchar2_3  => p_flexvalue.hidden_id,
577      (x_value       => g_cache_value,
578       p_varchar2_1  => p_flexvalue.displayed_value,
579       p_varchar2_2  => p_flexvalue.stored_value,
581       p_varchar2_4  => p_flexvalue.description,
582       p_varchar2_5  => p_flexvalue.format,
583       p_varchar2_6  => p_flexvalue.compiled_attributes,
584       p_varchar2_7  => p_flexvalue.summary_flag,
585       p_varchar2_8  => p_flexvalue.enabled_flag,
586       p_date_1      => p_flexvalue.start_valid,
587       p_date_2      => p_flexvalue.end_valid);
588 
589    fnd_plsql_cache.generic_1to1_put_value(fvc_cache_controller,
590                                           fvc_cache_storage,
591                                           g_cache_key,
592                                           g_cache_value);
593 EXCEPTION
594    WHEN OTHERS THEN
595       RETURN;
596 END update_fvc;
597 
598 /* ----------------------------------------------------------------------- */
599 /*      Checks each segment input to see if it is secured against the      */
600 /*      current user.  Returns index of first secured segment or 0 if      */
601 /*      no segments are secured or < 0 if error.                           */
602 /*      Segment index does not take displayed flag into account.           */
603 /*      Does not look up the values.  Stops at first secured value.        */
604 /*      Sets error message if security violated or on error.               */
605 /*      Uses only the non-coerced values in the segments field.            */
606 /*      Do not worry about orphans for dependent values.                   */
607 /* ----------------------------------------------------------------------- */
608 FUNCTION vals_secured(fstruct IN  FlexStructId,
609                       nsegs   IN  NUMBER,
610                       segs    IN  StringArray,
611                       displ   IN  DisplayedSegs,
612                       uappid  IN  NUMBER,
613                       respid  IN  NUMBER)
614   RETURN NUMBER
615   IS
616      segcounter          BINARY_INTEGER;
617      dispsegcounter      BINARY_INTEGER;
618      seg_displayed       BOOLEAN;
619      thisval             VARCHAR2(1000);
620      parentval           VARCHAR2(60);
621      parentindex         BINARY_INTEGER;
622      prior_vals          ValueArray;
623      prior_vsids         NumberArray;
624      segname             VARCHAR2(30);
625      segvsid             NUMBER;
626      segsecure           VARCHAR2(1);
627      vsinfo              ValueSetInfo;
628      l_return_code       NUMBER;
629 
630      CURSOR KeySegC(keystruct in FlexStructId) IS
631         SELECT segment_name, flex_value_set_id, security_enabled_flag
632           FROM fnd_id_flex_segments
633           WHERE application_id = keystruct.application_id
634           AND id_flex_code = keystruct.id_flex_code
635           AND id_flex_num = keystruct.id_flex_num
636           AND enabled_flag = 'Y'
637           ORDER BY segment_num;
638 
639      CURSOR DescSegC(descstruct in FlexStructId) IS
640         SELECT end_user_column_name, flex_value_set_id, security_enabled_flag
641           FROM fnd_descr_flex_column_usages
642           WHERE application_id = descstruct.application_id
643           AND descriptive_flexfield_name = descstruct.desc_flex_name
644           AND descriptive_flex_context_code = descstruct.desc_flex_context
645           AND enabled_flag = 'Y'
646           ORDER BY column_seq_num;
647 
648 BEGIN
649    IF (fnd_flex_server1.g_debug_level > 0) THEN
650       add_debug('BEGIN SV1.vals_secured()');
651    END IF;
652   segcounter := 0;
653   dispsegcounter := 0;
654   value_error_init;
655 
656   if(fstruct.isa_key_flexfield) then
657     open KeySegC(fstruct);
658   else
659     open DescSegC(fstruct);
660   end if;
661 
662 --  Begin main loop
663 
664   loop
665 
666     if(fstruct.isa_key_flexfield) then
667       fetch KeySegC into segname, segvsid, segsecure;
668       exit when (KeySegC%NOTFOUND or (KeySegC%NOTFOUND is null));
669     else
670       fetch DescSegC into segname, segvsid, segsecure;
671       exit when (DescSegC%NOTFOUND or (DescSegC%NOTFOUND is null));
672     end if;
673 
674     segcounter := segcounter + 1;
675 
676 --  Exit with error if exception occurred during check.
677 --
678     if(check_displayed(segcounter, displ, seg_displayed) = FALSE) THEN
679        l_return_code := -6;
680        GOTO goto_return;
681     end if;
682 
683 --  Just ignore non-displayed segments.
684 --
685     if(seg_displayed) then
686       dispsegcounter := dispsegcounter + 1;
687     else
688        IF (fnd_flex_server1.g_debug_level > 0) THEN
689           add_debug('Segment ' || to_char(segcounter) || ' not displayed ');
690        END IF;
691       thisval := NULL;
692       goto next_value;
693     end if;
694 
695 --  Treat remaining segments as NULL and quit if too few segments entered.
696 --
697     if(dispsegcounter > nsegs) then
698        IF (fnd_flex_server1.g_debug_level > 0) THEN
699           add_debug('No more values-exiting. ');
700        END IF;
701        l_return_code := 0;
702        GOTO goto_return;
703     end if;
704 
705 --  Initialize value.  Strip spaces.
706 --
707     thisval := RTRIM(LTRIM(segs(dispsegcounter)));
708 
712 
709     IF (fnd_flex_server1.g_debug_level > 0) THEN
710        add_debug('(' || thisval || ') ');
711     END IF;
713 --  If null, its not secured.
714 --
715     if(thisval is null) then
716       goto next_value;
717     end if;
718 
719 --  Get value set info.  If no value set, then it's not secured.
720 --
721     if(segvsid is null) then
722       goto next_value;
723     else
724        if(get_value_set(segvsid, segname, vsinfo) <> TRUE) THEN
725           l_return_code := -7;
726           GOTO goto_return;
727        end if;
728     end if;
729 
730     parentval := NULL;
731 
732 -- If dependent value set find parent value.
733 -- Orphans do not generate error, but lack of a parent value set does.
734 --
735     if(vsinfo.valtype = 'D') then
736       parentindex := 0;
737       for i in reverse 1..(segcounter - 1) loop
738         if((prior_vsids(i) is not null) and
739            (vsinfo.parent_vsid = prior_vsids(i))) then
740           parentindex := i;
741           parentval := prior_vals(i);
742           exit;
743         end if;
744       end loop;
745       if(parentindex = 0) then
746         FND_MESSAGE.set_name('FND', 'FLEX-NO PARENT SEGMENT');
747         FND_MESSAGE.set_token('CHILD', to_char(segcounter));
748           l_return_code := -3;
749           GOTO goto_return;
750       end if;
751     end if;
752 
753 -- Check security rules.  Stop if any value is secured.
754 --
755     if((vsinfo.valtype in ('I', 'D', 'F')) and
756        (vsinfo.valsecure in ('Y', 'H')) and (segsecure = 'Y')) then
757       if(check_security(thisval, vsinfo.vsformat, parentval,
758                         uappid, respid, vsinfo, TRUE) <> FF_VVALID) then
759          l_return_code := segcounter;
760          GOTO goto_return;
761       end if;
762     end if;
763 
764     <<next_value>>
765 
766 --  Record previous value set id's and values for parent value search
767 --  Add to table column, value_set_id, segment type, and seg_num arrays
768 --
769     prior_vsids(segcounter) := segvsid;
770     prior_vals(segcounter) := thisval;
771 
772   end loop;
773 
774 -- Close cursor.
775 --
776   if(fstruct.isa_key_flexfield) then
777     close KeySegC;
778   else
779     close DescSegC;
780   end if;
781 
782 --  Note error if no enabled segments for this flexfield.
783 --
784   if(fstruct.isa_key_flexfield and (segcounter <= 0)) then
785     FND_MESSAGE.set_name('FND', 'FLEX-CANT FIND SEGMENTS');
786     FND_MESSAGE.set_token('ROUTINE', 'Validate Values');
787     FND_MESSAGE.set_token('APPID', to_char(fstruct.application_id));
788     FND_MESSAGE.set_token('CODE', fstruct.id_flex_code);
789     FND_MESSAGE.set_token('NUM', to_char(fstruct.id_flex_num));
790     l_return_code := -1;
791     GOTO goto_return;
792   end if;
793 
794   l_return_code := 0;
795 
796   <<goto_return>>
797     IF (fnd_flex_server1.g_debug_level > 0) THEN
798        add_debug('END SV1.vals_secured()');
799     END IF;
800     return(l_return_code);
801 
802 EXCEPTION
803   WHEN NO_DATA_FOUND then
804      IF (fnd_flex_server1.g_debug_level > 0) THEN
805         add_debug('EXCEPTION no_data_found SV1.vals_secured()');
806      END IF;
807      if(fstruct.isa_key_flexfield) then
808         FND_MESSAGE.set_name('FND', 'FLEX-CANT FIND SEGMENTS');
809         FND_MESSAGE.set_token('ROUTINE', 'Validate Values');
810         FND_MESSAGE.set_token('APPID', to_char(fstruct.application_id));
811         FND_MESSAGE.set_token('CODE', fstruct.id_flex_code);
812         FND_MESSAGE.set_token('NUM', to_char(fstruct.id_flex_num));
813         return(-1);
814      end if;
815      return(0);
816   WHEN OTHERS then
817     FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
818     FND_MESSAGE.set_token('MSG', 'vals_secured() exception:  ' || SQLERRM);
819     IF (fnd_flex_server1.g_debug_level > 0) THEN
820        add_debug('EXCEPTION others SV1.vals_secured()');
821     END IF;
822     return(-2);
823 END vals_secured;
824 
825 /* ----------------------------------------------------------------------- */
826 /*      Performes independent, dependent, and table value validation.      */
827 /*      Returns value status number in priority order:                     */
828 /*              VV_VALID        If all values valid.  No errors at all.    */
829 /*              VV_SECURED      Only error is value security violation.    */
830 /*              VV_VALUES       A non-security value error was found.      */
831 /*              VV_UNSUPPORTED  Validation type not suppoted on server.    */
832 /*              VV_ERROR        Error worse than incorrect value entered.  */
833 /*                                                                         */
834 /*      Value validation affected by vflags.  See package spec. for        */
835 /*      description.  If no flags explicitly call for stopping validation  */
836 /*      this function tries to validate all segments even if there is an   */
837 /*      error and returns a message and the number of the first segment    */
838 /*      which caused the error.  If there is a value error in one segment  */
839 /*      and a subsequent segment has a more serious error, then the error  */
840 /*      segment number and message is that of the more serious error. See  */
844 /*      corresponds to the segment indicated.  The error segment number    */
841 /*      value_error_name() and token() for description.  This function     */
842 /*      carefully coordinates the setting of the error segment number with */
843 /*      the behavior of the value_error functions to ensure the message    */
845 /*      is the number of enabled segments with segment_num's <= the        */
846 /*      segment which caused the error.                                    */
847 /*                                                                         */
848 /*      If the validation flags indicate to not stop at value errors,      */
849 /*      then invalid segments will return with the displayed value set     */
850 /*      to the value the user typed in and the id and description null.    */
851 /*                                                                         */
852 /*      Returns the number of segment values and ids output.               */
853 /*                                                                         */
854 /*      Outputs several arrays of cached data on each segment:             */
855 /*        1) Column where to put segments in cross-validation table.       */
856 /*        2) Segment data types:  'C' = Char, 'N' = Number,                */
857 /*              'D' = Date "DD-MON-RR" or "DD-MON-YYYY" formats            */
858 /*              't' or 'I' = Time "HH24:MI" or "HH24:MI:SS" formats        */
859 /*              'T' = Date-Time in 'D' + space + 't' formats (4 in all)    */
860 /*        3) Numeric representation for numbers and date type data.        */
861 /*        4-6) Array of values, value_id's and value_meanings              */
862 /*        7) Compiled value attribute strings for each value.              */
863 /*        8) Individual segment value status codes in a char string        */
864 /*           where one character represents the status for each value.     */
865 /*                                                                         */
866 /*   Notes:     Checks format validation on ALL validation types.          */
867 /*              If format = "Numbers only" disallows non-numbers           */
868 /*                (present user exit allows any combination of             */
869 /*                 0-9, +, -, and . even if it is not a number             */
870 /* ----------------------------------------------------------------------- */
871 
872 FUNCTION validate_struct(fstruct      IN  FlexStructId,
873                          tbl_apid     IN  NUMBER,
874                          tbl_id       IN  NUMBER,
875                          nsegs_in     IN  NUMBER,
876                          segs         IN  StringArray,
877                          dispsegs     IN  DisplayedSegs,
878                          vflags       IN  ValueValidationFlags,
879                          v_date       IN  DATE,
880                          v_ruls       IN  Vrules,
881                          uappid       IN  NUMBER,
882                          respid       IN  NUMBER,
883                          nsegs_out    OUT nocopy NUMBER,
884                          segfmts      OUT nocopy SegFormats,
885                          segstats     OUT nocopy VARCHAR2,
886                          tabcols      OUT nocopy TabColArray,
887                          tabcoltypes  OUT nocopy CharArray,
888                          v_dispvals   OUT nocopy ValueArray,
889                          v_vals       OUT nocopy ValueArray,
890                          v_ids        OUT nocopy ValueIdArray,
891                          v_descs      OUT nocopy ValueDescArray,
892                          desc_lens    OUT nocopy NumberArray,
893                          dvals        OUT nocopy DerivedVals,
894                          dquals       OUT nocopy Qualifiers,
895                          errsegn      OUT nocopy NUMBER) RETURN NUMBER IS
896 
897   segcount            NUMBER;
898   dispsegcount        NUMBER;
899   errseg_num          NUMBER;
900   return_code         NUMBER;
901   isvalu              BOOLEAN;
902   seg_displayed       BOOLEAN;
903   secured_flag        BOOLEAN;
904   val_err_flag        BOOLEAN;
905   this_seg            VARCHAR2(1000);
906   segerrs             VARCHAR2(30);
907   v_status            VARCHAR2(1);
908   seg_quals           Qualifiers;
909   this_dval           DerivedVals;
910   drvd_quals          Qualifiers;
911   drvals              DerivedVals;
912   l_flexvalue         FlexValue;
913   prior_dispvals      ValueArray;
914   prior_vals          ValueArray;
915   prior_ids           ValueIdArray;
916   prior_descs         ValueDescArray;
917   prior_vsids         NumberArray;
918   prior_segnames      SegNameArray;
919   prior_vsnames       VsNameArray;
920   catdesc_lens        NumberArray;
921   seginfo             SegmentInfo;
922   l_str_cache_segs    str_cache_storage_type;
923   i                   NUMBER;
924   vsinfo              ValueSetInfo;
925 
926   CURSOR KeyC(keystruct in FlexStructId, t_apid in NUMBER, t_id in NUMBER) IS
927       SELECT  g.segment_name, g.application_column_name, c.column_type,
928               c.width, g.required_flag, g.security_enabled_flag,
929               g.concatenation_description_len,
930               g.default_type, g.default_value, g.flex_value_set_id,
931               g.runtime_property_function,
932               g.additional_where_clause
933        FROM fnd_id_flex_segments g, fnd_columns c
934       WHERE g.application_id = keystruct.application_id
935         AND g.id_flex_code = keystruct.id_flex_code
936         AND g.id_flex_num = keystruct.id_flex_num
940         AND c.column_name = g.application_column_name
937         AND g.enabled_flag = 'Y'
938         AND c.application_id = t_apid
939         AND c.table_id = t_id
941       ORDER BY g.segment_num;
942 
943   CURSOR DescC(descstruct in FlexStructId, t_apid in NUMBER, t_id in NUMBER)
944     IS SELECT g.end_user_column_name, g.application_column_name,
945               c.column_type, c.width, g.required_flag,
946               g.security_enabled_flag, g.concatenation_description_len,
947               g.default_type, g.default_value, g.flex_value_set_id,
948               g.runtime_property_function,
949               NULL
950        FROM fnd_descr_flex_column_usages g, fnd_columns c
951       WHERE g.application_id = descstruct.application_id
952         AND g.descriptive_flexfield_name = descstruct.desc_flex_name
953         AND g.descriptive_flex_context_code = descstruct.desc_flex_context
954         AND g.enabled_flag = 'Y'
955         AND c.application_id = t_apid
956         AND c.table_id = t_id
957         AND c.column_name = g.application_column_name
958       ORDER BY g.column_seq_num;
959 
960 BEGIN
961    IF (fnd_flex_server1.g_debug_level > 0) THEN
962       FND_FLEX_SERVER1.add_debug('BEGIN SV1.validate_struct() ');
963    END IF;
964 
965   value_error_init;
966   secured_flag := FALSE;
967   val_err_flag := FALSE;
968 
969 --  Initialize all returned values and all derived values with defaults
970 --
971   segcount := 0;
972   dispsegcount := 0;
973   nsegs_out := 0;
974   segfmts.nsegs := 0;
975   return_code := VV_ERROR;
976 
977   drvd_quals.nquals := 0;
978   dquals.nquals := 0;
979 
980   drvals.start_valid := NULL;
981   drvals.end_valid := NULL;
982   drvals.enabled_flag := 'Y';
983   drvals.summary_flag := 'N';
984   dvals := drvals;
985 
986   IF (fstruct.isa_key_flexfield) THEN
987      g_cache_key := ('KFF' || '.' ||
988                      fstruct.application_id || '.' ||
989                      fstruct.id_flex_code || '.' ||
990                      fstruct.id_flex_num || '.' ||
991                      tbl_apid || '.' ||
992                      tbl_id);
993    ELSE
994      g_cache_key := ('DFF' || '.' ||
995                      fstruct.application_id || '.' ||
996                      fstruct.desc_flex_name || '.' ||
997                      fstruct.desc_flex_context || '.' ||
998                      tbl_apid || '.' ||
999                      tbl_id);
1000   END IF;
1001 
1002   fnd_plsql_cache.custom_1tom_get_get_indexes(str_cache_controller,
1003                                               g_cache_key,
1004                                               g_cache_numof_indexes,
1005                                               g_cache_indexes,
1006                                               g_cache_return_code);
1007 
1008   IF (g_cache_return_code = fnd_plsql_cache.CACHE_FOUND) THEN
1009      --
1010      -- Copy cached values to local array.
1011      --
1012      FOR ii IN 1..g_cache_numof_indexes LOOP
1013         l_str_cache_segs(ii):= str_cache_storage(g_cache_indexes(ii));
1014      END LOOP;
1015    ELSE
1016      if(fstruct.isa_key_flexfield) THEN
1017         open KeyC(fstruct, tbl_apid, tbl_id);
1018       else
1019         open DescC(fstruct, tbl_apid, tbl_id);
1020      end if;
1021 
1022      i := 0;
1023      LOOP
1024         IF (fstruct.isa_key_flexfield) then
1025            FETCH KeyC INTO seginfo;
1026            EXIT WHEN (KeyC%NOTFOUND OR (KeyC%NOTFOUND is null));
1027          ELSE
1028            FETCH DescC INTO seginfo;
1029            EXIT WHEN (DescC%NOTFOUND OR (DescC%NOTFOUND is null));
1030         end if;
1031         i := i + 1;
1032 
1033         l_str_cache_segs(i) := seginfo;
1034      END LOOP;
1035      g_cache_numof_indexes := i;
1036 
1037      if(fstruct.isa_key_flexfield) THEN
1038         close keyc;
1039       else
1040         close descc;
1041      end if;
1042 
1043      fnd_plsql_cache.custom_1tom_get_put_indexes(str_cache_controller,
1044                                                  g_cache_key,
1045                                                  g_cache_numof_indexes,
1046                                                  g_cache_indexes,
1047                                                  g_cache_return_code);
1048      IF (g_cache_return_code = fnd_plsql_cache.CACHE_PUT_IS_SUCCESSFUL) THEN
1049         FOR ii IN 1..g_cache_numof_indexes LOOP
1050            str_cache_storage(g_cache_indexes(ii)) := l_str_cache_segs(ii);
1051         END LOOP;
1052      END IF;
1053   END IF;
1054 
1055   IF (fstruct.isa_key_flexfield) then
1056      IF (fnd_flex_server1.g_debug_level > 0) THEN
1057         add_debug('key segments: ');
1058      END IF;
1059    else
1060      IF (fnd_flex_server1.g_debug_level > 0) THEN
1061         add_debug('desc segments: ');
1062      END IF;
1063   end if;
1064 
1065   --
1066   --  Begin main loop
1067   --
1068   segcount := 0;
1069   WHILE (segcount < g_cache_numof_indexes) LOOP
1070      segcount := segcount + 1;
1071      seginfo := l_str_cache_segs(segcount);
1072 
1073      --
1074      --  Get value set information or make a virtual value set if vsid is null
1075      --
1076      if(seginfo.vsid is not null) then
1080            return_code := VV_ERROR;
1077         if(get_value_set(seginfo.vsid, seginfo.segname, vsinfo) <> TRUE) then
1078            errseg_num := segcount;
1079            segcount := segcount - 1;
1081            goto return_values;
1082         end if;
1083       else
1084         if(virtual_value_set(seginfo.coltype, seginfo.collen, seginfo.segname,
1085                              vsinfo) <> TRUE) then
1086            errseg_num := segcount;
1087            segcount := segcount - 1;
1088            return_code := VV_ERROR;
1089            goto return_values;
1090         end if;
1091      end if;
1092 
1093      --
1094      --  Check if segment displayed.  By definition all segments are
1095      --  displayed if inputs are ID's.
1096      --
1097      if(vflags.values_not_ids) then
1098         if(check_displayed(segcount, dispsegs, seg_displayed) = FALSE) then
1099            errseg_num := segcount;
1100            segcount := segcount - 1;
1101            return_code := VV_ERROR;
1102            goto return_values;
1103         end if;
1104       else
1105         seg_displayed := TRUE;
1106      end if;
1107 
1108      --
1109      --  If segment not displayed treat it as null.  If it is displayed then
1110      --  increment displayed count.   If displayed and exact number of segments
1111      --  not required, then treat missing segs as null.
1112      --  If nsegs_in = 0, could be that nsegs_in = 1 and that seg is null.
1113      --
1114      -- bug 1459072 values for all segs should be validated whether they are
1115      -- displayed or not. Also code was not validating right segment if a
1116      -- non-displayed segment was processed before a displayed segment.
1117 
1118      --
1119      -- Above comment is not quite true (bug 1459072), I need to do
1120      -- more research on that problem. Now I am backing up the changes.
1121      -- and adding comments to following code. golgun. 01/15/01
1122      --
1123 
1124      --
1125      -- If values are passed, DISPLAY mapping was used to parse concat string.
1126      -- So segs array has only displayed segment values.
1127      -- If Ids are passed, even if there is restriction in DISPLAY mapping,
1128      -- all segment values are assumed to be displayed, and segs array
1129      -- has all the segment values.
1130     --
1131      if(seg_displayed) then
1132         dispsegcount := dispsegcount + 1;
1133         if(dispsegcount > nsegs_in) THEN
1134            --
1135            -- Out of boundary.
1136            --
1137            if(vflags.exact_nsegs_required and
1138               not ((nsegs_in = 0) and (dispsegcount = 1))) then
1139               --
1140               -- Not enough segment values are passed and this is not OK.
1141               --
1142               FND_MESSAGE.set_name('FND', 'FLEX-MISSING CONCAT VALUES');
1143               errseg_num := segcount;
1144               segcount := segcount - 1;
1145               return_code := VV_ERROR;
1146               goto return_values;
1147             else
1148               --
1149               -- Not enough segment values are passed and this is OK.
1150               --
1151               this_seg := NULL;
1152            end if;
1153          else
1154            --
1155            -- seg is displayed (either (displayed 'V'), or 'I'),
1156            -- and the value is in the array.
1157            --
1158            this_seg := segs(dispsegcount);
1159         end if;
1160       else
1161         --
1162         -- seg is not displayed, only possible in 'V' case.
1163         --
1164         this_seg := NULL;
1165      end if;
1166 
1167      v_status := validate_seg(this_seg,
1168                               seg_displayed,
1169                               seginfo,
1170                               vsinfo,
1171                               vflags,
1172                               fstruct,
1173                               v_date,
1174                               v_ruls,
1175                               uappid,
1176                               respid,
1177                               segcount - 1,
1178                               prior_dispvals,
1179                               prior_vals,
1180                               prior_ids,
1181                               prior_descs,
1182                               prior_vsids,
1183                               prior_segnames,
1184                               prior_vsnames,
1185                               l_flexvalue,
1186                               seg_quals);
1187 
1188      --
1189      --  Record value and structure information
1190      --  Add value validation status to segment error string.
1191      --
1192      tabcols(segcount) := seginfo.colname;
1193      tabcoltypes(segcount) := seginfo.coltype;
1194      prior_vsids(segcount) := seginfo.vsid;
1195      prior_dispvals(segcount) := l_flexvalue.displayed_value;
1196      prior_vals(segcount) := l_flexvalue.stored_value;
1197      prior_ids(segcount) := l_flexvalue.hidden_id;
1198      prior_descs(segcount) := l_flexvalue.description;
1199      prior_segnames(segcount) := seginfo.segname;
1200      prior_vsnames(segcount) := vsinfo.vsname;
1201      catdesc_lens(segcount) := seginfo.catdesclen;
1202      segfmts.vs_format(segcount) := vsinfo.vsformat;
1203      segfmts.vs_maxsize(segcount) := vsinfo.maxsize;
1204      segerrs := segerrs || v_status;
1205 
1206      --
1210      --  overwritten any prior value errors, and then return.
1207      --  If values ok, then derive qualifiers and enabled dates.
1208      --  If serious error validating values, or if value validation is unsupported
1209      --  on the server, then set errseg_num to current segment since this error has
1211      --  If value is secured or other value error note the error in the local flag
1212      --  and optionally stop depending on the vflags.  In these cases the value
1213      --  error message will only have been put into FND_MESSAGE if it is the
1214      --  first error, so set errseg_num only if it's null.
1215      --
1216      IF (v_status = FF_VVALID) then
1217         this_dval.start_valid := l_flexvalue.start_valid;
1218         this_dval.end_valid := l_flexvalue.end_valid;
1219         this_dval.enabled_flag := l_flexvalue.enabled_flag;
1220         this_dval.summary_flag := l_flexvalue.summary_flag;
1221         if(derive_values(this_dval, seg_quals, drvals,drvd_quals) = FALSE) then
1222            return_code := VV_ERROR;
1223            goto return_values;
1224         end if;
1225       elsif(v_status = FF_VERROR) then
1226         errseg_num := segcount;
1227         return_code := VV_ERROR;
1228         goto return_values;
1229       elsif(v_status = FF_VUNKNOWN) then
1230         errseg_num := segcount;
1231         return_code := VV_UNSUPPORTED;
1232         goto return_values;
1233       elsif(v_status = FF_VSECURED) then
1234         secured_flag := TRUE;
1235         if((errseg_num is null) and vflags.message_on_security) then
1236            errseg_num := segcount;
1237         end if;
1238         if(vflags.stop_on_security) then
1239            return_code := VV_SECURED;
1240            goto return_values;
1241         end if;
1242       else
1243         val_err_flag := TRUE;
1244         if(errseg_num is null) then
1245            if((v_status <> FF_VREQUIRED) or (vflags.message_on_null)) then
1246               errseg_num := segcount;
1247            end if;
1248         end if;
1249         if(vflags.stop_on_value_error) then
1250            return_code := VV_VALUES;
1251            goto return_values;
1252         end if;
1253      end if;
1254 
1255   end loop;
1256 
1257   if(fstruct.isa_key_flexfield) then
1258      if(segcount <= 0) then
1259         FND_MESSAGE.set_name('FND', 'FLEX-CANT FIND SEGMENTS');
1260         FND_MESSAGE.set_token('ROUTINE', 'Validate Values');
1261         FND_MESSAGE.set_token('APPID', to_char(fstruct.application_id));
1262         FND_MESSAGE.set_token('CODE', fstruct.id_flex_code);
1263         FND_MESSAGE.set_token('NUM', to_char(fstruct.id_flex_num));
1264         return_code := VV_ERROR;
1265         goto return_values;
1266      end if;
1267    ELSE
1268      NULL;
1269   end if;
1270 
1271   --
1272   --  If exact number of segments required, then check for too many.
1273   --  Otherwise just stop.
1274   --  If nsegs_in = 0, could be that nsegs_in = 1 and that seg is null.
1275   --  Do not complain if dispsegcount is 1 in that case.
1276   --
1277   if(vflags.exact_nsegs_required and (dispsegcount <> nsegs_in) and
1278      not ((nsegs_in = 0) and (dispsegcount = 1))) then
1279      FND_MESSAGE.set_name('FND', 'FLEX-TOO MANY SEGS');
1280      FND_MESSAGE.set_token('NSEGS', to_char(dispsegcount));
1281      return_code := VV_ERROR;
1282      goto return_values;
1283   end if;
1284 
1285   IF (fnd_flex_server1.g_debug_level > 0) THEN
1286      add_debug(to_char(segcount) || ' segments found.');
1287   END IF;
1288 
1289   --
1290   --  Return most serious error or none if there are none.
1291   --
1292   if(val_err_flag) then
1293      return_code := VV_VALUES;
1294    elsif(secured_flag) then
1295      return_code := VV_SECURED;
1296    else
1297      return_code := VV_VALID;
1298   end if;
1299 
1300   <<return_values>>
1301   --
1302   -- Return values, derived values, qualifiers, segment format.
1303   --
1304   nsegs_out := segcount;
1305   segfmts.nsegs := segcount;
1306   segstats := segerrs;
1307   v_dispvals := prior_dispvals;
1308   v_vals := prior_vals;
1309   v_ids := prior_ids;
1310   v_descs := prior_descs;
1311   desc_lens := catdesc_lens;
1312   dvals := drvals;
1313   dquals := drvd_quals;
1314   errsegn := errseg_num;
1315 
1316   IF (fnd_flex_server1.g_debug_level > 0) THEN
1317      FND_FLEX_SERVER1.add_debug('END SV1.validate_struct()');
1318   END IF;
1319 
1320   return(return_code);
1321 
1322 EXCEPTION
1323    WHEN NO_DATA_FOUND then
1324       IF (fnd_flex_server1.g_debug_level > 0) THEN
1325          FND_FLEX_SERVER1.add_debug('EXCEPTION no_data_found SV1.validate_struct() ');
1326       END IF;
1327       if(fstruct.isa_key_flexfield) then
1328          FND_MESSAGE.set_name('FND', 'FLEX-CANT FIND SEGMENTS');
1329          FND_MESSAGE.set_token('ROUTINE', 'Validate Values');
1330          FND_MESSAGE.set_token('APPID', to_char(fstruct.application_id));
1331          FND_MESSAGE.set_token('CODE', fstruct.id_flex_code);
1332          FND_MESSAGE.set_token('NUM', to_char(fstruct.id_flex_num));
1333          return(VV_ERROR);
1334       end if;
1335       return(VV_VALID);
1336    WHEN OTHERS then
1337       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
1338       FND_MESSAGE.set_token('MSG', 'validate_struct() exception:  '||SQLERRM);
1339       IF (fnd_flex_server1.g_debug_level > 0) THEN
1340          FND_FLEX_SERVER1.add_debug('EXCEPTION others SV1.validate_struct() ');
1344 
1341       END IF;
1342 
1343       return(VV_ERROR);
1345 END validate_struct;
1346 
1347 /* ----------------------------------------------------------------------- */
1348 /*      Validates value returing status code indicating if the segment is  */
1349 /*      valid or if what if any errors are present.  Sets error message    */
1350 /*      using error prioritization functions if any errors in user-entered */
1351 /*      values.  If value invalid because of a value error rather than     */
1352 /*      an error in the data structures etc, then this program tries to    */
1353 /*      return as much of the value as possible.  If value cannot be       */
1354 /*      found, this program returns what the user typed in for the value   */
1355 /*      and null ids and descrs.  If the value is found, the whole value   */
1356 /*      is returned even if there is some other validation problem such    */
1357 /*      as a security violation or value is expired or disabled.           */
1358 /*      Outputs actual value, format of segment, and segment qualifiers.   */
1359 /* ----------------------------------------------------------------------- */
1360 
1361 FUNCTION validate_seg(seg_in          IN  VARCHAR2,
1362                     displayed       IN  BOOLEAN,
1363                     kseg            IN  SegmentInfo,
1364                     vsinf           IN  ValueSetInfo,
1365                     vflags          IN  ValueValidationFlags,
1366                     fstruct         IN  FlexStructId,
1367                     v_date          IN  DATE,
1368                     v_ruls          IN  Vrules,
1369                     uappid          IN  NUMBER,
1370                     respid          IN  NUMBER,
1371                     nprev           IN  NUMBER,
1372                     prev_dispvals   IN  ValueArray,
1373                     prev_vals       IN  ValueArray,
1374                     prev_ids        IN  ValueIdArray,
1375                     prev_descs      IN  ValueDescArray,
1376                     prev_vsids      IN  NumberArray,
1377                     prev_segnames   IN  SegNameArray,
1378                     prev_vsnames    IN  VsNameArray,
1379                     x_flexvalue     OUT nocopy FlexValue,
1380                     squals          OUT nocopy Qualifiers)
1381 RETURN VARCHAR2
1382 IS
1383    isvalu          BOOLEAN;
1384    defaulted       BOOLEAN;
1385    orphansok       BOOLEAN;
1386    vcode           VARCHAR2(1);
1387    thisseg         VARCHAR2(1000);
1388    parentval       VARCHAR2(150);
1389    segquals        Qualifiers;
1390    l_flexvalue     FlexValue;
1391    l_fvc_code      VARCHAR2(100);
1392    l_parent_index  BINARY_INTEGER;
1393    l_storage_value VARCHAR2(2000);
1394    l_display_value VARCHAR2(2000);
1395 BEGIN
1396  IF (fnd_flex_server1.g_debug_level > 0) THEN
1397     FND_FLEX_SERVER1.add_debug('BEGIN SV1.validate_seg() ');
1398  END IF;
1399 
1400  --
1401  --  Initialize all returned values
1402  --
1403  vcode := FF_VERROR;
1404  segquals.nquals := 0;
1405  l_flexvalue.enabled_flag := 'Y';
1406  l_flexvalue.summary_flag := 'N';
1407 
1408  isvalu := vflags.values_not_ids;
1409 
1410  --  Initialize value.  Strip spaces if user entered value rather than ID
1411  --
1412  IF (isvalu) then
1413     thisseg := RTRIM(LTRIM(seg_in));
1414     l_flexvalue.displayed_value := thisseg;
1415     l_flexvalue.stored_value := thisseg;
1416   else
1417     thisseg := seg_in;
1418     l_flexvalue.hidden_id := thisseg;
1419  end if;
1420 
1421  --  Get all flexfield and segment qualifiers enabled for this segment.
1422  --
1423  IF (get_qualifiers(fstruct, kseg.colname, segquals) < 0) then
1424     vcode := FF_VERROR;
1425     goto return_val;
1426  end if;
1427 
1428  --  Add segment qualifier list to debug string
1429  --
1430  IF (fnd_flex_server1.g_debug_level > 0) THEN
1431     if(segquals.nquals > 0) then
1432        add_debug('DefaultQuals=');
1433        for i in 1..segquals.nquals loop
1434           add_debug('(' || segquals.fq_names(i) || ', ' ||
1435                     segquals.sq_names(i) || ', ' ||
1436                     segquals.sq_values(i) || ', ' ||
1437                     segquals.derived_cols(i) || ')');
1438        end loop;
1439     end if;
1440  END IF;
1441 
1442  --  Attempt to default null values.
1443  --  Do not default if id or if value not null.
1444  --  Default only displayed value.
1445  --  Bug 1539718 added check for vflags.allow_nulls
1446  --  Bug 2221725 Need to default id if invoking_mode = 'D' and seg is null.
1447 
1448  if vflags.invoking_mode = 'D' then
1449     if thisseg is null then
1450        isvalu := TRUE;
1451      else
1452        isvalu := FALSE;            -- needed in case previous seg was null.
1453     end if;
1454  end if;
1455 
1456  defaulted := FALSE;
1457 
1458  --Bug 6074421, Modified IF statment to not override null value with
1459  --defalut value, if segment is not required. Added (kseg.required = 'Y')
1460  --Bug 7028502, Modified IF statment to allow non-req segments to default
1461  --if the invoking_mode = 'D'.
1462 
1463  IF (((isvalu) and (thisseg is null) and
1464       (kseg.required = 'Y' or vflags.invoking_mode = 'D')) and
1465      ((displayed and vflags.default_all_displayed and not vflags.allow_nulls) or
1466       ((kseg.required = 'Y') and vflags.default_all_required) or
1467       ((kseg.required = 'Y') and (not displayed) and
1468        vflags.default_non_displayed))) then
1472                          prev_dispvals, prev_vals, prev_ids, prev_descs,
1469     vcode := default_val(kseg.dflt_type, kseg.dflt_val, vsinf.vsformat,
1470                          vsinf.maxsize, vsinf.precis, vsinf.lettersok,
1471                          kseg.segname, nprev,
1473                          prev_segnames, prev_vsnames, thisseg);
1474     defaulted := TRUE;
1475     if(vcode <> FF_VVALID) then
1476 
1477        --  Bug 2778034-Flexfield is set to use defaulting from a form block
1478        --  and field, but in processing batch jobs this call is made to do
1479        --  defaulting, and the form block and field are not available, so
1480        --  ignore the error and set the field to NULL. This is only
1481        --  implementedfor invoking_mode 'D', which is for defaulting IDs.
1482        --  We are ONLY handling this case because we can be assured that
1483        --  the source is a batch job, and the :block.field cannot be
1484        --  expected to be available.  We will NOT change this for any
1485        --  other invoking mode since we cannot be sure of the source.
1486        --
1487 
1488        if ((vcode = FF_VUNKNOWN) and (vflags.invoking_mode = 'D')) then
1489           thisseg := NULL;
1490           vcode := FF_VVALID;
1491           IF (fnd_flex_server1.g_debug_level > 0) THEN
1492              add_debug('Segment NOT defaulted because of :block.field bind '
1493                        || to_char(nprev + 1));
1494           END IF;
1495         else
1496           goto return_val;
1497        end if;
1498 
1499     end if;
1500     l_flexvalue.displayed_value := thisseg;
1501     IF (fnd_flex_server1.g_debug_level > 0) THEN
1502        add_debug('Defaulted segment ' || to_char(nprev + 1));
1503        add_debug(' to ' || thisseg);
1504     END IF;
1505  end if;
1506 
1507  --  Check for nulls.  If null and this is OK then set values, ids and
1508  --  description to null and move on.
1509  --
1510  --  Bug 1879889 - added check for DFF null dependent segment
1511  --  We need to check the parent segment before issuing error.
1512  --  If parent seg is null then child can be null also.
1513  --  Bug 5560451 The same is true for Key Flexfields. If a parent
1514  --  is not required and is NULL, then dependent seg does not need value
1515  --  even if it is required. Removing the statment
1516  --  fstruct.isa_key_flexfield = FALSE
1517 
1518 
1519  if(thisseg is null) then
1520     if vsinf.parent_vsid is not NULL and vsinf.valtype = 'D'
1521     then
1522        NULL;       -- we will check again for DFF nulls after getting parent.
1523     else
1524        if((kseg.required = 'N') or (vflags.allow_nulls))
1525        then
1526           vcode := FF_VVALID;
1527           goto return_val;
1528         else
1529           vcode := FF_VREQUIRED;
1530           if(vflags.message_on_null) then
1531              value_error_name('FND', 'FLEX-NULL SEGMENT');
1532           end if;
1533           goto return_val;
1534        end if;
1535     end if;
1536  end if;
1537 
1538  -- Coerces user input from being a rough approximation of the displayed
1539  -- value format, to the value storage format.
1540  -- Also checks length and that value is in min-max range.
1541  -- Side effect: change thisseg to stored format appropriate to the value set.
1542  -- Added "and thisseg is not null" in conjuction with changes for bug 1879889
1543  -- as it is now possible to be here with a null segment.
1544 
1545  -- Validate None validated value sets too.
1546  IF ((isvalu) OR
1547      (vsinf.valtype = 'N')) and thisseg is not null then
1548     vcode := coerce_format(thisseg, isvalu, vsinf.vsformat, vsinf.vsname,
1549                            vsinf.maxsize, vsinf.lettersok, vsinf.capsonly,
1550                            vsinf.zfill, vsinf.precis, vsinf.minval,
1551                            vsinf.maxval,l_storage_value, l_display_value);
1552     thisseg := l_storage_value;
1553     if(vcode <> FF_VVALID) then
1554        goto return_val;
1555     end if;
1556  end if;
1557 
1558  --  Now look up value
1559 
1560  --  GL RELIES ON THE FOLLOWING STRANGE BEHAVIOR:
1561  --  To be compatible with client, orphans are ok if the child
1562  --  value was defaulted and nulls are allowed.
1563  --
1564  orphansok := (vflags.all_orphans_valid or
1565                (vflags.allow_nulls and defaulted));
1566 
1567  -- ==
1568  --
1569  -- Find parent value: took out from find_value.
1570  --
1571  -- ==
1572  l_fvc_code := fnd_plsql_cache.CACHE_NOTFOUND;
1573  IF (vsinf.valtype IN ('I','D','X','Y')) THEN
1574     IF (isvalu) then
1575        l_flexvalue.displayed_value := thisseg;
1576        l_flexvalue.stored_value := thisseg;
1577      else
1578        l_flexvalue.hidden_id := thisseg;
1579     end if;
1580     l_flexvalue.enabled_flag := 'Y';
1581     l_flexvalue.summary_flag := 'N';
1582     l_flexvalue.format := vsinf.vsformat;
1583 
1584     parentval := NULL;
1585 
1586     IF (vsinf.valtype in ('D','Y')) then
1587        IF (fnd_flex_server1.g_debug_level > 0) THEN
1588           add_debug(vsinf.valtype);
1589           for i in 1..nprev loop
1590              add_debug(to_char(prev_vsids(i)) || '.');
1591           end loop;
1592        END IF;
1593 
1594        --
1595        --  Find index to parent value set
1596        l_parent_index := 0;
1597        for i in reverse 1..nprev loop
1598           IF ((prev_vsids(i) is not null) and
1602                 parentval := prev_vals(i);
1599               (vsinf.parent_vsid = prev_vsids(i))) then
1600              l_parent_index := i;
1601              IF (vsinf.valtype = 'D') THEN
1603               ELSE
1604                 parentval := prev_ids(i);
1605              END IF;
1606              exit;
1607           end if;
1608        end loop;
1609 
1610        --
1611        --  Bug 1879889
1612        --  Check for DFF null dependent segment now that we have parent value.
1613        --  same if condition as used above to insure that we only process
1614        --  DFF dependent null segments.
1615        --  Bug 2933236
1616        --  Check dependent segment required flag. If a dependent segment
1617        --  has a parent, but is not is not required, then it is not
1618        --  requried to have a value. It only must have a value if the
1619        --  segment is required.
1620        --  Bug 5560451 The same is true for Key Flexfields.
1621        --  Removing the statment fstruct.isa_key_flexfield = FALSE
1622 
1623        if thisseg is null and vsinf.parent_vsid is not NULL
1624            and vsinf.valtype = 'D' then
1625           if parentval is null then
1626              vcode := FF_VVALID;
1627            else
1628              if (kseg.required = 'Y') then /* Bug 2933236 */
1629                 vcode := FF_VREQUIRED;
1630                 if(vflags.message_on_null) then
1631                    value_error_name('FND', 'FLEX-NULL SEGMENT');
1632                 end if;
1633               else
1634                 vcode := FF_VVALID;
1635              end if;
1636           end if;
1637           goto return_val;
1638        end if;
1639 
1640        IF (l_parent_index = 0) then
1641           FND_MESSAGE.set_name('FND', 'FLEX-NO PARENT SEGMENT');
1642           FND_MESSAGE.set_token('CHILD', kseg.segname);
1643           vcode := FF_VERROR;
1644           goto return_val;
1645        end if;
1646 
1647       IF ((parentval is null) and (not orphansok))then
1648          --
1649          -- Use FLEX-ORPHAN but need segment names of previous segments
1650          --
1651          value_error_name('FND', 'FLEX-ORPHAN');
1652          value_error_token('PARENT', prev_segnames(l_parent_index));
1653          value_error_token('SEGMENT', kseg.segname);
1654          vcode := FF_VORPHAN;
1655          goto return_val;
1656       end if;
1657      else
1658        IF (fnd_flex_server1.g_debug_level > 0) THEN
1659           add_debug(vsinf.valtype);
1660        END IF;
1661     end if;
1662 
1663     IF (kseg.additional_where_clause IS NULL) THEN
1664        IF (vsinf.valtype IN ('I', 'D')) THEN
1665           l_fvc_code := check_fvc(vsinf.vsid,
1666                                   parentval,
1667                                   thisseg,
1668                                   l_flexvalue);
1669        END IF;
1670     END IF;
1671  END IF;
1672 
1673  IF (l_fvc_code IN (fnd_plsql_cache.CACHE_FOUND)) THEN
1674     vcode := FF_VVALID;
1675   ELSE
1676     vcode := find_value(fstruct, kseg, vsinf, v_date,
1677                         thisseg,
1678                         isvalu, orphansok,
1679                         kseg.segname, nprev, prev_vsids,
1680                         prev_dispvals, prev_vals, prev_ids, prev_descs,
1681                         prev_segnames, prev_vsnames, parentval, l_flexvalue);
1682 
1683     --
1684     -- If value exists then cache it.
1685     --
1686     IF (kseg.additional_where_clause IS NULL) THEN
1687        IF ((vcode = FF_VVALID) AND
1688            (vsinf.valtype IN ('I', 'D'))) THEN
1689           update_fvc(vsinf.vsid, parentval, thisseg, l_flexvalue);
1690        END IF;
1691     END IF;
1692  END IF;
1693 
1694  IF (vcode <> FF_VVALID) then
1695     goto return_val;
1696  end if;
1697 
1698  --  Determine qualifier values for this segment from
1699  --  compiled_value_attributes (This function replaces the sq_values
1700  --  which differ from the defaults)
1701  if(l_flexvalue.compiled_attributes is not null) then
1702     if(qualifier_values(fstruct, vsinf.vsid, l_flexvalue.compiled_attributes,
1703                         segquals.nquals, segquals.fq_names,
1704                         segquals.sq_names,
1705                         segquals.sq_values) < 0) then
1706        vcode := FF_VERROR;
1707        goto return_val;
1708     end if;
1709  end if;
1710 
1711  --  Add modified segment qualifier values to debug string
1712  --
1713  IF (fnd_flex_server1.g_debug_level > 0) THEN
1714     if(segquals.nquals > 0) THEN
1715        g_debug_text := 'SegQualVals=';
1716        for i in 1..segquals.nquals loop
1717           g_debug_text := g_debug_text || '(' || segquals.sq_values(i) || ')';
1718        end loop;
1719        add_debug(g_debug_text);
1720     end if;
1721  END IF;
1722 
1723  --  Always check vrules.  They should not be checked in LOADID(), but
1724  --  the client does it anyway.
1725  --
1726  /* bug872437. Don't check vrules in loadid. */
1727 
1728  IF (vflags.invoking_mode <> 'L') THEN
1729     vcode := check_vrules(v_ruls, segquals, l_flexvalue.summary_flag);
1730     if(vcode <> FF_VVALID) then
1731        goto return_val;
1732     end if;
1733  END IF;
1734 
1735  -- Check security rules
1736  if(NOT vflags.ignore_security) then
1737     if((vsinf.valtype in ('I', 'D', 'F')) and
1741        END IF;
1738        (vsinf.valsecure in ('Y', 'H')) and (kseg.segsecure = 'Y')) THEN
1739        IF (fnd_flex_server1.g_debug_level > 0) THEN
1740           add_debug('Calling Security');
1742        vcode := check_security(l_flexvalue.stored_value, vsinf.vsformat,
1743                                parentval, uappid, respid, vsinf,
1744                                vflags.message_on_security);
1745        IF (vcode <> FF_VVALID) THEN
1746           IF (fnd_flex_server1.g_debug_level > 0) THEN
1747              add_debug('Security Failure Code: ' || vcode);
1748           END IF;
1749           goto return_val;
1750        end if;
1751        IF (fnd_flex_server1.g_debug_level > 0) THEN
1752           add_debug('NOT SECURED');
1753        END IF;
1754     end if;
1755  end if;
1756 
1757  -- Check to make sure value is enabled for the given validation date.
1758  --
1759  if(NOT vflags.ignore_disabled) then
1760     if(l_flexvalue.enabled_flag <> 'Y') then
1761        value_error_name('FND', 'FLEX-VALUE IS DISABLED');
1762        value_error_token('VALUE', l_flexvalue.displayed_value);
1763        vcode := FF_VDISABLED;
1764        goto return_val;
1765     end if;
1766  end if;
1767 
1768  if((NOT vflags.ignore_expired) and (v_date is not null)) then
1769     if((Trunc(v_date) < Trunc(nvl(l_flexvalue.start_valid, v_date))) or
1770        (Trunc(v_date) > Trunc(nvl(l_flexvalue.end_valid, v_date)))) then
1771        value_error_name('FND', 'FLEX-VALUE IS EXPIRED');
1772        value_error_token('VALUE', l_flexvalue.displayed_value);
1773        vcode := FF_VEXPIRED;
1774        goto return_val;
1775     end if;
1776  end if;
1777 
1778  <<return_val>>
1779  x_flexvalue := l_flexvalue;
1780  squals := segquals;
1781  IF (fnd_flex_server1.g_debug_level > 0) THEN
1782     FND_FLEX_SERVER1.add_debug('END SV1.validate_seg() ');
1783  END IF;
1784 
1785  return(vcode);
1786 
1787 EXCEPTION
1788  WHEN OTHERS then
1789     FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
1790     FND_MESSAGE.set_token('MSG', 'validate_seg() exception:  ' || SQLERRM);
1791     IF (fnd_flex_server1.g_debug_level > 0) THEN
1792        FND_FLEX_SERVER1.add_debug('EXCEPTION others SV1.validate_seg() ');
1793     END IF;
1794     return(FF_VERROR);
1795 END validate_seg;
1796 
1797 /* ----------------------------------------------------------------------- */
1798 /*      Given the dvals and qualifiers for the current segment and the     */
1799 /*      existing derived dvals and qualifiers, compute the new dvals and   */
1800 /*      qualifiers.  Presently only handles one set of derivation rules.   */
1801 /*      Returns TRUE if OK or FALSE and sets error message if errors.      */
1802 /* ----------------------------------------------------------------------- */
1803 
1804 FUNCTION derive_values(new_dvals      IN      DerivedVals,
1805                        new_quals      IN      Qualifiers,
1806                        drv_dvals      IN OUT  nocopy DerivedVals,
1807                        drv_quals      IN OUT  nocopy Qualifiers) RETURN BOOLEAN IS
1808 
1809   dqi BINARY_INTEGER;
1810 
1811 BEGIN
1812 
1813 -- Derive values for the enabled parameters and summary flag
1814 --
1815   if((new_dvals.start_valid is not null) and
1816      ((drv_dvals.start_valid is null) or
1817       (new_dvals.start_valid > drv_dvals.start_valid))) then
1818     drv_dvals.start_valid := new_dvals.start_valid;
1819   end if;
1820   if((new_dvals.end_valid is not null) and
1821      ((drv_dvals.end_valid is null) or
1822       (new_dvals.end_valid < drv_dvals.end_valid))) then
1823     drv_dvals.end_valid := new_dvals.end_valid;
1824   end if;
1825   if(new_dvals.enabled_flag = 'N') then
1826     drv_dvals.enabled_flag := 'N';
1827   end if;
1828   if(new_dvals.summary_flag = 'Y') then
1829     drv_dvals.summary_flag := 'Y';
1830   end if;
1831 
1832 --  Derive the qualifiers.
1833 --  Add each segment qualifier to the accumulated derived qualifiers.
1834 --  If it's a new qualifier add it to the array of derived qualifier names.
1835 --  Otherwise, compute the derived value using the Derivation rules:
1836 --  "If any segment qualifier value is 'N' the derived value is 'N'
1837 --
1838 --  Algorithm:  For each seg qual, find dqi = index to derived qual with
1839 --  the same fq and sq names.  If found, derive the value using the new seg
1840 --  qualifier value.  If not found, add a new qualifier to the list of
1841 --  derived qualifiers.
1842 --
1843   for i in 1..new_quals.nquals loop
1844     dqi := NULL;
1845     for j in 1..drv_quals.nquals loop
1846       if((drv_quals.fq_names(j) = new_quals.fq_names(i)) and
1847          (drv_quals.sq_names(j) = new_quals.sq_names(i))) then
1848         dqi := j;
1849         exit;
1850       end if;
1851     end loop;
1852     if(dqi is not null) then
1853       if(new_quals.sq_values(i) = 'N') then
1854         drv_quals.sq_values(dqi) := 'N';
1855       end if;
1856     else
1857       drv_quals.nquals := drv_quals.nquals + 1;
1858       dqi := drv_quals.nquals;
1859       drv_quals.fq_names(dqi) := new_quals.fq_names(i);
1860       drv_quals.sq_names(dqi) := new_quals.sq_names(i);
1861       drv_quals.sq_values(dqi) := new_quals.sq_values(i);
1862       drv_quals.derived_cols(dqi) := new_quals.derived_cols(i);
1863     end if;
1864   end loop;
1865 
1866   return(TRUE);
1867 
1868 EXCEPTION
1869   WHEN OTHERS then
1873 
1870     FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
1871     FND_MESSAGE.set_token('MSG', 'derive_values() exception:  ' || SQLERRM);
1872     return(FALSE);
1874 END derive_values;
1875 
1876 /* ----------------------------------------------------------------------- */
1877 /*      Coerces entered segment value into the value storage format        */
1878 /*      appropriate for the value set,                                     */
1879 /*      and checks to make sure value is not too long and is within the    */
1880 /*      the min-max range specified in the value set.                      */
1881 /*                                                                         */
1882 /*      Returns the value in stored format and TRUE on success or sets     */
1883 /*      error and returns FALSE on error.                                  */
1884 /* ----------------------------------------------------------------------- */
1885 
1886 FUNCTION coerce_format(user_value IN     VARCHAR2,
1887                        p_is_displayed IN BOOLEAN,
1888                        vs_format  IN     VARCHAR2,
1889                        vs_name    IN     VARCHAR2,
1890                        max_length IN     NUMBER,
1891                        letters_ok IN     VARCHAR2,
1892                        caps_only  IN     VARCHAR2,
1893                        zero_fill  IN     VARCHAR2,
1894                        precision  IN     VARCHAR2,
1895                        min_value  IN     VARCHAR2,
1896                        max_value  IN     VARCHAR2,
1897                        x_storage_value OUT nocopy VARCHAR2,
1898                        x_display_value OUT nocopy VARCHAR2) RETURN VARCHAR2 IS
1899 
1900   l_return    VARCHAR2(1);
1901   l_success   NUMBER;
1902   l_storage_value VARCHAR2(2000);
1903   l_display_value VARCHAR2(2000);
1904   l_utv_enc_message VARCHAR2(32000) := NULL;
1905   l_ssv_enc_message VARCHAR2(32000) := NULL;
1906 BEGIN
1907    IF (fnd_flex_server1.g_debug_level > 0) THEN
1908       FND_FLEX_SERVER1.add_debug('BEGIN SV1.coerce_format() ');
1909    END IF;
1910 
1911    x_storage_value := user_value;
1912    x_display_value := user_value;
1913 
1914    --
1915    -- Since validation utility is setting messages by using
1916    -- fnd_message, we will do a stacking trick here.
1917    --
1918    -- For different result, different style of messaging is used.
1919    -- If the error is serious, always overwrite the existing message.
1920    --
1921    IF (value_error_set) THEN
1922       l_ssv_enc_message := fnd_message.get_encoded;
1923    END IF;
1924 
1925    fnd_flex_val_util.validate_value_ssv
1926      (p_value     => user_value,
1927       p_is_displayed => p_is_displayed,
1928       p_vset_name => vs_name,
1929       p_vset_format => vs_format,
1930       p_max_length => max_length,
1931       p_precision => To_number(precision),
1932       p_alpha_allowed => letters_ok,
1933       p_uppercase_only => caps_only,
1934       p_zero_fill => zero_fill,
1935       p_min_value => min_value,
1936       p_max_value => max_value,
1937       x_storage_value => l_storage_value,
1938       x_display_value => l_display_value,
1939       x_success       => l_success);
1940 
1941    IF (fnd_flex_server1.g_debug_level > 0) THEN
1942       add_debug(Rtrim(Substr(fnd_flex_val_util.get_debug,1,2000), chr_newline));
1943    END IF;
1944    IF (l_success = fnd_flex_val_util.g_ret_no_error) THEN
1945       --
1946       -- No error case.
1947       --
1948       l_return := FF_VVALID;
1949       x_storage_value := l_storage_value;
1950       x_display_value := l_display_value;
1951       IF (value_error_set) THEN
1952          fnd_message.set_encoded(l_ssv_enc_message);
1953       END IF;
1954     ELSE
1955       --
1956       -- Since this is an error case, get the message.
1957       --
1958       l_utv_enc_message := fnd_message.get_encoded;
1959 
1960       IF ((l_success = fnd_flex_val_util.g_ret_value_too_long) OR
1961           (l_success = fnd_flex_val_util.g_ret_invalid_number) OR
1962           (l_success = fnd_flex_val_util.g_ret_invalid_date)) THEN
1963           --
1964           -- Format Errors.
1965           --
1966           l_return := FF_VFORMAT;
1967           IF (value_error_set) THEN
1968              fnd_message.set_encoded(l_ssv_enc_message);
1969            ELSE
1970              fnd_message.set_encoded(l_utv_enc_message);
1971           END IF;
1972        ELSIF ((l_success = fnd_flex_val_util.g_ret_vs_bad_precision) OR
1973               (l_success = fnd_flex_val_util.g_ret_vs_bad_format) OR
1974               (l_success = fnd_flex_val_util.g_ret_vs_bad_numrange) OR
1975               (l_success = fnd_flex_val_util.g_ret_vs_bad_daterange) OR
1976               (l_success = fnd_flex_val_util.g_ret_vs_bad_date) OR
1977               (l_success = fnd_flex_val_util.g_ret_exception_others)) THEN
1978          --
1979          -- Serious errors.
1980          --
1981          l_return := FF_VERROR;
1982          fnd_message.set_encoded(l_utv_enc_message);
1983 
1984        ELSIF (l_success = fnd_flex_val_util.g_ret_val_out_of_range) THEN
1985          --
1986          -- Bound Check Error.
1987          --
1988          l_return := FF_VBOUNDS;
1989          IF (value_error_set) THEN
1990             fnd_message.set_encoded(l_ssv_enc_message);
1991           ELSE
1992             fnd_message.set_encoded(l_utv_enc_message);
1993          END IF;
1994        ELSE
1995          --
1999          l_return := FF_VERROR;
1996          -- Other errors. This part is added, in case there will be changes
1997          -- in UTV package. As of 26-APR-99 code should not enter here.
1998          --
2000          fnd_message.set_encoded(l_utv_enc_message);
2001       END IF;
2002       --
2003       -- We are in error case, set messaging globals.
2004       --
2005       value_error_set := TRUE;
2006       entering_new_message := FALSE;
2007    END IF;
2008 
2009    IF (fnd_flex_server1.g_debug_level > 0) THEN
2010       FND_FLEX_SERVER1.add_debug('END SV1.coerce_format() ');
2011    END IF;
2012 
2013    RETURN(l_return);
2014 
2015 EXCEPTION
2016    WHEN OTHERS THEN
2017       IF (fnd_flex_server1.g_debug_level > 0) THEN
2018          FND_FLEX_SERVER1.add_debug('EXCEPTION SV1.coerce_format() ');
2019       END IF;
2020 
2021       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
2022       FND_MESSAGE.set_token('MSG', 'coerce_format() exception:  ' || SQLERRM);
2023       return(FF_VERROR);
2024 END coerce_format;
2025 
2026 /* ----------------------------------------------------------------------- */
2027 /*      Looks up value in appropriate validation tables.  Input the        */
2028 /*      character representation of the stored value or the id.  Returns   */
2029 /*      all information about the value in the FlexValue structure.  Also  */
2030 /*      returns the parent value in stored format if there is a parent.    */
2031 /*      This function needs to know about all previous segments to         */
2032 /*      handle dependent and table validated value sets.                   */
2033 /*      Returns TRUE if value is found or FALSE and sets error if not.     */
2034 /* ----------------------------------------------------------------------- */
2035 
2036 FUNCTION find_value(p_str_info          IN  FlexStructId,
2037                     p_seg_info          IN  SegmentInfo,
2038                     p_vs_info           IN  ValueSetInfo,
2039                     p_vdate             IN  DATE,
2040                     p_char_val          IN  VARCHAR2,
2041                     p_is_value          IN  BOOLEAN,
2042                     p_orphans_ok        IN  BOOLEAN,
2043                     p_this_segname      IN  VARCHAR2,
2044                     p_n_prev            IN  NUMBER,
2045                     p_prev_vsids        IN  NumberArray,
2046                     p_prev_dispvals     IN  ValueArray,
2047                     p_prev_vals         IN  ValueArray,
2048                     p_prev_ids          IN  ValueIdArray,
2049                     p_prev_descs        IN  ValueDescArray,
2050                     p_prev_segnames     IN  SegNameArray,
2051                     p_prev_vsnames      IN  VsNameArray,
2052                     p_parent_val        IN  VARCHAR2,
2053                     x_this_val_out      OUT nocopy FlexValue)
2054   RETURN VARCHAR2
2055   IS
2056      v_code                VARCHAR2(1);
2057      l_is_value            VARCHAR2(1);
2058      check_value_table     BOOLEAN;
2059      this_value            FlexValue;
2060 
2061   CURSOR IND_cursor(vsid IN NUMBER, val IN VARCHAR2) IS
2062     SELECT enabled_flag, start_date_active, end_date_active,
2063            summary_flag, compiled_value_attributes, description
2064       FROM fnd_flex_values_vl
2065      WHERE flex_value_set_id = vsid
2066        AND flex_value = val;
2067 
2068   CURSOR DEP_cursor(vsid IN NUMBER, val IN VARCHAR2, parnt IN VARCHAR2) IS
2069     SELECT enabled_flag, start_date_active, end_date_active,
2070            summary_flag, compiled_value_attributes, description
2071       FROM fnd_flex_values_vl
2072      WHERE flex_value_set_id = vsid
2073        AND flex_value = val
2074        AND parent_flex_value_low = parnt;
2075 
2076   CURSOR INDTL_cursor(vsid IN NUMBER,
2077                       val IN VARCHAR2,
2078                       p_is_value IN VARCHAR2) IS
2079     SELECT enabled_flag, start_date_active, end_date_active,
2080       summary_flag, compiled_value_attributes,
2081       flex_value, flex_value_meaning, description
2082       FROM fnd_flex_values_vl
2083      WHERE flex_value_set_id = vsid
2084       AND (((p_is_value = 'V') AND (flex_value_meaning = val)) OR
2085            ((p_is_value = 'I') AND (flex_value = val)));
2086 
2087   CURSOR DEPTL_cursor(vsid IN NUMBER,
2088                       val IN VARCHAR2,
2089                       parnt IN VARCHAR2,
2090                       p_is_value IN VARCHAR2) IS
2091     SELECT enabled_flag, start_date_active, end_date_active,
2092       summary_flag, compiled_value_attributes,
2093       flex_value, flex_value_meaning, description
2094       FROM fnd_flex_values_vl
2095       WHERE flex_value_set_id = vsid
2096       AND parent_flex_value_low = parnt
2097       AND (((p_is_value = 'V') AND (flex_value_meaning = val)) OR
2098            ((p_is_value = 'I') AND (flex_value = val)));
2099 
2100 BEGIN
2101    IF (fnd_flex_server1.g_debug_level > 0) THEN
2102       FND_FLEX_SERVER1.add_debug('BEGIN SV1.find_value()');
2103    END IF;
2104 
2105    --  Default the return value
2106 
2107    v_code := FF_VERROR;
2108 
2109 
2110    IF (p_is_value) THEN
2111       l_is_value := 'V';
2112       --
2113       -- R11.5 NLS: following is not true any more. char_val is stored value.
2114       -- However at the end of this function there is a conversion to
2115       -- displayed value.
2116       --
2117       this_value.displayed_value := p_char_val;
2121       this_value.hidden_id := p_char_val;
2118       this_value.stored_value := p_char_val;
2119     ELSE
2120       l_is_value := 'I';
2122    end if;
2123    this_value.enabled_flag := 'Y';
2124    this_value.summary_flag := 'N';
2125    this_value.format := p_vs_info.vsformat;
2126 
2127    --  Validation = None, do nothing.
2128    --
2129    if(p_vs_info.valtype = 'N') then
2130       IF (fnd_flex_server1.g_debug_level > 0) THEN
2131          add_debug('N');
2132       END IF;
2133       this_value.stored_value := p_char_val;
2134       this_value.hidden_id := p_char_val;
2135       v_code := FF_VVALID;
2136 
2137       --  Validation = Independent, or dependent look it up
2138       --
2139     ELSIF ((p_vs_info.valtype in ('I', 'D')) AND
2140            (p_seg_info.additional_where_clause IS NULL)) then
2141 
2142       --  Takes care of both dependent and independent VS
2143       --  Use the independent cursor if this is an independent value set
2144       --  or if this is a dependent value set and the parent_val is null.
2145       --  Both of these conditions will set parent_val to null
2146       --
2147       if(p_parent_val is null) then
2148          open IND_cursor(p_vs_info.vsid, p_char_val);
2149          fetch IND_cursor into this_value.enabled_flag, this_value.start_valid,
2150            this_value.end_valid, this_value.summary_flag,
2151            this_value.compiled_attributes, this_value.description;
2152          if(IND_cursor%NOTFOUND) then
2153             v_code := FF_VNOTFOUND;
2154           else
2155             v_code := FF_VVALID;
2156          end if;
2157          close IND_cursor;
2158        else
2159          open DEP_cursor(p_vs_info.vsid, p_char_val, p_parent_val);
2160          fetch DEP_cursor into this_value.enabled_flag, this_value.start_valid,
2161            this_value.end_valid, this_value.summary_flag,
2162            this_value.compiled_attributes, this_value.description;
2163          if(DEP_cursor%NOTFOUND) then
2164             v_code := FF_VNOTFOUND;
2165           else
2166             v_code := FF_VVALID;
2167          end if;
2168          close DEP_cursor;
2169       end if;
2170 
2171       -- Set error if value not found or set the returned value if found.
2172       -- Assumes v_code was either FF_VNOTFOUND or FF_VVALID.
2173       --
2174       if(v_code = FF_VNOTFOUND) then
2175          if(p_is_value) then
2176             value_error_name('FND', 'FLEX-VALUE DOES NOT EXIST');
2177 
2178             value_error_token('VALUESET', p_vs_info.vsname);
2179             value_error_token('SEGMENT', p_this_segname);
2180             value_error_token('VALUE', msg_val(p_vs_info.vsformat, p_vs_info.maxsize, p_vs_info.precis, p_vs_info.lettersok, p_char_val));
2181           else
2182             value_error_name('FND', 'FLEX-ID DOES NOT EXIST');
2183 
2184             value_error_token('ID', p_char_val);
2185             value_error_token('SEGMENT', p_this_segname);
2186             value_error_token('VALUESET', p_vs_info.vsname);
2187          end if;
2188          goto return_found_value;
2189        else
2190          this_value.stored_value := p_char_val;
2191          this_value.hidden_id := p_char_val;
2192       end if;
2193 
2194       --  Validation = TL Independent, or TL dependent look it up
2195       --
2196     ELSIF ((p_vs_info.valtype in ('X', 'Y'))  AND
2197            (p_seg_info.additional_where_clause IS NULL)) then
2198 
2199       --  Takes care of both TL dependent and TL independent VS
2200       --  Use the independent cursor if this is an independent value set
2201       --  or if this is a dependent value set and the parent_val is null.
2202       --  Both of these conditions will set parent_val to null
2203       --
2204       if(p_parent_val is null) then
2205          open INDTL_cursor(p_vs_info.vsid, p_char_val,l_is_value);
2206          fetch INDTL_cursor into this_value.enabled_flag,
2207            this_value.start_valid,
2208            this_value.end_valid, this_value.summary_flag,
2209            this_value.compiled_attributes,
2210            this_value.hidden_id, this_value.stored_value,
2211            this_value.description;
2212          if(INDTL_cursor%NOTFOUND) then
2213             v_code := FF_VNOTFOUND;
2214           else
2215             v_code := FF_VVALID;
2216          end if;
2217          close INDTL_cursor;
2218        else
2219          open DEPTL_cursor(p_vs_info.vsid, p_char_val, p_parent_val, l_is_value);
2220          fetch DEPTL_cursor into this_value.enabled_flag,
2221            this_value.start_valid,
2222            this_value.end_valid, this_value.summary_flag,
2223            this_value.compiled_attributes,
2224            this_value.hidden_id, this_value.stored_value,
2225            this_value.description;
2226          if(DEPTL_cursor%NOTFOUND) then
2227             v_code := FF_VNOTFOUND;
2228           else
2229             v_code := FF_VVALID;
2230          end if;
2231          close DEPTL_cursor;
2232       end if;
2233 
2234       -- Set error if value not found or set the returned value if found.
2235       -- Assumes v_code was either FF_VNOTFOUND or FF_VVALID.
2236       --
2237       IF (v_code = FF_VNOTFOUND) then
2238          if(p_is_value) then
2239             value_error_name('FND', 'FLEX-VALUE DOES NOT EXIST');
2240 
2241             value_error_token('VALUESET', p_vs_info.vsname);
2242             value_error_token('SEGMENT', p_this_segname);
2246 
2243             value_error_token('VALUE', msg_val(p_vs_info.vsformat, p_vs_info.maxsize, p_vs_info.precis, p_vs_info.lettersok, p_char_val));
2244           else
2245             value_error_name('FND', 'FLEX-ID DOES NOT EXIST');
2247             value_error_token('ID', p_char_val);
2248             value_error_token('SEGMENT', p_this_segname);
2249             value_error_token('VALUESET', p_vs_info.vsname);
2250          end if;
2251          goto return_found_value;
2252        else
2253          NULL;
2254          --        this_value.stored_value := p_char_val;
2255          --        this_value.hidden_id := p_char_val;
2256       end if;
2257 
2258     ELSIF ((p_vs_info.valtype in ('I', 'D')) AND
2259            (p_seg_info.additional_where_clause IS NOT NULL)) then
2260       --
2261       -- Similar to Table validation.
2262       --
2263 
2264       IF (fnd_flex_server1.g_debug_level > 0) THEN
2265          add_debug('~F(' || p_vs_info.valtype || ')');
2266       END IF;
2267 
2268       v_code := table_validate(p_str_info, p_seg_info, p_vs_info,
2269                                p_vdate, p_parent_val,
2270                                p_char_val, p_is_value,
2271                                p_n_prev, p_prev_dispvals, p_prev_vals,
2272                                p_prev_ids, p_prev_descs, p_prev_segnames,
2273                                p_prev_vsnames, check_value_table, this_value);
2274 
2275       --  table_validate() does not set error message if the problem is
2276       --  that the value is not found because we might have to look up
2277       --  the value in the values table.  Therefore we need to set the
2278       --  error if value was not found.
2279       if(v_code = FF_VNOTFOUND) then
2280          if(p_is_value) then
2281             value_error_name('FND', 'FLEX-VALUE DOES NOT EXIST');
2282 
2283             value_error_token('VALUESET', p_vs_info.vsname);
2284             value_error_token('SEGMENT', p_this_segname);
2285             value_error_token('VALUE', msg_val(p_vs_info.vsformat, p_vs_info.maxsize, p_vs_info.precis, p_vs_info.lettersok, p_char_val));
2286           else
2287             value_error_name('FND', 'FLEX-ID DOES NOT EXIST');
2288 
2289             value_error_token('ID', p_char_val);
2290             value_error_token('SEGMENT', p_this_segname);
2291             value_error_token('VALUESET', p_vs_info.vsname);
2292          end if;
2293       end if;
2294 
2295     ELSIF ((p_vs_info.valtype in ('X', 'Y'))  AND
2296            (p_seg_info.additional_where_clause IS NOT NULL)) THEN
2297 
2298       --
2299       -- Similar to Table validation.
2300       --
2301 
2302       IF (fnd_flex_server1.g_debug_level > 0) THEN
2303          add_debug('~F(' || p_vs_info.valtype || ')');
2304       END IF;
2305 
2306       v_code := table_validate(p_str_info, p_seg_info, p_vs_info,
2307                                p_vdate, p_parent_val,
2308                                p_char_val, p_is_value,
2309                                p_n_prev, p_prev_dispvals, p_prev_vals,
2310                                p_prev_ids, p_prev_descs, p_prev_segnames,
2311                                p_prev_vsnames, check_value_table, this_value);
2312 
2313       --  table_validate() does not set error message if the problem is
2314       --  that the value is not found because we might have to look up
2315       --  the value in the values table.  Therefore we need to set the
2316       --  error if value was not found.
2317       if(v_code = FF_VNOTFOUND) then
2318          if(p_is_value) then
2319             value_error_name('FND', 'FLEX-VALUE DOES NOT EXIST');
2320 
2321             value_error_token('VALUESET', p_vs_info.vsname);
2322             value_error_token('SEGMENT', p_this_segname);
2323             value_error_token('VALUE', msg_val(p_vs_info.vsformat, p_vs_info.maxsize, p_vs_info.precis, p_vs_info.lettersok, p_char_val));
2324           else
2325             value_error_name('FND', 'FLEX-ID DOES NOT EXIST');
2326 
2327             value_error_token('ID', p_char_val);
2328             value_error_token('SEGMENT', p_this_segname);
2329             value_error_token('VALUESET', p_vs_info.vsname);
2330          end if;
2331       end if;
2332 
2333       -- Table validation.
2334       --
2335     ELSIF (p_vs_info.valtype = 'F') then
2336 
2337       IF (fnd_flex_server1.g_debug_level > 0) THEN
2338          add_debug('F');
2339       END IF;
2340 
2341       v_code := table_validate(p_str_info, p_seg_info, p_vs_info,
2342                                p_vdate, p_parent_val,
2343                                p_char_val, p_is_value,
2344                                p_n_prev, p_prev_dispvals, p_prev_vals,
2345                                p_prev_ids, p_prev_descs, p_prev_segnames,
2346                                p_prev_vsnames, check_value_table, this_value);
2347 
2348       if((v_code = FF_VNOTFOUND) and (check_value_table = TRUE)) then
2349          open IND_cursor(p_vs_info.vsid, p_char_val);
2350          fetch IND_cursor into this_value.enabled_flag, this_value.start_valid,
2351            this_value.end_valid, this_value.summary_flag,
2352            this_value.compiled_attributes, this_value.description;
2353          if(IND_cursor%FOUND) then
2354             this_value.stored_value := p_char_val;
2355             this_value.hidden_id := p_char_val;
2356             v_code := FF_VVALID;
2357          end if;
2358          close IND_cursor;
2359       end if;
2360 
2361       --  table_validate() does not set error message if the problem is
2365       if(v_code = FF_VNOTFOUND) then
2362       --  that the value is not found because we might have to look up
2363       --  the value in the values table.  Therefore we need to set the
2364       --  error if value was not found.
2366          if(p_is_value) then
2367             value_error_name('FND', 'FLEX-VALUE DOES NOT EXIST');
2368 
2369             value_error_token('VALUESET', p_vs_info.vsname);
2370             value_error_token('SEGMENT', p_this_segname);
2371             value_error_token('VALUE', msg_val(p_vs_info.vsformat, p_vs_info.maxsize, p_vs_info.precis, p_vs_info.lettersok, p_char_val));
2372           else
2373             value_error_name('FND', 'FLEX-ID DOES NOT EXIST');
2374 
2375             value_error_token('ID', p_char_val);
2376             value_error_token('SEGMENT', p_this_segname);
2377             value_error_token('VALUESET', p_vs_info.vsname);
2378          end if;
2379       end if;
2380 
2381       -- Pair or Special validation unsupported.
2382       --
2383     ELSIF (p_vs_info.valtype in ('P', 'U')) then
2384       FND_MESSAGE.set_name('FND', 'FLEX-SSV UNSUPPORTED VDATION');
2385       FND_MESSAGE.set_token('VSNAME', p_vs_info.vsname);
2386       v_code := FF_VUNKNOWN;
2387 
2388       -- Undefined validation type
2389       --
2390     else
2391       FND_MESSAGE.set_name('FND', 'FLEX-VS BAD VDATION TYPE');
2392       FND_MESSAGE.set_token('VSNAME', p_vs_info.vsname);
2393       FND_MESSAGE.set_token('VTYPE', p_vs_info.valtype);
2394       v_code := FF_VERROR;
2395    end if;
2396 
2397    <<return_found_value>>
2398    if(v_code = FF_VVALID) THEN
2399       v_code := stored_to_displayed(p_vs_info.vsformat, p_vs_info.maxsize, p_vs_info.precis,
2400                                     p_vs_info.lettersok,
2401                                     this_value.stored_value,
2402                                     this_value.displayed_value);
2403    end if;
2404    x_this_val_out := this_value;
2405    IF (fnd_flex_server1.g_debug_level > 0) THEN
2406       FND_FLEX_SERVER1.add_debug('END SV1.find_value(returns:' ||
2407                                  v_code || ')');
2408    END IF;
2409 
2410    return(v_code);
2411 EXCEPTION
2412    WHEN OTHERS then
2413       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
2414       FND_MESSAGE.set_token('MSG', 'find_value() exception:  ' || SQLERRM);
2415       IF (fnd_flex_server1.g_debug_level > 0) THEN
2416          FND_FLEX_SERVER1.add_debug('EXCEPTION others SV1.find_value()');
2417       END IF;
2418 
2419       return(FF_VERROR);
2420 END find_value;
2421 
2422 /* ----------------------------------------------------------------------- */
2423 /*      Finds value from table validated value set.                        */
2424 /*      Returns value error code and sets message on error.                */
2425 /*      However, if value is not found, does not set the error message     */
2426 /*      because we may have to look it up in the values table if           */
2427 /*      check_valtab is returned as 'Y'                                    */
2428 /*      NOTE:  where_clause declared as VARCHAR2(30000) for implicit       */
2429 /*      conversion from LONG column type in the table.                     */
2430 /*      Generic exception raised if SQL fragment in where_clause is bad.   */
2431 /* ----------------------------------------------------------------------- */
2432 FUNCTION table_validate(p_str_info            IN  FlexStructId,
2433                         p_seg_info            IN  SegmentInfo,
2434                         p_vs_info             IN  ValueSetInfo,
2435                         p_vdate               IN  DATE,
2436                         p_parent_value        IN  VARCHAR2,
2437                         p_charval             IN  VARCHAR2,
2438                         p_is_value            IN  BOOLEAN,
2439                         p_nprev               IN  NUMBER,
2440                         p_prev_dispvals       IN  ValueArray,
2441                         p_prev_vals           IN  ValueArray,
2442                         p_prev_ids            IN  ValueIdArray,
2443                         p_prev_descs          IN  ValueDescArray,
2444                         p_prev_segnames       IN  SegNameArray,
2445                         p_prev_vsnames        IN  VsNameArray,
2446                         x_check_valtab        OUT nocopy BOOLEAN,
2447                         x_found_value         OUT nocopy FlexValue)
2448   RETURN VARCHAR2
2449   IS
2450      l_where_clause          VARCHAR2(32000);
2451      l_tmp_where_clause      VARCHAR2(32000);
2452      l_order_by_pos          NUMBER;
2453 
2454      l_vcode                 VARCHAR2(1);
2455      l_sql                   VARCHAR2(32000);
2456      l_nrecords              NUMBER;
2457      l_results               StringArray;
2458 
2459      CURSOR tbl_cursor(p_flex_value_set_id IN NUMBER) IS
2460         SELECT application_table_name, value_column_name, value_column_type,
2461           id_column_name, id_column_type, meaning_column_name,
2462           meaning_column_type, enabled_column_name, start_date_column_name,
2463           end_date_column_name, summary_column_name,
2464           compiled_attribute_column_name, additional_quickpick_columns,
2465           summary_allowed_flag, additional_where_clause
2466           FROM fnd_flex_validation_tables
2467           WHERE flex_value_set_id = p_flex_value_set_id;
2468 
2469      l_tbl_rec     tbl_cursor%ROWTYPE;
2470      l_sql_pieces  sql_pieces_tab_type;
2471 BEGIN
2472    IF (p_vs_info.valtype IN ('I', 'D', 'X', 'Y')) THEN
2476       l_tbl_rec.id_column_name := NULL;
2473       l_tbl_rec.application_table_name := 'FND_FLEX_VALUES_VL FND_FLEX_VALUES_VL';
2474       l_tbl_rec.value_column_name := 'FND_FLEX_VALUES_VL.FLEX_VALUE';
2475       l_tbl_rec.value_column_type := 'C';
2477       l_tbl_rec.id_column_type := NULL;
2478       l_tbl_rec.meaning_column_name := 'FND_FLEX_VALUES_VL.DESCRIPTION';
2479       l_tbl_rec.meaning_column_type := 'C';
2480       l_tbl_rec.enabled_column_name := 'FND_FLEX_VALUES_VL.ENABLED_FLAG';
2481       l_tbl_rec.start_date_column_name := 'FND_FLEX_VALUES_VL.START_DATE_ACTIVE';
2482       l_tbl_rec.end_date_column_name := 'FND_FLEX_VALUES_VL.END_DATE_ACTIVE';
2483       l_tbl_rec.summary_column_name := 'FND_FLEX_VALUES_VL.SUMMARY_FLAG';
2484       l_tbl_rec.compiled_attribute_column_name := 'FND_FLEX_VALUES_VL.COMPILED_VALUE_ATTRIBUTES';
2485       l_tbl_rec.additional_quickpick_columns := NULL;
2486       l_tbl_rec.summary_allowed_flag := 'N';
2487 
2488       IF (p_parent_value IS NULL) THEN
2489          l_tbl_rec.additional_where_clause := 'WHERE FND_FLEX_VALUES_VL.FLEX_VALUE_SET_ID = :$FLEX$.$VALUE_SET_ID$';
2490        ELSE
2491          l_tbl_rec.additional_where_clause := 'WHERE FND_FLEX_VALUES_VL.FLEX_VALUE_SET_ID = :$FLEX$.$VALUE_SET_ID$' ||
2492            ' AND FND_FLEX_VALUES_VL.PARENT_FLEX_VALUE_LOW = :$FLEX$.$PARENT_VALUE$';
2493       END IF;
2494 
2495     ELSE
2496       open TBL_cursor(p_vs_info.vsid);
2497       FETCH tbl_cursor INTO l_tbl_rec;
2498       IF (TBL_cursor%NOTFOUND) THEN
2499          close TBL_cursor;
2500          FND_MESSAGE.set_name('FND', 'FLEX-SSV MISSING TBLVS');
2501          FND_MESSAGE.set_token('VSNAME', p_vs_info.vsname);
2502          return(FF_VERROR);
2503       end if;
2504       close TBL_cursor;
2505    END IF;
2506 
2507    IF (l_tbl_rec.summary_allowed_flag = 'Y') then
2508       x_check_valtab := TRUE;
2509     else
2510       x_check_valtab := FALSE;
2511    end if;
2512 
2513    --  Return error if unsupported validation.
2514    --
2515    if((l_tbl_rec.additional_quickpick_columns is not null) and (INSTR(UPPER(l_tbl_rec.additional_quickpick_columns),'INTO') > 0)) then
2516       FND_MESSAGE.set_name('FND', 'FLEX-SSV NO TBL VS');
2517       FND_MESSAGE.set_token('VSNAME', p_vs_info.vsname);
2518       return(FF_VUNKNOWN);
2519    end if;
2520 
2521    --  Default column names if null
2522    --
2523    if(l_tbl_rec.id_column_name is null) then
2524       l_tbl_rec.id_column_name := l_tbl_rec.value_column_name;
2525       l_tbl_rec.id_column_type := l_tbl_rec.value_column_type;
2526    end if;
2527 
2528    if(l_tbl_rec.meaning_column_name is null) then
2529       l_tbl_rec.meaning_column_name := 'NULL';
2530       l_tbl_rec.meaning_column_type := 'V';
2531    end if;
2532 
2533    -- Now need to parse where/order by clause.  Clause is of the form:
2534    -- [where <condition>] [order by <ordering>]
2535    -- The order by portion is not relevant here and is dropped.
2536    -- "where" is optional, hence the first word in the string need not be
2537    -- "where".
2538    -- Note there can only be 1 space between "order" and "by".
2539    -- "where" and "order by" are found using case-insensitive comparisons.
2540    -- Case-insensitive comparison requires upper case conversion.
2541    -- Assume SQL strings in single-byte characters only.
2542    -- Substitute $FLEX$ and $PROFILES$ in where clause if its not null.
2543    --
2544    l_where_clause := ltrim(l_tbl_rec.additional_where_clause, WHITESPACE);
2545 
2546    l_sql_pieces.DELETE;
2547    if (l_where_clause is not null) then
2548       -- there is where clause
2549       l_tmp_where_clause := Upper(l_where_clause);
2550 
2551       if (l_tmp_where_clause LIKE 'WHERE%') then
2552          -- It starts with WHERE keyword
2553          -- Skip the leading WHERE keyword
2554          l_where_clause := Substr(l_where_clause, 6);
2555          l_tmp_where_clause := Upper(l_where_clause);
2556       end if;
2557 
2558       l_order_by_pos := Instr(l_tmp_where_clause, 'ORDER BY');
2559       if (l_order_by_pos > 0) then
2560          l_where_clause := Substr(l_where_clause, 1, l_order_by_pos - 1);
2561       end if;
2562 
2563       IF (p_seg_info.additional_where_clause IS NOT NULL) THEN
2564          l_where_clause := '(' || l_where_clause || ') AND (' ||
2565            p_seg_info.additional_where_clause || ')';
2566       END IF;
2567 
2568       l_vcode := substitute_flex_binds5(l_where_clause,
2569                                         p_str_info, p_seg_info,
2570                                         p_vdate, p_parent_value,
2571                                         p_nprev, p_prev_dispvals,
2572                                         p_prev_vals, p_prev_ids, p_prev_descs,
2573                                         p_prev_segnames, p_prev_vsnames,
2574                                         l_sql_pieces);
2575 
2576       if (l_vcode <> FF_VVALID) then
2577          return(l_vcode);
2578       end if;
2579 
2580       IF (fnd_flex_server1.g_debug_level > 0) THEN
2581          l_tmp_where_clause := NULL;
2582          IF (l_vcode = FF_VVALID) THEN
2583             FOR i IN 1 .. l_sql_pieces.COUNT LOOP
2584                IF (l_sql_pieces(i).piece_type = SSP_PIECE_TYPE_BIND) THEN
2585                   l_tmp_where_clause := l_tmp_where_clause ||
2586                     string_clause(l_sql_pieces(i).bind_value);
2587 
2588                 ELSE
2589                   l_tmp_where_clause := l_tmp_where_clause ||
2590                     l_sql_pieces(i).piece_text;
2594 
2591                END IF;
2592             END LOOP;
2593          END IF;
2595          l_where_clause := l_tmp_where_clause;
2596 
2597          if(l_where_clause is not null) then
2598             add_debug(' (where ' || SUBSTRB(l_where_clause, 1, 1000) || ') ');
2599          end if;
2600       END IF;
2601    end if;
2602 
2603    --  Build SQL statement to do the select from the table specified
2604    --  by APPLICATION_TABLE_NAME.
2605    --
2606    --  The columns SUMMARY_COLUMN_NAME, COMPILED_ATTRIBUTE_COLUMN_NAME,
2607    --  ENABLED_COLUMN_NAME, and START and END _DATE_COLUMN_NAME in the
2608    --  FND_FLEX_VALIDATION_TABLES table either contain the name of the
2609    --  column in the "application table" which contains those parameters,
2610    --  or they contain text strings which are part of a sql statement.
2611    --  For example, the COMPILED_ATTRIBUTES_COLUMN_NAME contains either the
2612    --  name of a column, or a SQL fragment of the form: "'Y\nN\nA'" which
2613    --  includes the single quotes.
2614    --
2615    --  In either case the contents of these fields should be blindly
2616    --  inserted into the SQL statement.
2617    --
2618    --  BUG:  To be compatible with client code behavior, we must surround
2619    --  non-character columns with the default to_char() conversion in the
2620    --  select statement.  This causes seconds to be lost from date columns.
2621    --  It also means that numbers are stored and displayed in their default
2622    --  format rather than the value set format.
2623    --
2624    --  This functionality is now in the select_clause() function.
2625    --
2626    l_sql := 'select ' ||
2627      select_clause(l_tbl_rec.value_column_name, l_tbl_rec.value_column_type,
2628                    VC_VALUE, p_vs_info.vsformat, p_vs_info.maxsize);
2629    l_sql := l_sql || ', ' ||
2630      select_clause(l_tbl_rec.id_column_name, l_tbl_rec.id_column_type,
2631                    VC_ID, p_vs_info.vsformat, p_vs_info.maxsize);
2632    l_sql := l_sql || ', ' ||
2633      select_clause(l_tbl_rec.meaning_column_name, l_tbl_rec.meaning_column_type,
2634                    VC_DESCRIPTION, p_vs_info.vsformat, p_vs_info.maxsize);
2635    l_sql := l_sql || ', ' || l_tbl_rec.enabled_column_name || ', ';
2636    l_sql := l_sql || 'to_char(' || l_tbl_rec.start_date_column_name ||',''YYYY/MM/DD HH24:MI:SS'')' || ', ';
2637    l_sql := l_sql || 'to_char(' || l_tbl_rec.end_date_column_name ||',''YYYY/MM/DD HH24:MI:SS'')' || ', ';
2638    l_sql := l_sql || l_tbl_rec.summary_column_name || ', ';
2639    l_sql := l_sql || l_tbl_rec.compiled_attribute_column_name;
2640    l_sql := l_sql || ' from ' || l_tbl_rec.application_table_name || ' where ';
2641 
2642    fnd_dsql.init;
2643    fnd_dsql.add_text(l_sql);
2644 
2645    --
2646    -- The where clause needs to be surrounded by parentheses so we can
2647    -- add additional restrictions using AND without overriding ORs inside it.
2648    --
2649    IF (l_sql_pieces.COUNT > 0) THEN
2650       fnd_dsql.add_text('(');
2651 
2652       FOR i IN 1 .. l_sql_pieces.COUNT LOOP
2653          IF (l_sql_pieces(i).piece_type = SSP_PIECE_TYPE_BIND) THEN
2654             fnd_dsql.add_bind(l_sql_pieces(i).bind_value);
2655           ELSE
2656             fnd_dsql.add_text(l_sql_pieces(i).piece_text);
2657          END IF;
2658       END LOOP;
2659 
2660       fnd_dsql.add_text(') and ');
2661    END IF;
2662 
2663    -- Build comparison appropriate for data type of value or id column
2664    --
2665    if(p_is_value) THEN
2666       fnd_dsql.add_text(l_tbl_rec.value_column_name || ' = ');
2667       x_compare_clause(l_tbl_rec.value_column_type, l_tbl_rec.value_column_name, p_charval,
2668                        VC_VALUE, p_vs_info.vsformat, p_vs_info.maxsize);
2669     else
2670       fnd_dsql.add_text(l_tbl_rec.id_column_name || ' = ');
2671       x_compare_clause(l_tbl_rec.id_column_type, l_tbl_rec.id_column_name, p_charval,
2672                        VC_ID, p_vs_info.vsformat, p_vs_info.maxsize);
2673    end if;
2674 
2675    --  Select the value from the user's table.
2676    --
2677    l_nrecords := x_dsql_select(8, l_results);
2678 
2679    if(l_nrecords > 0) then
2680       x_found_value.format := p_vs_info.vsformat;
2681       x_found_value.stored_value := l_results(1);
2682       x_found_value.hidden_id := l_results(2);
2683       x_found_value.description := l_results(3);
2684       x_found_value.enabled_flag := l_results(4);
2685       x_found_value.start_valid := to_date(l_results(5),'YYYY/MM/DD HH24:MI:SS');
2686       x_found_value.end_valid := to_date(l_results(6),'YYYY/MM/DD HH24:MI:SS');
2687       x_found_value.summary_flag := l_results(7);
2688       x_found_value.compiled_attributes := l_results(8);
2689       return(FF_VVALID);
2690     elsif(l_nrecords = 0) then
2691       return(FF_VNOTFOUND);
2692     else
2693       return(FF_VERROR);
2694    end if;
2695 
2696    return(FF_VERROR);
2697 
2698 EXCEPTION
2699    WHEN OTHERS then
2700       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
2701       FND_MESSAGE.set_token('MSG', 'table_validate() exception:  ' || SQLERRM);
2702       return(FF_VERROR);
2703 
2704 END table_validate;
2705 
2706 /* ----------------------------------------------------------------------- */
2707 /*      Returns the default value for this segment in displayed format.    */
2708 /*      For defaulting current date and current time into non-translatable */
2709 /*      date value sets, use the format based on the maximum size of the   */
2713 /*      succeeded, FF_VUNKNOWN if unsupported or FF_VERROR.                */
2710 /*      value set field alone.                                             */
2711 /*      Let ordinary value validation catch problems with the format       */
2712 /*      or length of the defaulted value.  Returns FF_VVALID if default    */
2714 /* ----------------------------------------------------------------------- */
2715 FUNCTION default_val(def_type         IN  VARCHAR2,
2716                      def_text         IN  VARCHAR2,
2717                      valset_fmt       IN  VARCHAR2,
2718                      valset_len       IN  NUMBER,
2719                      valset_precis    IN  NUMBER,
2720                      valset_lettersok IN VARCHAR2,
2721                      seg_name         IN  VARCHAR2,
2722                      nprev            IN  NUMBER,
2723                      prev_dispvals    IN  ValueArray,
2724                      prev_vals        IN  ValueArray,
2725                      prev_ids         IN  ValueIdArray,
2726                      prev_descs       IN  ValueDescArray,
2727                      prev_segnames    IN  SegNameArray,
2728                      prev_vsnames     IN  VsNameArray,
2729                      displayed_val    OUT nocopy VARCHAR2)
2730   RETURN VARCHAR2 IS
2731      nfound        NUMBER;
2732      v_code        VARCHAR2(1);
2733      datefmt       VARCHAR2(30);
2734      stored_val    VARCHAR2(1000);
2735      sql_string    VARCHAR2(2000);
2736      l_sql_pieces  sql_pieces_tab_type;
2737 BEGIN
2738    v_code := FF_VERROR;
2739 
2740    IF (def_type is null) then
2741       v_code := FF_VVALID;
2742     ELSIF (def_type = 'C') then
2743       --  Constant
2744       stored_val := SUBSTRB(def_text, 1, 1000);
2745       v_code := FF_VVALID;
2746 
2747     ELSIF (def_type = 'D') then
2748       -- Current date.
2749       IF (valset_fmt in ('X', 'Y')) then
2750          datefmt := stored_date_format(valset_fmt, valset_len);
2751        ELSIF (valset_len >= 11) then
2752          datefmt := stored_date_format('D', 11);
2753        else
2754          datefmt := stored_date_format('D', 9);
2755       end if;
2756       stored_val := to_char(sysdate, datefmt);
2757       v_code := FF_VVALID;
2758 
2759     ELSIF (def_type = 'T') then
2760       -- Current time or date-time depending on the size
2761       IF (valset_fmt in ('Y', 'Z')) then
2762          datefmt := stored_date_format(valset_fmt, valset_len);
2763        ELSIF (valset_len < 8) then
2764          datefmt := stored_date_format('I', 5);
2765        ELSIF (valset_len between 8 and 14) then
2766          datefmt := stored_date_format('I', 8);
2767        ELSIF (valset_len between 15 and 16) then
2768          datefmt := stored_date_format('T', 15);
2769        ELSIF (valset_len = 17) then
2770          datefmt := stored_date_format('T', 17);
2771        ELSIF (valset_len between 18 and 19) then
2772          datefmt := stored_date_format('T', 18);
2773        else
2774          datefmt := stored_date_format('T', 20);
2775       end if;
2776       stored_val := to_char(sysdate, datefmt);
2777       v_code := FF_VVALID;
2778 
2779     ELSIF (def_type = 'P') then
2780       sql_string := ':$PROFILES$.' || def_text;
2781       v_code := convert_bind_token(sql_string, nprev,
2782                                    prev_dispvals, prev_vals,
2783                                    prev_ids, prev_descs,
2784                                    prev_segnames, prev_vsnames,
2785                                    stored_val);
2786 
2787     ELSIF ((def_type = 's') OR (def_type = 'A')) then
2788       sql_string := ':$FLEX$.' || def_text;
2789       v_code := convert_bind_token(sql_string, nprev,
2790                                    prev_dispvals, prev_vals,
2791                                    prev_ids, prev_descs,
2792                                    prev_segnames, prev_vsnames,
2793                                    stored_val);
2794 
2795     ELSIF (def_type = 'S') then
2796       -- SQL statement
2797       v_code := substitute_flex_binds3(def_text, nprev,
2798                                        prev_dispvals, prev_vals,
2799                                        prev_ids, prev_descs,
2800                                        prev_segnames, prev_vsnames,
2801                                        l_sql_pieces);
2802       IF (v_code = FF_VVALID) THEN
2803          fnd_dsql.init;
2804 
2805          FOR i IN 1 .. l_sql_pieces.COUNT LOOP
2806             IF (l_sql_pieces(i).piece_type = SSP_PIECE_TYPE_BIND) THEN
2807                fnd_dsql.add_bind(l_sql_pieces(i).bind_value);
2808              ELSE
2809                fnd_dsql.add_text(l_sql_pieces(i).piece_text);
2810             END IF;
2811          END LOOP;
2812 
2813          nfound := x_dsql_select_one(stored_val);
2814          IF (nfound > 1) then
2815             FND_MESSAGE.set_name('FND', 'FLEX-DFLT MULTIPLE SQL ROWS');
2816             FND_MESSAGE.set_token('SQLSTR', SUBSTRB(fnd_dsql.get_text(FALSE), 1, 1000));
2817             v_code := FF_VERROR;
2818           ELSIF (nfound < 0) then
2819             v_code := FF_VERROR;
2820           else
2821             v_code := FF_VVALID;
2822          end if;
2823       end if;
2824 
2825     ELSIF (def_type = 'F') then
2826       -- 'F' => :block.field (the colon may or may not be in the def_text string)
2827       FND_MESSAGE.set_name('FND', 'FLEX-SSV UNSUPPORTED DEFAULT');
2828       v_code := FF_VUNKNOWN;
2829 
2830     ELSIF (def_type = 'E') then
2831       -- Environment variable
2835     ELSE
2832       FND_MESSAGE.set_name('FND', 'FLEX-SSV UNSUPPORTED DEFAULT');
2833       v_code := FF_VUNKNOWN;
2834 
2836       -- Unknown type.
2837       FND_MESSAGE.set_name('FND', 'FLEX-INVALID DEFAULT TYPE');
2838       FND_MESSAGE.set_token('SEGNAME', seg_name);
2839       v_code := FF_VERROR;
2840 
2841    END IF;
2842 
2843    IF (v_code = FF_VVALID) then
2844       v_code := stored_to_displayed(valset_fmt, valset_len, valset_precis,
2845                                     valset_lettersok,
2846                                     stored_val, displayed_val);
2847    end if;
2848    return(v_code);
2849 EXCEPTION
2850    WHEN OTHERS then
2851       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
2852       FND_MESSAGE.set_token('MSG', 'default_val() exception:  ' || SQLERRM);
2853       return(FF_VERROR);
2854 END default_val;
2855 
2856 /* ------------------------------------------------------------------------- */
2857 /*      Interprets $PROFILES$ in where token passed into FND_KEY_FLEX.DEFINE */
2858 /*      This cannot take $FLEX$, and :block.field is unsupported.            */
2859 /*      Returns Validataion error codes VV_VALID if ok, VV_UNSUPPORTED       */
2860 /*      if unsupported, or VV_ERROR if other error.                          */
2861 /* ------------------------------------------------------------------------- */
2862 
2863 FUNCTION parse_where_token(clause_in  IN  VARCHAR2,
2864                           clause_out OUT nocopy VARCHAR2) RETURN NUMBER IS
2865 vcode         VARCHAR2(1);
2866 dummy_dispvls ValueArray;
2867 dummy_vals    ValueArray;
2868 dummy_ids     ValueIdArray;
2869 dummy_descs   ValueDescArray;
2870 dummy_segname SegNameArray;
2871 dummy_vsnames VsNameArray;
2872      l_sql_pieces  sql_pieces_tab_type;
2873 
2874 BEGIN
2875 
2876 if(clause_in is not null) then
2877   if(INSTR(clause_in, ':$FLEX$') > 0) then
2878     FND_MESSAGE.set_name('FND', 'FLEX-NO FLEX IN WHERE TOKEN');
2879     return(VV_ERROR);
2880   end if;
2881   vcode := substitute_flex_binds3(clause_in, 0,
2882                                   dummy_dispvls, dummy_vals,
2883                                   dummy_ids, dummy_descs,
2884                                   dummy_segname, dummy_vsnames,
2885                                   l_sql_pieces);
2886 
2887   clause_out := NULL;
2888   IF (vcode = FF_VVALID) THEN
2889      FOR i IN 1 .. l_sql_pieces.COUNT LOOP
2890         IF (l_sql_pieces(i).piece_type = SSP_PIECE_TYPE_BIND) THEN
2891            clause_out := clause_out ||
2892              string_clause(l_sql_pieces(i).bind_value);
2893 
2894          ELSE
2895            clause_out := clause_out ||
2896              l_sql_pieces(i).piece_text;
2897         END IF;
2898      END LOOP;
2899   END IF;
2900 
2901   if(vcode = FF_VVALID) then
2902     return(VV_VALID);
2903   elsif(vcode = FF_VUNKNOWN) then
2904     return(VV_UNSUPPORTED);
2905   else
2906     return(VV_ERROR);
2907   end if;
2908 end if;
2909 return(VV_VALID);
2910 
2911 EXCEPTION
2912   WHEN OTHERS then
2913     FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
2914     FND_MESSAGE.set_token('MSG', 'parse_where_token() exception: '||SQLERRM);
2915     return(VV_ERROR);
2916 
2917 END parse_where_token;
2918 
2919 /* ------------------------------------------------------------------------ */
2920 /*      Takes input string possibly containing special flex bind variables  */
2921 /*      of :$PROFILES$.<profile>, :$FLEX$.<name>[.<output>] or :block.field */
2922 /*      and substitutes the flex values for them.  Some substitutions such  */
2923 /*      as :block.field cannot be handled on the server and results in an   */
2924 /*      FF_VUNKNOWN being returned.                                         */
2925 /*                                                                          */
2926 /*      Input string can contain quoted regions, within which no            */
2927 /*      substitutions should be performed.  The regions are marked by       */
2928 /*      single quotes.  Double quotes within these regions represent        */
2929 /*      the quote character.                                                */
2930 /*                                                                          */
2931 /*       Limitations:  string_in, string_out up to 30,000 bytes.            */
2932 /*                     bind_token and bind_value up to 2000 bytes.          */
2933 /*                                                                          */
2934 /*      Returns FF_VVALID if default succeeded, FF_VUNKNOWN if unsupported  */
2935 /*      or FF_VERROR on error.                                              */
2936 /* ------------------------------------------------------------------------ */
2937 FUNCTION substitute_flex_binds3(p_string_in     IN VARCHAR2,
2938                                 p_nprev         IN NUMBER,
2939                                 p_prev_dispvals IN ValueArray,
2940                                 p_prev_vals     IN ValueArray,
2941                                 p_prev_ids      IN ValueIdArray,
2942                                 p_prev_descs    IN ValueDescArray,
2943                                 p_prev_segnames IN SegNameArray,
2944                                 p_prev_vsnames  IN VsNameArray,
2945                                 px_sql_pieces   in out nocopy sql_pieces_tab_type)
2946   RETURN VARCHAR2
2947   IS
2948      v_code        VARCHAR2(1);
2949 BEGIN
2950    IF (fnd_flex_server1.g_debug_level > 0) THEN
2951       add_debug('BEGIN SV1.substitute_flex_binds3('''||
2955    BEGIN
2952                 SUBSTRB(p_string_in, 1, 500) || ''' ');
2953    END IF;
2954 
2956       parse_sql_string(p_string_in, px_sql_pieces);
2957    EXCEPTION
2958       WHEN OTHERS THEN
2959          RETURN(FF_VERROR);
2960    END;
2961 
2962    --
2963    -- Derive bind values
2964    --
2965    FOR i IN 1 .. px_sql_pieces.COUNT LOOP
2966       IF (px_sql_pieces(i).piece_type = SSP_PIECE_TYPE_BIND) THEN
2967          v_code := convert_bind_token(px_sql_pieces(i).piece_text,
2968                                       p_nprev, p_prev_dispvals,
2969                                       p_prev_vals, p_prev_ids, p_prev_descs,
2970                                       p_prev_segnames, p_prev_vsnames,
2971                                       px_sql_pieces(i).bind_value);
2972 
2973          IF (v_code <> FF_VVALID) then
2974             return(v_code);
2975          end if;
2976       END IF;
2977    END LOOP;
2978 
2979    return(FF_VVALID);
2980 
2981 EXCEPTION
2982    WHEN OTHERS then
2983       IF (fnd_flex_server1.g_debug_level > 0) THEN
2984          add_debug('EXCEPTION SV1.substitute_flex_binds3()');
2985       END IF;
2986       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
2987       FND_MESSAGE.set_token('MSG', 'substitute_flex_binds3() exception:  '
2988                             || SQLERRM);
2989       return(FF_VERROR);
2990 END substitute_flex_binds3;
2991 
2992 --
2993 -- The one with extension support.
2994 --
2995 /* ------------------------------------------------------------------------ */
2996 FUNCTION substitute_flex_binds5(p_string_in     IN VARCHAR2,
2997                                 p_str_info      IN FlexStructId,
2998                                 p_seg_info      IN SegmentInfo,
2999                                 p_vdate         IN DATE,
3000                                 p_parent_value  IN VARCHAR2,
3001                                 p_nprev         IN NUMBER,
3002                                 p_prev_dispvals IN ValueArray,
3003                                 p_prev_vals     IN ValueArray,
3004                                 p_prev_ids      IN ValueIdArray,
3005                                 p_prev_descs    IN ValueDescArray,
3006                                 p_prev_segnames IN SegNameArray,
3007                                 p_prev_vsnames  IN VsNameArray,
3008                                 px_sql_pieces   in out nocopy sql_pieces_tab_type)
3009   RETURN VARCHAR2
3010   IS
3011      v_code        VARCHAR2(1);
3012 BEGIN
3013    IF (fnd_flex_server1.g_debug_level > 0) THEN
3014       add_debug('BEGIN SV1.substitute_flex_binds5('''||
3015                 SUBSTRB(p_string_in, 1, 500) || ''' ');
3016    END IF;
3017 
3018    BEGIN
3019       parse_sql_string(p_string_in, px_sql_pieces);
3020    EXCEPTION
3021       WHEN OTHERS THEN
3022          RETURN(FF_VERROR);
3023    END;
3024 
3025    --
3026    -- Derive bind values
3027    --
3028    FOR i IN 1 .. px_sql_pieces.COUNT LOOP
3029       IF (px_sql_pieces(i).piece_type = SSP_PIECE_TYPE_BIND) THEN
3030          v_code := convert_bind_token2(px_sql_pieces(i).piece_text,
3031                                        p_str_info, p_seg_info,
3032                                        p_vdate, p_parent_value,
3033                                        p_nprev, p_prev_dispvals,
3034                                        p_prev_vals, p_prev_ids, p_prev_descs,
3035                                        p_prev_segnames, p_prev_vsnames,
3036                                        px_sql_pieces(i).bind_value);
3037 
3038          IF (v_code <> FF_VVALID) then
3039             return(v_code);
3040          end if;
3041       END IF;
3042    END LOOP;
3043 
3044    return(FF_VVALID);
3045 
3046 EXCEPTION
3047    WHEN OTHERS then
3048       IF (fnd_flex_server1.g_debug_level > 0) THEN
3049          add_debug('EXCEPTION SV1.substitute_flex_binds5()');
3050       END IF;
3051       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3052       FND_MESSAGE.set_token('MSG', 'substitute_flex_binds5() exception:  '
3053                             || SQLERRM);
3054       return(FF_VERROR);
3055 END substitute_flex_binds5;
3056 
3057 /* ----------------------------------------------------------------------- */
3058 /*      Converts a flex bind token to its character string value.          */
3059 /*      Bind tokens begin with a colon and are of the form:                */
3060 /*      :$FLEX$.<vsname>[.<portion>] or :$PROFILES$.<profile_name>         */
3061 /*      If [.<portion>] not specified uses the ID not the VALUE.           */
3062 /*      Note server can never handle :BLOCK.FIELD                          */
3063 /*      Returns FF_VVALID if substitution succeeded, FF_VUNKNOWN if        */
3064 /*      unsupported or FF_VERROR on error.                                 */
3065 /* ----------------------------------------------------------------------- */
3066 FUNCTION convert_bind_token(bind_token    IN  VARCHAR2,
3067                             nprev         IN  NUMBER,
3068                             prev_dispvals IN  ValueArray,
3069                             prev_vals     IN  ValueArray,
3070                             prev_ids      IN  ValueIdArray,
3071                             prev_descs    IN  ValueDescArray,
3072                             prev_segnames IN  SegNameArray,
3073                             prev_vsnames  IN  VsNameArray,
3074                             bind_value    OUT nocopy VARCHAR2)
3075   RETURN VARCHAR2
3079      seg_portion   VARCHAR2(30);
3076   IS
3077      bind_val      VARCHAR2(2000);
3078      seg_name      VARCHAR2(60);
3080      dot_pointer   NUMBER;
3081      col_pointer   NUMBER;
3082      l_length      NUMBER;
3083      s_index       BINARY_INTEGER;
3084      l_return_code VARCHAR2(100);
3085 
3086 BEGIN
3087    --  Determine character string value of bind token.
3088    -- :$PROFILES$.<name> where <name> is case-insensitive profile option name.
3089    -- :$FLEX$.<name>[.<portion>] where name is case-sensitive, but portion not.
3090    -- :BLOCK.FIELD causes return of FF_VUNKNOWN error.
3091    --
3092    IF (fnd_flex_server1.g_debug_level > 0) THEN
3093       add_debug('BEGIN SV1.convert_bind_token(token=' || bind_token || ')');
3094    END IF;
3095 
3096    IF (INSTR(bind_token, ':$PROFILES$.') = 1) then
3097       FND_PROFILE.get(UPPER(SUBSTR(bind_token, 13)), bind_val);
3098 
3099     ELSIF (INSTR(bind_token, ':$FLEX$.') = 1) then
3100 
3101       -- If default segment name is of the form <name>.ID, <name>.VALUE
3102       -- or <name>.MEANING, then break it into seg_name and seg_portion.
3103       -- Note ID, VALUE and MEANING are all case insensitive
3104       --
3105       -- Bug 1783461: Flexfield API does not handle :NULL suffix.
3106       -- the original code did not strip off the variables after the value set/
3107       -- or segment name and when used resulted in a "ORA-20001 The data that
3108       -- defines the flexfield may be inconsistent".
3109       -- The syntax for using bind variables in the default where clause of a
3110       -- value set is as follows (for $FLEX$);
3111       --
3112       --    :$FLEX$.[valuesetname|segmentname][.ID|.VALUE|.MEANING][:NULL]
3113 
3114       dot_pointer := INSTR(bind_token, '.', 9);
3115       col_pointer := INSTR(bind_token,':NULL',9);
3116       l_length := length(bind_token);
3117       if (dot_pointer > 0) then
3118          if (col_pointer > 0) then
3119             null;
3120           else
3121             col_pointer := l_length + 1;
3122          end if;
3123        else
3124          if (col_pointer > 0) then
3125             dot_pointer := col_pointer;
3126           else
3127             dot_pointer := l_length + 1;
3128             col_pointer := l_length + 1;
3129          end if;
3130       end if;
3131 
3132       if (dot_pointer > col_pointer) then
3133          FND_MESSAGE.set_name('FND','FLEX-INVALID PORTION');
3134          FND_MESSAGE.set_token('BTOKEN',bind_token);
3135          l_return_code := FF_VERROR;
3136          GOTO goto_return;
3137       end if;
3138 
3139       seg_name := SUBSTR(bind_token,9,dot_pointer-9);
3140       seg_portion := SUBSTR(bind_token,dot_pointer+1,col_pointer-dot_pointer-1);
3141 
3142       if (seg_portion is null) then
3143          seg_portion := 'ID';
3144       end if;
3145 
3146       -- Find index to previous segment or 0 if previous segment not found.
3147       -- Previous segment value set name or segment name.
3148       --
3149       s_index := 0;
3150       for i in reverse 1..nprev loop
3151          if((prev_segnames(i) = seg_name) or (prev_vsnames(i) = seg_name)) then
3152             s_index := i;
3153             exit;
3154          end if;
3155       end loop;
3156 
3157       -- Copy value, id or meaning to output if found, otherwise error.
3158       --
3159       if(s_index > 0) then
3160          if(seg_portion = 'VALUE') then
3161             bind_val := prev_vals(s_index);
3162           elsif(seg_portion = 'ID') then
3163             bind_val := prev_ids(s_index);
3164           elsif(seg_portion = 'MEANING') then
3165             bind_val := prev_descs(s_index);
3166           else
3167             FND_MESSAGE.set_name('FND', 'FLEX-INVALID PORTION');
3168             FND_MESSAGE.set_token('BTOKEN', bind_token);
3169             l_return_code := FF_VERROR;
3170             GOTO goto_return;
3171          end if;
3172        else
3173          FND_MESSAGE.set_name('FND', 'FLEX-PRIOR SEG NOTFOUND');
3174          FND_MESSAGE.set_token('BTOKEN', bind_token);
3175          l_return_code := FF_VERROR;
3176          GOTO goto_return;
3177       end if;
3178 
3179     else
3180 
3181       -- :BLOCK.FIELD cannot be handled here
3182       --
3183       FND_MESSAGE.set_name('FND', 'FLEX-UNSUPPORTED FLEX BIND');
3184       l_return_code := FF_VUNKNOWN;
3185       GOTO goto_return;
3186 
3187    end if;
3188 
3189    bind_value := bind_val;
3190    l_return_code := FF_VVALID;
3191 
3192    <<goto_return>>
3193      IF (fnd_flex_server1.g_debug_level > 0) THEN
3194         add_debug('END SV1.convert_bind_token(value=' || bind_val || ')');
3195      END IF;
3196      RETURN(l_return_code);
3197 EXCEPTION
3198    WHEN OTHERS then
3199       IF (fnd_flex_server1.g_debug_level > 0) THEN
3200          add_debug('EXCEPTION others SV1.convert_bind_token()');
3201       END IF;
3202       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3203       FND_MESSAGE.set_token('MSG','convert_bind_token() exception: '||SQLERRM);
3204       return(FF_VERROR);
3205 END convert_bind_token;
3206 
3207 --
3208 -- The one with extension support.
3209 --
3210 FUNCTION convert_bind_token2(p_bind_token    IN  VARCHAR2,
3211                              p_str_info      IN  FlexStructId,
3212                              p_seg_info      IN  SegmentInfo,
3216                              p_prev_dispvals IN  ValueArray,
3213                              p_vdate         IN  DATE,
3214                              p_parent_value  IN  VARCHAR2,
3215                              p_nprev         IN  NUMBER,
3217                              p_prev_vals     IN  ValueArray,
3218                              p_prev_ids      IN  ValueIdArray,
3219                              p_prev_descs    IN  ValueDescArray,
3220                              p_prev_segnames IN  SegNameArray,
3221                              p_prev_vsnames  IN  VsNameArray,
3222                              x_bind_value    OUT nocopy VARCHAR2)
3223   RETURN VARCHAR2
3224   IS
3225      l_bind_value  VARCHAR2(2000);
3226      l_return_code VARCHAR2(100);
3227 
3228 BEGIN
3229    IF (fnd_flex_server1.g_debug_level > 0) THEN
3230       add_debug('BEGIN SV1.convert_bind_token2(bind=' || p_bind_token || ')');
3231    END IF;
3232 
3233    l_bind_value := NULL;
3234    IF (p_bind_token = ':$FLEX$.$VDATE$') THEN
3235       IF (p_vdate IS NULL) THEN
3236          l_bind_value := NULL;
3237        ELSE
3238          l_bind_value := To_char(p_vdate, 'YYYY/MM/DD HH24:MI:SS');
3239       END IF;
3240 
3241     ELSIF (p_bind_token = ':$FLEX$.$APPLICATION_ID$') THEN
3242       l_bind_value := p_str_info.application_id;
3243 
3244     ELSIF (p_bind_token = ':$FLEX$.$ID_FLEX_CODE$') THEN
3245       IF (p_str_info.isa_key_flexfield) THEN
3246          l_bind_value := p_str_info.id_flex_code;
3247       END IF;
3248 
3249     ELSIF (p_bind_token = ':$FLEX$.$ID_FLEX_NUM$') THEN
3250       IF (p_str_info.isa_key_flexfield) THEN
3251          l_bind_value := p_str_info.id_flex_num;
3252       END IF;
3253 
3254     ELSIF (p_bind_token = ':$FLEX$.$APPLICATION_COLUMN_NAME$') THEN
3255       l_bind_value := p_seg_info.colname;
3256 
3257     ELSIF (p_bind_token = ':$FLEX$.$VALUE_SET_ID$') THEN
3258       l_bind_value := p_seg_info.vsid;
3259 
3260     ELSIF (p_bind_token = ':$FLEX$.$PARENT_VALUE$') THEN
3261       l_bind_value := p_parent_value;
3262 
3263     ELSE
3264       l_return_code := convert_bind_token(p_bind_token, p_nprev,
3265                                           p_prev_dispvals, p_prev_vals,
3266                                           p_prev_ids, p_prev_descs,
3267                                           p_prev_segnames, p_prev_vsnames,
3268                                           x_bind_value);
3269       GOTO goto_return;
3270    END IF;
3271 
3272    x_bind_value := l_bind_value;
3273    l_return_code := FF_VVALID;
3274 
3275    <<goto_return>>
3276    IF (fnd_flex_server1.g_debug_level > 0) THEN
3277       add_debug('END SV1.convert_bind_token2(value=' || l_bind_value || ')');
3278    END IF;
3279    RETURN(l_return_code);
3280 EXCEPTION
3281    WHEN OTHERS then
3282       IF (fnd_flex_server1.g_debug_level > 0) THEN
3283          add_debug('EXCEPTION others SV1.convert_bind_token2()');
3284       END IF;
3285       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3286       FND_MESSAGE.set_token('MSG','convert_bind_token2() exception: '||SQLERRM);
3287       return(FF_VERROR);
3288 END convert_bind_token2;
3289 
3290 /* ----------------------------------------------------------------------- */
3291 /*      Checks vrules.  Returns TRUE and sets error message if any are     */
3292 /*      violated.  Checks rules in forward order for compatibility with    */
3293 /*      C code.  Also checks SUMMARY_FLAG.                                 */
3294 /* ----------------------------------------------------------------------- */
3295 FUNCTION check_vrules(vrs     IN Vrules,
3296                       sqs     IN Qualifiers,
3297                       sumflg  IN VARCHAR2) RETURN VARCHAR2 IS
3298 
3299   testval     VARCHAR2(245);
3300 
3301 BEGIN
3302 
3303 --  Check vrules in forward order for compatibility with C code.
3304 --
3305   for i in 1..vrs.nvrules loop
3306     if((vrs.fq_names(i) is null) and (vrs.sq_names(i) = 'SUMMARY_FLAG')) then
3307       testval := SEPARATOR || sumflg || SEPARATOR;
3308       if(INSTR(vrs.cat_vals(i), testval) > 0) then
3309         if(vrs.ie_flags(i) = 'E') then
3310           value_error_name(vrs.app_names(i), vrs.err_names(i));
3311           return(FF_VVRULE);
3312         end if;
3313       else
3314         if(vrs.ie_flags(i) = 'I') then
3315           value_error_name(vrs.app_names(i), vrs.err_names(i));
3316           return(FF_VVRULE);
3317         end if;
3318       end if;
3319     else
3320       for j in 1..sqs.nquals loop
3321         if((vrs.sq_names(i) = sqs.sq_names(j)) and
3322            (vrs.fq_names(i) = sqs.fq_names(j))) then
3323           testval := SEPARATOR || sqs.sq_values(j) || SEPARATOR;
3324           if((vrs.cat_vals(i) is not null) and
3325               (INSTR(vrs.cat_vals(i), testval) > 0)) then
3326             if(vrs.ie_flags(i) = 'E') then
3327               value_error_name(vrs.app_names(i), vrs.err_names(i));
3328               return(FF_VVRULE);
3329             end if;
3330           else
3331             if(vrs.ie_flags(i) = 'I') then
3332               value_error_name(vrs.app_names(i), vrs.err_names(i));
3333               return(FF_VVRULE);
3334             end if;
3335           end if;
3336         end if;
3337       end loop;
3338     end if;
3339   end loop;
3340 
3341   return(FF_VVALID);
3342 
3343   EXCEPTION
3344     WHEN OTHERS then
3348 
3345       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3346       FND_MESSAGE.set_token('MSG', 'check_vrules() exception: ' || SQLERRM);
3347       return(FF_VERROR);
3349 END check_vrules;
3350 
3351 /* ----------------------------------------------------------------------- */
3352 /*      Checks vrules on combinations based on the qualifiers in the       */
3353 /*      combinations table.  This function is external to this file being  */
3354 /*      called from AFFFSSVB.pls.                                          */
3355 /*      Returns VV_VALID if all rules pass, or VV_VALUES or VV_ERROR and   */
3356 /*      sets message name if any rules violated.                           */
3357 /* ----------------------------------------------------------------------- */
3358 
3359 FUNCTION check_comb_vrules(vrs    IN  Vrules,
3360                            sqs    IN  Qualifiers,
3361                            sumflg IN  VARCHAR2) RETURN NUMBER IS
3362 v_code    VARCHAR2(1);
3363 retcode   NUMBER;
3364 
3365 BEGIN
3366 
3367 --  First must initialize the value errors since we always want to display
3368 --  the error if any rule violated.
3369 --
3370   value_error_init;
3371 
3372 --  Now call function above to check the rules.
3373 --
3374   v_code := check_vrules(vrs, sqs, sumflg);
3375   if(v_code = FF_VVALID) then
3376      IF (fnd_flex_server1.g_debug_level > 0) THEN
3377         add_debug(' Combination passed vrules. ');
3378      END IF;
3379     retcode := VV_VALID;
3380   elsif(v_code = FF_VVRULE) then
3381      IF (fnd_flex_server1.g_debug_level > 0) THEN
3382         add_debug(' Combination failed vrules. ');
3383      END IF;
3384     retcode := VV_VALUES;
3385   else
3386     retcode := VV_ERROR;
3387   end if;
3388 
3389   return(retcode);
3390 
3391   EXCEPTION
3392     WHEN OTHERS then
3393      FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3394      FND_MESSAGE.set_token('MSG','check_comb_vrules() exception: '||SQLERRM);
3395      return(VV_ERROR);
3396 
3397 END check_comb_vrules;
3398 
3399 /* ----------------------------------------------------------------------- */
3400 /*      Checks value security rules for any which are violated.            */
3401 /*      Returns status codes of FF_VVALID if no security rule violated,    */
3402 /*      FF_VSECURED if security violated, or FF_VERROR if some error       */
3403 /*      checking security.                                                 */
3404 /*      If security is violated a value error message is added             */
3405 /*      only if set_message is TRUE.                                       */
3406 /* ----------------------------------------------------------------------- */
3407 
3408 FUNCTION check_security(val          IN VARCHAR2,
3409                         valfmt       IN VARCHAR2,
3410                         parentval    IN VARCHAR2,
3411                         user_apid    IN NUMBER,
3412                         user_respid  IN NUMBER,
3413                         vsinfo       IN ValueSetInfo,
3414                         set_message  IN BOOLEAN) RETURN VARCHAR2 IS
3415 
3416   bufstr      VARCHAR2(500);
3417   rulemsgbuf  VARCHAR2(240);
3418   nfound      NUMBER;
3419   l_vsc_code  VARCHAR2(10);
3420   l_return_code VARCHAR2(10);
3421   l_security_status VARCHAR2(2000);
3422   l_error_message   VARCHAR2(2000);
3423 BEGIN
3424    IF (fnd_flex_server1.g_debug_level > 0) THEN
3425       add_debug('BEGIN SV1.check_security()');
3426    END IF;
3427 
3428 --
3429 -- Return immediately if user info is not set.
3430 --
3431  IF ((user_apid = -1) AND (user_respid = -1)) THEN
3432     RETURN(FF_VVALID);
3433  END IF;
3434 --
3435 -- First check the VSC
3436 --
3437    l_vsc_code :=  check_vsc(user_apid, user_respid, vsinfo.vsid,
3438                             parentval, val, l_return_code);
3439    IF (l_vsc_code IN (fnd_plsql_cache.CACHE_VALID,
3440                       fnd_plsql_cache.CACHE_INVALID)) THEN
3441       IF (fnd_flex_server1.g_debug_level > 0) THEN
3442          add_debug('Found in vsc.');
3443       END IF;
3444       GOTO label_return;
3445    END IF;
3446 
3447    --
3448    -- l_vsc_code is either CACHE_NOTFOUND.
3449    -- Continue on security check.
3450    --
3451      l_return_code := FF_VVALID;
3452 
3453      fnd_flex_server.check_value_security
3454        (p_security_check_mode   => 'YH',
3455         p_flex_value_set_id     => vsinfo.vsid,
3456         p_parent_flex_value     => parentval,
3457         p_flex_value            => val,
3458         p_resp_application_id   => user_apid,
3459         p_responsibility_id     => user_respid,
3460         x_security_status       => l_security_status,
3461         x_error_message         => l_error_message);
3462      IF (fnd_flex_server1.g_debug_level > 0) THEN
3463         add_debug('Hierarchy security: status :'||l_security_status || ' message : ' || l_error_message);
3464      END IF;
3465 
3466      IF (l_security_status <> 'NOT-SECURED') THEN
3467         IF (set_message) THEN
3468            value_error_name('FND', 'FLEX-USER DEFINED ERROR');
3469            value_error_token('MSG', l_error_message);
3470         END IF;
3471         l_return_code := FF_VSECURED;
3472         GOTO label_return;
3473      END IF;
3474 
3475      GOTO label_return;
3476 
3477 
3478   <<label_return>>
3482     END IF;
3479     IF (l_vsc_code IN (fnd_plsql_cache.CACHE_NOTFOUND)) THEN
3480        update_vsc(user_apid, user_respid, vsinfo.vsid,
3481                   parentval, val, l_return_code);
3483     IF (fnd_flex_server1.g_debug_level > 0) THEN
3484        add_debug('END SV1.check_security()');
3485     END IF;
3486     RETURN(l_return_code);
3487   EXCEPTION
3488     WHEN OTHERS then
3489       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3490       FND_MESSAGE.set_token('MSG','check_security() exception: ' || SQLERRM);
3491       IF (fnd_flex_server1.g_debug_level > 0) THEN
3492          add_debug('EXCEPTION SV1.check_security()');
3493       END IF;
3494 
3495       return(FF_VERROR);
3496 
3497 END check_security;
3498 
3499 /* ----------------------------------------------------------------------- */
3500 /*      Checks to see whether this segment is displayed.                   */
3501 /*      Returns displayed_flag as output.                                  */
3502 /*      Returns TRUE on success or FALSE if error or exception.            */
3503 /* ----------------------------------------------------------------------- */
3504 
3505 FUNCTION check_displayed(segindex     IN  NUMBER,
3506                          disp_tokmap  IN  DisplayedSegs,
3507                          d_flag       OUT nocopy BOOLEAN) RETURN BOOLEAN IS
3508 
3509 BEGIN
3510 
3511   d_flag := disp_tokmap.segflags(segindex);
3512   return(TRUE);
3513 
3514   EXCEPTION
3515     WHEN OTHERS then
3516       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3517       FND_MESSAGE.set_token('MSG','check_displayed() exception: ' ||SQLERRM);
3518       return(FALSE);
3519 
3520 END check_displayed;
3521 
3522 /* ----------------------------------------------------------------------- */
3523 /*      Interprets the compiled value attribute (CVA) string and returns   */
3524 /*      segment qualifier values.  From the value set id looks up all      */
3525 /*      qualifiers which might be associated with this value set and       */
3526 /*      orders them in the same order as they are stored in the CVA        */
3527 /*      string.  Then interprets the CVA string.  For each qualifier       */
3528 /*      associated with this flexfield segment, the default qualifier value*/
3529 /*      is overwritten by the value from the CVA string if the CVA string  */
3530 /*      contains a non-null value.  Returns the updated qualifier values   */
3531 /*      array and number of qualifier values found or < 0 if error.        */
3532 /*      No qualifier values for descriptive flexfields.                    */
3533 /*                                                                         */
3534 /*      Note:  Do not order by segment_attribute_type as this causes       */
3535 /*      GL_ACCOUNT/GL_ACCOUNT_TYPE to appear before GL_GLOBAL/DETAIL...    */
3536 /*      instead of after it as is the case in the client code.             */
3537 /* ----------------------------------------------------------------------- */
3538 FUNCTION qualifier_values(ffstruct       IN  FlexStructId,
3539                           valset_id      IN  NUMBER,
3540                           cvas           IN  VARCHAR2,
3541                           nqualifs       IN  NUMBER,
3542                           fqnames        IN  QualNameArray,
3543                           sqnames        IN  QualNameArray,
3544                           sqvals         IN OUT nocopy ValAttribArray) RETURN NUMBER IS
3545 
3546   cva_index           NUMBER;
3547   n_value_attributes  NUMBER;
3548   value_attributes    StringArray;
3549   l_vsq_code          VARCHAR2(200);
3550   i                   NUMBER;
3551 
3552   CURSOR CVA_Cursor(vs_id IN NUMBER) IS
3553     SELECT id_flex_application_id fapid, id_flex_code fcode,
3554            segment_attribute_type fqname, value_attribute_type sqname
3555       FROM fnd_flex_validation_qualifiers
3556      WHERE flex_value_set_id = vs_id
3557   ORDER BY assignment_date, id_flex_application_id, id_flex_code,
3558            value_attribute_type;
3559   vq  cva_cursor%ROWTYPE;
3560 BEGIN
3561 --  Quickly handle case where there are no qualifiers. (eg Descr flex)
3562 --
3563   if((not ffstruct.isa_key_flexfield) or (nqualifs = 0)) then
3564     return(0);
3565   end if;
3566 
3567 --  Convert compiled value attributes to array.
3568   --
3569   IF (cvas IS NOT NULL) THEN
3570      n_value_attributes := to_stringarray2(cvas, NEWLINE, value_attributes);
3571    ELSE
3572      n_value_attributes := 0;
3573   END IF;
3574 
3575 --  Set returned segment qualifier values to defaults
3576 --
3577 --    for i in 1..nqualifs loop
3578 --      sqvals(i) := default_sqvals(i);
3579 --    end loop;
3580 
3581 --  cva_index is position of the value attribute in the CVA string.
3582 --
3583   cva_index := 0;
3584 
3585 --  CVA_Cursor returns the flexfields and names of the attibutes associated
3586 --  with this value set in the order that they are stored in the cva string.
3587 --
3588 
3589   g_cache_key := valset_id;
3590 
3591   fnd_plsql_cache.generic_1tom_get_values(vsq_cache_controller,
3592                                           vsq_cache_storage,
3593                                           g_cache_key,
3594                                           g_cache_numof_values,
3595                                           g_cache_values,
3596                                           g_cache_return_code);
3597 
3601      i := 0;
3598   IF (g_cache_return_code = fnd_plsql_cache.CACHE_FOUND) THEN
3599      NULL;
3600    ELSE
3602      FOR vq IN cva_cursor(valset_id) LOOP
3603         i := i + 1;
3604         fnd_plsql_cache.generic_cache_new_value
3605           (x_value      => g_cache_value,
3606            p_number_1   => vq.fapid,
3607            p_varchar2_1 => vq.fcode,
3608            p_varchar2_2 => vq.fqname,
3609            p_varchar2_3 => vq.sqname);
3610         g_cache_values(i) := g_cache_value;
3611      END LOOP;
3612      g_cache_numof_values := i;
3613 
3614      fnd_plsql_cache.generic_1tom_put_values(vsq_cache_controller,
3615                                                   vsq_cache_storage,
3616                                                   g_cache_key,
3617                                                   g_cache_numof_values,
3618                                                   g_cache_values);
3619   END IF;
3620 
3621   FOR ii IN 1..g_cache_numof_values LOOP
3622      vq.fapid  := g_cache_values(ii).number_1;
3623      vq.fcode  := g_cache_values(ii).varchar2_1;
3624      vq.fqname := g_cache_values(ii).varchar2_2;
3625      vq.sqname := g_cache_values(ii).varchar2_3;
3626 
3627 --    for vq in CVA_Cursor(valset_id) loop
3628      cva_index := cva_index + 1;
3629 
3630 --  If the selected attribute applies to the flexfied under consideration
3631 --  then find the attribute by name in the list of those which apply to this
3632 --  segment and replace its default value with the appropriate value from
3633 --  the cva string.
3634 --
3635     if((vq.fapid = ffstruct.application_id) and
3636        (vq.fcode = ffstruct.id_flex_code)) then
3637       for i in 1..nqualifs loop
3638         if((vq.fqname = fqnames(i)) and (vq.sqname = sqnames(i)) and
3639            (cva_index <= n_value_attributes)) then
3640             sqvals(i) := value_attributes(cva_index);
3641         end if;
3642       end loop;
3643     end if;
3644   end loop;
3645 
3646   return(cva_index);
3647 
3648 EXCEPTION
3649   WHEN OTHERS then
3650     FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3651     FND_MESSAGE.set_token('MSG', 'qualifier_values() exception:  '||SQLERRM);
3652     return(-1);
3653 
3654 END qualifier_values;
3655 
3656 /* ----------------------------------------------------------------------- */
3657 /*      Gets the **enabled** flexfield and segment qualifiers for this     */
3658 /*      segment.  Segment is uniquely determined by combination of         */
3659 /*      flex apid, code, struct num, with the name of the column in the    */
3660 /*      code combinations table which will hold the segment value.         */
3661 /*      No qualifiers enabled for descriptive flexs.                       */
3662 /*                                                                         */
3663 /*      Returns the number of qualifiers found or < 0 if error.            */
3664 /*                                                                         */
3665 /*      Also returns FQ name, SQ name, derived_column, and default value   */
3666 /*      of the segment qualifiers for this segment.                        */
3667 /* ----------------------------------------------------------------------- */
3668 FUNCTION get_qualifiers(ffstruct      IN  FlexStructId,
3669                         seg_colname   IN  VARCHAR2,
3670                         seg_quals     OUT nocopy Qualifiers)
3671   RETURN NUMBER
3672   IS
3673      sqcount      NUMBER;
3674 
3675   CURSOR Qual_Cursor(keystruct IN FlexStructId, colname IN VARCHAR2) IS
3676       SELECT v.segment_attribute_type fq_name,
3677              v.value_attribute_type sq_name,
3678              v.application_column_name drv_colname,
3679              v.default_value dflt_val
3680         FROM fnd_value_attribute_types v, fnd_segment_attribute_values s
3681        WHERE v.application_id = s.application_id
3682          AND v.id_flex_code = s.id_flex_code
3683          AND v.segment_attribute_type = s.segment_attribute_type
3684          AND s.application_id = keystruct.application_id
3685          AND s.id_flex_code = keystruct.id_flex_code
3686          AND s.id_flex_num = keystruct.id_flex_num
3687          AND s.application_column_name = colname
3688          AND s.attribute_value = 'Y';
3689 BEGIN
3690    IF (fnd_flex_server1.g_debug_level > 0) THEN
3691       fnd_flex_server1.add_debug('BEGIN SV1.get_qualifiers()');
3692    END IF;
3693 
3694    sqcount := 0;
3695    IF (ffstruct.isa_key_flexfield) THEN
3696       g_cache_key := (ffstruct.application_id || '.' ||
3697                       ffstruct.id_flex_code || '.' ||
3698                       ffstruct.id_flex_num || '.' ||
3699                       seg_colname);
3700 
3701       fnd_plsql_cache.generic_1tom_get_values(fsq_cache_controller,
3702                                               fsq_cache_storage,
3703                                               g_cache_key,
3704                                               g_cache_numof_values,
3705                                               g_cache_values,
3706                                               g_cache_return_code);
3707 
3708       IF (g_cache_return_code = fnd_plsql_cache.CACHE_FOUND) THEN
3709          sqcount := g_cache_numof_values;
3710        ELSE
3711          FOR squal IN qual_cursor(ffstruct, seg_colname) LOOP
3712             sqcount := sqcount + 1;
3713 
3714             fnd_plsql_cache.generic_cache_new_value
3715               (x_value      => g_cache_value,
3719                p_varchar2_4 => squal.drv_colname);
3716                p_varchar2_1 => squal.fq_name,
3717                p_varchar2_2 => squal.sq_name,
3718                p_varchar2_3 => squal.dflt_val,
3720             g_cache_values(sqcount) := g_cache_value;
3721          END LOOP;
3722          g_cache_numof_values := sqcount;
3723 
3724          fnd_plsql_cache.generic_1tom_put_values(fsq_cache_controller,
3725                                                  fsq_cache_storage,
3726                                                  g_cache_key,
3727                                                  g_cache_numof_values,
3728                                                  g_cache_values);
3729       END IF;
3730 
3731       FOR ii IN 1..sqcount LOOP
3732          seg_quals.fq_names(ii) := g_cache_values(ii).varchar2_1;
3733          seg_quals.sq_names(ii) := g_cache_values(ii).varchar2_2;
3734          seg_quals.sq_values(ii) := g_cache_values(ii).varchar2_3;
3735          seg_quals.derived_cols(ii) := g_cache_values(ii).varchar2_4;
3736       END LOOP;
3737    END IF;
3738 
3739    seg_quals.nquals := sqcount;
3740 
3741    IF (fnd_flex_server1.g_debug_level > 0) THEN
3742       fnd_flex_server1.add_debug('END SV1.get_qualifiers()');
3743    END IF;
3744 
3745    RETURN(sqcount);
3746 EXCEPTION
3747   WHEN OTHERS then
3748     FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3749     FND_MESSAGE.set_token('MSG', 'get_qualifiers() exception:  ' || SQLERRM);
3750     IF (fnd_flex_server1.g_debug_level > 0) THEN
3751        fnd_flex_server1.add_debug('EXCEPTION SV1.get_qualifiers()');
3752     END IF;
3753 
3754     return(-1);
3755 
3756 END get_qualifiers;
3757 
3758 /* ----------------------------------------------------------------------- */
3759 /*      Gets the value set information for a given value set id.           */
3760 /*      Returns TRUE if found or FALSE and sets error message on error.    */
3761 /* ----------------------------------------------------------------------- */
3762 FUNCTION get_value_set(value_set_id   IN  NUMBER,
3763                        segment_name   IN  VARCHAR2,
3764                        vs_info        OUT nocopy ValueSetInfo)
3765   RETURN BOOLEAN
3766   IS
3767      l_vsi  valuesetinfo;
3768 BEGIN
3769    IF (fnd_flex_server1.g_debug_level > 0) THEN
3770       fnd_flex_server1.add_debug('CALL SV1.get_value_set(' ||
3771                                  'vsid:' || value_set_id || ')');
3772    END IF;
3773 
3774    g_cache_key := value_set_id;
3775    fnd_plsql_cache.generic_1to1_get_value(vst_cache_controller,
3776                                           vst_cache_storage,
3777                                           g_cache_key,
3778                                           g_cache_value,
3779                                           g_cache_return_code);
3780 
3781    IF (g_cache_return_code = fnd_plsql_cache.CACHE_FOUND) THEN
3782       vs_info.vsid        := value_set_id;
3783       vs_info.parent_vsid := g_cache_value.number_1;
3784       vs_info.valsecure   := g_cache_value.varchar2_1;
3785       vs_info.valtype     := g_cache_value.varchar2_2;
3786       vs_info.vsformat    := g_cache_value.varchar2_3;
3787       vs_info.maxsize     := g_cache_value.number_2;
3788       vs_info.lettersok   := g_cache_value.varchar2_4;
3789       vs_info.capsonly    := g_cache_value.varchar2_5;
3790       vs_info.zfill       := g_cache_value.varchar2_6;
3791       vs_info.precis      := g_cache_value.number_3;
3792       vs_info.minval      := g_cache_value.varchar2_7;
3793       vs_info.maxval      := g_cache_value.varchar2_8;
3794       vs_info.vsname      := g_cache_value.varchar2_9;
3795     ELSE
3796       SELECT flex_value_set_id, parent_flex_value_set_id,
3797         security_enabled_flag,
3798         validation_type, format_type, maximum_size,
3799         alphanumeric_allowed_flag, uppercase_only_flag,
3800         numeric_mode_enabled_flag, number_precision, minimum_value,
3801         maximum_value, flex_value_set_name
3802         INTO l_vsi
3803         FROM fnd_flex_value_sets
3804         WHERE flex_value_set_id = value_set_id;
3805 
3806       fnd_plsql_cache.generic_cache_new_value
3807         (x_value      => g_cache_value,
3808          p_number_1   => l_vsi.parent_vsid,
3809          p_varchar2_1 => l_vsi.valsecure,
3810          p_varchar2_2 => l_vsi.valtype,
3811          p_varchar2_3 => l_vsi.vsformat,
3812          p_number_2   => l_vsi.maxsize,
3813          p_varchar2_4 => l_vsi.lettersok,
3814          p_varchar2_5 => l_vsi.capsonly,
3815          p_varchar2_6 => l_vsi.zfill,
3816          p_number_3   => l_vsi.precis,
3817          p_varchar2_7 => l_vsi.minval,
3818          p_varchar2_8 => l_vsi.maxval,
3819          p_varchar2_9 => l_vsi.vsname);
3820 
3821       fnd_plsql_cache.generic_1to1_put_value(vst_cache_controller,
3822                                              vst_cache_storage,
3823                                              g_cache_key,
3824                                              g_cache_value);
3825       vs_info := l_vsi;
3826    END IF;
3827    return(TRUE);
3828 EXCEPTION
3829   WHEN NO_DATA_FOUND then
3830     FND_MESSAGE.set_name('FND', 'FLEX-VALUE SET NOT FOUND');
3831     FND_MESSAGE.set_token('SEGMENT', segment_name);
3832     return(FALSE);
3833   WHEN OTHERS then
3834     FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3835     FND_MESSAGE.set_token('MSG', 'get_value_set() exception:  ' || SQLERRM);
3836     return(FALSE);
3840 /*      Creates value set information for segment without a value set      */
3837 END get_value_set;
3838 
3839 /* ----------------------------------------------------------------------- */
3841 /*      based on the specification of the column into which it will go.    */
3842 /*      We document that this only works for CHAR or VARCHAR2 type columns.*/
3843 /*      Returns TRUE if ok or FALSE and sets error message on error.       */
3844 /* ----------------------------------------------------------------------- */
3845 FUNCTION virtual_value_set(column_type  IN  VARCHAR2,
3846                            column_width IN  NUMBER,
3847                            segment_name IN  VARCHAR2,
3848                            vs_info      OUT nocopy ValueSetInfo) RETURN BOOLEAN IS
3849 BEGIN
3850 
3851 --  Assumes all components of vs_info are initially null
3852 --
3853   if(column_type in ('C', 'V')) then
3854     vs_info.valsecure := 'N';
3855     vs_info.valtype := 'N';
3856     vs_info.vsformat := 'C';
3857     vs_info.maxsize := column_width;
3858     vs_info.lettersok := 'Y';
3859     vs_info.capsonly := 'N';
3860     vs_info.zfill := 'N';
3861     return(TRUE);
3862   end if;
3863   FND_MESSAGE.set_name('FND', 'FLEX-VALUE SET REQUIRED');
3864   FND_MESSAGE.set_token('SEGMENT', segment_name);
3865   return(FALSE);
3866 
3867 EXCEPTION
3868   WHEN OTHERS then
3869     FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3870     FND_MESSAGE.set_token('MSG','virtual_value_set() exception:  '||SQLERRM);
3871     return(FALSE);
3872 
3873 END virtual_value_set;
3874 
3875 /* ----------------------------------------------------------------------- */
3876 /*      Message handler functions for value validation errors.  Needed     */
3877 /*      because value validation does not always stop at the first         */
3878 /*      error encountered.  This handler makes sure that FND_MESSAGE       */
3879 /*      error is set to the first value error if there are no other        */
3880 /*      errors.  For more serious errors, we set the message directly      */
3881 /*      using the FND_MESSAGE package.   Note this assumes the main        */
3882 /*      validate_struct() function knows to stop on the first serious      */
3883 /*      error otherwise we risk overwriting a more serious error with      */
3884 /*      a value error.                                                     */
3885 /*      If the application short name is null, then we use the             */
3886 /*      FLEX-USER DEFINED ERROR to display the message name as text.       */
3887 /*      This is used in check_vrules().                                    */
3888 /* ----------------------------------------------------------------------- */
3889 
3890 /* ----------------------------------------------------------------------- */
3891 /*      Initializes value error message global variables.                  */
3892 /* ----------------------------------------------------------------------- */
3893 
3894 PROCEDURE value_error_init IS
3895 BEGIN
3896   value_error_set := FALSE;
3897   entering_new_message := FALSE;
3898 EXCEPTION
3899   WHEN OTHERS then
3900      IF (fnd_flex_server1.g_debug_level > 0) THEN
3901         add_debug('value_error_init() exception: ' || SQLERRM);
3902      END IF;
3903 END value_error_init;
3904 
3905 /* ------------------------------------------------------------------------ */
3906 /*      Sets error message name if no other value errors have been set.     */
3907 /*      Also sets entering_new_message flag to indicate new message being   */
3908 /*      entered if this is the first value error, otherwise resets it.      */
3909 /* ------------------------------------------------------------------------ */
3910 PROCEDURE value_error_name(appl_sname      IN  VARCHAR2,
3911                            errmsg_name     IN  VARCHAR2) IS
3912 BEGIN
3913   if(value_error_set = FALSE) then
3914     if(appl_sname is null) then
3915       FND_MESSAGE.set_name('FND', 'FLEX-USER DEFINED ERROR');
3916       FND_MESSAGE.set_token('MSG', errmsg_name);
3917     else
3918       FND_MESSAGE.set_name(appl_sname, errmsg_name);
3919     end if;
3920     value_error_set := TRUE;
3921     entering_new_message := TRUE;
3922   else
3923     entering_new_message := FALSE;
3924   end if;
3925 EXCEPTION
3926   WHEN OTHERS then
3927      IF (fnd_flex_server1.g_debug_level > 0) THEN
3928         add_debug('value_error_name() exception: ' || SQLERRM);
3929      END IF;
3930 END value_error_name;
3931 
3932 /* ----------------------------------------------------------------------- */
3933 /*      Sets error message token if currently entering a new message.      */
3934 /*      Otherwise just ignores the token.  Call only after setting         */
3935 /*      value error name with value_error_name() above.                    */
3936 /* ----------------------------------------------------------------------- */
3937 PROCEDURE value_error_token(token_name   IN  VARCHAR2,
3938                             token_value  IN  VARCHAR2) IS
3939 BEGIN
3940   if(entering_new_message) then
3941     FND_MESSAGE.set_token(token_name, token_value);
3942   end if;
3943 EXCEPTION
3944   WHEN OTHERS then
3945      IF (fnd_flex_server1.g_debug_level > 0) THEN
3946         add_debug('value_error_token() exception: ' || SQLERRM);
3947      END IF;
3948 END value_error_token;
3949 
3950 /* ----------------------------------------------------------------------- */
3951 /*      Converts the value to be output in an error message from stored    */
3955 FUNCTION msg_val(valset_fmt  IN  VARCHAR2,
3952 /*      format to the displayed format appropriate for the given value set.*/
3953 /*      Returns the value in stored format if any errors encountered.      */
3954 /* ----------------------------------------------------------------------- */
3956                  valset_len  IN  NUMBER,
3957                  valset_prec IN  NUMBER,
3958                  valset_lettersok IN VARCHAR2,
3959                  stored_val  IN  VARCHAR2) RETURN VARCHAR2 IS
3960   d_val  VARCHAR2(1000);
3961 BEGIN
3962   if(stored_to_displayed(valset_fmt, valset_len,
3963                          valset_prec, valset_lettersok,
3964                          stored_val, d_val) <> FF_VVALID) then
3965     d_val := stored_val;
3966   end if;
3967   return(d_val);
3968 EXCEPTION
3969   WHEN OTHERS then
3970     return(stored_val);
3971 END msg_val;
3972 
3973 /* ----------------------------------------------------------------------- */
3974 /*      Converts value from stored format to displayed format.             */
3975 /*      Returns FF_VVALID on success, or FF_VERROR otherwise.              */
3976 /* ----------------------------------------------------------------------- */
3977 FUNCTION stored_to_displayed(valset_fmt  IN  VARCHAR2,
3978                              valset_len  IN  NUMBER,
3979                              valset_prec IN  NUMBER,
3980                              valset_lettersok IN VARCHAR2,
3981                              stored_val  IN  VARCHAR2,
3982                              disp_val    OUT nocopy VARCHAR2) RETURN VARCHAR2 IS
3983   datebuf     DATE;
3984 BEGIN
3985 if(valset_fmt in ('X', 'Y', 'Z')) then
3986   if(isa_stored_date(stored_val, valset_fmt, datebuf)) then
3987    disp_val := to_char(datebuf,displayed_date_format(valset_fmt,valset_len));
3988   else
3989     return(FF_VERROR);
3990   end if;
3991  ELSIF ((valset_fmt = 'N') OR
3992         ((valset_fmt = 'C') AND
3993          (valset_lettersok = 'N'))) THEN
3994    disp_val := REPLACE(stored_val,m_nc,m_nd);
3995  else
3996   disp_val := stored_val;
3997 end if;
3998 
3999 return(FF_VVALID);
4000 
4001 EXCEPTION
4002   WHEN OTHERS then
4003     return(FF_VERROR);
4004 END stored_to_displayed;
4005 
4006 /* ----------------------------------------------------------------------- */
4007 /*      Converts character representation of a number to a number.         */
4008 /*      Returns TRUE if it's a valid number, and FALSE otherwise.          */
4009 /* ----------------------------------------------------------------------- */
4010 FUNCTION isa_number(teststr IN VARCHAR2,
4011                      outnum OUT nocopy NUMBER) RETURN BOOLEAN IS
4012 BEGIN
4013   outnum := to_number(teststr);
4014   return(TRUE);
4015 EXCEPTION
4016   WHEN OTHERS then
4017     return(FALSE);
4018 END isa_number;
4019 
4020 /* ----------------------------------------------------------------------- */
4021 /*      Converts character representation of a stored date to a date.      */
4022 /*      Returns TRUE if it's a valid date, and FALSE otherwise.    */
4023 /* ----------------------------------------------------------------------- */
4024 FUNCTION isa_stored_date(teststr IN VARCHAR2,
4025                          flexfmt IN VARCHAR2,
4026                          outdate OUT nocopy DATE) RETURN BOOLEAN IS
4027 BEGIN
4028   if(teststr is null) then
4029     return(TRUE);
4030   end if;
4031   return(isa_date(teststr, stored_date_format(flexfmt, LENGTH(teststr)),
4032          outdate));
4033 EXCEPTION
4034   WHEN OTHERS then
4035      IF (fnd_flex_server1.g_debug_level > 0) THEN
4036         add_debug('isa_stored_date() exception: ' || SQLERRM);
4037      END IF;
4038     return(FALSE);
4039 END isa_stored_date;
4040 
4041 
4042 /* ----------------------------------------------------------------------- */
4043 /*      Converts character representation of a displayed date to a date.   */
4044 /*      Returns TRUE if it's a valid date, and FALSE otherwise.            */
4045 /* ----------------------------------------------------------------------- */
4046 FUNCTION isa_displayed_date(teststr IN VARCHAR2,
4047                             flexfmt IN VARCHAR2,
4048                             outdate OUT nocopy DATE) RETURN BOOLEAN IS
4049 BEGIN
4050   if(teststr is null) then
4051     return(TRUE);
4052   end if;
4053   return(isa_date(teststr, displayed_date_format(flexfmt, LENGTH(teststr)),
4054          outdate));
4055 EXCEPTION
4056   WHEN OTHERS then
4057      IF (fnd_flex_server1.g_debug_level > 0) THEN
4058         add_debug('isa_displayed_date() exception: ' || SQLERRM);
4059      END IF;
4060     return(FALSE);
4061 END isa_displayed_date;
4062 
4063 /* ----------------------------------------------------------------------- */
4064 /*      Converts test string to date using supplied format.                */
4065 /*      If date conversion fails or supplied format is null, returns FALSE */
4066 /*      otherwise returns TRUE.                                            */
4067 /*      This function is a wrapper around to_date() to make it always work */
4068 /*      even if the supplied format is 'DD-MON-YY'  (See bug)              */
4069 /* ----------------------------------------------------------------------- */
4070 FUNCTION isa_date(teststr IN VARCHAR2,
4071                   datefmt IN VARCHAR2,
4072                   outdate OUT nocopy DATE) RETURN BOOLEAN IS
4073 BEGIN
4074   if(teststr is null) then
4078     return(FALSE);
4075     return(TRUE);
4076   end if;
4077   if(datefmt is null) then
4079   elsif(datefmt = 'DD-MON-YY') then
4080     outdate := to_date(teststr, datefmt);
4081   elsif(datefmt = 'DD-MON-RR') then
4082     outdate := to_date(teststr, datefmt);
4083   else
4084     outdate := to_date(teststr, datefmt);
4085   end if;
4086   return(TRUE);
4087 EXCEPTION
4088   WHEN OTHERS then
4089      IF (fnd_flex_server1.g_debug_level > 0) THEN
4090         add_debug('isa_date() exception: ' || SQLERRM);
4091      END IF;
4092     return(FALSE);
4093 END isa_date;
4094 
4095 /* ----------------------------------------------------------------------- */
4096 /*      Returns format string for converting a date to a character string  */
4097 /*      that represents the displayed value of a flex date, time, or       */
4098 /*      date-time.                                                         */
4099 /*      Returns NULL if not valid flex date format.                        */
4100 /* ----------------------------------------------------------------------- */
4101 FUNCTION displayed_date_format(flex_data_type IN VARCHAR2,
4102                                string_length  IN NUMBER) RETURN VARCHAR2 IS
4103 
4104   l_format_in VARCHAR2(500);
4105   l_format_out VARCHAR2(500);
4106 BEGIN
4107    IF (fnd_flex_val_util.get_display_format
4108        (p_vset_format => flex_data_type,
4109         p_max_length => string_length,
4110         p_precision => NULL,
4111         x_format_in => l_format_in,
4112         x_format_out => l_format_out)) THEN
4113       RETURN(l_format_out);
4114     ELSE
4115       RETURN(NULL);
4116    END IF;
4117 
4118   EXCEPTION
4119     WHEN OTHERS then
4120       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
4121       FND_MESSAGE.set_token('MSG',
4122                       'displayed_date_format() exception:  ' || SQLERRM);
4123       return(NULL);
4124 
4125 END displayed_date_format;
4126 
4127 /* ----------------------------------------------------------------------- */
4128 /*      Returns format string for converting character representation      */
4129 /*      of stored flex date, time, or date-time data to a date datatype    */
4130 /*      using the to_date() conversion utility.                            */
4131 /*      Returns NULL if not valid flex date format.                        */
4132 /*      Modified for DD-MON-RR conversion in Prod 16   12-26-96            */
4133 /* ----------------------------------------------------------------------- */
4134 FUNCTION stored_date_format(flex_data_type IN VARCHAR2,
4135                             string_length  IN NUMBER) RETURN VARCHAR2 IS
4136 
4137   l_format VARCHAR2(500);
4138 BEGIN
4139    IF (fnd_flex_val_util.get_storage_format(p_vset_format => flex_data_type,
4140                                             p_max_length  => string_length,
4141                                             p_precision   => NULL,
4142                                             x_format      => l_format)) THEN
4143       RETURN(l_format);
4144     ELSE
4145       RETURN(NULL);
4146    END IF;
4147 
4148 EXCEPTION
4149    WHEN OTHERS then
4150       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
4151       FND_MESSAGE.set_token('MSG',
4152                             'stored_date_format() exception:  ' || SQLERRM);
4153       return(NULL);
4154 
4155 END stored_date_format;
4156 
4157 /* ----------------------------------------------------------------------- */
4158 /*              Generally useful utilities - Externalized                  */
4159 /* ----------------------------------------------------------------------- */
4160 
4161 /* ----------------------------------------------------------------------- */
4162 /*              Initializes all global variables                           */
4163 /* ----------------------------------------------------------------------- */
4164 FUNCTION init_globals RETURN BOOLEAN IS
4165 
4166 BEGIN
4167 
4168   n_sqlstrings := 0;
4169   g_debug_array_size := 0;
4170   return(TRUE);
4171 
4172 EXCEPTION
4173   WHEN OTHERS then
4174     FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
4175     FND_MESSAGE.set_token('MSG', 'init_globals() exception:  ' || SQLERRM);
4176     return(FALSE);
4177 
4178 END init_globals;
4179 
4180 /* ----------------------------------------------------------------------- */
4181 /*      Creates an "and clause" of a SQL select statement for determining  */
4182 /*      if the value passed in is in between the values in the columns     */
4183 /*      whose names are in mincol and maxcol.  Returns NULL if no          */
4184 /*      statement required for this column                                 */
4185 /*                                                                         */
4186 /*      By isolating all in range clauses to this routine we can ensure    */
4187 /*      uniform range behavior.                                            */
4188 /*                                                                         */
4189 /*      Null handling:  If val is NULL, requires either mincol or maxcol   */
4190 /*      to be null.  If the value contained in mincol (maxcol) is NULL it  */
4191 /*      means there is no lower(upper) limit on the range of val           */
4192 /*                                                                         */
4193 /*      Clause is of the form:                                             */
4197 /* ----------------------------------------------------------------------- */
4194 /*      'and (10 between nvl(to_number(MINCOL), 10)                        */
4195 /*             and nvl(to_number(MAXCOL), 10)) '                           */
4196 /*                                                                         */
4198 PROCEDURE x_inrange_clause(valstr  IN VARCHAR2,
4199                            valtype IN VARCHAR2,
4200                            mincol  IN VARCHAR2,
4201                            maxcol  IN VARCHAR2) IS
4202 
4203   clause      VARCHAR2(500);
4204   val         VARCHAR2(200);
4205   collo       VARCHAR2(200);
4206   colhi       VARCHAR2(200);
4207   datefmt     VARCHAR2(24);
4208 
4209 BEGIN
4210    fnd_dsql.add_text('and (');
4211    IF (valstr IS NULL) THEN
4212       fnd_dsql.add_text(mincol || ' is null or ' ||
4213                         maxcol || ' is null) ');
4214     ELSE
4215       IF (valtype = 'N') THEN
4216          fnd_dsql.add_bind(fnd_number.canonical_to_number(valstr));
4217 
4218          fnd_dsql.add_text(' between nvl(fnd_number.canonical_to_number('
4219                            || mincol || '),');
4220          fnd_dsql.add_bind(fnd_number.canonical_to_number(valstr));
4221 
4222          fnd_dsql.add_text(') and nvl(fnd_number.canonical_to_number('
4223                            || maxcol || '),');
4224          fnd_dsql.add_bind(fnd_number.canonical_to_number(valstr));
4225 
4226        ELSIF (valtype in ('D', 'T', 't', 'I', 'X', 'Y', 'Z')) THEN
4227          datefmt := stored_date_format(valtype, LENGTH(valstr));
4228          fnd_dsql.add_bind(To_date(valstr, datefmt));
4229 
4230          fnd_dsql.add_text(' between nvl(to_date(' ||
4231                            mincol || ',''' || datefmt || '''),');
4232          fnd_dsql.add_bind(To_date(valstr, datefmt));
4233 
4234          fnd_dsql.add_text(') and nvl(to_date(' ||
4235                            maxcol || ',''' || datefmt || '''),');
4236          fnd_dsql.add_bind(To_date(valstr, datefmt));
4237 
4238        ELSE
4239          fnd_dsql.add_bind(valstr);
4240 
4241          fnd_dsql.add_text(' between nvl(' || mincol || ',');
4242          fnd_dsql.add_bind(valstr);
4243 
4244          fnd_dsql.add_text(') and nvl(' || maxcol || ',');
4245          fnd_dsql.add_bind(valstr);
4246 
4247       END IF;
4248       fnd_dsql.add_text(')) ');
4249    END IF;
4250 END x_inrange_clause;
4251 
4252 /* ----------------------------------------------------------------------- */
4253 /*      Function to convert a column name into a SQL clause for selecting  */
4254 /*      a value, id, or description from that column into the correct      */
4255 /*      character format for the given value set.                          */
4256 /*                                                                         */
4257 /*      This function does the default to_char() conversion for            */
4258 /*      non-translatable date, time, date-time, or number value sets       */
4259 /*      in order to maintain backward compatibility with old client code.  */
4260 /*      For translatable date, time, and date-time value sets this code    */
4261 /*      converts the data stored in the date column to date storage format */
4262 /*                                                                         */
4263 /*      Does not check for compatibility of column type and value set.     */
4264 /* ----------------------------------------------------------------------- */
4265 
4266 FUNCTION select_clause(colname     IN  VARCHAR2,
4267                        coltype     IN  VARCHAR2,
4268                        v_component IN  BINARY_INTEGER,
4269                        vs_fmt      IN  VARCHAR2,
4270                        vs_len      IN  NUMBER) RETURN VARCHAR2 IS
4271 
4272   clause      VARCHAR2(2000);
4273 
4274 BEGIN
4275 
4276   if(coltype not in ('C', 'V')) then
4277     clause := 'to_char(' || colname;
4278     if(vs_fmt in ('X', 'Y', 'Z')) then
4279       clause := clause || ', ''';
4280       if((v_component = VC_ID) OR (v_component = VC_VALUE)) then
4281         clause := clause || stored_date_format(vs_fmt, vs_len) || ''')';
4282       else
4283         clause := clause || displayed_date_format(vs_fmt, vs_len) || ''')';
4284       end if;
4285      ELSIF (vs_fmt = 'N') THEN
4286        clause := clause || ')';
4287        clause := 'replace(' || clause || ',''' || m_nb || ''','''
4288          || m_nc || ''')';
4289      else
4290        clause := clause || ')';
4291     end if;
4292   else
4293     clause := colname;
4294   end if;
4295   return(clause);
4296 
4297 END select_clause;
4298 
4299 /* ----------------------------------------------------------------------- */
4300 /*      Function to convert a value into a SQL clause for comparing that   */
4301 /*      value into a table column of the given type, or for inserting that */
4302 /*      value to a value stored in a table column of the given type.       */
4303 /*                                                                         */
4304 /*      If the table column is a number assume the value input is a number */
4305 /*      and just use the text of the number.  If the table column is       */
4306 /*      CHAR or VARCHAR2, then substitute all single quotes in the value   */
4307 /*      with double quotes and surround the value with single quotes.      */
4308 /*      If table column is DATE, do to_date() conversion using the format  */
4309 /*      appropriate for the value set.                                     */
4310 /*                                                                         */
4314 /*      conversions are done.  This means non-validated Date-time values   */
4311 /*      To maintin backward compatibility with existing client code must   */
4312 /*      build in the BUG that if value set format type is old-fashioned    */
4313 /*      date, time or date-time (D, T or t), then default to_date()        */
4315 /*      cannot be inserted into the combinations table.                    */
4316 /* ----------------------------------------------------------------------- */
4317 
4318 PROCEDURE x_compare_clause(coltype     IN  VARCHAR2,
4319                            colname     IN  VARCHAR2,
4320                            char_val    IN  VARCHAR2,
4321                            v_component IN  BINARY_INTEGER,
4322                            vs_fmt      IN  VARCHAR2,
4323                            vs_len      IN  NUMBER)
4324   IS
4325      datefmt VARCHAR2(30);
4326 BEGIN
4327    IF (coltype = 'N') THEN
4328       fnd_dsql.add_bind(fnd_number.canonical_to_number(char_val));
4329     ELSIF (coltype = 'D') then
4330       IF (vs_fmt in ('X', 'Y', 'Z', 'D', 'T', 'I', 't')) then
4331          datefmt := stored_date_format(vs_fmt, vs_len);
4332          fnd_dsql.add_bind(To_date(char_val, datefmt));
4333        ELSE
4334          fnd_dsql.add_bind(char_val);
4335       end if;
4336     else
4337       fnd_dsql.add_bind(char_val);
4338    end if;
4339 
4340 END x_compare_clause;
4341 
4342 /* ----------------------------------------------------------------------- */
4343 /*      Creates a SQL clause for binding a character string.               */
4344 /*      Replaces single quotes with double quotes and surrounds the        */
4345 /*      string with quotes.                                                */
4346 /* ----------------------------------------------------------------------- */
4347 
4348 FUNCTION string_clause(char_string IN VARCHAR2) RETURN VARCHAR2 IS
4349 BEGIN
4350   return('''' || REPLACE(char_string, '''', '''''') || '''');
4351 END string_clause;
4352 
4353 -- /* ----------------------------------------------------------------------- */
4354 -- /*      MADE NULL TO MAKE MORE ROOM FOR USEFUL CODE.                       */
4355 -- /*      Breaks concatenated segments in rule lines table into separate     */
4356 -- /*      columns for each segment.  Returns number of segments or < 0       */
4357 -- /*      and sets FND_MESSAGE if error.  This is called only from trigger   */
4358 -- /*      FND_FLEX_VALIDATION_RULE_LINES_T1.  The trigger should use         */
4359 -- /*      FND_MESSAGE.raise_exception if this function returns error.        */
4360 -- /* ----------------------------------------------------------------------- */
4361 --   FUNCTION breakup_segs(appid IN NUMBER,
4362 --                 flex_code IN VARCHAR2, flex_num IN NUMBER,
4363 --                 catsegs IN VARCHAR2, nsegs OUT NUMBER,
4364 --                 seg1  OUT VARCHAR2, seg2  OUT VARCHAR2,
4365 --                 seg3  OUT VARCHAR2, seg4  OUT VARCHAR2,
4366 --                 seg5  OUT VARCHAR2, seg6  OUT VARCHAR2,
4367 --                 seg7  OUT VARCHAR2, seg8  OUT VARCHAR2,
4368 --                 seg9  OUT VARCHAR2, seg10 OUT VARCHAR2,
4369 --                 seg11 OUT VARCHAR2, seg12 OUT VARCHAR2,
4370 --                 seg13 OUT VARCHAR2, seg14 OUT VARCHAR2,
4371 --                 seg15 OUT VARCHAR2, seg16 OUT VARCHAR2,
4372 --                 seg17 OUT VARCHAR2, seg18 OUT VARCHAR2,
4373 --                 seg19 OUT VARCHAR2, seg20 OUT VARCHAR2,
4374 --                 seg21 OUT VARCHAR2, seg22 OUT VARCHAR2,
4375 --                 seg23 OUT VARCHAR2, seg24 OUT VARCHAR2,
4376 --                 seg25 OUT VARCHAR2, seg26 OUT VARCHAR2,
4377 --                 seg27 OUT VARCHAR2, seg28 OUT VARCHAR2,
4378 --                 seg29 OUT VARCHAR2, seg30 OUT VARCHAR2) RETURN NUMBER IS
4379 --
4380 --     n_segs      NUMBER;
4381 --     sg          StringArray;
4382 --     sepchar     VARCHAR2(1);
4383 --
4384 --   BEGIN
4385 --     return(-1);
4386 --
4387 --   EXCEPTION
4388 --     WHEN OTHERS then
4389 --       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
4390 --       FND_MESSAGE.set_token('MSG', 'breakup_segs() exception: ' || SQLERRM);
4391 --       return(-2);
4392 --
4393 --   END breakup_segs;
4394 
4395 /* ----------------------------------------------------------------------- */
4396 /*      Executes a dynamic SQL statement.                                  */
4397 /*      Returns number of rows processed or -1 if error (add_message)      */
4398 /* ----------------------------------------------------------------------- */
4399 FUNCTION x_dsql_execute RETURN NUMBER IS
4400 
4401 cursornum     INTEGER;
4402 nprocessed    INTEGER;
4403 sql_statement    VARCHAR2(32000);
4404 
4405 BEGIN
4406 
4407 --  Copy SQL string to array for debugging purposes
4408 --
4409   add_sql_string(fnd_dsql.get_text(p_with_debug => TRUE));
4410 
4411   cursornum := dbms_sql.open_cursor;
4412   fnd_dsql.set_cursor(cursornum);
4413 
4414   sql_statement := fnd_dsql.get_text(p_with_debug => FALSE);
4415   dbms_sql.parse(cursornum, sql_statement, dbms_sql.v7);
4416 
4417   fnd_dsql.do_binds;
4418 
4419   nprocessed := dbms_sql.execute(cursornum);
4420   IF (fnd_flex_server1.g_debug_level > 0) THEN
4421      add_debug('(DSQL_execute processed ' || to_char(nprocessed));
4422      add_debug(' rows.)');
4423   END IF;
4424   dbms_sql.close_cursor(cursornum);
4425   return(nprocessed);
4426 
4427 EXCEPTION
4428   WHEN OTHERS then
4432     FND_MESSAGE.set_name('FND', 'FLEX-DSQL EXCEPTION');
4429     if(dbms_sql.is_open(cursornum)) then
4430       dbms_sql.close_cursor(cursornum);
4431     end if;
4433     FND_MESSAGE.set_token('MSG', SQLERRM);
4434     FND_MESSAGE.set_token('SQLSTR', SUBSTRB(sql_statement, 1, 1000));
4435     return(-1);
4436 
4437 END x_dsql_execute;
4438 
4439 /* ----------------------------------------------------------------------- */
4440 /*      Uses dynamic SQL to select up to one varchar2 valued column from   */
4441 /*      a table using the select statement passed in.  Returns 0, NULL     */
4442 /*      if no rows found, or 1 and the column value if 1 row found, or     */
4443 /*      2 and the column value of the first row found if more than 1 row   */
4444 /*      matches selection criteria, or < 0 if other errors.                */
4445 /*      Invalid rowid exception mapped back to no data found.              */
4446 /* ----------------------------------------------------------------------- */
4447 FUNCTION x_dsql_select_one(returned_column OUT nocopy VARCHAR2) RETURN NUMBER IS
4448 cursornum     INTEGER;
4449 num_returned  INTEGER;
4450 selected_col  VARCHAR2(2000);
4451 invalid_rowid EXCEPTION;
4452 sql_statement    VARCHAR2(32000);
4453 
4454 PRAGMA EXCEPTION_INIT(invalid_rowid, -1410);
4455 
4456 BEGIN
4457 
4458 --  Copy SQL string to array for debugging purposes
4459 --
4460   add_sql_string(fnd_dsql.get_text(p_with_debug => TRUE));
4461 
4462   selected_col := NULL;
4463   cursornum := dbms_sql.open_cursor;
4464   fnd_dsql.set_cursor(cursornum);
4465 
4466   sql_statement := fnd_dsql.get_text(p_with_debug => FALSE);
4467   dbms_sql.parse(cursornum, sql_statement, dbms_sql.v7);
4468 
4469   fnd_dsql.do_binds;
4470 
4471   dbms_sql.define_column(cursornum, 1, selected_col, 2000);
4472   num_returned := dbms_sql.execute_and_fetch(cursornum, TRUE);
4473   if(num_returned = 1) then
4474     dbms_sql.column_value(cursornum, 1, selected_col);
4475     returned_column := selected_col;
4476     IF (fnd_flex_server1.g_debug_level > 0) THEN
4477        add_debug('(DSQL returned ' || selected_col || ')');
4478     END IF;
4479   else
4480     num_returned := -1;
4481     returned_column := NULL;
4482     FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
4483     FND_MESSAGE.set_token('MSG', 'x_dsql_select_one() could not fetch rows');
4484   end if;
4485 dbms_sql.close_cursor(cursornum);
4486 return(num_returned);
4487 
4488 EXCEPTION
4489   WHEN NO_DATA_FOUND or invalid_rowid then
4490     returned_column := NULL;
4491     IF (fnd_flex_server1.g_debug_level > 0) THEN
4492        add_debug('(DSQL returned: NULL)');
4493     END IF;
4494     dbms_sql.close_cursor(cursornum);
4495     return(0);
4496   WHEN TOO_MANY_ROWS then
4497     dbms_sql.column_value(cursornum, 1, selected_col);
4498     returned_column := selected_col;
4499     IF (fnd_flex_server1.g_debug_level > 0) THEN
4500        add_debug('(DSQL returned: TOO MANY ROWS)');
4501     END IF;
4502     dbms_sql.close_cursor(cursornum);
4503     return(2);
4504   WHEN OTHERS then
4505     if(dbms_sql.is_open(cursornum)) then
4506       dbms_sql.close_cursor(cursornum);
4507     end if;
4508     FND_MESSAGE.set_name('FND', 'FLEX-DSQL EXCEPTION');
4509     FND_MESSAGE.set_token('MSG', SQLERRM);
4510     FND_MESSAGE.set_token('SQLSTR', SUBSTRB(sql_statement, 1, 1000));
4511     return(-2);
4512 
4513 END x_dsql_select_one;
4514 
4515 /* ----------------------------------------------------------------------- */
4516 /*      Uses dynamic SQL to select n_selected_cols of VARCHAR2 type from   */
4517 /*      a table using the select statement passed in.  Returns number      */
4518 /*      of rows found, or sets error and returns < 0 if error.             */
4519 /*      Invalid rowid exception mapped back to no data found.              */
4520 /* ----------------------------------------------------------------------- */
4521 FUNCTION x_dsql_select(n_selected_cols  IN  NUMBER,
4522                        returned_columns OUT nocopy StringArray) RETURN NUMBER
4523   IS
4524      cursornum        INTEGER;
4525      num_returned     INTEGER;
4526      selected_cols    StringArray;
4527      invalid_rowid    EXCEPTION;
4528      sql_statement    VARCHAR2(32000);
4529 
4530      PRAGMA EXCEPTION_INIT(invalid_rowid, -1410);
4531 BEGIN
4532 
4533    --  Copy SQL string to array for debugging purposes
4534    --
4535    add_sql_string(fnd_dsql.get_text(p_with_debug => TRUE));
4536 
4537    cursornum := dbms_sql.open_cursor;
4538    fnd_dsql.set_cursor(cursornum);
4539 
4540    sql_statement := fnd_dsql.get_text(p_with_debug => FALSE);
4541    dbms_sql.parse(cursornum, sql_statement, dbms_sql.v7);
4542 
4543    fnd_dsql.do_binds;
4544 
4545    for i in 1..n_selected_cols loop
4546       --    The following prevents NO-DATA-FOUND exception...
4547       selected_cols(i) := NULL;
4548       dbms_sql.define_column(cursornum, i, selected_cols(i), 2000);
4549    end loop;
4550    num_returned := dbms_sql.execute_and_fetch(cursornum, TRUE);
4551    if(num_returned = 1) then
4552       IF (fnd_flex_server1.g_debug_level > 0) THEN
4553          add_debug('(DSQL returned');
4554       END IF;
4555       for i in 1..n_selected_cols loop
4556          dbms_sql.column_value(cursornum, i, selected_cols(i));
4557          IF (fnd_flex_server1.g_debug_level > 0) THEN
4561       IF (fnd_flex_server1.g_debug_level > 0) THEN
4558             add_debug(' ''' || selected_cols(i) || '''');
4559          END IF;
4560       end loop;
4562          add_debug(')');
4563       END IF;
4564     else
4565       num_returned := -1;
4566       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
4567       FND_MESSAGE.set_token('MSG', 'x_dsql_select() could not fetch rows');
4568    end if;
4569    dbms_sql.close_cursor(cursornum);
4570    returned_columns := selected_cols;
4571    return(num_returned);
4572 
4573 EXCEPTION
4574   WHEN NO_DATA_FOUND OR invalid_rowid then
4575      IF (fnd_flex_server1.g_debug_level > 0) THEN
4576         add_debug('(DSQL returned: NULL)');
4577      END IF;
4578     dbms_sql.close_cursor(cursornum);
4579     return(0);
4580   WHEN TOO_MANY_ROWS then
4581      IF (fnd_flex_server1.g_debug_level > 0) THEN
4582         add_debug('(DSQL returned');
4583      END IF;
4584     for i in 1..n_selected_cols loop
4585       dbms_sql.column_value(cursornum, i, selected_cols(i));
4586       IF (fnd_flex_server1.g_debug_level > 0) THEN
4587          add_debug(' ''' || selected_cols(i) || '''');
4588       END IF;
4589     end loop;
4590     IF (fnd_flex_server1.g_debug_level > 0) THEN
4591        add_debug(')');
4592        add_debug('(DSQL returned: TOO MANY ROWS)');
4593     END IF;
4594     dbms_sql.close_cursor(cursornum);
4595     returned_columns := selected_cols;
4596     return(2);
4597   WHEN OTHERS then
4598     if(dbms_sql.is_open(cursornum)) then
4599       dbms_sql.close_cursor(cursornum);
4600     end if;
4601     FND_MESSAGE.set_name('FND', 'FLEX-DSQL EXCEPTION');
4602     FND_MESSAGE.set_token('MSG', SQLERRM);
4603     FND_MESSAGE.set_token('SQLSTR', SUBSTRB(sql_statement, 1, 1000));
4604     return(-2);
4605 
4606 END x_dsql_select;
4607 
4608 /* ----------------------------------------------------------------------- */
4609 /*      Adds string to array of dynamic sql strings.                       */
4610 /*      The buffer is zeroed when init_globals is called.                  */
4611 /* ----------------------------------------------------------------------- */
4612 PROCEDURE add_sql_string(sql_statement IN VARCHAR2) IS
4613 BEGIN
4614   n_sqlstrings := n_sqlstrings + 1;
4615   sqlstrings(n_sqlstrings) := sql_statement;
4616 END add_sql_string;
4617 
4618 /* ----------------------------------------------------------------------- */
4619 /*      For debugging.                                                     */
4620 /*      Returns number of SQL statements created during last call          */
4621 /*      to validate().  Use in conjunction with get_sql().                 */
4622 /* ----------------------------------------------------------------------- */
4623 FUNCTION get_nsql_internal RETURN NUMBER IS
4624 BEGIN
4625   return(nvl(to_number(n_sqlstrings), 0));
4626 END get_nsql_internal;
4627 
4628 /* ----------------------------------------------------------------------- */
4629 /*      For debugging.                                                     */
4630 /*      Returns SQL statements created during last call                    */
4631 /*      to validate().  Use in conjunction with get_sql().                 */
4632 /* ----------------------------------------------------------------------- */
4633 FUNCTION get_sql_internal(statement_number IN NUMBER,
4634                  statement_portion IN NUMBER DEFAULT 1) RETURN VARCHAR2 IS
4635 
4636   dsql_start  NUMBER;
4637 
4638 BEGIN
4639 
4640   if((statement_number is null) or (statement_number < 1) or
4641      (statement_number > nvl(to_number(n_sqlstrings), 0)) or
4642      (statement_portion is null) or (statement_portion < 1) or
4643      (sqlstrings(statement_number) is null)) then
4644      return(NULL);
4645   end if;
4646 
4647   dsql_start := 1 + ((statement_portion - 1) * MAX_RETSTR_LEN);
4648   if(dsql_start > LENGTH(sqlstrings(statement_number))) then
4649     return(NULL);
4650   end if;
4651 
4652   return(SUBSTR(sqlstrings(statement_number), dsql_start, MAX_RETSTR_LEN));
4653 
4654   EXCEPTION
4655   WHEN NO_DATA_FOUND then
4656       return('get_sql_internal('||to_char(statement_number)||') statement not found');
4657   WHEN OTHERS then
4658       return('get_sql_internal() exception: ' || SQLERRM);
4659 
4660 END get_sql_internal;
4661 
4662 /* ----------------------------------------------------------------------- */
4663 /*                      Adds to debug string                               */
4664 /* ----------------------------------------------------------------------- */
4665 PROCEDURE set_debugging(p_debug_mode IN VARCHAR2)
4666   IS
4667 BEGIN
4668    IF (p_debug_mode = 'OFF') THEN
4669       fnd_flex_server1.g_debug_level := 0;
4670     ELSIF (p_debug_mode = 'ERROR') THEN
4671       fnd_flex_server1.g_debug_level := 1;
4672     ELSIF (p_debug_mode = 'EXCEPTION') THEN
4673       fnd_flex_server1.g_debug_level := 2;
4674     ELSIF (p_debug_mode = 'EVENT') THEN
4675       fnd_flex_server1.g_debug_level := 3;
4676     ELSIF (p_debug_mode = 'PROCEDURE') THEN
4677       fnd_flex_server1.g_debug_level := 4;
4678     ELSIF (p_debug_mode = 'STATEMENT') THEN
4679       fnd_flex_server1.g_debug_level := 5;
4680     ELSIF (p_debug_mode = 'ALL') THEN
4681       fnd_flex_server1.g_debug_level := 6;
4682       fnd_flex_val_util.set_debugging(TRUE);
4683     ELSE
4684       fnd_flex_server1.g_debug_level := 0;
4685    END IF;
4689 END set_debugging;
4686 EXCEPTION
4687    WHEN OTHERS THEN
4688       fnd_flex_server1.g_debug_level := 0;
4690 
4691 /* ----------------------------------------------------------------------- */
4692 /*                      Adds to debug string                               */
4693 /* ----------------------------------------------------------------------- */
4694 PROCEDURE add_debug(p_debug_string IN VARCHAR2,
4695                     p_debug_mode   IN VARCHAR2 DEFAULT 'STATEMENT')
4696   IS
4697      l_code_level NUMBER;
4698      l_debug_string VARCHAR2(32000);
4699      l_newline_pos  NUMBER;
4700      l_debug_line   VARCHAR2(32000);
4701 BEGIN
4702    IF (fnd_flex_server1.g_debug_level = 0) THEN
4703       RETURN;
4704    END IF;
4705    IF (p_debug_mode = 'OFF') THEN
4706       l_code_level := 0;
4707     ELSIF (p_debug_mode = 'ERROR') THEN
4708       l_code_level := 1;
4709     ELSIF (p_debug_mode = 'EXCEPTION') THEN
4710       l_code_level := 2;
4711     ELSIF (p_debug_mode = 'EVENT') THEN
4712       l_code_level := 3;
4713     ELSIF (p_debug_mode = 'PROCEDURE') THEN
4714       l_code_level := 4;
4715     ELSIF (p_debug_mode = 'STATEMENT') THEN
4716       l_code_level := 5;
4717     ELSIF (p_debug_mode = 'ALL') THEN
4718       l_code_level := 6;
4719     ELSE
4720       l_code_level := 0;
4721    END IF;
4722 
4723    IF (l_code_level <= fnd_flex_server1.g_debug_level) THEN
4724       IF (g_debug_array_size = 0) THEN
4725          g_debug_array_size := 1;
4726          g_debug_array(g_debug_array_size) :=
4727            ('DEBUG LEVEL:'||To_char(fnd_flex_server1.g_debug_level) ||
4728             chr_newline);
4729       END IF;
4730 
4731       l_debug_string := (Substr(Rtrim(Ltrim(p_debug_string)), 1, MAX_RETSTR_LEN-10) ||
4732                          chr_newline);
4733 
4734       WHILE (l_debug_string IS NOT NULL) LOOP
4735          l_newline_pos := Instr(l_debug_string, chr_newline, 1, 1);
4736          IF (l_newline_pos +
4737              Nvl(Length(g_debug_array(g_debug_array_size)), 0) < MAX_RETSTR_LEN) THEN
4738             l_debug_line := Substr(l_debug_string, 1, l_newline_pos);
4739             l_debug_string := Substr(l_debug_string, l_newline_pos + 1);
4740             IF (l_debug_line LIKE 'BEGIN %' OR
4741                 l_debug_line LIKE 'END %' OR
4742                 l_debug_line LIKE 'CALL %' OR
4743                 l_debug_line LIKE 'EXCEPTION %') THEN
4744                g_debug_array(g_debug_array_size) :=
4745                  g_debug_array(g_debug_array_size) || l_debug_line;
4746              ELSE
4747                g_debug_array(g_debug_array_size) :=
4748                  g_debug_array(g_debug_array_size) || ' ' || l_debug_line;
4749             END IF;
4750           ELSE
4751             g_debug_array_size := g_debug_array_size + 1;
4752             g_debug_array(g_debug_array_size) := NULL;
4753          END IF;
4754       END LOOP;
4755    END IF;
4756 EXCEPTION
4757    WHEN OTHERS THEN
4758       NULL;
4759 END add_debug;
4760 
4761 /* ----------------------------------------------------------------------- */
4762 /*      Returns the debug string.                                          */
4763 /* ----------------------------------------------------------------------- */
4764 FUNCTION get_debug_internal(string_n IN NUMBER) RETURN VARCHAR2 IS
4765 BEGIN
4766    IF ((string_n is not null) and
4767        (string_n >= 1) AND
4768        (string_n) <= g_debug_array_size) THEN
4769       RETURN(g_debug_array(string_n));
4770    end if;
4771    return(NULL);
4772 
4773 EXCEPTION
4774    WHEN OTHERS then
4775       return('get_debug_internal() exception: ' || SQLERRM);
4776 END get_debug_internal;
4777 
4778 /* -------------------------------------------------- */
4779 /* New client side debug functions                    */
4780 /* -------------------------------------------------- */
4781 PROCEDURE x_get_nsql(x_nsql OUT nocopy NUMBER)
4782   IS
4783 BEGIN
4784    x_nsql := fnd_flex_server1.get_nsql_internal;
4785 EXCEPTION
4786    WHEN OTHERS THEN
4787       x_nsql := 0;
4788 END;
4789 
4790 PROCEDURE x_get_sql_npiece(p_sql_num IN NUMBER,
4791                            x_npiece  OUT nocopy NUMBER)
4792   IS
4793      l_sql_num NUMBER;
4794 BEGIN
4795    l_sql_num := Nvl(p_sql_num, 0);
4796    x_npiece := 0;
4797    IF ((l_sql_num > 0) AND
4798        (l_sql_num <= fnd_flex_server1.get_nsql_internal)) THEN
4799       x_npiece :=Ceil(Nvl(Lengthb(sqlstrings(l_sql_num)),0)/MAX_RETSTR_LEN);
4800    END IF;
4801 EXCEPTION
4802    WHEN OTHERS THEN
4803       x_npiece := 0;
4804 END;
4805 
4806 PROCEDURE x_get_sql_piece(p_sql_num   IN NUMBER,
4807                           p_piece_num IN NUMBER,
4808                           x_sql_piece OUT nocopy VARCHAR2)
4809   IS
4810      l_sql_num NUMBER;
4811      l_piece_num NUMBER;
4812 BEGIN
4813    l_sql_num := Nvl(p_sql_num, 0);
4814    l_piece_num := Nvl(p_piece_num, 0);
4815    x_sql_piece := NULL;
4816    IF ((l_sql_num > 0) AND
4817        (l_sql_num <= fnd_flex_server1.get_nsql_internal) AND
4818        (l_piece_num > 0)) THEN
4819       x_sql_piece := substrb(sqlstrings(l_sql_num),
4820                              1 + (l_piece_num - 1) * MAX_RETSTR_LEN,
4821                              MAX_RETSTR_LEN);
4822    END IF;
4823 EXCEPTION
4824    WHEN OTHERS THEN
4828 PROCEDURE x_get_ndebug(x_ndebug OUT nocopy NUMBER)
4825       x_sql_piece := substrb('EXCEPTION:' || Sqlerrm,1,MAX_RETSTR_LEN);
4826 END;
4827 
4829   IS
4830 BEGIN
4831    x_ndebug := g_debug_array_size;
4832 EXCEPTION
4833    WHEN OTHERS THEN
4834       x_ndebug := 0;
4835 END;
4836 
4837 PROCEDURE x_get_debug(p_debug_num IN NUMBER,
4838                       x_debug OUT nocopy VARCHAR2)
4839   IS
4840      l_debug_num NUMBER;
4841 BEGIN
4842    l_debug_num := Nvl(p_debug_num, 0);
4843    IF (l_debug_num >= 1 AND
4844        l_debug_num <= g_debug_array_size) THEN
4845       x_debug := g_debug_array(l_debug_num);
4846     ELSE
4847       x_debug := 'INDEX OUT OF RANGE [1..' || g_debug_array_size || '].';
4848    END IF;
4849 EXCEPTION
4850    WHEN OTHERS THEN
4851       x_debug := substrb('EXCEPTION:' || Sqlerrm,1,MAX_RETSTR_LEN);
4852 END;
4853 
4854 /* ----------------------------------------------------------------------- */
4855 /*               Converts concatenated segments to segment array           */
4856 /*      Segment array is 1-based containing entries for 1 <= i <= nsegs    */
4857 /* ----------------------------------------------------------------------- */
4858 FUNCTION to_stringarray(catsegs IN  VARCHAR2,
4859                         sepchar in  VARCHAR2,
4860                         segs    OUT nocopy StringArray)
4861   RETURN NUMBER
4862   IS
4863      l_wc         VARCHAR2(10);
4864      l_flex_value VARCHAR2(2000);
4865      i            NUMBER;
4866      l_segnum     PLS_INTEGER;
4867      l_delimiter  VARCHAR2(10);
4868      l_tmp_str    VARCHAR2(32000);
4869      l_delim_pos  PLS_INTEGER;
4870      l_old_delim_pos  PLS_INTEGER;
4871 BEGIN
4872    l_delimiter := Substr(sepchar, 1, 1);
4873 
4874    --
4875    -- Make sure delimiter is valid.
4876    --
4877    IF ((l_delimiter IS NULL) OR (l_delimiter = FLEX_DELIMITER_ESCAPE)) THEN
4878       raise_application_error(-20001,
4879                               'SV2.to_stringarray. Invalid delimiter:''' ||
4880                               Nvl(sepchar, '<NULL>') || '''');
4881    END IF;
4882 
4883    --
4884    -- If catsegs is NULL then assume there is only one segment.
4885    --
4886    IF (catsegs IS NULL) THEN
4887       l_segnum := 1;
4888       segs(1) := catsegs;
4889       GOTO return_success;
4890    END IF;
4891 
4892    l_segnum := 0;
4893    i := 1;
4894 
4895    -- We need to go through un-escaping logic only if
4896    -- there is an ESCAPE character in the string.
4897    -- Bug 4501279.
4898 
4899    IF (instr(catsegs, FLEX_DELIMITER_ESCAPE) > 0) THEN
4900 
4901       --
4902       -- Loop for each segment.
4903       --
4904       LOOP
4905          l_flex_value := NULL;
4906 
4907          --
4908          -- Un-escaping loop.
4909          --
4910          LOOP
4911 
4912             l_wc := Substr(catsegs, i, 1);
4913             i := i + 1;
4914 
4915             IF (l_wc IS NULL) THEN
4916                EXIT;
4917             ELSIF (l_wc = l_delimiter) THEN
4918                EXIT;
4919             ELSIF (l_wc = FLEX_DELIMITER_ESCAPE) THEN
4920 
4921                l_wc := Substr(catsegs, i, 1);
4922                i := i + 1;
4923 
4924                IF (l_wc IS NULL) THEN
4925                   EXIT;
4926                END IF;
4927 
4928             END IF;
4929 
4930             l_flex_value := l_flex_value || l_wc;
4931 
4932          END LOOP;
4933 
4934          l_segnum := l_segnum + 1;
4935          segs(l_segnum) := l_flex_value;
4936          IF (l_wc IS NULL) THEN
4937             EXIT;
4938          END IF;
4939       END LOOP;
4940 
4941    ELSE
4942 
4943       -- No un-escaping logic required here.
4944 
4945       l_tmp_str := catsegs;
4946       l_delim_pos := 0;
4947       l_old_delim_pos := 0;
4948 
4949       LOOP
4950 
4951          l_delim_pos := instr(l_tmp_str, l_delimiter, l_delim_pos+1);
4952 
4953          IF (l_delim_pos <> 0) THEN
4954             l_segnum := l_segnum + 1;
4955             segs(l_segnum) := substr(l_tmp_str, l_old_delim_pos+1, l_delim_pos-l_old_delim_pos-1);
4956             l_old_delim_pos := l_delim_pos;
4957          ELSE
4958             l_segnum := l_segnum + 1;
4959             segs(l_segnum) := substr(l_tmp_str, l_old_delim_pos+1);
4960             EXIT;
4961          END IF;
4962 
4963       END LOOP;
4964 
4965    END IF;
4966 
4967    <<return_success>>
4968      RETURN(l_segnum);
4969 
4970 EXCEPTION
4971    WHEN OTHERS THEN
4972       raise_application_error(-20001, 'SV2.to_stringarray. SQLERRM : ' ||
4973                               Sqlerrm);
4974 END to_stringarray;
4975 
4976 /* ----------------------------------------------------------------------- */
4977 /*               Converts segment array to concatenated segments           */
4978 /*      Segment array is 1-based containing entries for 1 <= i <= nsegs    */
4979 /* ----------------------------------------------------------------------- */
4980 FUNCTION from_stringarray(nsegs   IN NUMBER,
4981                           segs    IN StringArray,
4982                           sepchar IN VARCHAR2) RETURN VARCHAR2
4983   IS
4984      l_wc          VARCHAR2(10);
4985      l_return      VARCHAR2(32000) := NULL;
4986      i             pls_integer;
4990    l_delimiter := Substr(sepchar, 1, 1);
4987      l_segnum      pls_integer;
4988      l_delimiter   VARCHAR2(10);
4989 BEGIN
4991    IF (fnd_flex_server1.g_debug_level > 0) THEN
4992       fnd_flex_server1.add_debug('BEGIN SV1.from_stringarray()');
4993    END IF;
4994    --
4995    -- Make sure delimiter is valid.
4996    --
4997    IF ((l_delimiter IS NULL) OR (l_delimiter = FLEX_DELIMITER_ESCAPE)) THEN
4998       raise_application_error(-20001,
4999                               'SV1.from_stringarray. Invalid delimiter:''' ||
5000                               Nvl(sepchar, '<NULL>') || '''');
5001    END IF;
5002 
5003    --
5004    -- Make sure array size is valid.
5005    --
5006    IF ((nsegs IS NULL) OR (nsegs < 1)) THEN
5007       raise_application_error(-20001,
5008                               'SV1.from_stringarray. For specified context there are ''' ||
5009                               Nvl(to_char(nsegs), '<NULL>') || '''' || ' displayed segments');
5010    END IF;
5011 
5012    --
5013    -- If only one segment then no need for concatenating or escaping.
5014    --
5015    IF (nsegs = 1) THEN
5016       l_return := segs(1);
5017       GOTO return_success;
5018    END IF;
5019 
5020    --
5021    -- Loop for each segment
5022    --
5023    FOR l_segnum IN 1..nsegs LOOP
5024 
5025       i := 1;
5026 
5027       --
5028       -- Escaping loop.
5029       --
5030       LOOP
5031 
5032          l_wc := Substr(segs(l_segnum), i, 1);
5033          i := i + 1;
5034 
5035          IF (l_wc IS NULL) THEN
5036             EXIT;
5037           ELSIF (l_wc = FLEX_DELIMITER_ESCAPE) THEN
5038             l_return := l_return || FLEX_DELIMITER_ESCAPE;
5039             l_return := l_return || FLEX_DELIMITER_ESCAPE;
5040           ELSIF (l_wc = l_delimiter) THEN
5041             l_return := l_return || FLEX_DELIMITER_ESCAPE;
5042             l_return := l_return || l_delimiter;
5043           ELSE
5044             l_return := l_return || l_wc;
5045          END IF;
5046 
5047       END LOOP;
5048 
5049       --
5050       -- No delimiter after the last value.
5051       --
5052       IF (l_segnum < nsegs) THEN
5053          l_return := l_return || l_delimiter;
5054       END IF;
5055    END LOOP;
5056 
5057    <<return_success>>
5058      IF (fnd_flex_server1.g_debug_level > 0) THEN
5059         fnd_flex_server1.add_debug('END SV1.from_stringarray()');
5060      END IF;
5061      RETURN(l_return);
5062 EXCEPTION
5063    WHEN OTHERS THEN
5064       IF (fnd_flex_server1.g_debug_level > 0) THEN
5065          fnd_flex_server1.add_debug('EXCEPTION SV1.from_stringarray()');
5066       END IF;
5067       raise_application_error(-20001, 'SV1.from_stringarray. SQLERRM : ' || Sqlerrm);
5068 END from_stringarray;
5069 
5070 /* ----------------------------------------------------------------------- */
5071 /*               Converts concatenated segments to segment array           */
5072 /*      Segment array is 1-based containing entries for 1 <= i <= nsegs    */
5073 /*      Bug 1375146 added elsif statement to allow for only 1 segment      */
5074 /*                  which is null.                                         */
5075 /* ----------------------------------------------------------------------- */
5076 FUNCTION to_stringarray2(catsegs IN  VARCHAR2,
5077                          sepchar in  VARCHAR2,
5078                          segs    OUT nocopy StringArray)
5079   RETURN NUMBER
5080   IS
5081      seg_start        NUMBER;
5082      seg_end          NUMBER;
5083      seg_len          NUMBER;
5084      catseg_len       NUMBER;
5085      sepchar_len      NUMBER;
5086      seg_index        BINARY_INTEGER;
5087      keep_going       BOOLEAN;
5088 BEGIN
5089    seg_index := 1;
5090    seg_start := 1;
5091    keep_going := TRUE;
5092    IF ((catsegs IS NOT NULL) AND (sepchar IS NOT NULL)) THEN
5093       catseg_len := LENGTH(catsegs);
5094       sepchar_len := LENGTH(sepchar);
5095       WHILE (keep_going = TRUE) LOOP
5096          IF (seg_start > catseg_len) THEN
5097             segs(seg_index) := NULL;
5098             keep_going := FALSE;
5099           ELSE
5100             seg_end := INSTR(catsegs, sepchar, seg_start);
5101             IF (seg_end = 0) THEN
5102                seg_end := catseg_len + 1;
5103                keep_going := FALSE;
5104             END IF;
5105             seg_len := seg_end - seg_start;
5106             IF (seg_len = 0) THEN
5107                segs(seg_index) := NULL;
5108              ELSE
5109                segs(seg_index) := REPLACE(SUBSTR(catsegs, seg_start, seg_len),
5110                                           NEWLINE, sepchar);
5111             END IF;
5112          END IF;
5113          seg_index := seg_index + 1;
5114          seg_start := seg_end + sepchar_len;
5115       END LOOP;
5116     ELSIF ((catsegs IS NULL) AND (sepchar IS NULL)) THEN
5117       seg_index :=1;
5118     ELSIF ((catsegs IS NULL) AND (sepchar IS NOT NULL)) THEN
5119       segs(1) := NULL;
5120       seg_index := 2;
5121     ELSIF ((catsegs IS NOT NULL) AND (sepchar IS NULL)) THEN
5122       seg_index := 1;
5123    END IF;
5124    RETURN(To_number(seg_index - 1));
5125 END to_stringarray2;
5126 
5127 /* ----------------------------------------------------------------------- */
5128 /*               Converts segment array to concatenated segments           */
5132                            segs    IN StringArray,
5129 /*      Segment array is 1-based containing entries for 1 <= i <= nsegs    */
5130 /* ----------------------------------------------------------------------- */
5131 FUNCTION from_stringarray2(nsegs   IN NUMBER,
5133                            sepchar IN VARCHAR2) RETURN VARCHAR2
5134   IS
5135      l_return VARCHAR2(2000) := NULL;
5136 BEGIN
5137    IF (fnd_flex_server1.g_debug_level > 0) THEN
5138       fnd_flex_server1.add_debug('CALL SV1.from_stringarray2()');
5139    END IF;
5140    --
5141    -- Concatenate the segment values. No separator after the last value.
5142    --
5143    IF (nsegs > 0) THEN
5144       FOR i IN 1..(nsegs-1) LOOP
5145          l_return := l_return || REPLACE(segs(i), sepchar, NEWLINE) || sepchar;
5146       END LOOP;
5147       l_return := l_return || REPLACE(segs(nsegs), sepchar, NEWLINE);
5148    END IF;
5149    RETURN(l_return);
5150 END from_stringarray2;
5151 
5152 
5153 --------------------------------------------------------------------------------
5154 -- This procedure parses a SQL string into following pieces:
5155 --   - bind               (i.e. :bind portion of a SQL statement)
5156 --   - single quoted      (i.e. string literal portion of a SQL statement)
5157 --   - sql                (i.e. rest of the sql statement)
5158 --
5159 --------------------------------------------------------------------------------
5160 procedure parse_sql_string(p_sql_string  in varchar2,
5161                            px_sql_pieces in out nocopy sql_pieces_tab_type)
5162   IS
5163      l_sql_string      varchar2(32000);
5164      l_sql_piece_count BINARY_INTEGER;
5165      l_first_chr       varchar2(1);
5166      l_tmp_string      varchar2(32000);
5167 
5168      l_quote_pos       number;
5169      l_quote2_pos      number;
5170      l_colon_pos       number;
5171      l_end_pos         number;
5172 begin
5173    l_sql_string := p_sql_string;
5174    l_sql_piece_count := 0;
5175    px_sql_pieces.DELETE;
5176 
5177    while (l_sql_string is not null) loop
5178 
5179       l_first_chr := substr(l_sql_string, 1, 1);
5180 
5181       if (l_first_chr = SSP_QUOTE) then
5182          --
5183          -- single quoted section, find the end
5184          --
5185          l_quote2_pos := 0;
5186          loop
5187             --
5188             -- Skip double single quotes
5189             --
5190             l_quote_pos := instr(l_sql_string, SSP_QUOTE, l_quote2_pos + 2);
5191             if (l_quote_pos = 0) then
5192                --
5193                -- Error, not terminated properly
5194                --
5195                FND_MESSAGE.set_name('FND', 'FLEX-SQL MISSING QUOTE');
5196                FND_MESSAGE.set_token('CLAUSE', p_sql_string);
5197 
5198                raise_application_error
5199                  (-20001,
5200                   'Error: Single Quote is not terminated properly. ' ||
5201                   'SQL: ' || p_sql_string);
5202             else
5203                l_quote2_pos := instr(l_sql_string, SSP_QUOTE2, l_quote_pos);
5204                if (l_quote2_pos = l_quote_pos) then
5205                   --
5206                   -- double single quote, skip it
5207                   --
5208                   null;
5209                else
5210                   --
5211                   -- end of single quoted section
5212                   --
5213                   exit;
5214                end if;
5215             end if;
5216          end loop;
5217 
5218          l_sql_piece_count := l_sql_piece_count + 1;
5219          px_sql_pieces(l_sql_piece_count).piece_type := SSP_PIECE_TYPE_QUOTED;
5220          px_sql_pieces(l_sql_piece_count).piece_text := substr(l_sql_string, 1, l_quote_pos);
5221 
5222          l_sql_string := substr(l_sql_string, l_quote_pos + 1);
5223 
5224       elsif (l_first_chr = SSP_COLON) then
5225          --
5226          -- bind section
5227          --
5228          l_tmp_string := ltrim(l_sql_string, SSP_BIND_CHARS);
5229 
5230          l_sql_piece_count := l_sql_piece_count + 1;
5231          px_sql_pieces(l_sql_piece_count).piece_type := SSP_PIECE_TYPE_BIND;
5232          px_sql_pieces(l_sql_piece_count).piece_text := substr(l_sql_string, 1, length(l_sql_string) - nvl(length(l_tmp_string), 0));
5233 
5234          l_sql_string := l_tmp_string;
5235 
5236       else
5237          --
5238          -- sql section, find the end
5239          --
5240          l_quote_pos := instr(l_sql_string, SSP_QUOTE);
5241          l_colon_pos := instr(l_sql_string, SSP_COLON);
5242 
5243          if ((l_quote_pos = 0) and (l_colon_pos = 0)) then
5244             --
5245             -- no quotes, no binds, the remaining section is just sql
5246             --
5247             l_end_pos := length(l_sql_string);
5248 
5249          elsif (l_quote_pos = 0) then
5250             --
5251             -- no quotes
5252             --
5253             l_end_pos := l_colon_pos - 1;
5254 
5255          elsif (l_colon_pos = 0) then
5256             --
5257             -- no binds
5258             --
5259             l_end_pos := l_quote_pos - 1;
5260 
5261          else
5262             --
5263             -- both quotes, and binds
5264             --
5265             l_end_pos := least(l_quote_pos, l_colon_pos) - 1;
5266 
5267          end if;
5268 
5269          l_sql_piece_count := l_sql_piece_count + 1;
5270          px_sql_pieces(l_sql_piece_count).piece_type := SSP_PIECE_TYPE_SQL;
5271          px_sql_pieces(l_sql_piece_count).piece_text := substr(l_sql_string, 1, l_end_pos);
5272 
5273          l_sql_string := substr(l_sql_string, l_end_pos + 1);
5274 
5275       end if;
5276    end loop;
5277 end parse_sql_string;
5278 
5279 BEGIN
5280    chr_newline := fnd_global.newline;
5281    NEWLINE     := fnd_global.newline;
5282    TAB         := fnd_global.tab;
5283    WHITESPACE  := ' ' || TAB || NEWLINE;
5284 
5285    fnd_plsql_cache.generic_1to1_init('SV1.VST',
5286                                      vst_cache_controller,
5287                                      vst_cache_storage);
5288 
5289    fnd_plsql_cache.generic_1to1_init('SV1.VSC',
5290                                      vsc_cache_controller,
5291                                      vsc_cache_storage);
5292 
5293    fnd_plsql_cache.generic_1to1_init('SV1.FVC',
5294                                      fvc_cache_controller,
5295                                      fvc_cache_storage);
5296 
5297    fnd_plsql_cache.generic_1tom_init('SV1.FSQ',
5298                                      fsq_cache_controller,
5299                                      fsq_cache_storage);
5300 
5301    fnd_plsql_cache.generic_1tom_init('SV1.VSQ',
5302                                      vsq_cache_controller,
5303                                      vsq_cache_storage);
5304 
5305    fnd_plsql_cache.custom_1tom_init('SV1.STR',
5306                                     str_cache_controller);
5307    str_cache_storage.DELETE;
5308 
5309    --
5310    -- Decimal separators.
5311    --
5312    IF (fnd_flex_val_util.get_mask('CANONICAL_NUMERIC_CHARS',tmp_varchar2)) THEN
5313       m_nc := Substr(tmp_varchar2,1,1);
5314     ELSE
5315       m_nc := '.';
5316    END IF;
5317 
5318    IF (fnd_flex_val_util.get_mask('DB_NUMERIC_CHARS',tmp_varchar2)) THEN
5319       m_nb := Substr(tmp_varchar2,1,1);
5320     ELSE
5321       m_nb := '.';
5322    END IF;
5323 
5324    IF (fnd_flex_val_util.get_mask('NLS_NUMERIC_CHARS_OUT',tmp_varchar2)) THEN
5325       m_nd := Substr(tmp_varchar2,1,1);
5326     ELSE
5327       m_nd := '.';
5328    END IF;
5329 END fnd_flex_server1;