DBA Data[Home] [Help]

PACKAGE BODY: APPS.FND_FLEX_SERVER1

Source


1 PACKAGE BODY fnd_flex_server1 AS
2 /* $Header: AFFFSV1B.pls 120.29.12020000.2 2012/07/19 00:32:43 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;
330 
331 FUNCTION check_vrules(vrs     IN Vrules,
332                       sqs     IN Qualifiers,
333                       sumflg  IN VARCHAR2) RETURN VARCHAR2;
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,
447                    p_responsibility_id IN NUMBER,
448                    p_value_set_id      IN NUMBER,
449                    p_parent_value      IN VARCHAR2,
450                    p_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
577      (x_value       => g_cache_value,
578       p_varchar2_1  => p_flexvalue.displayed_value,
579       p_varchar2_2  => p_flexvalue.stored_value,
580       p_varchar2_3  => p_flexvalue.hidden_id,
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 
709     IF (fnd_flex_server1.g_debug_level > 0) THEN
710        add_debug('(' || thisval || ') ');
711     END IF;
712 
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  */
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    */
844 /*      corresponds to the segment indicated.  The error segment number    */
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(201);
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
937         AND g.enabled_flag = 'Y'
938         AND c.application_id = t_apid
939         AND c.table_id = t_id
940         AND c.column_name = g.application_column_name
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
1077         if(get_value_set(seginfo.vsid, seginfo.segname, vsinfo) <> TRUE) then
1078            errseg_num := segcount;
1079            segcount := segcount - 1;
1080            return_code := VV_ERROR;
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      --
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
1210      --  overwritten any prior value errors, and then return.
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() ');
1341       END IF;
1342 
1343       return(VV_ERROR);
1344 
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
1469     vcode := default_val(kseg.dflt_type, kseg.dflt_val, vsinf.vsformat,
1470                          vsinf.maxsize, vsinf.precis, vsinf.lettersok,
1471                          kseg.segname, nprev,
1472                          prev_dispvals, prev_vals, prev_ids, prev_descs,
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  --  Bug 13394636 - when a required segment is queried and the data is a null
1519  --  value for that segment, the client and server validation code differ in
1520  --  behavior.  The client code gives no error, however the server code does.
1521  --  We are syncing the behaviour in favor of the client code by adding the
1522  --  check for invoking_mode = 'L'
1523 
1524 
1525  if(thisseg is null) then
1526     if vsinf.parent_vsid is not NULL and vsinf.valtype = 'D'
1527     then
1528        NULL;       -- we will check again for DFF nulls after getting parent.
1529     else
1530        if((kseg.required = 'N') or (vflags.allow_nulls) or (vflags.invoking_mode = 'L'))
1531        then
1532           vcode := FF_VVALID;
1533           goto return_val;
1534         else
1535           vcode := FF_VREQUIRED;
1536           if(vflags.message_on_null) then
1537              value_error_name('FND', 'FLEX-NULL REQUIRED SEGMENT');
1538              value_error_token('SEGMENT_NAME', kseg.segname);
1539           /* Bug 9006077 value_error_name('FND', 'FLEX-NULL SEGMENT');*/
1540           end if;
1541           goto return_val;
1542        end if;
1543     end if;
1544  end if;
1545 
1546  -- Coerces user input from being a rough approximation of the displayed
1547  -- value format, to the value storage format.
1548  -- Also checks length and that value is in min-max range.
1549  -- Side effect: change thisseg to stored format appropriate to the value set.
1550  -- Added "and thisseg is not null" in conjuction with changes for bug 1879889
1551  -- as it is now possible to be here with a null segment.
1552 
1553  -- Validate None validated value sets too.
1554  IF ((isvalu) OR
1555      (vsinf.valtype = 'N')) and thisseg is not null then
1556     vcode := coerce_format(thisseg, isvalu, vsinf.vsformat, vsinf.vsname,
1557                            vsinf.maxsize, vsinf.lettersok, vsinf.capsonly,
1558                            vsinf.zfill, vsinf.precis, vsinf.minval,
1559                            vsinf.maxval,l_storage_value, l_display_value);
1560     thisseg := l_storage_value;
1561     if(vcode <> FF_VVALID) then
1562        goto return_val;
1563     end if;
1564  end if;
1565 
1566  --  Now look up value
1567 
1568  --  GL RELIES ON THE FOLLOWING STRANGE BEHAVIOR:
1569  --  To be compatible with client, orphans are ok if the child
1570  --  value was defaulted and nulls are allowed.
1571  --
1572  orphansok := (vflags.all_orphans_valid or
1573                (vflags.allow_nulls and defaulted));
1574 
1575  -- ==
1576  --
1577  -- Find parent value: took out from find_value.
1578  --
1579  -- ==
1580  l_fvc_code := fnd_plsql_cache.CACHE_NOTFOUND;
1581  IF (vsinf.valtype IN ('I','D','X','Y')) THEN
1582     IF (isvalu) then
1583        l_flexvalue.displayed_value := thisseg;
1584        l_flexvalue.stored_value := thisseg;
1585      else
1586        l_flexvalue.hidden_id := thisseg;
1587     end if;
1588     l_flexvalue.enabled_flag := 'Y';
1589     l_flexvalue.summary_flag := 'N';
1590     l_flexvalue.format := vsinf.vsformat;
1591 
1592     parentval := NULL;
1593 
1594     IF (vsinf.valtype in ('D','Y')) then
1595        IF (fnd_flex_server1.g_debug_level > 0) THEN
1596           add_debug(vsinf.valtype);
1597           for i in 1..nprev loop
1598              add_debug(to_char(prev_vsids(i)) || '.');
1599           end loop;
1600        END IF;
1601 
1602        --
1603        --  Find index to parent value set
1604        l_parent_index := 0;
1605        for i in reverse 1..nprev loop
1606           IF ((prev_vsids(i) is not null) and
1607               (vsinf.parent_vsid = prev_vsids(i))) then
1608              l_parent_index := i;
1609              IF (vsinf.valtype = 'D') THEN
1610                 parentval := prev_vals(i);
1611               ELSE
1612                 parentval := prev_ids(i);
1613              END IF;
1614              exit;
1615           end if;
1616        end loop;
1617 
1618        --
1619        --  Bug 1879889
1620        --  Check for DFF null dependent segment now that we have parent value.
1621        --  same if condition as used above to insure that we only process
1622        --  DFF dependent null segments.
1623        --  Bug 2933236
1624        --  Check dependent segment required flag. If a dependent segment
1625        --  has a parent, but is not is not required, then it is not
1626        --  requried to have a value. It only must have a value if the
1627        --  segment is required.
1628        --  Bug 5560451 The same is true for Key Flexfields.
1629        --  Removing the statment fstruct.isa_key_flexfield = FALSE
1630        --  Bug 8579560
1631        --  Do additional check whether allow_nulls is set to FALSE before
1632        --  issuing error
1633        --  Note-Dual checkin was broken for 12.1 at time of last arcs in
1634        if thisseg is null and vsinf.parent_vsid is not NULL
1635            and vsinf.valtype = 'D' then
1636           if parentval is null then
1637              vcode := FF_VVALID;
1638            else
1639              if ((kseg.required = 'Y') AND (not vflags.allow_nulls))then /* Bug 2933236 */
1640                 vcode := FF_VREQUIRED;
1641                 if(vflags.message_on_null) then
1642                    value_error_name('FND', 'FLEX-NULL REQUIRED SEGMENT');
1643                    value_error_token('SEGMENT_NAME', kseg.segname);
1644                 /* Bug 9006077 value_error_name('FND', 'FLEX-NULL SEGMENT');*/
1645                 end if;
1646               else
1647                 vcode := FF_VVALID;
1648              end if;
1649           end if;
1650           goto return_val;
1651        end if;
1652 
1653        IF (l_parent_index = 0) then
1654           FND_MESSAGE.set_name('FND', 'FLEX-NO PARENT SEGMENT');
1655           FND_MESSAGE.set_token('CHILD', kseg.segname);
1656           vcode := FF_VERROR;
1657           goto return_val;
1658        end if;
1659 
1660       IF ((parentval is null) and (not orphansok))then
1661          --
1662          -- Use FLEX-ORPHAN but need segment names of previous segments
1663          --
1664          value_error_name('FND', 'FLEX-ORPHAN');
1665          value_error_token('PARENT', prev_segnames(l_parent_index));
1666          value_error_token('SEGMENT', kseg.segname);
1667          vcode := FF_VORPHAN;
1668          goto return_val;
1669       end if;
1670      else
1671        IF (fnd_flex_server1.g_debug_level > 0) THEN
1672           add_debug(vsinf.valtype);
1673        END IF;
1674     end if;
1675 
1676     IF (kseg.additional_where_clause IS NULL) THEN
1677        IF (vsinf.valtype IN ('I', 'D')) THEN
1678           l_fvc_code := check_fvc(vsinf.vsid,
1679                                   parentval,
1680                                   thisseg,
1681                                   l_flexvalue);
1682        END IF;
1683     END IF;
1684  END IF;
1685 
1686  IF (l_fvc_code IN (fnd_plsql_cache.CACHE_FOUND)) THEN
1687     vcode := FF_VVALID;
1688   ELSE
1689     vcode := find_value(fstruct, kseg, vsinf, v_date,
1690                         thisseg,
1691                         isvalu, orphansok,
1692                         kseg.segname, nprev, prev_vsids,
1693                         prev_dispvals, prev_vals, prev_ids, prev_descs,
1694                         prev_segnames, prev_vsnames, parentval, l_flexvalue);
1695 
1696     --
1697     -- If value exists then cache it.
1698     --
1699     IF (kseg.additional_where_clause IS NULL) THEN
1700        IF ((vcode = FF_VVALID) AND
1701            (vsinf.valtype IN ('I', 'D'))) THEN
1702           update_fvc(vsinf.vsid, parentval, thisseg, l_flexvalue);
1703        END IF;
1704     END IF;
1705  END IF;
1706 
1707  IF (vcode <> FF_VVALID) then
1708     goto return_val;
1709  end if;
1710 
1711  --  Determine qualifier values for this segment from
1712  --  compiled_value_attributes (This function replaces the sq_values
1713  --  which differ from the defaults)
1714  if(l_flexvalue.compiled_attributes is not null) then
1715     if(qualifier_values(fstruct, vsinf.vsid, l_flexvalue.compiled_attributes,
1716                         segquals.nquals, segquals.fq_names,
1717                         segquals.sq_names,
1718                         segquals.sq_values) < 0) then
1719        vcode := FF_VERROR;
1720        goto return_val;
1721     end if;
1722  end if;
1723 
1724  --  Add modified segment qualifier values to debug string
1725  --
1726  IF (fnd_flex_server1.g_debug_level > 0) THEN
1727     if(segquals.nquals > 0) THEN
1728        g_debug_text := 'SegQualVals=';
1729        for i in 1..segquals.nquals loop
1730           g_debug_text := g_debug_text || '(' || segquals.sq_values(i) || ')';
1731        end loop;
1732        add_debug(g_debug_text);
1733     end if;
1734  END IF;
1735 
1736  --  Always check vrules.  They should not be checked in LOADID(), but
1737  --  the client does it anyway.
1738  --
1739  /* bug872437. Don't check vrules in loadid. */
1740 
1741  IF ((vflags.invoking_mode <> 'L') AND
1742      (vflags.invoking_mode <> 'G')) THEN
1743     vcode := check_vrules(v_ruls, segquals, l_flexvalue.summary_flag);
1744     if(vcode <> FF_VVALID) then
1745        goto return_val;
1746     end if;
1747  END IF;
1748 
1749  -- Check security rules
1750  if(NOT vflags.ignore_security) then
1751     if((vsinf.valtype in ('I', 'D', 'F')) and
1752        (vsinf.valsecure in ('Y', 'H')) and (kseg.segsecure = 'Y')) THEN
1753        IF (fnd_flex_server1.g_debug_level > 0) THEN
1754           add_debug('Calling Security');
1755        END IF;
1756        vcode := check_security(l_flexvalue.stored_value, vsinf.vsformat,
1757                                parentval, uappid, respid, vsinf,
1758                                vflags.message_on_security);
1759        IF (vcode <> FF_VVALID) THEN
1760           IF (fnd_flex_server1.g_debug_level > 0) THEN
1761              add_debug('Security Failure Code: ' || vcode);
1762           END IF;
1763           goto return_val;
1764        end if;
1765        IF (fnd_flex_server1.g_debug_level > 0) THEN
1766           add_debug('NOT SECURED');
1767        END IF;
1768     end if;
1769  end if;
1770 
1771  -- Check to make sure value is enabled for the given validation date.
1772  --
1773  if(NOT vflags.ignore_disabled) then
1774     if(l_flexvalue.enabled_flag <> 'Y') then
1775        value_error_name('FND', 'FLEX-VALUE IS DISABLED');
1776        value_error_token('VALUE', l_flexvalue.displayed_value);
1777        vcode := FF_VDISABLED;
1778        goto return_val;
1779     end if;
1780  end if;
1781 
1782  if((NOT vflags.ignore_expired) and (v_date is not null)) then
1783     if((Trunc(v_date) < Trunc(nvl(l_flexvalue.start_valid, v_date))) or
1784        (Trunc(v_date) > Trunc(nvl(l_flexvalue.end_valid, v_date)))) then
1785        value_error_name('FND', 'FLEX-VALUE IS EXPIRED');
1786        value_error_token('VALUE', l_flexvalue.displayed_value);
1787        vcode := FF_VEXPIRED;
1788        goto return_val;
1789     end if;
1790  end if;
1791 
1792  <<return_val>>
1793  x_flexvalue := l_flexvalue;
1794  squals := segquals;
1795  IF (fnd_flex_server1.g_debug_level > 0) THEN
1796     FND_FLEX_SERVER1.add_debug('END SV1.validate_seg() ');
1797  END IF;
1798 
1799  return(vcode);
1800 
1801 EXCEPTION
1802  WHEN OTHERS then
1803     FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
1804     FND_MESSAGE.set_token('MSG', 'validate_seg() exception:  ' || SQLERRM);
1805     IF (fnd_flex_server1.g_debug_level > 0) THEN
1806        FND_FLEX_SERVER1.add_debug('EXCEPTION others SV1.validate_seg() ');
1807     END IF;
1808     return(FF_VERROR);
1809 END validate_seg;
1810 
1811 /* ----------------------------------------------------------------------- */
1812 /*      Given the dvals and qualifiers for the current segment and the     */
1813 /*      existing derived dvals and qualifiers, compute the new dvals and   */
1814 /*      qualifiers.  Presently only handles one set of derivation rules.   */
1815 /*      Returns TRUE if OK or FALSE and sets error message if errors.      */
1816 /* ----------------------------------------------------------------------- */
1817 
1818 FUNCTION derive_values(new_dvals      IN      DerivedVals,
1819                        new_quals      IN      Qualifiers,
1820                        drv_dvals      IN OUT  nocopy DerivedVals,
1821                        drv_quals      IN OUT  nocopy Qualifiers) RETURN BOOLEAN IS
1822 
1823   dqi BINARY_INTEGER;
1824 
1825 BEGIN
1826 
1827 -- Derive values for the enabled parameters and summary flag
1828 --
1829   if((new_dvals.start_valid is not null) and
1830      ((drv_dvals.start_valid is null) or
1831       (new_dvals.start_valid > drv_dvals.start_valid))) then
1832     drv_dvals.start_valid := new_dvals.start_valid;
1833   end if;
1834   if((new_dvals.end_valid is not null) and
1835      ((drv_dvals.end_valid is null) or
1836       (new_dvals.end_valid < drv_dvals.end_valid))) then
1837     drv_dvals.end_valid := new_dvals.end_valid;
1838   end if;
1839   if(new_dvals.enabled_flag = 'N') then
1840     drv_dvals.enabled_flag := 'N';
1841   end if;
1842   if(new_dvals.summary_flag = 'Y') then
1843     drv_dvals.summary_flag := 'Y';
1844   end if;
1845 
1846 --  Derive the qualifiers.
1847 --  Add each segment qualifier to the accumulated derived qualifiers.
1848 --  If it's a new qualifier add it to the array of derived qualifier names.
1849 --  Otherwise, compute the derived value using the Derivation rules:
1850 --  "If any segment qualifier value is 'N' the derived value is 'N'
1851 --
1852 --  Algorithm:  For each seg qual, find dqi = index to derived qual with
1853 --  the same fq and sq names.  If found, derive the value using the new seg
1854 --  qualifier value.  If not found, add a new qualifier to the list of
1855 --  derived qualifiers.
1856 --
1857   for i in 1..new_quals.nquals loop
1858     dqi := NULL;
1859     for j in 1..drv_quals.nquals loop
1860       if((drv_quals.fq_names(j) = new_quals.fq_names(i)) and
1861          (drv_quals.sq_names(j) = new_quals.sq_names(i))) then
1862         dqi := j;
1863         exit;
1864       end if;
1865     end loop;
1866     if(dqi is not null) then
1867       if(new_quals.sq_values(i) = 'N') then
1868         drv_quals.sq_values(dqi) := 'N';
1869       end if;
1870     else
1871       drv_quals.nquals := drv_quals.nquals + 1;
1872       dqi := drv_quals.nquals;
1873       drv_quals.fq_names(dqi) := new_quals.fq_names(i);
1874       drv_quals.sq_names(dqi) := new_quals.sq_names(i);
1875       drv_quals.sq_values(dqi) := new_quals.sq_values(i);
1876       drv_quals.derived_cols(dqi) := new_quals.derived_cols(i);
1877     end if;
1878   end loop;
1879 
1880   return(TRUE);
1881 
1882 EXCEPTION
1883   WHEN OTHERS then
1884     FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
1885     FND_MESSAGE.set_token('MSG', 'derive_values() exception:  ' || SQLERRM);
1886     return(FALSE);
1887 
1888 END derive_values;
1889 
1890 /* ----------------------------------------------------------------------- */
1891 /*      Coerces entered segment value into the value storage format        */
1892 /*      appropriate for the value set,                                     */
1893 /*      and checks to make sure value is not too long and is within the    */
1894 /*      the min-max range specified in the value set.                      */
1895 /*                                                                         */
1896 /*      Returns the value in stored format and TRUE on success or sets     */
1897 /*      error and returns FALSE on error.                                  */
1898 /* ----------------------------------------------------------------------- */
1899 
1900 FUNCTION coerce_format(user_value IN     VARCHAR2,
1901                        p_is_displayed IN BOOLEAN,
1902                        vs_format  IN     VARCHAR2,
1903                        vs_name    IN     VARCHAR2,
1904                        max_length IN     NUMBER,
1905                        letters_ok IN     VARCHAR2,
1906                        caps_only  IN     VARCHAR2,
1907                        zero_fill  IN     VARCHAR2,
1908                        precision  IN     VARCHAR2,
1909                        min_value  IN     VARCHAR2,
1910                        max_value  IN     VARCHAR2,
1911                        x_storage_value OUT nocopy VARCHAR2,
1912                        x_display_value OUT nocopy VARCHAR2) RETURN VARCHAR2 IS
1913 
1914   l_return    VARCHAR2(1);
1915   l_success   NUMBER;
1916   l_storage_value VARCHAR2(2000);
1917   l_display_value VARCHAR2(2000);
1918   l_utv_enc_message VARCHAR2(32000) := NULL;
1919   l_ssv_enc_message VARCHAR2(32000) := NULL;
1920 BEGIN
1921    IF (fnd_flex_server1.g_debug_level > 0) THEN
1922       FND_FLEX_SERVER1.add_debug('BEGIN SV1.coerce_format() ');
1923    END IF;
1924 
1925    x_storage_value := user_value;
1926    x_display_value := user_value;
1927 
1928    --
1929    -- Since validation utility is setting messages by using
1930    -- fnd_message, we will do a stacking trick here.
1931    --
1932    -- For different result, different style of messaging is used.
1933    -- If the error is serious, always overwrite the existing message.
1934    --
1935    IF (value_error_set) THEN
1936       l_ssv_enc_message := fnd_message.get_encoded;
1937    END IF;
1938 
1939    fnd_flex_val_util.validate_value_ssv
1940      (p_value     => user_value,
1941       p_is_displayed => p_is_displayed,
1942       p_vset_name => vs_name,
1943       p_vset_format => vs_format,
1944       p_max_length => max_length,
1945       p_precision => To_number(precision),
1946       p_alpha_allowed => letters_ok,
1947       p_uppercase_only => caps_only,
1948       p_zero_fill => zero_fill,
1949       p_min_value => min_value,
1950       p_max_value => max_value,
1951       x_storage_value => l_storage_value,
1952       x_display_value => l_display_value,
1953       x_success       => l_success);
1954 
1955    IF (fnd_flex_server1.g_debug_level > 0) THEN
1956       add_debug(Rtrim(Substr(fnd_flex_val_util.get_debug,1,2000), chr_newline));
1957    END IF;
1958    IF (l_success = fnd_flex_val_util.g_ret_no_error) THEN
1959       --
1960       -- No error case.
1961       --
1962       l_return := FF_VVALID;
1963       x_storage_value := l_storage_value;
1964       x_display_value := l_display_value;
1965       IF (value_error_set) THEN
1966          fnd_message.set_encoded(l_ssv_enc_message);
1967       END IF;
1968     ELSE
1969       --
1970       -- Since this is an error case, get the message.
1971       --
1972       l_utv_enc_message := fnd_message.get_encoded;
1973 
1974       IF ((l_success = fnd_flex_val_util.g_ret_value_too_long) OR
1975           (l_success = fnd_flex_val_util.g_ret_invalid_number) OR
1976           (l_success = fnd_flex_val_util.g_ret_invalid_date)) THEN
1977           --
1978           -- Format Errors.
1979           --
1980           l_return := FF_VFORMAT;
1981           IF (value_error_set) THEN
1982              fnd_message.set_encoded(l_ssv_enc_message);
1983            ELSE
1984              fnd_message.set_encoded(l_utv_enc_message);
1985           END IF;
1986        ELSIF ((l_success = fnd_flex_val_util.g_ret_vs_bad_precision) OR
1987               (l_success = fnd_flex_val_util.g_ret_vs_bad_format) OR
1988               (l_success = fnd_flex_val_util.g_ret_vs_bad_numrange) OR
1989               (l_success = fnd_flex_val_util.g_ret_vs_bad_daterange) OR
1990               (l_success = fnd_flex_val_util.g_ret_vs_bad_date) OR
1991               (l_success = fnd_flex_val_util.g_ret_exception_others)) THEN
1992          --
1993          -- Serious errors.
1994          --
1995          l_return := FF_VERROR;
1996          fnd_message.set_encoded(l_utv_enc_message);
1997 
1998        ELSIF (l_success = fnd_flex_val_util.g_ret_val_out_of_range) THEN
1999          --
2000          -- Bound Check Error.
2001          --
2002          l_return := FF_VBOUNDS;
2003          IF (value_error_set) THEN
2004             fnd_message.set_encoded(l_ssv_enc_message);
2005           ELSE
2006             fnd_message.set_encoded(l_utv_enc_message);
2007          END IF;
2008        ELSE
2009          --
2010          -- Other errors. This part is added, in case there will be changes
2011          -- in UTV package. As of 26-APR-99 code should not enter here.
2012          --
2013          l_return := FF_VERROR;
2014          fnd_message.set_encoded(l_utv_enc_message);
2015       END IF;
2016       --
2017       -- We are in error case, set messaging globals.
2018       --
2019       value_error_set := TRUE;
2020       entering_new_message := FALSE;
2021    END IF;
2022 
2023    IF (fnd_flex_server1.g_debug_level > 0) THEN
2024       FND_FLEX_SERVER1.add_debug('END SV1.coerce_format() ');
2025    END IF;
2026 
2027    RETURN(l_return);
2028 
2029 EXCEPTION
2030    WHEN OTHERS THEN
2031       IF (fnd_flex_server1.g_debug_level > 0) THEN
2032          FND_FLEX_SERVER1.add_debug('EXCEPTION SV1.coerce_format() ');
2033       END IF;
2034 
2035       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
2036       FND_MESSAGE.set_token('MSG', 'coerce_format() exception:  ' || SQLERRM);
2037       return(FF_VERROR);
2038 END coerce_format;
2039 
2040 /* ----------------------------------------------------------------------- */
2041 /*      Looks up value in appropriate validation tables.  Input the        */
2042 /*      character representation of the stored value or the id.  Returns   */
2043 /*      all information about the value in the FlexValue structure.  Also  */
2044 /*      returns the parent value in stored format if there is a parent.    */
2045 /*      This function needs to know about all previous segments to         */
2046 /*      handle dependent and table validated value sets.                   */
2047 /*      Returns TRUE if value is found or FALSE and sets error if not.     */
2048 /* ----------------------------------------------------------------------- */
2049 
2050 FUNCTION find_value(p_str_info          IN  FlexStructId,
2051                     p_seg_info          IN  SegmentInfo,
2052                     p_vs_info           IN  ValueSetInfo,
2053                     p_vdate             IN  DATE,
2054                     p_char_val          IN  VARCHAR2,
2055                     p_is_value          IN  BOOLEAN,
2056                     p_orphans_ok        IN  BOOLEAN,
2057                     p_this_segname      IN  VARCHAR2,
2058                     p_n_prev            IN  NUMBER,
2059                     p_prev_vsids        IN  NumberArray,
2060                     p_prev_dispvals     IN  ValueArray,
2061                     p_prev_vals         IN  ValueArray,
2062                     p_prev_ids          IN  ValueIdArray,
2063                     p_prev_descs        IN  ValueDescArray,
2064                     p_prev_segnames     IN  SegNameArray,
2065                     p_prev_vsnames      IN  VsNameArray,
2066                     p_parent_val        IN  VARCHAR2,
2067                     x_this_val_out      OUT nocopy FlexValue)
2068   RETURN VARCHAR2
2069   IS
2070      v_code                VARCHAR2(1);
2071      l_is_value            VARCHAR2(1);
2072      check_value_table     BOOLEAN;
2073      this_value            FlexValue;
2074 
2075   CURSOR IND_cursor(vsid IN NUMBER, val IN VARCHAR2) IS
2076     SELECT enabled_flag, start_date_active, end_date_active,
2077            summary_flag, compiled_value_attributes, description
2078       FROM fnd_flex_values_vl
2079      WHERE flex_value_set_id = vsid
2080        AND flex_value = val;
2081 
2082   CURSOR DEP_cursor(vsid IN NUMBER, val IN VARCHAR2, parnt IN VARCHAR2) IS
2083     SELECT enabled_flag, start_date_active, end_date_active,
2084            summary_flag, compiled_value_attributes, description
2085       FROM fnd_flex_values_vl
2086      WHERE flex_value_set_id = vsid
2087        AND flex_value = val
2088        AND parent_flex_value_low = parnt;
2089 
2090   CURSOR INDTL_cursor(vsid IN NUMBER,
2091                       val IN VARCHAR2,
2092                       p_is_value IN VARCHAR2) IS
2093     SELECT enabled_flag, start_date_active, end_date_active,
2094       summary_flag, compiled_value_attributes,
2095       flex_value, flex_value_meaning, description
2096       FROM fnd_flex_values_vl
2097      WHERE flex_value_set_id = vsid
2098       AND (((p_is_value = 'V') AND (flex_value_meaning = val)) OR
2099            ((p_is_value = 'I') AND (flex_value = val)));
2100 
2101   CURSOR DEPTL_cursor(vsid IN NUMBER,
2102                       val IN VARCHAR2,
2103                       parnt IN VARCHAR2,
2104                       p_is_value IN VARCHAR2) IS
2105     SELECT enabled_flag, start_date_active, end_date_active,
2106       summary_flag, compiled_value_attributes,
2107       flex_value, flex_value_meaning, description
2108       FROM fnd_flex_values_vl
2109       WHERE flex_value_set_id = vsid
2110       AND parent_flex_value_low = parnt
2111       AND (((p_is_value = 'V') AND (flex_value_meaning = val)) OR
2112            ((p_is_value = 'I') AND (flex_value = val)));
2113 
2114 BEGIN
2115    IF (fnd_flex_server1.g_debug_level > 0) THEN
2116       FND_FLEX_SERVER1.add_debug('BEGIN SV1.find_value()');
2117    END IF;
2118 
2119    --  Default the return value
2120 
2121    v_code := FF_VERROR;
2122 
2123 
2124    IF (p_is_value) THEN
2125       l_is_value := 'V';
2126       --
2127       -- R11.5 NLS: following is not true any more. char_val is stored value.
2128       -- However at the end of this function there is a conversion to
2129       -- displayed value.
2130       --
2131       this_value.displayed_value := p_char_val;
2132       this_value.stored_value := p_char_val;
2133     ELSE
2134       l_is_value := 'I';
2135       this_value.hidden_id := p_char_val;
2136    end if;
2137    this_value.enabled_flag := 'Y';
2138    this_value.summary_flag := 'N';
2139    this_value.format := p_vs_info.vsformat;
2140 
2141    --  Validation = None, do nothing.
2142    --
2143    if(p_vs_info.valtype = 'N') then
2144       IF (fnd_flex_server1.g_debug_level > 0) THEN
2145          add_debug('N');
2146       END IF;
2147       this_value.stored_value := p_char_val;
2148       this_value.hidden_id := p_char_val;
2149       v_code := FF_VVALID;
2150 
2151       --  Validation = Independent, or dependent look it up
2152       --
2153     ELSIF ((p_vs_info.valtype in ('I', 'D')) AND
2154            (p_seg_info.additional_where_clause IS NULL)) then
2155 
2156       --  Takes care of both dependent and independent VS
2157       --  Use the independent cursor if this is an independent value set
2158       --  or if this is a dependent value set and the parent_val is null.
2159       --  Both of these conditions will set parent_val to null
2160       --
2161       if(p_parent_val is null) then
2162          open IND_cursor(p_vs_info.vsid, p_char_val);
2163          fetch IND_cursor into this_value.enabled_flag, this_value.start_valid,
2164            this_value.end_valid, this_value.summary_flag,
2165            this_value.compiled_attributes, this_value.description;
2166          if(IND_cursor%NOTFOUND) then
2167             v_code := FF_VNOTFOUND;
2168           else
2169             v_code := FF_VVALID;
2170          end if;
2171          close IND_cursor;
2172        else
2173          open DEP_cursor(p_vs_info.vsid, p_char_val, p_parent_val);
2174          fetch DEP_cursor into this_value.enabled_flag, this_value.start_valid,
2175            this_value.end_valid, this_value.summary_flag,
2176            this_value.compiled_attributes, this_value.description;
2177          if(DEP_cursor%NOTFOUND) then
2178             v_code := FF_VNOTFOUND;
2179           else
2180             v_code := FF_VVALID;
2181          end if;
2182          close DEP_cursor;
2183       end if;
2184 
2185       -- Set error if value not found or set the returned value if found.
2186       -- Assumes v_code was either FF_VNOTFOUND or FF_VVALID.
2187       --
2188       if(v_code = FF_VNOTFOUND) then
2189 --         if(p_is_value) then
2190          if(TRUE) then -- Better error message for user
2191             value_error_name('FND', 'FLEX-VALUE DOES NOT EXIST');
2192 
2193             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));
2194             value_error_token('SEGMENT', p_this_segname);
2195             value_error_token('VALUESET', p_vs_info.vsname);
2196           else
2197             value_error_name('FND', 'FLEX-ID DOES NOT EXIST');
2198 
2199             value_error_token('ID', p_char_val);
2200             value_error_token('SEGMENT', p_this_segname);
2201             value_error_token('VALUESET', p_vs_info.vsname);
2202          end if;
2203          goto return_found_value;
2204        else
2205          this_value.stored_value := p_char_val;
2206          this_value.hidden_id := p_char_val;
2207       end if;
2208 
2209       --  Validation = TL Independent, or TL dependent look it up
2210       --
2211     ELSIF ((p_vs_info.valtype in ('X', 'Y'))  AND
2212            (p_seg_info.additional_where_clause IS NULL)) then
2213 
2214       --  Takes care of both TL dependent and TL independent VS
2215       --  Use the independent cursor if this is an independent value set
2216       --  or if this is a dependent value set and the parent_val is null.
2217       --  Both of these conditions will set parent_val to null
2218       --
2219       if(p_parent_val is null) then
2220          open INDTL_cursor(p_vs_info.vsid, p_char_val,l_is_value);
2221          fetch INDTL_cursor into this_value.enabled_flag,
2222            this_value.start_valid,
2223            this_value.end_valid, this_value.summary_flag,
2224            this_value.compiled_attributes,
2225            this_value.hidden_id, this_value.stored_value,
2226            this_value.description;
2227          if(INDTL_cursor%NOTFOUND) then
2228             v_code := FF_VNOTFOUND;
2229           else
2230             v_code := FF_VVALID;
2231          end if;
2232          close INDTL_cursor;
2233        else
2234          open DEPTL_cursor(p_vs_info.vsid, p_char_val, p_parent_val, l_is_value);
2235          fetch DEPTL_cursor into this_value.enabled_flag,
2236            this_value.start_valid,
2237            this_value.end_valid, this_value.summary_flag,
2238            this_value.compiled_attributes,
2239            this_value.hidden_id, this_value.stored_value,
2240            this_value.description;
2241          if(DEPTL_cursor%NOTFOUND) then
2242             v_code := FF_VNOTFOUND;
2243           else
2244             v_code := FF_VVALID;
2245          end if;
2246          close DEPTL_cursor;
2247       end if;
2248 
2249       -- Set error if value not found or set the returned value if found.
2250       -- Assumes v_code was either FF_VNOTFOUND or FF_VVALID.
2251       --
2252       IF (v_code = FF_VNOTFOUND) then
2253 --         if(p_is_value) then
2254          if(TRUE) then -- Better error message for user
2255             value_error_name('FND', 'FLEX-VALUE DOES NOT EXIST');
2256 
2257             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));
2258             value_error_token('SEGMENT', p_this_segname);
2259             value_error_token('VALUESET', p_vs_info.vsname);
2260           else
2261             value_error_name('FND', 'FLEX-ID DOES NOT EXIST');
2262 
2263             value_error_token('ID', p_char_val);
2264             value_error_token('SEGMENT', p_this_segname);
2265             value_error_token('VALUESET', p_vs_info.vsname);
2266          end if;
2267          goto return_found_value;
2268        else
2269          NULL;
2270          --        this_value.stored_value := p_char_val;
2271          --        this_value.hidden_id := p_char_val;
2272       end if;
2273 
2274     ELSIF ((p_vs_info.valtype in ('I', 'D')) AND
2275            (p_seg_info.additional_where_clause IS NOT NULL)) then
2276       --
2277       -- Similar to Table validation.
2278       --
2279 
2280       IF (fnd_flex_server1.g_debug_level > 0) THEN
2281          add_debug('~F(' || p_vs_info.valtype || ')');
2282       END IF;
2283 
2284       v_code := table_validate(p_str_info, p_seg_info, p_vs_info,
2285                                p_vdate, p_parent_val,
2286                                p_char_val, p_is_value,
2287                                p_n_prev, p_prev_dispvals, p_prev_vals,
2288                                p_prev_ids, p_prev_descs, p_prev_segnames,
2289                                p_prev_vsnames, check_value_table, this_value);
2290 
2291       --  table_validate() does not set error message if the problem is
2292       --  that the value is not found because we might have to look up
2293       --  the value in the values table.  Therefore we need to set the
2294       --  error if value was not found.
2295       if(v_code = FF_VNOTFOUND) then
2296 --         if(p_is_value) then
2297          if(TRUE) then -- Better error message for user
2298             value_error_name('FND', 'FLEX-VALUE DOES NOT EXIST');
2299 
2300             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));
2301             value_error_token('SEGMENT', p_this_segname);
2302             value_error_token('VALUESET', p_vs_info.vsname);
2303           else
2304             value_error_name('FND', 'FLEX-ID DOES NOT EXIST');
2305 
2306             value_error_token('ID', p_char_val);
2307             value_error_token('SEGMENT', p_this_segname);
2308             value_error_token('VALUESET', p_vs_info.vsname);
2309          end if;
2310       end if;
2311 
2312     ELSIF ((p_vs_info.valtype in ('X', 'Y'))  AND
2313            (p_seg_info.additional_where_clause IS NOT NULL)) THEN
2314 
2315       --
2316       -- Similar to Table validation.
2317       --
2318 
2319       IF (fnd_flex_server1.g_debug_level > 0) THEN
2320          add_debug('~F(' || p_vs_info.valtype || ')');
2321       END IF;
2322 
2323       v_code := table_validate(p_str_info, p_seg_info, p_vs_info,
2324                                p_vdate, p_parent_val,
2325                                p_char_val, p_is_value,
2326                                p_n_prev, p_prev_dispvals, p_prev_vals,
2327                                p_prev_ids, p_prev_descs, p_prev_segnames,
2328                                p_prev_vsnames, check_value_table, this_value);
2329 
2330       --  table_validate() does not set error message if the problem is
2331       --  that the value is not found because we might have to look up
2332       --  the value in the values table.  Therefore we need to set the
2333       --  error if value was not found.
2334       if(v_code = FF_VNOTFOUND) then
2335 --         if(p_is_value) then
2336          if(TRUE) then -- Better error message for user
2337             value_error_name('FND', 'FLEX-VALUE DOES NOT EXIST');
2338 
2339             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));
2340             value_error_token('SEGMENT', p_this_segname);
2341             value_error_token('VALUESET', p_vs_info.vsname);
2342           else
2343             value_error_name('FND', 'FLEX-ID DOES NOT EXIST');
2344 
2345             value_error_token('ID', p_char_val);
2346             value_error_token('SEGMENT', p_this_segname);
2347             value_error_token('VALUESET', p_vs_info.vsname);
2348          end if;
2349       end if;
2350 
2351       -- Table validation.
2352       --
2353     ELSIF (p_vs_info.valtype = 'F') then
2354 
2355       IF (fnd_flex_server1.g_debug_level > 0) THEN
2356          add_debug('F');
2357       END IF;
2358 
2359       v_code := table_validate(p_str_info, p_seg_info, p_vs_info,
2360                                p_vdate, p_parent_val,
2361                                p_char_val, p_is_value,
2362                                p_n_prev, p_prev_dispvals, p_prev_vals,
2363                                p_prev_ids, p_prev_descs, p_prev_segnames,
2364                                p_prev_vsnames, check_value_table, this_value);
2365 
2366       if((v_code = FF_VNOTFOUND) and (check_value_table = TRUE)) then
2367          open IND_cursor(p_vs_info.vsid, p_char_val);
2368          fetch IND_cursor into this_value.enabled_flag, this_value.start_valid,
2369            this_value.end_valid, this_value.summary_flag,
2370            this_value.compiled_attributes, this_value.description;
2371          if(IND_cursor%FOUND) then
2372             this_value.stored_value := p_char_val;
2373             this_value.hidden_id := p_char_val;
2374             v_code := FF_VVALID;
2375          end if;
2376          close IND_cursor;
2377       end if;
2378 
2379       --  table_validate() does not set error message if the problem is
2380       --  that the value is not found because we might have to look up
2381       --  the value in the values table.  Therefore we need to set the
2382       --  error if value was not found.
2383       if(v_code = FF_VNOTFOUND) then
2384 --         if(p_is_value) then
2385          if(TRUE) then -- Better error message for user
2386             value_error_name('FND', 'FLEX-VALUE DOES NOT EXIST');
2387 
2388             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));
2389             value_error_token('SEGMENT', p_this_segname);
2390             value_error_token('VALUESET', p_vs_info.vsname);
2391           else
2392             value_error_name('FND', 'FLEX-ID DOES NOT EXIST');
2393 
2394             value_error_token('ID', p_char_val);
2395             value_error_token('SEGMENT', p_this_segname);
2396             value_error_token('VALUESET', p_vs_info.vsname);
2397          end if;
2398       end if;
2399 
2400       -- Pair or Special validation unsupported.
2401       --
2402     ELSIF (p_vs_info.valtype in ('P', 'U')) then
2403       FND_MESSAGE.set_name('FND', 'FLEX-SSV UNSUPPORTED VDATION');
2404       FND_MESSAGE.set_token('VSNAME', p_vs_info.vsname);
2405       v_code := FF_VUNKNOWN;
2406 
2407       -- Undefined validation type
2408       --
2409     else
2410       FND_MESSAGE.set_name('FND', 'FLEX-VS BAD VDATION TYPE');
2411       FND_MESSAGE.set_token('VSNAME', p_vs_info.vsname);
2412       FND_MESSAGE.set_token('VTYPE', p_vs_info.valtype);
2413       v_code := FF_VERROR;
2414    end if;
2415 
2416    <<return_found_value>>
2417    if(v_code = FF_VVALID) THEN
2418       v_code := stored_to_displayed(p_vs_info.vsformat, p_vs_info.maxsize, p_vs_info.precis,
2419                                     p_vs_info.lettersok,
2420                                     this_value.stored_value,
2421                                     this_value.displayed_value);
2422    end if;
2423    x_this_val_out := this_value;
2424    IF (fnd_flex_server1.g_debug_level > 0) THEN
2425       FND_FLEX_SERVER1.add_debug('END SV1.find_value(returns:' ||
2426                                  v_code || ')');
2427    END IF;
2428 
2429    return(v_code);
2430 EXCEPTION
2431    WHEN OTHERS then
2432       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
2433       FND_MESSAGE.set_token('MSG', 'find_value() exception:  ' || SQLERRM);
2434       IF (fnd_flex_server1.g_debug_level > 0) THEN
2435          FND_FLEX_SERVER1.add_debug('EXCEPTION others SV1.find_value()');
2436       END IF;
2437 
2438       return(FF_VERROR);
2439 END find_value;
2440 
2441 /* ----------------------------------------------------------------------- */
2442 /*      Finds value from table validated value set.                        */
2443 /*      Returns value error code and sets message on error.                */
2444 /*      However, if value is not found, does not set the error message     */
2445 /*      because we may have to look it up in the values table if           */
2446 /*      check_valtab is returned as 'Y'                                    */
2447 /*      NOTE:  where_clause declared as VARCHAR2(30000) for implicit       */
2448 /*      conversion from LONG column type in the table.                     */
2449 /*      Generic exception raised if SQL fragment in where_clause is bad.   */
2450 /* ----------------------------------------------------------------------- */
2451 FUNCTION table_validate(p_str_info            IN  FlexStructId,
2452                         p_seg_info            IN  SegmentInfo,
2453                         p_vs_info             IN  ValueSetInfo,
2454                         p_vdate               IN  DATE,
2455                         p_parent_value        IN  VARCHAR2,
2456                         p_charval             IN  VARCHAR2,
2457                         p_is_value            IN  BOOLEAN,
2458                         p_nprev               IN  NUMBER,
2459                         p_prev_dispvals       IN  ValueArray,
2460                         p_prev_vals           IN  ValueArray,
2461                         p_prev_ids            IN  ValueIdArray,
2462                         p_prev_descs          IN  ValueDescArray,
2463                         p_prev_segnames       IN  SegNameArray,
2464                         p_prev_vsnames        IN  VsNameArray,
2465                         x_check_valtab        OUT nocopy BOOLEAN,
2466                         x_found_value         OUT nocopy FlexValue)
2467   RETURN VARCHAR2
2468   IS
2469      l_where_clause          VARCHAR2(32000);
2470      l_tmp_where_clause      VARCHAR2(32000);
2471      l_order_by_pos          NUMBER;
2472 
2473      l_vcode                 VARCHAR2(1);
2474      l_sql                   VARCHAR2(32000);
2475      l_nrecords              NUMBER;
2476      l_results               StringArray;
2477 
2478      CURSOR tbl_cursor(p_flex_value_set_id IN NUMBER) IS
2479         SELECT application_table_name, value_column_name, value_column_type,
2480           id_column_name, id_column_type, meaning_column_name,
2481           meaning_column_type, enabled_column_name, start_date_column_name,
2482           end_date_column_name, summary_column_name,
2483           compiled_attribute_column_name, additional_quickpick_columns,
2484           summary_allowed_flag, additional_where_clause
2485           FROM fnd_flex_validation_tables
2486           WHERE flex_value_set_id = p_flex_value_set_id;
2487 
2488      l_tbl_rec     tbl_cursor%ROWTYPE;
2489      l_sql_pieces  sql_pieces_tab_type;
2490 BEGIN
2491    IF (p_vs_info.valtype IN ('I', 'D', 'X', 'Y')) THEN
2492       l_tbl_rec.application_table_name := 'FND_FLEX_VALUES_VL FND_FLEX_VALUES_VL';
2493       l_tbl_rec.value_column_name := 'FND_FLEX_VALUES_VL.FLEX_VALUE';
2494       l_tbl_rec.value_column_type := 'C';
2495       l_tbl_rec.id_column_name := NULL;
2496       l_tbl_rec.id_column_type := NULL;
2497       l_tbl_rec.meaning_column_name := 'FND_FLEX_VALUES_VL.DESCRIPTION';
2498       l_tbl_rec.meaning_column_type := 'C';
2499       l_tbl_rec.enabled_column_name := 'FND_FLEX_VALUES_VL.ENABLED_FLAG';
2500       l_tbl_rec.start_date_column_name := 'FND_FLEX_VALUES_VL.START_DATE_ACTIVE';
2501       l_tbl_rec.end_date_column_name := 'FND_FLEX_VALUES_VL.END_DATE_ACTIVE';
2502       l_tbl_rec.summary_column_name := 'FND_FLEX_VALUES_VL.SUMMARY_FLAG';
2503       l_tbl_rec.compiled_attribute_column_name := 'FND_FLEX_VALUES_VL.COMPILED_VALUE_ATTRIBUTES';
2504       l_tbl_rec.additional_quickpick_columns := NULL;
2505       l_tbl_rec.summary_allowed_flag := 'N';
2506 
2507       IF (p_parent_value IS NULL) THEN
2508          l_tbl_rec.additional_where_clause := 'WHERE FND_FLEX_VALUES_VL.FLEX_VALUE_SET_ID = :$FLEX$.$VALUE_SET_ID$';
2509        ELSE
2510          l_tbl_rec.additional_where_clause := 'WHERE FND_FLEX_VALUES_VL.FLEX_VALUE_SET_ID = :$FLEX$.$VALUE_SET_ID$' ||
2511            ' AND FND_FLEX_VALUES_VL.PARENT_FLEX_VALUE_LOW = :$FLEX$.$PARENT_VALUE$';
2512       END IF;
2513 
2514     ELSE
2515       open TBL_cursor(p_vs_info.vsid);
2516       FETCH tbl_cursor INTO l_tbl_rec;
2517       IF (TBL_cursor%NOTFOUND) THEN
2518          close TBL_cursor;
2519          FND_MESSAGE.set_name('FND', 'FLEX-SSV MISSING TBLVS');
2520          FND_MESSAGE.set_token('VSNAME', p_vs_info.vsname);
2521          return(FF_VERROR);
2522       end if;
2523       close TBL_cursor;
2524    END IF;
2525 
2526    IF (l_tbl_rec.summary_allowed_flag = 'Y') then
2527       x_check_valtab := TRUE;
2528     else
2529       x_check_valtab := FALSE;
2530    end if;
2531 
2532    --  Return error if unsupported validation.
2533    --
2534    if((l_tbl_rec.additional_quickpick_columns is not null) and (INSTR(UPPER(l_tbl_rec.additional_quickpick_columns),'INTO') > 0)) then
2535       FND_MESSAGE.set_name('FND', 'FLEX-SSV NO TBL VS');
2536       FND_MESSAGE.set_token('VSNAME', p_vs_info.vsname);
2537       return(FF_VUNKNOWN);
2538    end if;
2539 
2540    --  Default column names if null
2541    --
2542    if(l_tbl_rec.id_column_name is null) then
2543       l_tbl_rec.id_column_name := l_tbl_rec.value_column_name;
2544       l_tbl_rec.id_column_type := l_tbl_rec.value_column_type;
2545    end if;
2546 
2547    if(l_tbl_rec.meaning_column_name is null) then
2548       l_tbl_rec.meaning_column_name := 'NULL';
2549       l_tbl_rec.meaning_column_type := 'V';
2550    end if;
2551 
2552    -- Now need to parse where/order by clause.  Clause is of the form:
2553    -- [where <condition>] [order by <ordering>]
2554    -- The order by portion is not relevant here and is dropped.
2555    -- "where" is optional, hence the first word in the string need not be
2556    -- "where".
2557    -- Note there can only be 1 space between "order" and "by".
2558    -- "where" and "order by" are found using case-insensitive comparisons.
2559    -- Case-insensitive comparison requires upper case conversion.
2560    -- Assume SQL strings in single-byte characters only.
2561    -- Substitute $FLEX$ and $PROFILES$ in where clause if its not null.
2562    --
2563    l_where_clause := ltrim(l_tbl_rec.additional_where_clause, WHITESPACE);
2564 
2565    l_sql_pieces.DELETE;
2566    if (l_where_clause is not null) then
2567       -- there is where clause
2568       l_tmp_where_clause := Upper(l_where_clause);
2569 
2570       if (l_tmp_where_clause LIKE 'WHERE%') then
2571          -- It starts with WHERE keyword
2572          -- Skip the leading WHERE keyword
2573          l_where_clause := Substr(l_where_clause, 6);
2574          l_tmp_where_clause := Upper(l_where_clause);
2575       end if;
2576 
2577       l_order_by_pos := Instr(l_tmp_where_clause, 'ORDER BY');
2578       if (l_order_by_pos > 0) then
2579          l_where_clause := Substr(l_where_clause, 1, l_order_by_pos - 1);
2580       end if;
2581 
2582       IF (p_seg_info.additional_where_clause IS NOT NULL) THEN
2583          l_where_clause := '(' || l_where_clause || ') AND (' ||
2584            p_seg_info.additional_where_clause || ')';
2585       END IF;
2586 
2587       l_vcode := substitute_flex_binds5(l_where_clause,
2588                                         p_str_info, p_seg_info,
2589                                         p_vdate, p_parent_value,
2590                                         p_nprev, p_prev_dispvals,
2591                                         p_prev_vals, p_prev_ids, p_prev_descs,
2592                                         p_prev_segnames, p_prev_vsnames,
2593                                         l_sql_pieces);
2594 
2595       if (l_vcode <> FF_VVALID) then
2596          return(l_vcode);
2597       end if;
2598 
2599       IF (fnd_flex_server1.g_debug_level > 0) THEN
2600          l_tmp_where_clause := NULL;
2601          IF (l_vcode = FF_VVALID) THEN
2602             FOR i IN 1 .. l_sql_pieces.COUNT LOOP
2603                IF (l_sql_pieces(i).piece_type = SSP_PIECE_TYPE_BIND) THEN
2604                   l_tmp_where_clause := l_tmp_where_clause ||
2605                     string_clause(l_sql_pieces(i).bind_value);
2606 
2607                 ELSE
2608                   l_tmp_where_clause := l_tmp_where_clause ||
2609                     l_sql_pieces(i).piece_text;
2610                END IF;
2611             END LOOP;
2612          END IF;
2613 
2614          l_where_clause := l_tmp_where_clause;
2615 
2616          if(l_where_clause is not null) then
2617             add_debug(' (where ' || SUBSTRB(l_where_clause, 1, 1000) || ') ');
2618          end if;
2619       END IF;
2620    end if;
2621 
2622    --  Build SQL statement to do the select from the table specified
2623    --  by APPLICATION_TABLE_NAME.
2624    --
2625    --  The columns SUMMARY_COLUMN_NAME, COMPILED_ATTRIBUTE_COLUMN_NAME,
2626    --  ENABLED_COLUMN_NAME, and START and END _DATE_COLUMN_NAME in the
2627    --  FND_FLEX_VALIDATION_TABLES table either contain the name of the
2628    --  column in the "application table" which contains those parameters,
2629    --  or they contain text strings which are part of a sql statement.
2630    --  For example, the COMPILED_ATTRIBUTES_COLUMN_NAME contains either the
2631    --  name of a column, or a SQL fragment of the form: "'Y\nN\nA'" which
2632    --  includes the single quotes.
2633    --
2634    --  In either case the contents of these fields should be blindly
2635    --  inserted into the SQL statement.
2636    --
2637    --  BUG:  To be compatible with client code behavior, we must surround
2638    --  non-character columns with the default to_char() conversion in the
2639    --  select statement.  This causes seconds to be lost from date columns.
2640    --  It also means that numbers are stored and displayed in their default
2641    --  format rather than the value set format.
2642    --
2643    --  This functionality is now in the select_clause() function.
2644    --
2645    l_sql := 'select ' ||
2646      select_clause(l_tbl_rec.value_column_name, l_tbl_rec.value_column_type,
2647                    VC_VALUE, p_vs_info.vsformat, p_vs_info.maxsize);
2648    l_sql := l_sql || ', ' ||
2649      select_clause(l_tbl_rec.id_column_name, l_tbl_rec.id_column_type,
2650                    VC_ID, p_vs_info.vsformat, p_vs_info.maxsize);
2651    l_sql := l_sql || ', ' ||
2652      select_clause(l_tbl_rec.meaning_column_name, l_tbl_rec.meaning_column_type,
2653                    VC_DESCRIPTION, p_vs_info.vsformat, p_vs_info.maxsize);
2654    l_sql := l_sql || ', ' || l_tbl_rec.enabled_column_name || ', ';
2655    l_sql := l_sql || 'to_char(' || l_tbl_rec.start_date_column_name ||',''YYYY/MM/DD HH24:MI:SS'')' || ', ';
2656    l_sql := l_sql || 'to_char(' || l_tbl_rec.end_date_column_name ||',''YYYY/MM/DD HH24:MI:SS'')' || ', ';
2657    l_sql := l_sql || l_tbl_rec.summary_column_name || ', ';
2658    l_sql := l_sql || l_tbl_rec.compiled_attribute_column_name;
2659    l_sql := l_sql || ' from ' || l_tbl_rec.application_table_name || ' where ';
2660 
2661    fnd_dsql.init;
2662    fnd_dsql.add_text(l_sql);
2663 
2664    --
2665    -- The where clause needs to be surrounded by parentheses so we can
2666    -- add additional restrictions using AND without overriding ORs inside it.
2667    --
2668    IF (l_sql_pieces.COUNT > 0) THEN
2669       fnd_dsql.add_text('(');
2670 
2671       FOR i IN 1 .. l_sql_pieces.COUNT LOOP
2672          IF (l_sql_pieces(i).piece_type = SSP_PIECE_TYPE_BIND) THEN
2673             fnd_dsql.add_bind(l_sql_pieces(i).bind_value);
2674           ELSE
2675             fnd_dsql.add_text(l_sql_pieces(i).piece_text);
2676          END IF;
2677       END LOOP;
2678 
2679       fnd_dsql.add_text(') and ');
2680    END IF;
2681 
2682    -- Build comparison appropriate for data type of value or id column
2683    --
2684    if(p_is_value) THEN
2685       fnd_dsql.add_text(l_tbl_rec.value_column_name || ' = ');
2686       x_compare_clause(l_tbl_rec.value_column_type, l_tbl_rec.value_column_name, p_charval,
2687                        VC_VALUE, p_vs_info.vsformat, p_vs_info.maxsize);
2688     else
2689       fnd_dsql.add_text(l_tbl_rec.id_column_name || ' = ');
2690       x_compare_clause(l_tbl_rec.id_column_type, l_tbl_rec.id_column_name, p_charval,
2691                        VC_ID, p_vs_info.vsformat, p_vs_info.maxsize);
2692    end if;
2693 
2694 
2695    --  Select the value from the user's table.
2696    --
2697    l_nrecords := x_dsql_select(8, l_results);
2698 
2699    if(l_nrecords > 0) then
2700       x_found_value.format := p_vs_info.vsformat;
2701       x_found_value.stored_value := l_results(1);
2702       x_found_value.hidden_id := l_results(2);
2703       x_found_value.description := l_results(3);
2704       x_found_value.enabled_flag := l_results(4);
2705       x_found_value.start_valid := to_date(l_results(5),'YYYY/MM/DD HH24:MI:SS');
2706       x_found_value.end_valid := to_date(l_results(6),'YYYY/MM/DD HH24:MI:SS');
2707       x_found_value.summary_flag := l_results(7);
2708       x_found_value.compiled_attributes := l_results(8);
2709       return(FF_VVALID);
2710     elsif(l_nrecords = 0) then
2711       return(FF_VNOTFOUND);
2712     else
2713       return(FF_VERROR);
2714    end if;
2715 
2716    return(FF_VERROR);
2717 
2718 EXCEPTION
2719    WHEN OTHERS then
2720       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
2721       FND_MESSAGE.set_token('MSG', 'table_validate() exception:  ' || SQLERRM);
2722       return(FF_VERROR);
2723 
2724 END table_validate;
2725 
2726 /* ----------------------------------------------------------------------- */
2727 /*      Returns the default value for this segment in displayed format.    */
2728 /*      For defaulting current date and current time into non-translatable */
2729 /*      date value sets, use the format based on the maximum size of the   */
2730 /*      value set field alone.                                             */
2731 /*      Let ordinary value validation catch problems with the format       */
2732 /*      or length of the defaulted value.  Returns FF_VVALID if default    */
2733 /*      succeeded, FF_VUNKNOWN if unsupported or FF_VERROR.                */
2734 /* ----------------------------------------------------------------------- */
2735 FUNCTION default_val(def_type         IN  VARCHAR2,
2736                      def_text         IN  VARCHAR2,
2737                      valset_fmt       IN  VARCHAR2,
2738                      valset_len       IN  NUMBER,
2739                      valset_precis    IN  NUMBER,
2740                      valset_lettersok IN VARCHAR2,
2741                      seg_name         IN  VARCHAR2,
2742                      nprev            IN  NUMBER,
2743                      prev_dispvals    IN  ValueArray,
2744                      prev_vals        IN  ValueArray,
2745                      prev_ids         IN  ValueIdArray,
2746                      prev_descs       IN  ValueDescArray,
2747                      prev_segnames    IN  SegNameArray,
2748                      prev_vsnames     IN  VsNameArray,
2749                      displayed_val    OUT nocopy VARCHAR2)
2750   RETURN VARCHAR2 IS
2751      nfound        NUMBER;
2752      v_code        VARCHAR2(1);
2753      datefmt       VARCHAR2(30);
2754      stored_val    VARCHAR2(1000);
2755      sql_string    VARCHAR2(2000);
2756      l_sql_pieces  sql_pieces_tab_type;
2757 BEGIN
2758    v_code := FF_VERROR;
2759 
2760    IF (def_type is null) then
2761       v_code := FF_VVALID;
2762     ELSIF (def_type = 'C') then
2763       --  Constant
2764       stored_val := SUBSTRB(def_text, 1, 1000);
2765       v_code := FF_VVALID;
2766 
2767     ELSIF (def_type = 'D') then
2768       -- Current date.
2769       IF (valset_fmt in ('X', 'Y')) then
2770          datefmt := stored_date_format(valset_fmt, valset_len);
2771        ELSIF (valset_len >= 11) then
2772          datefmt := stored_date_format('D', 11);
2773        else
2774          datefmt := stored_date_format('D', 9);
2775       end if;
2776       stored_val := to_char(sysdate, datefmt);
2777       v_code := FF_VVALID;
2778 
2779     ELSIF (def_type = 'T') then
2780       -- Current time or date-time depending on the size
2781       IF (valset_fmt in ('Y', 'Z')) then
2782          datefmt := stored_date_format(valset_fmt, valset_len);
2783        ELSIF (valset_len < 8) then
2784          datefmt := stored_date_format('I', 5);
2785        ELSIF (valset_len between 8 and 14) then
2786          datefmt := stored_date_format('I', 8);
2787        ELSIF (valset_len between 15 and 16) then
2788          datefmt := stored_date_format('T', 15);
2789        ELSIF (valset_len = 17) then
2790          datefmt := stored_date_format('T', 17);
2791        ELSIF (valset_len between 18 and 19) then
2792          datefmt := stored_date_format('T', 18);
2793        else
2794          datefmt := stored_date_format('T', 20);
2795       end if;
2796       stored_val := to_char(sysdate, datefmt);
2797       v_code := FF_VVALID;
2798 
2799     ELSIF (def_type = 'P') then
2800       sql_string := ':$PROFILES$.' || def_text;
2801       v_code := convert_bind_token(sql_string, nprev,
2802                                    prev_dispvals, prev_vals,
2803                                    prev_ids, prev_descs,
2804                                    prev_segnames, prev_vsnames,
2805                                    stored_val);
2806 
2807     ELSIF ((def_type = 's') OR (def_type = 'A')) then
2808       sql_string := ':$FLEX$.' || def_text;
2809       v_code := convert_bind_token(sql_string, nprev,
2810                                    prev_dispvals, prev_vals,
2811                                    prev_ids, prev_descs,
2812                                    prev_segnames, prev_vsnames,
2813                                    stored_val);
2814 
2815     ELSIF (def_type = 'S') then
2816       -- SQL statement
2817       v_code := substitute_flex_binds3(def_text, nprev,
2818                                        prev_dispvals, prev_vals,
2819                                        prev_ids, prev_descs,
2820                                        prev_segnames, prev_vsnames,
2821                                        l_sql_pieces);
2822       IF (v_code = FF_VVALID) THEN
2823          fnd_dsql.init;
2824 
2825          FOR i IN 1 .. l_sql_pieces.COUNT LOOP
2826             IF (l_sql_pieces(i).piece_type = SSP_PIECE_TYPE_BIND) THEN
2827                fnd_dsql.add_bind(l_sql_pieces(i).bind_value);
2828              ELSE
2829                fnd_dsql.add_text(l_sql_pieces(i).piece_text);
2830             END IF;
2831          END LOOP;
2832 
2833          nfound := x_dsql_select_one(stored_val);
2834          IF (nfound > 1) then
2835             FND_MESSAGE.set_name('FND', 'FLEX-DFLT MULTIPLE SQL ROWS');
2836             FND_MESSAGE.set_token('SQLSTR', SUBSTRB(fnd_dsql.get_text(FALSE), 1, 1000));
2837             v_code := FF_VERROR;
2838           ELSIF (nfound < 0) then
2839             v_code := FF_VERROR;
2840           else
2841             v_code := FF_VVALID;
2842          end if;
2843       end if;
2844 
2845     ELSIF (def_type = 'F') then
2846       -- 'F' => :block.field (the colon may or may not be in the def_text string)
2847       FND_MESSAGE.set_name('FND', 'FLEX-SSV UNSUPPORTED DEFAULT');
2848       v_code := FF_VUNKNOWN;
2849 
2850     ELSIF (def_type = 'E') then
2851       -- Environment variable
2852       FND_MESSAGE.set_name('FND', 'FLEX-SSV UNSUPPORTED DEFAULT');
2853       v_code := FF_VUNKNOWN;
2854 
2855     ELSE
2856       -- Unknown type.
2857       FND_MESSAGE.set_name('FND', 'FLEX-INVALID DEFAULT TYPE');
2858       FND_MESSAGE.set_token('SEGNAME', seg_name);
2859       v_code := FF_VERROR;
2860 
2861    END IF;
2862 
2863    IF (v_code = FF_VVALID) then
2864       v_code := stored_to_displayed(valset_fmt, valset_len, valset_precis,
2865                                     valset_lettersok,
2866                                     stored_val, displayed_val);
2867    end if;
2868    return(v_code);
2869 EXCEPTION
2870    WHEN OTHERS then
2871       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
2872       FND_MESSAGE.set_token('MSG', 'default_val() exception:  ' || SQLERRM);
2873       return(FF_VERROR);
2874 END default_val;
2875 
2876 /* ------------------------------------------------------------------------- */
2877 /*      Interprets $PROFILES$ in where token passed into FND_KEY_FLEX.DEFINE */
2878 /*      This cannot take $FLEX$, and :block.field is unsupported.            */
2879 /*      Returns Validataion error codes VV_VALID if ok, VV_UNSUPPORTED       */
2880 /*      if unsupported, or VV_ERROR if other error.                          */
2881 /* ------------------------------------------------------------------------- */
2882 
2883 FUNCTION parse_where_token(clause_in  IN  VARCHAR2,
2884                           clause_out OUT nocopy VARCHAR2) RETURN NUMBER IS
2885 vcode         VARCHAR2(1);
2886 dummy_dispvls ValueArray;
2887 dummy_vals    ValueArray;
2888 dummy_ids     ValueIdArray;
2889 dummy_descs   ValueDescArray;
2890 dummy_segname SegNameArray;
2891 dummy_vsnames VsNameArray;
2892      l_sql_pieces  sql_pieces_tab_type;
2893 
2894 BEGIN
2895 
2896 if(clause_in is not null) then
2897   if(INSTR(clause_in, ':$FLEX$') > 0) then
2898     FND_MESSAGE.set_name('FND', 'FLEX-NO FLEX IN WHERE TOKEN');
2899     return(VV_ERROR);
2900   end if;
2901   vcode := substitute_flex_binds3(clause_in, 0,
2902                                   dummy_dispvls, dummy_vals,
2903                                   dummy_ids, dummy_descs,
2904                                   dummy_segname, dummy_vsnames,
2905                                   l_sql_pieces);
2906 
2907   clause_out := NULL;
2908   IF (vcode = FF_VVALID) THEN
2909      FOR i IN 1 .. l_sql_pieces.COUNT LOOP
2910         IF (l_sql_pieces(i).piece_type = SSP_PIECE_TYPE_BIND) THEN
2911            clause_out := clause_out ||
2912              string_clause(l_sql_pieces(i).bind_value);
2913 
2914          ELSE
2915            clause_out := clause_out ||
2916              l_sql_pieces(i).piece_text;
2917         END IF;
2918      END LOOP;
2919   END IF;
2920 
2921   if(vcode = FF_VVALID) then
2922     return(VV_VALID);
2923   elsif(vcode = FF_VUNKNOWN) then
2924     return(VV_UNSUPPORTED);
2925   else
2926     return(VV_ERROR);
2927   end if;
2928 end if;
2929 return(VV_VALID);
2930 
2931 EXCEPTION
2932   WHEN OTHERS then
2933     FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
2934     FND_MESSAGE.set_token('MSG', 'parse_where_token() exception: '||SQLERRM);
2935     return(VV_ERROR);
2936 
2937 END parse_where_token;
2938 
2939 /* ------------------------------------------------------------------------ */
2940 /*      Takes input string possibly containing special flex bind variables  */
2941 /*      of :$PROFILES$.<profile>, :$FLEX$.<name>[.<output>] or :block.field */
2942 /*      and substitutes the flex values for them.  Some substitutions such  */
2943 /*      as :block.field cannot be handled on the server and results in an   */
2944 /*      FF_VUNKNOWN being returned.                                         */
2945 /*                                                                          */
2946 /*      Input string can contain quoted regions, within which no            */
2947 /*      substitutions should be performed.  The regions are marked by       */
2948 /*      single quotes.  Double quotes within these regions represent        */
2949 /*      the quote character.                                                */
2950 /*                                                                          */
2951 /*       Limitations:  string_in, string_out up to 30,000 bytes.            */
2952 /*                     bind_token and bind_value up to 2000 bytes.          */
2953 /*                                                                          */
2954 /*      Returns FF_VVALID if default succeeded, FF_VUNKNOWN if unsupported  */
2955 /*      or FF_VERROR on error.                                              */
2956 /* ------------------------------------------------------------------------ */
2957 FUNCTION substitute_flex_binds3(p_string_in     IN VARCHAR2,
2958                                 p_nprev         IN NUMBER,
2959                                 p_prev_dispvals IN ValueArray,
2960                                 p_prev_vals     IN ValueArray,
2961                                 p_prev_ids      IN ValueIdArray,
2962                                 p_prev_descs    IN ValueDescArray,
2963                                 p_prev_segnames IN SegNameArray,
2964                                 p_prev_vsnames  IN VsNameArray,
2965                                 px_sql_pieces   in out nocopy sql_pieces_tab_type)
2966   RETURN VARCHAR2
2967   IS
2968      v_code        VARCHAR2(1);
2969 BEGIN
2970    IF (fnd_flex_server1.g_debug_level > 0) THEN
2971       add_debug('BEGIN SV1.substitute_flex_binds3('''||
2972                 SUBSTRB(p_string_in, 1, 500) || ''' ');
2973    END IF;
2974 
2975    BEGIN
2976       parse_sql_string(p_string_in, px_sql_pieces);
2977    EXCEPTION
2978       WHEN OTHERS THEN
2979          RETURN(FF_VERROR);
2980    END;
2981 
2982    --
2983    -- Derive bind values
2984    --
2985    FOR i IN 1 .. px_sql_pieces.COUNT LOOP
2986       IF (px_sql_pieces(i).piece_type = SSP_PIECE_TYPE_BIND) THEN
2987          v_code := convert_bind_token(px_sql_pieces(i).piece_text,
2988                                       p_nprev, p_prev_dispvals,
2989                                       p_prev_vals, p_prev_ids, p_prev_descs,
2990                                       p_prev_segnames, p_prev_vsnames,
2991                                       px_sql_pieces(i).bind_value);
2992 
2993          IF (v_code <> FF_VVALID) then
2994             return(v_code);
2995          end if;
2996       END IF;
2997    END LOOP;
2998 
2999    return(FF_VVALID);
3000 
3001 EXCEPTION
3002    WHEN OTHERS then
3003       IF (fnd_flex_server1.g_debug_level > 0) THEN
3004          add_debug('EXCEPTION SV1.substitute_flex_binds3()');
3005       END IF;
3006       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3007       FND_MESSAGE.set_token('MSG', 'substitute_flex_binds3() exception:  '
3008                             || SQLERRM);
3009       return(FF_VERROR);
3010 END substitute_flex_binds3;
3011 
3012 --
3013 -- The one with extension support.
3014 --
3015 /* ------------------------------------------------------------------------ */
3016 FUNCTION substitute_flex_binds5(p_string_in     IN VARCHAR2,
3017                                 p_str_info      IN FlexStructId,
3018                                 p_seg_info      IN SegmentInfo,
3019                                 p_vdate         IN DATE,
3020                                 p_parent_value  IN VARCHAR2,
3021                                 p_nprev         IN NUMBER,
3022                                 p_prev_dispvals IN ValueArray,
3023                                 p_prev_vals     IN ValueArray,
3024                                 p_prev_ids      IN ValueIdArray,
3025                                 p_prev_descs    IN ValueDescArray,
3026                                 p_prev_segnames IN SegNameArray,
3027                                 p_prev_vsnames  IN VsNameArray,
3028                                 px_sql_pieces   in out nocopy sql_pieces_tab_type)
3029   RETURN VARCHAR2
3030   IS
3031      v_code        VARCHAR2(1);
3032 BEGIN
3033    IF (fnd_flex_server1.g_debug_level > 0) THEN
3034       add_debug('BEGIN SV1.substitute_flex_binds5('''||
3035                 SUBSTRB(p_string_in, 1, 500) || ''' ');
3036    END IF;
3037 
3038    BEGIN
3039       parse_sql_string(p_string_in, px_sql_pieces);
3040    EXCEPTION
3041       WHEN OTHERS THEN
3042          RETURN(FF_VERROR);
3043    END;
3044 
3045    --
3046    -- Derive bind values
3047    --
3048    FOR i IN 1 .. px_sql_pieces.COUNT LOOP
3049       IF (px_sql_pieces(i).piece_type = SSP_PIECE_TYPE_BIND) THEN
3050          v_code := convert_bind_token2(px_sql_pieces(i).piece_text,
3051                                        p_str_info, p_seg_info,
3052                                        p_vdate, p_parent_value,
3053                                        p_nprev, p_prev_dispvals,
3054                                        p_prev_vals, p_prev_ids, p_prev_descs,
3055                                        p_prev_segnames, p_prev_vsnames,
3056                                        px_sql_pieces(i).bind_value);
3057 
3058          IF (v_code <> FF_VVALID) then
3059             return(v_code);
3060          end if;
3061       END IF;
3062    END LOOP;
3063 
3064    return(FF_VVALID);
3065 
3066 EXCEPTION
3067    WHEN OTHERS then
3068       IF (fnd_flex_server1.g_debug_level > 0) THEN
3069          add_debug('EXCEPTION SV1.substitute_flex_binds5()');
3070       END IF;
3071       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3072       FND_MESSAGE.set_token('MSG', 'substitute_flex_binds5() exception:  '
3073                             || SQLERRM);
3074       return(FF_VERROR);
3075 END substitute_flex_binds5;
3076 
3077 /* ----------------------------------------------------------------------- */
3078 /*      Converts a flex bind token to its character string value.          */
3079 /*      Bind tokens begin with a colon and are of the form:                */
3080 /*      :$FLEX$.<vsname>[.<portion>] or :$PROFILES$.<profile_name>         */
3081 /*      If [.<portion>] not specified uses the ID not the VALUE.           */
3082 /*      Note server can never handle :BLOCK.FIELD                          */
3083 /*      Returns FF_VVALID if substitution succeeded, FF_VUNKNOWN if        */
3084 /*      unsupported or FF_VERROR on error.                                 */
3085 /* ----------------------------------------------------------------------- */
3086 FUNCTION convert_bind_token(bind_token    IN  VARCHAR2,
3087                             nprev         IN  NUMBER,
3088                             prev_dispvals IN  ValueArray,
3089                             prev_vals     IN  ValueArray,
3090                             prev_ids      IN  ValueIdArray,
3091                             prev_descs    IN  ValueDescArray,
3092                             prev_segnames IN  SegNameArray,
3093                             prev_vsnames  IN  VsNameArray,
3094                             bind_value    OUT nocopy VARCHAR2)
3095   RETURN VARCHAR2
3096   IS
3097      bind_val      VARCHAR2(2000);
3098      seg_name      VARCHAR2(60);
3099      seg_portion   VARCHAR2(30);
3100      dot_pointer   NUMBER;
3101      col_pointer   NUMBER;
3102      l_length      NUMBER;
3103      s_index       BINARY_INTEGER;
3104      l_return_code VARCHAR2(100);
3105 
3106 BEGIN
3107    --  Determine character string value of bind token.
3108    -- :$PROFILES$.<name> where <name> is case-insensitive profile option name.
3109    -- :$FLEX$.<name>[.<portion>] where name is case-sensitive, but portion not.
3110    -- :BLOCK.FIELD causes return of FF_VUNKNOWN error.
3111    --
3112    IF (fnd_flex_server1.g_debug_level > 0) THEN
3113       add_debug('BEGIN SV1.convert_bind_token(token=' || bind_token || ')');
3114    END IF;
3115 
3116    IF (INSTR(bind_token, ':$PROFILES$.') = 1) then
3117       FND_PROFILE.get(UPPER(SUBSTR(bind_token, 13)), bind_val);
3118 
3119     ELSIF (INSTR(bind_token, ':$FLEX$.') = 1) then
3120 
3121       -- If default segment name is of the form <name>.ID, <name>.VALUE
3122       -- or <name>.MEANING, then break it into seg_name and seg_portion.
3123       -- Note ID, VALUE and MEANING are all case insensitive
3124       --
3125       -- Bug 1783461: Flexfield API does not handle :NULL suffix.
3126       -- the original code did not strip off the variables after the value set/
3127       -- or segment name and when used resulted in a "ORA-20001 The data that
3128       -- defines the flexfield may be inconsistent".
3129       -- The syntax for using bind variables in the default where clause of a
3130       -- value set is as follows (for $FLEX$);
3131       --
3132       --    :$FLEX$.[valuesetname|segmentname][.ID|.VALUE|.MEANING][:NULL]
3133 
3134       dot_pointer := INSTR(bind_token, '.', 9);
3135       col_pointer := INSTR(bind_token,':NULL',9);
3136       l_length := length(bind_token);
3137       if (dot_pointer > 0) then
3138          if (col_pointer > 0) then
3139             null;
3140           else
3141             col_pointer := l_length + 1;
3142          end if;
3143        else
3144          if (col_pointer > 0) then
3145             dot_pointer := col_pointer;
3146           else
3147             dot_pointer := l_length + 1;
3148             col_pointer := l_length + 1;
3149          end if;
3150       end if;
3151 
3152       if (dot_pointer > col_pointer) then
3153          FND_MESSAGE.set_name('FND','FLEX-INVALID PORTION');
3154          FND_MESSAGE.set_token('BTOKEN',bind_token);
3155          l_return_code := FF_VERROR;
3156          GOTO goto_return;
3157       end if;
3158 
3159       seg_name := SUBSTR(bind_token,9,dot_pointer-9);
3160       seg_portion := SUBSTR(bind_token,dot_pointer+1,col_pointer-dot_pointer-1);
3161 
3162       if (seg_portion is null) then
3163          seg_portion := 'ID';
3164       end if;
3165 
3166       -- Find index to previous segment or 0 if previous segment not found.
3167       -- Previous segment value set name or segment name.
3168       --
3169       s_index := 0;
3170       for i in reverse 1..nprev loop
3171          if((prev_segnames(i) = seg_name) or (prev_vsnames(i) = seg_name)) then
3172             s_index := i;
3173             exit;
3174          end if;
3175       end loop;
3176 
3177       -- Copy value, id or meaning to output if found, otherwise error.
3178       --
3179       if(s_index > 0) then
3180          if(seg_portion = 'VALUE') then
3181             bind_val := prev_vals(s_index);
3182           elsif(seg_portion = 'ID') then
3183             bind_val := prev_ids(s_index);
3184           elsif(seg_portion = 'MEANING') then
3185             bind_val := prev_descs(s_index);
3186           else
3187             FND_MESSAGE.set_name('FND', 'FLEX-INVALID PORTION');
3188             FND_MESSAGE.set_token('BTOKEN', bind_token);
3189             l_return_code := FF_VERROR;
3190             GOTO goto_return;
3191          end if;
3192        else
3193          FND_MESSAGE.set_name('FND', 'FLEX-PRIOR SEG NOTFOUND');
3194          FND_MESSAGE.set_token('BTOKEN', bind_token);
3195          l_return_code := FF_VERROR;
3196          GOTO goto_return;
3197       end if;
3198 
3199     else
3200 
3201       -- :BLOCK.FIELD cannot be handled here
3202       --
3203       FND_MESSAGE.set_name('FND', 'FLEX-UNSUPPORTED FLEX BIND');
3204       l_return_code := FF_VUNKNOWN;
3205       GOTO goto_return;
3206 
3207    end if;
3208 
3209    bind_value := bind_val;
3210    l_return_code := FF_VVALID;
3211 
3212    <<goto_return>>
3213      IF (fnd_flex_server1.g_debug_level > 0) THEN
3214         add_debug('END SV1.convert_bind_token(value=' || bind_val || ')');
3215      END IF;
3216      RETURN(l_return_code);
3217 EXCEPTION
3218    WHEN OTHERS then
3219       IF (fnd_flex_server1.g_debug_level > 0) THEN
3220          add_debug('EXCEPTION others SV1.convert_bind_token()');
3221       END IF;
3222       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3223       FND_MESSAGE.set_token('MSG','convert_bind_token() exception: '||SQLERRM);
3224       return(FF_VERROR);
3225 END convert_bind_token;
3226 
3227 --
3228 -- The one with extension support.
3229 --
3230 FUNCTION convert_bind_token2(p_bind_token    IN  VARCHAR2,
3231                              p_str_info      IN  FlexStructId,
3232                              p_seg_info      IN  SegmentInfo,
3233                              p_vdate         IN  DATE,
3234                              p_parent_value  IN  VARCHAR2,
3235                              p_nprev         IN  NUMBER,
3236                              p_prev_dispvals IN  ValueArray,
3237                              p_prev_vals     IN  ValueArray,
3238                              p_prev_ids      IN  ValueIdArray,
3239                              p_prev_descs    IN  ValueDescArray,
3240                              p_prev_segnames IN  SegNameArray,
3241                              p_prev_vsnames  IN  VsNameArray,
3242                              x_bind_value    OUT nocopy VARCHAR2)
3243   RETURN VARCHAR2
3244   IS
3245      l_bind_value  VARCHAR2(2000);
3246      l_return_code VARCHAR2(100);
3247 
3248 BEGIN
3249    IF (fnd_flex_server1.g_debug_level > 0) THEN
3250       add_debug('BEGIN SV1.convert_bind_token2(bind=' || p_bind_token || ')');
3251    END IF;
3252 
3253    l_bind_value := NULL;
3254    IF (p_bind_token = ':$FLEX$.$VDATE$') THEN
3255       IF (p_vdate IS NULL) THEN
3256          l_bind_value := NULL;
3257        ELSE
3258          l_bind_value := To_char(p_vdate, 'YYYY/MM/DD HH24:MI:SS');
3259       END IF;
3260 
3261     ELSIF (p_bind_token = ':$FLEX$.$APPLICATION_ID$') THEN
3262       l_bind_value := p_str_info.application_id;
3263 
3264     ELSIF (p_bind_token = ':$FLEX$.$ID_FLEX_CODE$') THEN
3265       IF (p_str_info.isa_key_flexfield) THEN
3266          l_bind_value := p_str_info.id_flex_code;
3267       END IF;
3268 
3269     ELSIF (p_bind_token = ':$FLEX$.$ID_FLEX_NUM$') THEN
3270       IF (p_str_info.isa_key_flexfield) THEN
3271          l_bind_value := p_str_info.id_flex_num;
3272       END IF;
3273 
3274     ELSIF (p_bind_token = ':$FLEX$.$APPLICATION_COLUMN_NAME$') THEN
3275       l_bind_value := p_seg_info.colname;
3276 
3277     ELSIF (p_bind_token = ':$FLEX$.$VALUE_SET_ID$') THEN
3278       l_bind_value := p_seg_info.vsid;
3279 
3280     ELSIF (p_bind_token = ':$FLEX$.$PARENT_VALUE$') THEN
3281       l_bind_value := p_parent_value;
3282 
3283     ELSE
3284       l_return_code := convert_bind_token(p_bind_token, p_nprev,
3285                                           p_prev_dispvals, p_prev_vals,
3286                                           p_prev_ids, p_prev_descs,
3287                                           p_prev_segnames, p_prev_vsnames,
3288                                           x_bind_value);
3289       GOTO goto_return;
3290    END IF;
3291 
3292    x_bind_value := l_bind_value;
3293    l_return_code := FF_VVALID;
3294 
3295    <<goto_return>>
3296    IF (fnd_flex_server1.g_debug_level > 0) THEN
3297       add_debug('END SV1.convert_bind_token2(value=' || l_bind_value || ')');
3298    END IF;
3299    RETURN(l_return_code);
3300 EXCEPTION
3301    WHEN OTHERS then
3302       IF (fnd_flex_server1.g_debug_level > 0) THEN
3303          add_debug('EXCEPTION others SV1.convert_bind_token2()');
3304       END IF;
3305       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3306       FND_MESSAGE.set_token('MSG','convert_bind_token2() exception: '||SQLERRM);
3307       return(FF_VERROR);
3308 END convert_bind_token2;
3309 
3310 /* ----------------------------------------------------------------------- */
3311 /*      Checks vrules.  Returns TRUE and sets error message if any are     */
3312 /*      violated.  Checks rules in forward order for compatibility with    */
3313 /*      C code.  Also checks SUMMARY_FLAG.                                 */
3314 /* ----------------------------------------------------------------------- */
3315 FUNCTION check_vrules(vrs     IN Vrules,
3316                       sqs     IN Qualifiers,
3317                       sumflg  IN VARCHAR2) RETURN VARCHAR2 IS
3318 
3319   testval     VARCHAR2(245);
3320 
3321 BEGIN
3322 
3323 --  Check vrules in forward order for compatibility with C code.
3324 --
3325   for i in 1..vrs.nvrules loop
3326     if((vrs.fq_names(i) is null) and (vrs.sq_names(i) = 'SUMMARY_FLAG')) then
3327       testval := SEPARATOR || sumflg || SEPARATOR;
3328       if(INSTR(vrs.cat_vals(i), testval) > 0) then
3329         if(vrs.ie_flags(i) = 'E') then
3330           value_error_name(vrs.app_names(i), vrs.err_names(i));
3331           return(FF_VVRULE);
3332         end if;
3333       else
3334         if(vrs.ie_flags(i) = 'I') then
3335           value_error_name(vrs.app_names(i), vrs.err_names(i));
3336           return(FF_VVRULE);
3337         end if;
3338       end if;
3339     else
3340       for j in 1..sqs.nquals loop
3341         if((vrs.sq_names(i) = sqs.sq_names(j)) and
3342            (vrs.fq_names(i) = sqs.fq_names(j))) then
3343           testval := SEPARATOR || sqs.sq_values(j) || SEPARATOR;
3344           if((vrs.cat_vals(i) is not null) and
3345               (INSTR(vrs.cat_vals(i), testval) > 0)) then
3346             if(vrs.ie_flags(i) = 'E') then
3347               value_error_name(vrs.app_names(i), vrs.err_names(i));
3348               return(FF_VVRULE);
3349             end if;
3350           else
3351             if(vrs.ie_flags(i) = 'I') then
3352               value_error_name(vrs.app_names(i), vrs.err_names(i));
3353               return(FF_VVRULE);
3354             end if;
3355           end if;
3356         end if;
3357       end loop;
3358     end if;
3359   end loop;
3360 
3361   return(FF_VVALID);
3362 
3363   EXCEPTION
3364     WHEN OTHERS then
3365       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3366       FND_MESSAGE.set_token('MSG', 'check_vrules() exception: ' || SQLERRM);
3367       return(FF_VERROR);
3368 
3369 END check_vrules;
3370 
3371 /* ----------------------------------------------------------------------- */
3372 /*      Checks vrules on combinations based on the qualifiers in the       */
3373 /*      combinations table.  This function is external to this file being  */
3374 /*      called from AFFFSSVB.pls.                                          */
3375 /*      Returns VV_VALID if all rules pass, or VV_VALUES or VV_ERROR and   */
3376 /*      sets message name if any rules violated.                           */
3377 /* ----------------------------------------------------------------------- */
3378 
3379 FUNCTION check_comb_vrules(vrs    IN  Vrules,
3380                            sqs    IN  Qualifiers,
3381                            sumflg IN  VARCHAR2) RETURN NUMBER IS
3382 v_code    VARCHAR2(1);
3383 retcode   NUMBER;
3384 
3385 BEGIN
3386 
3387 --  First must initialize the value errors since we always want to display
3388 --  the error if any rule violated.
3389 --
3390   value_error_init;
3391 
3392 --  Now call function above to check the rules.
3393 --
3394   v_code := check_vrules(vrs, sqs, sumflg);
3395   if(v_code = FF_VVALID) then
3396      IF (fnd_flex_server1.g_debug_level > 0) THEN
3397         add_debug(' Combination passed vrules. ');
3398      END IF;
3399     retcode := VV_VALID;
3400   elsif(v_code = FF_VVRULE) then
3401      IF (fnd_flex_server1.g_debug_level > 0) THEN
3402         add_debug(' Combination failed vrules. ');
3403      END IF;
3404     retcode := VV_VALUES;
3405   else
3406     retcode := VV_ERROR;
3407   end if;
3408 
3409   return(retcode);
3410 
3411   EXCEPTION
3412     WHEN OTHERS then
3413      FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3414      FND_MESSAGE.set_token('MSG','check_comb_vrules() exception: '||SQLERRM);
3415      return(VV_ERROR);
3416 
3417 END check_comb_vrules;
3418 
3419 /* ----------------------------------------------------------------------- */
3420 /*      Checks value security rules for any which are violated.            */
3421 /*      Returns status codes of FF_VVALID if no security rule violated,    */
3422 /*      FF_VSECURED if security violated, or FF_VERROR if some error       */
3423 /*      checking security.                                                 */
3424 /*      If security is violated a value error message is added             */
3425 /*      only if set_message is TRUE.                                       */
3426 /* ----------------------------------------------------------------------- */
3427 
3428 FUNCTION check_security(val          IN VARCHAR2,
3429                         valfmt       IN VARCHAR2,
3430                         parentval    IN VARCHAR2,
3431                         user_apid    IN NUMBER,
3432                         user_respid  IN NUMBER,
3433                         vsinfo       IN ValueSetInfo,
3434                         set_message  IN BOOLEAN) RETURN VARCHAR2 IS
3435 
3436   bufstr      VARCHAR2(500);
3437   rulemsgbuf  VARCHAR2(240);
3438   nfound      NUMBER;
3439   l_vsc_code  VARCHAR2(10);
3440   l_return_code VARCHAR2(10);
3441   l_security_status VARCHAR2(2000);
3442   l_error_message   VARCHAR2(2000);
3443 BEGIN
3444    IF (fnd_flex_server1.g_debug_level > 0) THEN
3445       add_debug('BEGIN SV1.check_security()');
3446    END IF;
3447 
3448 --
3449 -- Return immediately if user info is not set.
3450 --
3451  IF ((user_apid = -1) AND (user_respid = -1)) THEN
3452     RETURN(FF_VVALID);
3453  END IF;
3454 --
3455 -- First check the VSC
3456 --
3457    l_vsc_code :=  check_vsc(user_apid, user_respid, vsinfo.vsid,
3458                             parentval, val, l_return_code);
3459    IF (l_vsc_code IN (fnd_plsql_cache.CACHE_VALID,
3460                       fnd_plsql_cache.CACHE_INVALID)) THEN
3461       IF (fnd_flex_server1.g_debug_level > 0) THEN
3462          add_debug('Found in vsc.');
3463       END IF;
3464       GOTO label_return;
3465    END IF;
3466 
3467    --
3468    -- l_vsc_code is either CACHE_NOTFOUND.
3469    -- Continue on security check.
3470    --
3471      l_return_code := FF_VVALID;
3472 
3473      fnd_flex_server.check_value_security
3474        (p_security_check_mode   => 'YH',
3475         p_flex_value_set_id     => vsinfo.vsid,
3476         p_parent_flex_value     => parentval,
3477         p_flex_value            => val,
3478         p_resp_application_id   => user_apid,
3479         p_responsibility_id     => user_respid,
3480         x_security_status       => l_security_status,
3481         x_error_message         => l_error_message);
3482      IF (fnd_flex_server1.g_debug_level > 0) THEN
3483         add_debug('Hierarchy security: status :'||l_security_status || ' message : ' || l_error_message);
3484      END IF;
3485 
3486      IF (l_security_status <> 'NOT-SECURED') THEN
3487         IF (set_message) THEN
3488            value_error_name('FND', 'FLEX-USER DEFINED ERROR');
3489            value_error_token('MSG', l_error_message);
3490         END IF;
3491         l_return_code := FF_VSECURED;
3492         GOTO label_return;
3493      END IF;
3494 
3495      GOTO label_return;
3496 
3497 
3498   <<label_return>>
3499     IF (l_vsc_code IN (fnd_plsql_cache.CACHE_NOTFOUND)) THEN
3500        update_vsc(user_apid, user_respid, vsinfo.vsid,
3501                   parentval, val, l_return_code);
3502     END IF;
3503     IF (fnd_flex_server1.g_debug_level > 0) THEN
3504        add_debug('END SV1.check_security()');
3505     END IF;
3506     RETURN(l_return_code);
3507   EXCEPTION
3508     WHEN OTHERS then
3509       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3510       FND_MESSAGE.set_token('MSG','check_security() exception: ' || SQLERRM);
3511       IF (fnd_flex_server1.g_debug_level > 0) THEN
3512          add_debug('EXCEPTION SV1.check_security()');
3513       END IF;
3514 
3515       return(FF_VERROR);
3516 
3517 END check_security;
3518 
3519 /* ----------------------------------------------------------------------- */
3520 /*      Checks to see whether this segment is displayed.                   */
3521 /*      Returns displayed_flag as output.                                  */
3522 /*      Returns TRUE on success or FALSE if error or exception.            */
3523 /* ----------------------------------------------------------------------- */
3524 
3525 FUNCTION check_displayed(segindex     IN  NUMBER,
3526                          disp_tokmap  IN  DisplayedSegs,
3527                          d_flag       OUT nocopy BOOLEAN) RETURN BOOLEAN IS
3528 
3529 BEGIN
3530 
3531   d_flag := disp_tokmap.segflags(segindex);
3532   return(TRUE);
3533 
3534   EXCEPTION
3535     WHEN OTHERS then
3536       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3537       FND_MESSAGE.set_token('MSG','check_displayed() exception: ' ||SQLERRM);
3538       return(FALSE);
3539 
3540 END check_displayed;
3541 
3542 /* ----------------------------------------------------------------------- */
3543 /*      Interprets the compiled value attribute (CVA) string and returns   */
3544 /*      segment qualifier values.  From the value set id looks up all      */
3545 /*      qualifiers which might be associated with this value set and       */
3546 /*      orders them in the same order as they are stored in the CVA        */
3547 /*      string.  Then interprets the CVA string.  For each qualifier       */
3548 /*      associated with this flexfield segment, the default qualifier value*/
3549 /*      is overwritten by the value from the CVA string if the CVA string  */
3550 /*      contains a non-null value.  Returns the updated qualifier values   */
3551 /*      array and number of qualifier values found or < 0 if error.        */
3552 /*      No qualifier values for descriptive flexfields.                    */
3553 /*                                                                         */
3554 /*      Note:  Do not order by segment_attribute_type as this causes       */
3555 /*      GL_ACCOUNT/GL_ACCOUNT_TYPE to appear before GL_GLOBAL/DETAIL...    */
3556 /*      instead of after it as is the case in the client code.             */
3557 /* ----------------------------------------------------------------------- */
3558 FUNCTION qualifier_values(ffstruct       IN  FlexStructId,
3559                           valset_id      IN  NUMBER,
3560                           cvas           IN  VARCHAR2,
3561                           nqualifs       IN  NUMBER,
3562                           fqnames        IN  QualNameArray,
3563                           sqnames        IN  QualNameArray,
3564                           sqvals         IN OUT nocopy ValAttribArray) RETURN NUMBER IS
3565 
3566   cva_index           NUMBER;
3567   n_value_attributes  NUMBER;
3568   value_attributes    StringArray;
3569   l_vsq_code          VARCHAR2(200);
3570   i                   NUMBER;
3571 
3572   CURSOR CVA_Cursor(vs_id IN NUMBER) IS
3573     SELECT id_flex_application_id fapid, id_flex_code fcode,
3574            segment_attribute_type fqname, value_attribute_type sqname
3575       FROM fnd_flex_validation_qualifiers
3576      WHERE flex_value_set_id = vs_id
3577   ORDER BY assignment_date, id_flex_application_id, id_flex_code,
3578            value_attribute_type;
3579   vq  cva_cursor%ROWTYPE;
3580 BEGIN
3581 --  Quickly handle case where there are no qualifiers. (eg Descr flex)
3582 --
3583   if((not ffstruct.isa_key_flexfield) or (nqualifs = 0)) then
3584     return(0);
3585   end if;
3586 
3587 --  Convert compiled value attributes to array.
3588   --
3589   IF (cvas IS NOT NULL) THEN
3590      n_value_attributes := to_stringarray2(cvas, NEWLINE, value_attributes);
3591    ELSE
3592      n_value_attributes := 0;
3593   END IF;
3594 
3595 --  Set returned segment qualifier values to defaults
3596 --
3597 --    for i in 1..nqualifs loop
3598 --      sqvals(i) := default_sqvals(i);
3599 --    end loop;
3600 
3601 --  cva_index is position of the value attribute in the CVA string.
3602 --
3603   cva_index := 0;
3604 
3605 --  CVA_Cursor returns the flexfields and names of the attibutes associated
3606 --  with this value set in the order that they are stored in the cva string.
3607 --
3608 
3609   g_cache_key := valset_id;
3610 
3611   fnd_plsql_cache.generic_1tom_get_values(vsq_cache_controller,
3612                                           vsq_cache_storage,
3613                                           g_cache_key,
3614                                           g_cache_numof_values,
3615                                           g_cache_values,
3616                                           g_cache_return_code);
3617 
3618   IF (g_cache_return_code = fnd_plsql_cache.CACHE_FOUND) THEN
3619      NULL;
3620    ELSE
3621      i := 0;
3622      FOR vq IN cva_cursor(valset_id) LOOP
3623         i := i + 1;
3624         fnd_plsql_cache.generic_cache_new_value
3625           (x_value      => g_cache_value,
3626            p_number_1   => vq.fapid,
3627            p_varchar2_1 => vq.fcode,
3628            p_varchar2_2 => vq.fqname,
3629            p_varchar2_3 => vq.sqname);
3630         g_cache_values(i) := g_cache_value;
3631      END LOOP;
3632      g_cache_numof_values := i;
3633 
3634      fnd_plsql_cache.generic_1tom_put_values(vsq_cache_controller,
3635                                                   vsq_cache_storage,
3636                                                   g_cache_key,
3637                                                   g_cache_numof_values,
3638                                                   g_cache_values);
3639   END IF;
3640 
3641   FOR ii IN 1..g_cache_numof_values LOOP
3642      vq.fapid  := g_cache_values(ii).number_1;
3643      vq.fcode  := g_cache_values(ii).varchar2_1;
3644      vq.fqname := g_cache_values(ii).varchar2_2;
3645      vq.sqname := g_cache_values(ii).varchar2_3;
3646 
3647 --    for vq in CVA_Cursor(valset_id) loop
3648      cva_index := cva_index + 1;
3649 
3650 --  If the selected attribute applies to the flexfied under consideration
3651 --  then find the attribute by name in the list of those which apply to this
3652 --  segment and replace its default value with the appropriate value from
3653 --  the cva string.
3654 --
3655     if((vq.fapid = ffstruct.application_id) and
3656        (vq.fcode = ffstruct.id_flex_code)) then
3657       for i in 1..nqualifs loop
3658         if((vq.fqname = fqnames(i)) and (vq.sqname = sqnames(i)) and
3659            (cva_index <= n_value_attributes)) then
3660             sqvals(i) := value_attributes(cva_index);
3661         end if;
3662       end loop;
3663     end if;
3664   end loop;
3665 
3666   return(cva_index);
3667 
3668 EXCEPTION
3669   WHEN OTHERS then
3670     FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3671     FND_MESSAGE.set_token('MSG', 'qualifier_values() exception:  '||SQLERRM);
3672     return(-1);
3673 
3674 END qualifier_values;
3675 
3676 /* ----------------------------------------------------------------------- */
3677 /*      Gets the **enabled** flexfield and segment qualifiers for this     */
3678 /*      segment.  Segment is uniquely determined by combination of         */
3679 /*      flex apid, code, struct num, with the name of the column in the    */
3680 /*      code combinations table which will hold the segment value.         */
3681 /*      No qualifiers enabled for descriptive flexs.                       */
3682 /*                                                                         */
3683 /*      Returns the number of qualifiers found or < 0 if error.            */
3684 /*                                                                         */
3685 /*      Also returns FQ name, SQ name, derived_column, and default value   */
3686 /*      of the segment qualifiers for this segment.                        */
3687 /* ----------------------------------------------------------------------- */
3688 FUNCTION get_qualifiers(ffstruct      IN  FlexStructId,
3689                         seg_colname   IN  VARCHAR2,
3690                         seg_quals     OUT nocopy Qualifiers)
3691   RETURN NUMBER
3692   IS
3693      sqcount      NUMBER;
3694 
3695   CURSOR Qual_Cursor(keystruct IN FlexStructId, colname IN VARCHAR2) IS
3696       SELECT v.segment_attribute_type fq_name,
3697              v.value_attribute_type sq_name,
3698              v.application_column_name drv_colname,
3699              v.default_value dflt_val
3700         FROM fnd_value_attribute_types v, fnd_segment_attribute_values s
3701        WHERE v.application_id = s.application_id
3702          AND v.id_flex_code = s.id_flex_code
3703          AND v.segment_attribute_type = s.segment_attribute_type
3704          AND s.application_id = keystruct.application_id
3705          AND s.id_flex_code = keystruct.id_flex_code
3706          AND s.id_flex_num = keystruct.id_flex_num
3707          AND s.application_column_name = colname
3708          AND s.attribute_value = 'Y';
3709 BEGIN
3710    IF (fnd_flex_server1.g_debug_level > 0) THEN
3711       fnd_flex_server1.add_debug('BEGIN SV1.get_qualifiers()');
3712    END IF;
3713 
3714    sqcount := 0;
3715    IF (ffstruct.isa_key_flexfield) THEN
3716       g_cache_key := (ffstruct.application_id || '.' ||
3717                       ffstruct.id_flex_code || '.' ||
3718                       ffstruct.id_flex_num || '.' ||
3719                       seg_colname);
3720 
3721       fnd_plsql_cache.generic_1tom_get_values(fsq_cache_controller,
3722                                               fsq_cache_storage,
3723                                               g_cache_key,
3724                                               g_cache_numof_values,
3725                                               g_cache_values,
3726                                               g_cache_return_code);
3727 
3728       IF (g_cache_return_code = fnd_plsql_cache.CACHE_FOUND) THEN
3729          sqcount := g_cache_numof_values;
3730        ELSE
3731          FOR squal IN qual_cursor(ffstruct, seg_colname) LOOP
3732             sqcount := sqcount + 1;
3733 
3734             fnd_plsql_cache.generic_cache_new_value
3735               (x_value      => g_cache_value,
3736                p_varchar2_1 => squal.fq_name,
3737                p_varchar2_2 => squal.sq_name,
3738                p_varchar2_3 => squal.dflt_val,
3739                p_varchar2_4 => squal.drv_colname);
3740             g_cache_values(sqcount) := g_cache_value;
3741          END LOOP;
3742          g_cache_numof_values := sqcount;
3743 
3744          fnd_plsql_cache.generic_1tom_put_values(fsq_cache_controller,
3745                                                  fsq_cache_storage,
3746                                                  g_cache_key,
3747                                                  g_cache_numof_values,
3748                                                  g_cache_values);
3749       END IF;
3750 
3751       FOR ii IN 1..sqcount LOOP
3752          seg_quals.fq_names(ii) := g_cache_values(ii).varchar2_1;
3753          seg_quals.sq_names(ii) := g_cache_values(ii).varchar2_2;
3754          seg_quals.sq_values(ii) := g_cache_values(ii).varchar2_3;
3755          seg_quals.derived_cols(ii) := g_cache_values(ii).varchar2_4;
3756       END LOOP;
3757    END IF;
3758 
3759    seg_quals.nquals := sqcount;
3760 
3761    IF (fnd_flex_server1.g_debug_level > 0) THEN
3762       fnd_flex_server1.add_debug('END SV1.get_qualifiers()');
3763    END IF;
3764 
3765    RETURN(sqcount);
3766 EXCEPTION
3767   WHEN OTHERS then
3768     FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3769     FND_MESSAGE.set_token('MSG', 'get_qualifiers() exception:  ' || SQLERRM);
3770     IF (fnd_flex_server1.g_debug_level > 0) THEN
3771        fnd_flex_server1.add_debug('EXCEPTION SV1.get_qualifiers()');
3772     END IF;
3773 
3774     return(-1);
3775 
3776 END get_qualifiers;
3777 
3778 /* ----------------------------------------------------------------------- */
3779 /*      Gets the value set information for a given value set id.           */
3780 /*      Returns TRUE if found or FALSE and sets error message on error.    */
3781 /* ----------------------------------------------------------------------- */
3782 FUNCTION get_value_set(value_set_id   IN  NUMBER,
3783                        segment_name   IN  VARCHAR2,
3784                        vs_info        OUT nocopy ValueSetInfo)
3785   RETURN BOOLEAN
3786   IS
3787      l_vsi  valuesetinfo;
3788 BEGIN
3789    IF (fnd_flex_server1.g_debug_level > 0) THEN
3790       fnd_flex_server1.add_debug('CALL SV1.get_value_set(' ||
3791                                  'vsid:' || value_set_id || ')');
3792    END IF;
3793 
3794    g_cache_key := value_set_id;
3795    fnd_plsql_cache.generic_1to1_get_value(vst_cache_controller,
3796                                           vst_cache_storage,
3797                                           g_cache_key,
3798                                           g_cache_value,
3799                                           g_cache_return_code);
3800 
3801    IF (g_cache_return_code = fnd_plsql_cache.CACHE_FOUND) THEN
3802       vs_info.vsid        := value_set_id;
3803       vs_info.parent_vsid := g_cache_value.number_1;
3804       vs_info.valsecure   := g_cache_value.varchar2_1;
3805       vs_info.valtype     := g_cache_value.varchar2_2;
3806       vs_info.vsformat    := g_cache_value.varchar2_3;
3807       vs_info.maxsize     := g_cache_value.number_2;
3808       vs_info.lettersok   := g_cache_value.varchar2_4;
3809       vs_info.capsonly    := g_cache_value.varchar2_5;
3810       vs_info.zfill       := g_cache_value.varchar2_6;
3811       vs_info.precis      := g_cache_value.number_3;
3812       vs_info.minval      := g_cache_value.varchar2_7;
3813       vs_info.maxval      := g_cache_value.varchar2_8;
3814       vs_info.vsname      := g_cache_value.varchar2_9;
3815     ELSE
3816       SELECT flex_value_set_id, parent_flex_value_set_id,
3817         security_enabled_flag,
3818         validation_type, format_type, maximum_size,
3819         alphanumeric_allowed_flag, uppercase_only_flag,
3820         numeric_mode_enabled_flag, number_precision, minimum_value,
3821         maximum_value, flex_value_set_name
3822         INTO l_vsi
3823         FROM fnd_flex_value_sets
3824         WHERE flex_value_set_id = value_set_id;
3825 
3826       fnd_plsql_cache.generic_cache_new_value
3827         (x_value      => g_cache_value,
3828          p_number_1   => l_vsi.parent_vsid,
3829          p_varchar2_1 => l_vsi.valsecure,
3830          p_varchar2_2 => l_vsi.valtype,
3831          p_varchar2_3 => l_vsi.vsformat,
3832          p_number_2   => l_vsi.maxsize,
3833          p_varchar2_4 => l_vsi.lettersok,
3834          p_varchar2_5 => l_vsi.capsonly,
3835          p_varchar2_6 => l_vsi.zfill,
3836          p_number_3   => l_vsi.precis,
3837          p_varchar2_7 => l_vsi.minval,
3838          p_varchar2_8 => l_vsi.maxval,
3839          p_varchar2_9 => l_vsi.vsname);
3840 
3841       fnd_plsql_cache.generic_1to1_put_value(vst_cache_controller,
3842                                              vst_cache_storage,
3843                                              g_cache_key,
3844                                              g_cache_value);
3845       vs_info := l_vsi;
3846    END IF;
3847    return(TRUE);
3848 EXCEPTION
3849   WHEN NO_DATA_FOUND then
3850     FND_MESSAGE.set_name('FND', 'FLEX-VALUE SET NOT FOUND');
3851     FND_MESSAGE.set_token('SEGMENT', segment_name);
3852     return(FALSE);
3853   WHEN OTHERS then
3854     FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3855     FND_MESSAGE.set_token('MSG', 'get_value_set() exception:  ' || SQLERRM);
3856     return(FALSE);
3857 END get_value_set;
3858 
3859 /* ----------------------------------------------------------------------- */
3860 /*      Creates value set information for segment without a value set      */
3861 /*      based on the specification of the column into which it will go.    */
3862 /*      We document that this only works for CHAR or VARCHAR2 type columns.*/
3863 /*      Returns TRUE if ok or FALSE and sets error message on error.       */
3864 /* ----------------------------------------------------------------------- */
3865 FUNCTION virtual_value_set(column_type  IN  VARCHAR2,
3866                            column_width IN  NUMBER,
3867                            segment_name IN  VARCHAR2,
3868                            vs_info      OUT nocopy ValueSetInfo) RETURN BOOLEAN IS
3869 BEGIN
3870 
3871 --  Assumes all components of vs_info are initially null
3872 --
3873   if(column_type in ('C', 'V')) then
3874     vs_info.valsecure := 'N';
3875     vs_info.valtype := 'N';
3876     vs_info.vsformat := 'C';
3877     vs_info.maxsize := column_width;
3878     vs_info.lettersok := 'Y';
3879     vs_info.capsonly := 'N';
3880     vs_info.zfill := 'N';
3881     return(TRUE);
3882   end if;
3883   FND_MESSAGE.set_name('FND', 'FLEX-VALUE SET REQUIRED');
3884   FND_MESSAGE.set_token('SEGMENT', segment_name);
3885   return(FALSE);
3886 
3887 EXCEPTION
3888   WHEN OTHERS then
3889     FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
3890     FND_MESSAGE.set_token('MSG','virtual_value_set() exception:  '||SQLERRM);
3891     return(FALSE);
3892 
3893 END virtual_value_set;
3894 
3895 /* ----------------------------------------------------------------------- */
3896 /*      Message handler functions for value validation errors.  Needed     */
3897 /*      because value validation does not always stop at the first         */
3898 /*      error encountered.  This handler makes sure that FND_MESSAGE       */
3899 /*      error is set to the first value error if there are no other        */
3900 /*      errors.  For more serious errors, we set the message directly      */
3901 /*      using the FND_MESSAGE package.   Note this assumes the main        */
3902 /*      validate_struct() function knows to stop on the first serious      */
3903 /*      error otherwise we risk overwriting a more serious error with      */
3904 /*      a value error.                                                     */
3905 /*      If the application short name is null, then we use the             */
3906 /*      FLEX-USER DEFINED ERROR to display the message name as text.       */
3907 /*      This is used in check_vrules().                                    */
3908 /* ----------------------------------------------------------------------- */
3909 
3910 /* ----------------------------------------------------------------------- */
3911 /*      Initializes value error message global variables.                  */
3912 /* ----------------------------------------------------------------------- */
3913 
3914 PROCEDURE value_error_init IS
3915 BEGIN
3916   value_error_set := FALSE;
3917   entering_new_message := FALSE;
3918 EXCEPTION
3919   WHEN OTHERS then
3920      IF (fnd_flex_server1.g_debug_level > 0) THEN
3921         add_debug('value_error_init() exception: ' || SQLERRM);
3922      END IF;
3923 END value_error_init;
3924 
3925 /* ------------------------------------------------------------------------ */
3926 /*      Sets error message name if no other value errors have been set.     */
3927 /*      Also sets entering_new_message flag to indicate new message being   */
3928 /*      entered if this is the first value error, otherwise resets it.      */
3929 /* ------------------------------------------------------------------------ */
3930 PROCEDURE value_error_name(appl_sname      IN  VARCHAR2,
3931                            errmsg_name     IN  VARCHAR2) IS
3932 BEGIN
3933   if(value_error_set = FALSE) then
3934     if(appl_sname is null) then
3935       FND_MESSAGE.set_name('FND', 'FLEX-USER DEFINED ERROR');
3936       FND_MESSAGE.set_token('MSG', errmsg_name);
3937     else
3938       FND_MESSAGE.set_name(appl_sname, errmsg_name);
3939     end if;
3940     value_error_set := TRUE;
3941     entering_new_message := TRUE;
3942   else
3943     entering_new_message := FALSE;
3944   end if;
3945 EXCEPTION
3946   WHEN OTHERS then
3947      IF (fnd_flex_server1.g_debug_level > 0) THEN
3948         add_debug('value_error_name() exception: ' || SQLERRM);
3949      END IF;
3950 END value_error_name;
3951 
3952 /* ----------------------------------------------------------------------- */
3953 /*      Sets error message token if currently entering a new message.      */
3954 /*      Otherwise just ignores the token.  Call only after setting         */
3955 /*      value error name with value_error_name() above.                    */
3956 /* ----------------------------------------------------------------------- */
3957 PROCEDURE value_error_token(token_name   IN  VARCHAR2,
3958                             token_value  IN  VARCHAR2) IS
3959 BEGIN
3960   if(entering_new_message) then
3961     FND_MESSAGE.set_token(token_name, token_value);
3962   end if;
3963 EXCEPTION
3964   WHEN OTHERS then
3965      IF (fnd_flex_server1.g_debug_level > 0) THEN
3966         add_debug('value_error_token() exception: ' || SQLERRM);
3967      END IF;
3968 END value_error_token;
3969 
3970 /* ----------------------------------------------------------------------- */
3971 /*      Converts the value to be output in an error message from stored    */
3972 /*      format to the displayed format appropriate for the given value set.*/
3973 /*      Returns the value in stored format if any errors encountered.      */
3974 /* ----------------------------------------------------------------------- */
3975 FUNCTION msg_val(valset_fmt  IN  VARCHAR2,
3976                  valset_len  IN  NUMBER,
3977                  valset_prec IN  NUMBER,
3978                  valset_lettersok IN VARCHAR2,
3979                  stored_val  IN  VARCHAR2) RETURN VARCHAR2 IS
3980   d_val  VARCHAR2(1000);
3981 BEGIN
3982   if(stored_to_displayed(valset_fmt, valset_len,
3983                          valset_prec, valset_lettersok,
3984                          stored_val, d_val) <> FF_VVALID) then
3985     d_val := stored_val;
3986   end if;
3987   return(d_val);
3988 EXCEPTION
3989   WHEN OTHERS then
3990     return(stored_val);
3991 END msg_val;
3992 
3993 /* ----------------------------------------------------------------------- */
3994 /*      Converts value from stored format to displayed format.             */
3995 /*      Returns FF_VVALID on success, or FF_VERROR otherwise.              */
3996 /* ----------------------------------------------------------------------- */
3997 FUNCTION stored_to_displayed(valset_fmt  IN  VARCHAR2,
3998                              valset_len  IN  NUMBER,
3999                              valset_prec IN  NUMBER,
4000                              valset_lettersok IN VARCHAR2,
4001                              stored_val  IN  VARCHAR2,
4002                              disp_val    OUT nocopy VARCHAR2) RETURN VARCHAR2 IS
4003   datebuf     DATE;
4004 BEGIN
4005 if(valset_fmt in ('X', 'Y', 'Z')) then
4006   if(isa_stored_date(stored_val, valset_fmt, datebuf)) then
4007    disp_val := to_char(datebuf,displayed_date_format(valset_fmt,valset_len));
4008   else
4009     return(FF_VERROR);
4010   end if;
4011  ELSIF ((valset_fmt = 'N') OR
4012         ((valset_fmt = 'C') AND
4013          (valset_lettersok = 'N'))) THEN
4014    disp_val := REPLACE(stored_val,m_nc,m_nd);
4015  else
4016   disp_val := stored_val;
4017 end if;
4018 
4019 return(FF_VVALID);
4020 
4021 EXCEPTION
4022   WHEN OTHERS then
4023     return(FF_VERROR);
4024 END stored_to_displayed;
4025 
4026 /* ----------------------------------------------------------------------- */
4027 /*      Converts character representation of a number to a number.         */
4028 /*      Returns TRUE if it's a valid number, and FALSE otherwise.          */
4029 /* ----------------------------------------------------------------------- */
4030 FUNCTION isa_number(teststr IN VARCHAR2,
4031                      outnum OUT nocopy NUMBER) RETURN BOOLEAN IS
4032 BEGIN
4033   outnum := to_number(teststr);
4034   return(TRUE);
4035 EXCEPTION
4036   WHEN OTHERS then
4037     return(FALSE);
4038 END isa_number;
4039 
4040 /* ----------------------------------------------------------------------- */
4041 /*      Converts character representation of a stored date to a date.      */
4042 /*      Returns TRUE if it's a valid date, and FALSE otherwise.    */
4043 /* ----------------------------------------------------------------------- */
4044 FUNCTION isa_stored_date(teststr IN VARCHAR2,
4045                          flexfmt IN VARCHAR2,
4046                          outdate OUT nocopy DATE) RETURN BOOLEAN IS
4047 BEGIN
4048   if(teststr is null) then
4049     return(TRUE);
4050   end if;
4051   return(isa_date(teststr, stored_date_format(flexfmt, LENGTH(teststr)),
4052          outdate));
4053 EXCEPTION
4054   WHEN OTHERS then
4055      IF (fnd_flex_server1.g_debug_level > 0) THEN
4056         add_debug('isa_stored_date() exception: ' || SQLERRM);
4057      END IF;
4058     return(FALSE);
4059 END isa_stored_date;
4060 
4061 
4062 /* ----------------------------------------------------------------------- */
4063 /*      Converts character representation of a displayed date to a date.   */
4064 /*      Returns TRUE if it's a valid date, and FALSE otherwise.            */
4065 /* ----------------------------------------------------------------------- */
4066 FUNCTION isa_displayed_date(teststr IN VARCHAR2,
4067                             flexfmt IN VARCHAR2,
4068                             outdate OUT nocopy DATE) RETURN BOOLEAN IS
4069 BEGIN
4070   if(teststr is null) then
4071     return(TRUE);
4072   end if;
4073   return(isa_date(teststr, displayed_date_format(flexfmt, LENGTH(teststr)),
4074          outdate));
4075 EXCEPTION
4076   WHEN OTHERS then
4077      IF (fnd_flex_server1.g_debug_level > 0) THEN
4078         add_debug('isa_displayed_date() exception: ' || SQLERRM);
4079      END IF;
4080     return(FALSE);
4081 END isa_displayed_date;
4082 
4083 /* ----------------------------------------------------------------------- */
4084 /*      Converts test string to date using supplied format.                */
4085 /*      If date conversion fails or supplied format is null, returns FALSE */
4086 /*      otherwise returns TRUE.                                            */
4087 /*      This function is a wrapper around to_date() to make it always work */
4088 /*      even if the supplied format is 'DD-MON-YY'  (See bug)              */
4089 /* ----------------------------------------------------------------------- */
4090 FUNCTION isa_date(teststr IN VARCHAR2,
4091                   datefmt IN VARCHAR2,
4092                   outdate OUT nocopy DATE) RETURN BOOLEAN IS
4093 BEGIN
4094   if(teststr is null) then
4095     return(TRUE);
4096   end if;
4097   if(datefmt is null) then
4098     return(FALSE);
4099   elsif(datefmt = 'DD-MON-YY') then
4100     outdate := to_date(teststr, datefmt);
4101   elsif(datefmt = 'DD-MON-RR') then
4102     outdate := to_date(teststr, datefmt);
4103   else
4104     outdate := to_date(teststr, datefmt);
4105   end if;
4106   return(TRUE);
4107 EXCEPTION
4108   WHEN OTHERS then
4109      IF (fnd_flex_server1.g_debug_level > 0) THEN
4110         add_debug('isa_date() exception: ' || SQLERRM);
4111      END IF;
4112     return(FALSE);
4113 END isa_date;
4114 
4115 /* ----------------------------------------------------------------------- */
4116 /*      Returns format string for converting a date to a character string  */
4117 /*      that represents the displayed value of a flex date, time, or       */
4118 /*      date-time.                                                         */
4119 /*      Returns NULL if not valid flex date format.                        */
4120 /* ----------------------------------------------------------------------- */
4121 FUNCTION displayed_date_format(flex_data_type IN VARCHAR2,
4122                                string_length  IN NUMBER) RETURN VARCHAR2 IS
4123 
4124   l_format_in VARCHAR2(500);
4125   l_format_out VARCHAR2(500);
4126 BEGIN
4127    IF (fnd_flex_val_util.get_display_format
4128        (p_vset_format => flex_data_type,
4129         p_max_length => string_length,
4130         p_precision => NULL,
4131         x_format_in => l_format_in,
4132         x_format_out => l_format_out)) THEN
4133       RETURN(l_format_out);
4134     ELSE
4135       RETURN(NULL);
4136    END IF;
4137 
4138   EXCEPTION
4139     WHEN OTHERS then
4140       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
4141       FND_MESSAGE.set_token('MSG',
4142                       'displayed_date_format() exception:  ' || SQLERRM);
4143       return(NULL);
4144 
4145 END displayed_date_format;
4146 
4147 /* ----------------------------------------------------------------------- */
4148 /*      Returns format string for converting character representation      */
4149 /*      of stored flex date, time, or date-time data to a date datatype    */
4150 /*      using the to_date() conversion utility.                            */
4151 /*      Returns NULL if not valid flex date format.                        */
4152 /*      Modified for DD-MON-RR conversion in Prod 16   12-26-96            */
4153 /* ----------------------------------------------------------------------- */
4154 FUNCTION stored_date_format(flex_data_type IN VARCHAR2,
4155                             string_length  IN NUMBER) RETURN VARCHAR2 IS
4156 
4157   l_format VARCHAR2(500);
4158 BEGIN
4159    IF (fnd_flex_val_util.get_storage_format(p_vset_format => flex_data_type,
4160                                             p_max_length  => string_length,
4161                                             p_precision   => NULL,
4162                                             x_format      => l_format)) THEN
4163       RETURN(l_format);
4164     ELSE
4165       RETURN(NULL);
4166    END IF;
4167 
4168 EXCEPTION
4169    WHEN OTHERS then
4170       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
4171       FND_MESSAGE.set_token('MSG',
4172                             'stored_date_format() exception:  ' || SQLERRM);
4173       return(NULL);
4174 
4175 END stored_date_format;
4176 
4177 /* ----------------------------------------------------------------------- */
4178 /*              Generally useful utilities - Externalized                  */
4179 /* ----------------------------------------------------------------------- */
4180 
4181 /* ----------------------------------------------------------------------- */
4182 /*              Initializes all global variables                           */
4183 /* ----------------------------------------------------------------------- */
4184 FUNCTION init_globals RETURN BOOLEAN IS
4185 
4186 BEGIN
4187 
4188   n_sqlstrings := 0;
4189   g_debug_array_size := 0;
4190   return(TRUE);
4191 
4192 EXCEPTION
4193   WHEN OTHERS then
4194     FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
4195     FND_MESSAGE.set_token('MSG', 'init_globals() exception:  ' || SQLERRM);
4196     return(FALSE);
4197 
4198 END init_globals;
4199 
4200 /* ----------------------------------------------------------------------- */
4201 /*      Creates an "and clause" of a SQL select statement for determining  */
4202 /*      if the value passed in is in between the values in the columns     */
4203 /*      whose names are in mincol and maxcol.  Returns NULL if no          */
4204 /*      statement required for this column                                 */
4205 /*                                                                         */
4206 /*      By isolating all in range clauses to this routine we can ensure    */
4207 /*      uniform range behavior.                                            */
4208 /*                                                                         */
4209 /*      Null handling:  If val is NULL, requires either mincol or maxcol   */
4210 /*      to be null.  If the value contained in mincol (maxcol) is NULL it  */
4211 /*      means there is no lower(upper) limit on the range of val           */
4212 /*                                                                         */
4213 /*      Clause is of the form:                                             */
4214 /*      'and (10 between nvl(to_number(MINCOL), 10)                        */
4215 /*             and nvl(to_number(MAXCOL), 10)) '                           */
4216 /*                                                                         */
4217 /* ----------------------------------------------------------------------- */
4218 PROCEDURE x_inrange_clause(valstr  IN VARCHAR2,
4219                            valtype IN VARCHAR2,
4220                            mincol  IN VARCHAR2,
4221                            maxcol  IN VARCHAR2) IS
4222 
4223   clause      VARCHAR2(500);
4224   val         VARCHAR2(200);
4225   collo       VARCHAR2(200);
4226   colhi       VARCHAR2(200);
4227   datefmt     VARCHAR2(24);
4228 
4229 BEGIN
4230    fnd_dsql.add_text('and (');
4231    IF (valstr IS NULL) THEN
4232       fnd_dsql.add_text(mincol || ' is null or ' ||
4233                         maxcol || ' is null) ');
4234     ELSE
4235       IF (valtype = 'N') THEN
4236          fnd_dsql.add_bind(fnd_number.canonical_to_number(valstr));
4237 
4238          fnd_dsql.add_text(' between nvl(fnd_number.canonical_to_number('
4239                            || mincol || '),');
4240          fnd_dsql.add_bind(fnd_number.canonical_to_number(valstr));
4241 
4242          fnd_dsql.add_text(') and nvl(fnd_number.canonical_to_number('
4243                            || maxcol || '),');
4244          fnd_dsql.add_bind(fnd_number.canonical_to_number(valstr));
4245 
4246        ELSIF (valtype in ('D', 'T', 't', 'I', 'X', 'Y', 'Z')) THEN
4247          datefmt := stored_date_format(valtype, LENGTH(valstr));
4248          fnd_dsql.add_bind(To_date(valstr, datefmt));
4249 
4250          fnd_dsql.add_text(' between nvl(to_date(' ||
4251                            mincol || ',''' || datefmt || '''),');
4252          fnd_dsql.add_bind(To_date(valstr, datefmt));
4253 
4254          fnd_dsql.add_text(') and nvl(to_date(' ||
4255                            maxcol || ',''' || datefmt || '''),');
4256          fnd_dsql.add_bind(To_date(valstr, datefmt));
4257 
4258        ELSE
4259          fnd_dsql.add_bind(valstr);
4260 
4261          fnd_dsql.add_text(' between nvl(' || mincol || ',');
4262          fnd_dsql.add_bind(valstr);
4263 
4264          fnd_dsql.add_text(') and nvl(' || maxcol || ',');
4265          fnd_dsql.add_bind(valstr);
4266 
4267       END IF;
4268       fnd_dsql.add_text(')) ');
4269    END IF;
4270 END x_inrange_clause;
4271 
4272 /* ----------------------------------------------------------------------- */
4273 /*      Function to convert a column name into a SQL clause for selecting  */
4274 /*      a value, id, or description from that column into the correct      */
4275 /*      character format for the given value set.                          */
4276 /*                                                                         */
4277 /*      This function does the default to_char() conversion for            */
4278 /*      non-translatable date, time, date-time, or number value sets       */
4279 /*      in order to maintain backward compatibility with old client code.  */
4280 /*      For translatable date, time, and date-time value sets this code    */
4281 /*      converts the data stored in the date column to date storage format */
4282 /*                                                                         */
4283 /*      Does not check for compatibility of column type and value set.     */
4284 /* ----------------------------------------------------------------------- */
4285 
4286 FUNCTION select_clause(colname     IN  VARCHAR2,
4287                        coltype     IN  VARCHAR2,
4288                        v_component IN  BINARY_INTEGER,
4289                        vs_fmt      IN  VARCHAR2,
4290                        vs_len      IN  NUMBER) RETURN VARCHAR2 IS
4291 
4292   clause      VARCHAR2(2000);
4293 
4294 BEGIN
4295 
4296   if(coltype not in ('C', 'V')) then
4297     clause := 'to_char(' || colname;
4298     if(vs_fmt in ('X', 'Y', 'Z')) then
4299       clause := clause || ', ''';
4300       if((v_component = VC_ID) OR (v_component = VC_VALUE)) then
4301         clause := clause || stored_date_format(vs_fmt, vs_len) || ''')';
4302       else
4303         clause := clause || displayed_date_format(vs_fmt, vs_len) || ''')';
4304       end if;
4305      ELSIF (vs_fmt = 'N') THEN
4306        clause := clause || ')';
4307        clause := 'replace(' || clause || ',''' || m_nb || ''','''
4308          || m_nc || ''')';
4309      else
4310        clause := clause || ')';
4311     end if;
4312   else
4313     clause := colname;
4314   end if;
4315   return(clause);
4316 
4317 END select_clause;
4318 
4319 /* ----------------------------------------------------------------------- */
4320 /*      Function to convert a value into a SQL clause for comparing that   */
4321 /*      value into a table column of the given type, or for inserting that */
4322 /*      value to a value stored in a table column of the given type.       */
4323 /*                                                                         */
4324 /*      If the table column is a number assume the value input is a number */
4325 /*      and just use the text of the number.  If the table column is       */
4326 /*      CHAR or VARCHAR2, then substitute all single quotes in the value   */
4327 /*      with double quotes and surround the value with single quotes.      */
4328 /*      If table column is DATE, do to_date() conversion using the format  */
4329 /*      appropriate for the value set.                                     */
4330 /*                                                                         */
4331 /*      To maintin backward compatibility with existing client code must   */
4332 /*      build in the BUG that if value set format type is old-fashioned    */
4333 /*      date, time or date-time (D, T or t), then default to_date()        */
4334 /*      conversions are done.  This means non-validated Date-time values   */
4335 /*      cannot be inserted into the combinations table.                    */
4336 /* ----------------------------------------------------------------------- */
4337 
4338 PROCEDURE x_compare_clause(coltype     IN  VARCHAR2,
4339                            colname     IN  VARCHAR2,
4340                            char_val    IN  VARCHAR2,
4341                            v_component IN  BINARY_INTEGER,
4342                            vs_fmt      IN  VARCHAR2,
4343                            vs_len      IN  NUMBER)
4344   IS
4345      datefmt VARCHAR2(30);
4346 BEGIN
4347    IF (coltype = 'N') THEN
4348       fnd_dsql.add_bind(fnd_number.canonical_to_number(char_val));
4349     ELSIF (coltype = 'D') then
4350       IF (vs_fmt in ('X', 'Y', 'Z', 'D', 'T', 'I', 't')) then
4351          datefmt := stored_date_format(vs_fmt, vs_len);
4352          fnd_dsql.add_bind(To_date(char_val, datefmt));
4353        ELSE
4354          fnd_dsql.add_bind(char_val);
4355       end if;
4356     else
4357       fnd_dsql.add_bind(char_val);
4358    end if;
4359 
4360 END x_compare_clause;
4361 
4362 /* ----------------------------------------------------------------------- */
4363 /*      Creates a SQL clause for binding a character string.               */
4364 /*      Replaces single quotes with double quotes and surrounds the        */
4365 /*      string with quotes.                                                */
4366 /* ----------------------------------------------------------------------- */
4367 
4368 FUNCTION string_clause(char_string IN VARCHAR2) RETURN VARCHAR2 IS
4369 BEGIN
4370   return('''' || REPLACE(char_string, '''', '''''') || '''');
4371 END string_clause;
4372 
4373 -- /* ----------------------------------------------------------------------- */
4374 -- /*      MADE NULL TO MAKE MORE ROOM FOR USEFUL CODE.                       */
4375 -- /*      Breaks concatenated segments in rule lines table into separate     */
4376 -- /*      columns for each segment.  Returns number of segments or < 0       */
4377 -- /*      and sets FND_MESSAGE if error.  This is called only from trigger   */
4378 -- /*      FND_FLEX_VALIDATION_RULE_LINES_T1.  The trigger should use         */
4379 -- /*      FND_MESSAGE.raise_exception if this function returns error.        */
4380 -- /* ----------------------------------------------------------------------- */
4381 --   FUNCTION breakup_segs(appid IN NUMBER,
4382 --                 flex_code IN VARCHAR2, flex_num IN NUMBER,
4383 --                 catsegs IN VARCHAR2, nsegs OUT NUMBER,
4384 --                 seg1  OUT VARCHAR2, seg2  OUT VARCHAR2,
4385 --                 seg3  OUT VARCHAR2, seg4  OUT VARCHAR2,
4386 --                 seg5  OUT VARCHAR2, seg6  OUT VARCHAR2,
4387 --                 seg7  OUT VARCHAR2, seg8  OUT VARCHAR2,
4388 --                 seg9  OUT VARCHAR2, seg10 OUT VARCHAR2,
4389 --                 seg11 OUT VARCHAR2, seg12 OUT VARCHAR2,
4390 --                 seg13 OUT VARCHAR2, seg14 OUT VARCHAR2,
4391 --                 seg15 OUT VARCHAR2, seg16 OUT VARCHAR2,
4392 --                 seg17 OUT VARCHAR2, seg18 OUT VARCHAR2,
4393 --                 seg19 OUT VARCHAR2, seg20 OUT VARCHAR2,
4394 --                 seg21 OUT VARCHAR2, seg22 OUT VARCHAR2,
4395 --                 seg23 OUT VARCHAR2, seg24 OUT VARCHAR2,
4396 --                 seg25 OUT VARCHAR2, seg26 OUT VARCHAR2,
4397 --                 seg27 OUT VARCHAR2, seg28 OUT VARCHAR2,
4398 --                 seg29 OUT VARCHAR2, seg30 OUT VARCHAR2) RETURN NUMBER IS
4399 --
4400 --     n_segs      NUMBER;
4401 --     sg          StringArray;
4402 --     sepchar     VARCHAR2(1);
4403 --
4404 --   BEGIN
4405 --     return(-1);
4406 --
4407 --   EXCEPTION
4408 --     WHEN OTHERS then
4409 --       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
4410 --       FND_MESSAGE.set_token('MSG', 'breakup_segs() exception: ' || SQLERRM);
4411 --       return(-2);
4412 --
4413 --   END breakup_segs;
4414 
4415 /* ----------------------------------------------------------------------- */
4416 /*      Executes a dynamic SQL statement.                                  */
4417 /*      Returns number of rows processed or -1 if error (add_message)      */
4418 /* ----------------------------------------------------------------------- */
4419 FUNCTION x_dsql_execute RETURN NUMBER IS
4420 
4421 cursornum     INTEGER;
4422 nprocessed    INTEGER;
4423 sql_statement    VARCHAR2(32000);
4424 
4425 BEGIN
4426 
4427 --  Copy SQL string to array for debugging purposes
4428 --
4429   add_sql_string(fnd_dsql.get_text(p_with_debug => TRUE));
4430 
4431   cursornum := dbms_sql.open_cursor;
4432   fnd_dsql.set_cursor(cursornum);
4433 
4434   sql_statement := fnd_dsql.get_text(p_with_debug => FALSE);
4435   dbms_sql.parse(cursornum, sql_statement, dbms_sql.v7);
4436 
4437   fnd_dsql.do_binds;
4438 
4439   nprocessed := dbms_sql.execute(cursornum);
4440   IF (fnd_flex_server1.g_debug_level > 0) THEN
4441      add_debug('(DSQL_execute processed ' || to_char(nprocessed));
4442      add_debug(' rows.)');
4443   END IF;
4444   dbms_sql.close_cursor(cursornum);
4445   return(nprocessed);
4446 
4447 EXCEPTION
4448   WHEN OTHERS then
4449     if(dbms_sql.is_open(cursornum)) then
4450       dbms_sql.close_cursor(cursornum);
4451     end if;
4452     FND_MESSAGE.set_name('FND', 'FLEX-DSQL EXCEPTION');
4453     FND_MESSAGE.set_token('MSG', SQLERRM);
4454     FND_MESSAGE.set_token('SQLSTR', SUBSTRB(sql_statement, 1, 1000));
4455     return(-1);
4456 
4457 END x_dsql_execute;
4458 
4459 /* ----------------------------------------------------------------------- */
4460 /*      Uses dynamic SQL to select up to one varchar2 valued column from   */
4461 /*      a table using the select statement passed in.  Returns 0, NULL     */
4462 /*      if no rows found, or 1 and the column value if 1 row found, or     */
4463 /*      2 and the column value of the first row found if more than 1 row   */
4464 /*      matches selection criteria, or < 0 if other errors.                */
4465 /*      Invalid rowid exception mapped back to no data found.              */
4466 /* ----------------------------------------------------------------------- */
4467 FUNCTION x_dsql_select_one(returned_column OUT nocopy VARCHAR2) RETURN NUMBER IS
4468 cursornum     INTEGER;
4469 num_returned  INTEGER;
4470 selected_col  VARCHAR2(2000);
4471 invalid_rowid EXCEPTION;
4472 sql_statement    VARCHAR2(32000);
4473 
4474 PRAGMA EXCEPTION_INIT(invalid_rowid, -1410);
4475 
4476 BEGIN
4477 
4478 --  Copy SQL string to array for debugging purposes
4479 --
4480   add_sql_string(fnd_dsql.get_text(p_with_debug => TRUE));
4481 
4482   selected_col := NULL;
4483   cursornum := dbms_sql.open_cursor;
4484   fnd_dsql.set_cursor(cursornum);
4485 
4486   sql_statement := fnd_dsql.get_text(p_with_debug => FALSE);
4487   dbms_sql.parse(cursornum, sql_statement, dbms_sql.v7);
4488 
4489   fnd_dsql.do_binds;
4490 
4491   dbms_sql.define_column(cursornum, 1, selected_col, 2000);
4492   num_returned := dbms_sql.execute_and_fetch(cursornum, TRUE);
4493   if(num_returned = 1) then
4494     dbms_sql.column_value(cursornum, 1, selected_col);
4495     returned_column := selected_col;
4496     IF (fnd_flex_server1.g_debug_level > 0) THEN
4497        add_debug('(DSQL returned ' || selected_col || ')');
4498     END IF;
4499   else
4500     num_returned := -1;
4501     returned_column := NULL;
4502     FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
4503     FND_MESSAGE.set_token('MSG', 'x_dsql_select_one() could not fetch rows');
4504   end if;
4505 dbms_sql.close_cursor(cursornum);
4506 return(num_returned);
4507 
4508 EXCEPTION
4509   WHEN NO_DATA_FOUND or invalid_rowid then
4510     returned_column := NULL;
4511     IF (fnd_flex_server1.g_debug_level > 0) THEN
4512        add_debug('(DSQL returned: NULL)');
4513     END IF;
4514     dbms_sql.close_cursor(cursornum);
4515     return(0);
4516   WHEN TOO_MANY_ROWS then
4517     dbms_sql.column_value(cursornum, 1, selected_col);
4518     returned_column := selected_col;
4519     IF (fnd_flex_server1.g_debug_level > 0) THEN
4520        add_debug('(DSQL returned: TOO MANY ROWS)');
4521     END IF;
4522     dbms_sql.close_cursor(cursornum);
4523     return(2);
4524   WHEN OTHERS then
4525     if(dbms_sql.is_open(cursornum)) then
4526       dbms_sql.close_cursor(cursornum);
4527     end if;
4528     FND_MESSAGE.set_name('FND', 'FLEX-DSQL EXCEPTION');
4529     FND_MESSAGE.set_token('MSG', SQLERRM);
4530     FND_MESSAGE.set_token('SQLSTR', SUBSTRB(sql_statement, 1, 1000));
4531     return(-2);
4532 
4533 END x_dsql_select_one;
4534 
4535 /* ----------------------------------------------------------------------- */
4536 /*      Uses dynamic SQL to select n_selected_cols of VARCHAR2 type from   */
4537 /*      a table using the select statement passed in.  Returns number      */
4538 /*      of rows found, or sets error and returns < 0 if error.             */
4539 /*      Invalid rowid exception mapped back to no data found.              */
4540 /* ----------------------------------------------------------------------- */
4541 FUNCTION x_dsql_select(n_selected_cols  IN  NUMBER,
4542                        returned_columns OUT nocopy StringArray) RETURN NUMBER
4543   IS
4544      cursornum        INTEGER;
4545      num_returned     INTEGER;
4546      selected_cols    StringArray;
4547      invalid_rowid    EXCEPTION;
4548      sql_statement    VARCHAR2(32000);
4549 
4550      PRAGMA EXCEPTION_INIT(invalid_rowid, -1410);
4551 BEGIN
4552 
4553    --  Copy SQL string to array for debugging purposes
4554    --
4555    add_sql_string(fnd_dsql.get_text(p_with_debug => TRUE));
4556 
4557    cursornum := dbms_sql.open_cursor;
4558    fnd_dsql.set_cursor(cursornum);
4559 
4560    sql_statement := fnd_dsql.get_text(p_with_debug => FALSE);
4561    dbms_sql.parse(cursornum, sql_statement, dbms_sql.v7);
4562 
4563    fnd_dsql.do_binds;
4564 
4565    for i in 1..n_selected_cols loop
4566       --    The following prevents NO-DATA-FOUND exception...
4567       selected_cols(i) := NULL;
4568       dbms_sql.define_column(cursornum, i, selected_cols(i), 2000);
4569    end loop;
4570    num_returned := dbms_sql.execute_and_fetch(cursornum, TRUE);
4571    if(num_returned = 1) then
4572       IF (fnd_flex_server1.g_debug_level > 0) THEN
4573          add_debug('(DSQL returned');
4574       END IF;
4575       for i in 1..n_selected_cols loop
4576          dbms_sql.column_value(cursornum, i, selected_cols(i));
4577          IF (fnd_flex_server1.g_debug_level > 0) THEN
4578             add_debug(' ''' || selected_cols(i) || '''');
4579          END IF;
4580       end loop;
4581       IF (fnd_flex_server1.g_debug_level > 0) THEN
4582          add_debug(')');
4583       END IF;
4584     else
4585       num_returned := -1;
4586       FND_MESSAGE.set_name('FND', 'FLEX-SSV EXCEPTION');
4587       FND_MESSAGE.set_token('MSG', 'x_dsql_select() could not fetch rows');
4588    end if;
4589    dbms_sql.close_cursor(cursornum);
4590    returned_columns := selected_cols;
4591    return(num_returned);
4592 
4593 EXCEPTION
4594   WHEN NO_DATA_FOUND OR invalid_rowid then
4595      IF (fnd_flex_server1.g_debug_level > 0) THEN
4596         add_debug('(DSQL returned: NULL)');
4597      END IF;
4598     dbms_sql.close_cursor(cursornum);
4599     return(0);
4600   WHEN TOO_MANY_ROWS then
4601      IF (fnd_flex_server1.g_debug_level > 0) THEN
4602         add_debug('(DSQL returned');
4603      END IF;
4604     for i in 1..n_selected_cols loop
4605       dbms_sql.column_value(cursornum, i, selected_cols(i));
4606       IF (fnd_flex_server1.g_debug_level > 0) THEN
4607          add_debug(' ''' || selected_cols(i) || '''');
4608       END IF;
4609     end loop;
4610     IF (fnd_flex_server1.g_debug_level > 0) THEN
4611        add_debug(')');
4612        add_debug('(DSQL returned: TOO MANY ROWS)');
4613     END IF;
4614     dbms_sql.close_cursor(cursornum);
4615     returned_columns := selected_cols;
4616     return(2);
4617   WHEN OTHERS then
4618     if(dbms_sql.is_open(cursornum)) then
4619       dbms_sql.close_cursor(cursornum);
4620     end if;
4621     FND_MESSAGE.set_name('FND', 'FLEX-DSQL EXCEPTION');
4622     FND_MESSAGE.set_token('MSG', SQLERRM);
4623     FND_MESSAGE.set_token('SQLSTR', SUBSTRB(sql_statement, 1, 1000));
4624     return(-2);
4625 
4626 END x_dsql_select;
4627 
4628 /* ----------------------------------------------------------------------- */
4629 /*      Adds string to array of dynamic sql strings.                       */
4630 /*      The buffer is zeroed when init_globals is called.                  */
4631 /* ----------------------------------------------------------------------- */
4632 PROCEDURE add_sql_string(sql_statement IN VARCHAR2) IS
4633 BEGIN
4634   n_sqlstrings := n_sqlstrings + 1;
4635   sqlstrings(n_sqlstrings) := sql_statement;
4636 END add_sql_string;
4637 
4638 /* ----------------------------------------------------------------------- */
4639 /*      For debugging.                                                     */
4640 /*      Returns number of SQL statements created during last call          */
4641 /*      to validate().  Use in conjunction with get_sql().                 */
4642 /* ----------------------------------------------------------------------- */
4643 FUNCTION get_nsql_internal RETURN NUMBER IS
4644 BEGIN
4645   return(nvl(to_number(n_sqlstrings), 0));
4646 END get_nsql_internal;
4647 
4648 /* ----------------------------------------------------------------------- */
4649 /*      For debugging.                                                     */
4650 /*      Returns SQL statements created during last call                    */
4651 /*      to validate().  Use in conjunction with get_sql().                 */
4652 /* ----------------------------------------------------------------------- */
4653 FUNCTION get_sql_internal(statement_number IN NUMBER,
4654                  statement_portion IN NUMBER DEFAULT 1) RETURN VARCHAR2 IS
4655 
4656   dsql_start  NUMBER;
4657 
4658 BEGIN
4659 
4660   if((statement_number is null) or (statement_number < 1) or
4661      (statement_number > nvl(to_number(n_sqlstrings), 0)) or
4662      (statement_portion is null) or (statement_portion < 1) or
4663      (sqlstrings(statement_number) is null)) then
4664      return(NULL);
4665   end if;
4666 
4667   dsql_start := 1 + ((statement_portion - 1) * MAX_RETSTR_LEN);
4668   if(dsql_start > LENGTH(sqlstrings(statement_number))) then
4669     return(NULL);
4670   end if;
4671 
4672   return(SUBSTR(sqlstrings(statement_number), dsql_start, MAX_RETSTR_LEN));
4673 
4674   EXCEPTION
4675   WHEN NO_DATA_FOUND then
4676       return('get_sql_internal('||to_char(statement_number)||') statement not found');
4677   WHEN OTHERS then
4678       return('get_sql_internal() exception: ' || SQLERRM);
4679 
4680 END get_sql_internal;
4681 
4682 /* ----------------------------------------------------------------------- */
4683 /*                      Adds to debug string                               */
4684 /* ----------------------------------------------------------------------- */
4685 PROCEDURE set_debugging(p_debug_mode IN VARCHAR2)
4686   IS
4687 BEGIN
4688    IF (p_debug_mode = 'OFF') THEN
4689       fnd_flex_server1.g_debug_level := 0;
4690     ELSIF (p_debug_mode = 'ERROR') THEN
4691       fnd_flex_server1.g_debug_level := 1;
4692     ELSIF (p_debug_mode = 'EXCEPTION') THEN
4693       fnd_flex_server1.g_debug_level := 2;
4694     ELSIF (p_debug_mode = 'EVENT') THEN
4695       fnd_flex_server1.g_debug_level := 3;
4696     ELSIF (p_debug_mode = 'PROCEDURE') THEN
4697       fnd_flex_server1.g_debug_level := 4;
4698     ELSIF (p_debug_mode = 'STATEMENT') THEN
4699       fnd_flex_server1.g_debug_level := 5;
4700     ELSIF (p_debug_mode = 'ALL') THEN
4701       fnd_flex_server1.g_debug_level := 6;
4702       fnd_flex_val_util.set_debugging(TRUE);
4703     ELSE
4704       fnd_flex_server1.g_debug_level := 0;
4705    END IF;
4706 EXCEPTION
4707    WHEN OTHERS THEN
4708       fnd_flex_server1.g_debug_level := 0;
4709 END set_debugging;
4710 
4711 /* ----------------------------------------------------------------------- */
4712 /*                      Adds to debug string                               */
4713 /* ----------------------------------------------------------------------- */
4714 PROCEDURE add_debug(p_debug_string IN VARCHAR2,
4715                     p_debug_mode   IN VARCHAR2 DEFAULT 'STATEMENT')
4716   IS
4717      l_code_level NUMBER;
4718      l_debug_string VARCHAR2(32000);
4719      l_newline_pos  NUMBER;
4720      l_debug_line   VARCHAR2(32000);
4721 BEGIN
4722    IF (fnd_flex_server1.g_debug_level = 0) THEN
4723       RETURN;
4724    END IF;
4725    IF (p_debug_mode = 'OFF') THEN
4726       l_code_level := 0;
4727     ELSIF (p_debug_mode = 'ERROR') THEN
4728       l_code_level := 1;
4729     ELSIF (p_debug_mode = 'EXCEPTION') THEN
4730       l_code_level := 2;
4731     ELSIF (p_debug_mode = 'EVENT') THEN
4732       l_code_level := 3;
4733     ELSIF (p_debug_mode = 'PROCEDURE') THEN
4734       l_code_level := 4;
4735     ELSIF (p_debug_mode = 'STATEMENT') THEN
4736       l_code_level := 5;
4737     ELSIF (p_debug_mode = 'ALL') THEN
4738       l_code_level := 6;
4739     ELSE
4740       l_code_level := 0;
4741    END IF;
4742 
4743    IF (l_code_level <= fnd_flex_server1.g_debug_level) THEN
4744       IF (g_debug_array_size = 0) THEN
4745          g_debug_array_size := 1;
4746          g_debug_array(g_debug_array_size) :=
4747            ('DEBUG LEVEL:'||To_char(fnd_flex_server1.g_debug_level) ||
4748             chr_newline);
4749       END IF;
4750 
4751       l_debug_string := (Substr(Rtrim(Ltrim(p_debug_string)), 1, MAX_RETSTR_LEN-10) ||
4752                          chr_newline);
4753 
4754       WHILE (l_debug_string IS NOT NULL) LOOP
4755          l_newline_pos := Instr(l_debug_string, chr_newline, 1, 1);
4756          IF (l_newline_pos +
4757              Nvl(Length(g_debug_array(g_debug_array_size)), 0) < MAX_RETSTR_LEN) THEN
4758             l_debug_line := Substr(l_debug_string, 1, l_newline_pos);
4759             l_debug_string := Substr(l_debug_string, l_newline_pos + 1);
4760             IF (l_debug_line LIKE 'BEGIN %' OR
4761                 l_debug_line LIKE 'END %' OR
4762                 l_debug_line LIKE 'CALL %' OR
4763                 l_debug_line LIKE 'EXCEPTION %') THEN
4764                g_debug_array(g_debug_array_size) :=
4765                  g_debug_array(g_debug_array_size) || l_debug_line;
4766              ELSE
4767                g_debug_array(g_debug_array_size) :=
4768                  g_debug_array(g_debug_array_size) || ' ' || l_debug_line;
4769             END IF;
4770           ELSE
4771             g_debug_array_size := g_debug_array_size + 1;
4772             g_debug_array(g_debug_array_size) := NULL;
4773          END IF;
4774       END LOOP;
4775    END IF;
4776 EXCEPTION
4777    WHEN OTHERS THEN
4778       NULL;
4779 END add_debug;
4780 
4781 /* ----------------------------------------------------------------------- */
4782 /*      Returns the debug string.                                          */
4783 /* ----------------------------------------------------------------------- */
4784 FUNCTION get_debug_internal(string_n IN NUMBER) RETURN VARCHAR2 IS
4785 BEGIN
4786    IF ((string_n is not null) and
4787        (string_n >= 1) AND
4788        (string_n) <= g_debug_array_size) THEN
4789       RETURN(g_debug_array(string_n));
4790    end if;
4791    return(NULL);
4792 
4793 EXCEPTION
4794    WHEN OTHERS then
4795       return('get_debug_internal() exception: ' || SQLERRM);
4796 END get_debug_internal;
4797 
4798 /* -------------------------------------------------- */
4799 /* New client side debug functions                    */
4800 /* -------------------------------------------------- */
4801 PROCEDURE x_get_nsql(x_nsql OUT nocopy NUMBER)
4802   IS
4803 BEGIN
4804    x_nsql := fnd_flex_server1.get_nsql_internal;
4805 EXCEPTION
4806    WHEN OTHERS THEN
4807       x_nsql := 0;
4808 END;
4809 
4810 PROCEDURE x_get_sql_npiece(p_sql_num IN NUMBER,
4811                            x_npiece  OUT nocopy NUMBER)
4812   IS
4813      l_sql_num NUMBER;
4814 BEGIN
4815    l_sql_num := Nvl(p_sql_num, 0);
4816    x_npiece := 0;
4817    IF ((l_sql_num > 0) AND
4818        (l_sql_num <= fnd_flex_server1.get_nsql_internal)) THEN
4819       x_npiece :=Ceil(Nvl(Lengthb(sqlstrings(l_sql_num)),0)/MAX_RETSTR_LEN);
4820    END IF;
4821 EXCEPTION
4822    WHEN OTHERS THEN
4823       x_npiece := 0;
4824 END;
4825 
4826 PROCEDURE x_get_sql_piece(p_sql_num   IN NUMBER,
4827                           p_piece_num IN NUMBER,
4828                           x_sql_piece OUT nocopy VARCHAR2)
4829   IS
4830      l_sql_num NUMBER;
4831      l_piece_num NUMBER;
4832 BEGIN
4833    l_sql_num := Nvl(p_sql_num, 0);
4834    l_piece_num := Nvl(p_piece_num, 0);
4835    x_sql_piece := NULL;
4836    IF ((l_sql_num > 0) AND
4837        (l_sql_num <= fnd_flex_server1.get_nsql_internal) AND
4838        (l_piece_num > 0)) THEN
4839       x_sql_piece := substrb(sqlstrings(l_sql_num),
4840                              1 + (l_piece_num - 1) * MAX_RETSTR_LEN,
4841                              MAX_RETSTR_LEN);
4842    END IF;
4843 EXCEPTION
4844    WHEN OTHERS THEN
4845       x_sql_piece := substrb('EXCEPTION:' || Sqlerrm,1,MAX_RETSTR_LEN);
4846 END;
4847 
4848 PROCEDURE x_get_ndebug(x_ndebug OUT nocopy NUMBER)
4849   IS
4850 BEGIN
4851    x_ndebug := g_debug_array_size;
4852 EXCEPTION
4853    WHEN OTHERS THEN
4854       x_ndebug := 0;
4855 END;
4856 
4857 PROCEDURE x_get_debug(p_debug_num IN NUMBER,
4858                       x_debug OUT nocopy VARCHAR2)
4859   IS
4860      l_debug_num NUMBER;
4861 BEGIN
4862    l_debug_num := Nvl(p_debug_num, 0);
4863    IF (l_debug_num >= 1 AND
4864        l_debug_num <= g_debug_array_size) THEN
4865       x_debug := g_debug_array(l_debug_num);
4866     ELSE
4867       x_debug := 'INDEX OUT OF RANGE [1..' || g_debug_array_size || '].';
4868    END IF;
4869 EXCEPTION
4870    WHEN OTHERS THEN
4871       x_debug := substrb('EXCEPTION:' || Sqlerrm,1,MAX_RETSTR_LEN);
4872 END;
4873 
4874 /* ----------------------------------------------------------------------- */
4875 /*               Converts concatenated segments to segment array           */
4876 /*      Segment array is 1-based containing entries for 1 <= i <= nsegs    */
4877 /* ----------------------------------------------------------------------- */
4878 FUNCTION to_stringarray(catsegs IN  VARCHAR2,
4879                         sepchar in  VARCHAR2,
4880                         segs    OUT nocopy StringArray)
4881   RETURN NUMBER
4882   IS
4883      l_wc         VARCHAR2(10);
4884      l_flex_value VARCHAR2(2000);
4885      i            NUMBER;
4886      l_segnum     PLS_INTEGER;
4887      l_delimiter  VARCHAR2(10);
4888      l_tmp_str    VARCHAR2(32000);
4889      l_delim_pos  PLS_INTEGER;
4890      l_old_delim_pos  PLS_INTEGER;
4891 BEGIN
4892    l_delimiter := Substr(sepchar, 1, 1);
4893 
4894    --
4895    -- Make sure delimiter is valid.
4896    --
4897    IF ((l_delimiter IS NULL) OR (l_delimiter = FLEX_DELIMITER_ESCAPE)) THEN
4898       raise_application_error(-20001,
4899                               'SV2.to_stringarray. Invalid delimiter:''' ||
4900                               Nvl(sepchar, '<NULL>') || '''');
4901    END IF;
4902 
4903    --
4904    -- If catsegs is NULL then assume there is only one segment.
4905    --
4906    IF (catsegs IS NULL) THEN
4907       l_segnum := 1;
4908       segs(1) := catsegs;
4909       GOTO return_success;
4910    END IF;
4911 
4912    l_segnum := 0;
4913    i := 1;
4914 
4915    -- We need to go through un-escaping logic only if
4916    -- there is an ESCAPE character in the string.
4917    -- Bug 4501279.
4918 
4919    IF (instr(catsegs, FLEX_DELIMITER_ESCAPE) > 0) THEN
4920 
4921       --
4922       -- Loop for each segment.
4923       --
4924       LOOP
4925          l_flex_value := NULL;
4926 
4927          --
4928          -- Un-escaping loop.
4929          --
4930          LOOP
4931 
4932             l_wc := Substr(catsegs, i, 1);
4933             i := i + 1;
4934 
4935             IF (l_wc IS NULL) THEN
4936                EXIT;
4937             ELSIF (l_wc = l_delimiter) THEN
4938                EXIT;
4939             ELSIF (l_wc = FLEX_DELIMITER_ESCAPE) THEN
4940 
4941                l_wc := Substr(catsegs, i, 1);
4942                i := i + 1;
4943 
4944                IF (l_wc IS NULL) THEN
4945                   EXIT;
4946                END IF;
4947 
4948             END IF;
4949 
4950             l_flex_value := l_flex_value || l_wc;
4951 
4952          END LOOP;
4953 
4954          l_segnum := l_segnum + 1;
4955          segs(l_segnum) := l_flex_value;
4956          IF (l_wc IS NULL) THEN
4957             EXIT;
4958          END IF;
4959       END LOOP;
4960 
4961    ELSE
4962 
4963       -- No un-escaping logic required here.
4964 
4965       l_tmp_str := catsegs;
4966       l_delim_pos := 0;
4967       l_old_delim_pos := 0;
4968 
4969       LOOP
4970 
4971          l_delim_pos := instr(l_tmp_str, l_delimiter, l_delim_pos+1);
4972 
4973          IF (l_delim_pos <> 0) THEN
4974             l_segnum := l_segnum + 1;
4975             segs(l_segnum) := substr(l_tmp_str, l_old_delim_pos+1, l_delim_pos-l_old_delim_pos-1);
4976             l_old_delim_pos := l_delim_pos;
4977          ELSE
4978             l_segnum := l_segnum + 1;
4979             segs(l_segnum) := substr(l_tmp_str, l_old_delim_pos+1);
4980             EXIT;
4981          END IF;
4982 
4983       END LOOP;
4984 
4985    END IF;
4986 
4987    <<return_success>>
4988      RETURN(l_segnum);
4989 
4990 EXCEPTION
4991    WHEN OTHERS THEN
4992       raise_application_error(-20001, 'SV2.to_stringarray. SQLERRM : ' ||
4993                               Sqlerrm);
4994 END to_stringarray;
4995 
4996 /* ----------------------------------------------------------------------- */
4997 /*               Converts segment array to concatenated segments           */
4998 /*      Segment array is 1-based containing entries for 1 <= i <= nsegs    */
4999 /* ----------------------------------------------------------------------- */
5000 FUNCTION from_stringarray(nsegs   IN NUMBER,
5001                           segs    IN StringArray,
5002                           sepchar IN VARCHAR2) RETURN VARCHAR2
5003   IS
5004      l_wc          VARCHAR2(10);
5005      l_return      VARCHAR2(32000) := NULL;
5006      i             pls_integer;
5007      l_segnum      pls_integer;
5008      l_delimiter   VARCHAR2(10);
5009 BEGIN
5010    l_delimiter := Substr(sepchar, 1, 1);
5011    IF (fnd_flex_server1.g_debug_level > 0) THEN
5012       fnd_flex_server1.add_debug('BEGIN SV1.from_stringarray()');
5013    END IF;
5014    --
5015    -- Make sure delimiter is valid.
5016    --
5017    IF ((l_delimiter IS NULL) OR (l_delimiter = FLEX_DELIMITER_ESCAPE)) THEN
5018       raise_application_error(-20001,
5019                               'SV1.from_stringarray. Invalid delimiter:''' ||
5020                               Nvl(sepchar, '<NULL>') || '''');
5021    END IF;
5022 
5023    --
5024    -- Make sure array size is valid.
5025    --
5026    IF ((nsegs IS NULL) OR (nsegs < 1)) THEN
5027       raise_application_error(-20001,
5028                               'SV1.from_stringarray. For specified context there are ''' ||
5029                               Nvl(to_char(nsegs), '<NULL>') || '''' || ' displayed segments');
5030    END IF;
5031 
5032    --
5033    -- If only one segment then no need for concatenating or escaping.
5034    --
5035    IF (nsegs = 1) THEN
5036       l_return := segs(1);
5037       GOTO return_success;
5038    END IF;
5039 
5040    --
5041    -- Loop for each segment
5042    --
5043    FOR l_segnum IN 1..nsegs LOOP
5044 
5045       i := 1;
5046 
5047       --
5048       -- Escaping loop.
5049       --
5050       LOOP
5051 
5052          l_wc := Substr(segs(l_segnum), i, 1);
5053          i := i + 1;
5054 
5055          IF (l_wc IS NULL) THEN
5056             EXIT;
5057           ELSIF (l_wc = FLEX_DELIMITER_ESCAPE) THEN
5058             l_return := l_return || FLEX_DELIMITER_ESCAPE;
5059             l_return := l_return || FLEX_DELIMITER_ESCAPE;
5060           ELSIF (l_wc = l_delimiter) THEN
5061             l_return := l_return || FLEX_DELIMITER_ESCAPE;
5062             l_return := l_return || l_delimiter;
5063           ELSE
5064             l_return := l_return || l_wc;
5065          END IF;
5066 
5067       END LOOP;
5068 
5069       --
5070       -- No delimiter after the last value.
5071       --
5072       IF (l_segnum < nsegs) THEN
5073          l_return := l_return || l_delimiter;
5074       END IF;
5075    END LOOP;
5076 
5077    <<return_success>>
5078      IF (fnd_flex_server1.g_debug_level > 0) THEN
5079         fnd_flex_server1.add_debug('END SV1.from_stringarray()');
5080      END IF;
5081      RETURN(l_return);
5082 EXCEPTION
5083    WHEN OTHERS THEN
5084       IF (fnd_flex_server1.g_debug_level > 0) THEN
5085          fnd_flex_server1.add_debug('EXCEPTION SV1.from_stringarray()');
5086       END IF;
5087       raise_application_error(-20001, 'SV1.from_stringarray. SQLERRM : ' || Sqlerrm);
5088 END from_stringarray;
5089 
5090 /* ----------------------------------------------------------------------- */
5091 /*               Converts concatenated segments to segment array           */
5092 /*      Segment array is 1-based containing entries for 1 <= i <= nsegs    */
5093 /*      Bug 1375146 added elsif statement to allow for only 1 segment      */
5094 /*                  which is null.                                         */
5095 /* ----------------------------------------------------------------------- */
5096 FUNCTION to_stringarray2(catsegs IN  VARCHAR2,
5097                          sepchar in  VARCHAR2,
5098                          segs    OUT nocopy StringArray)
5099   RETURN NUMBER
5100   IS
5101      seg_start        NUMBER;
5102      seg_end          NUMBER;
5103      seg_len          NUMBER;
5104      catseg_len       NUMBER;
5105      sepchar_len      NUMBER;
5106      seg_index        BINARY_INTEGER;
5107      keep_going       BOOLEAN;
5108 BEGIN
5109    seg_index := 1;
5110    seg_start := 1;
5111    keep_going := TRUE;
5112    IF ((catsegs IS NOT NULL) AND (sepchar IS NOT NULL)) THEN
5113       catseg_len := LENGTH(catsegs);
5114       sepchar_len := LENGTH(sepchar);
5115       WHILE (keep_going = TRUE) LOOP
5116          IF (seg_start > catseg_len) THEN
5117             segs(seg_index) := NULL;
5118             keep_going := FALSE;
5119           ELSE
5120             seg_end := INSTR(catsegs, sepchar, seg_start);
5121             IF (seg_end = 0) THEN
5122                seg_end := catseg_len + 1;
5123                keep_going := FALSE;
5124             END IF;
5125             seg_len := seg_end - seg_start;
5126             IF (seg_len = 0) THEN
5127                segs(seg_index) := NULL;
5128              ELSE
5129                segs(seg_index) := REPLACE(SUBSTR(catsegs, seg_start, seg_len),
5130                                           NEWLINE, sepchar);
5131             END IF;
5132          END IF;
5133          seg_index := seg_index + 1;
5134          seg_start := seg_end + sepchar_len;
5135       END LOOP;
5136     ELSIF ((catsegs IS NULL) AND (sepchar IS NULL)) THEN
5137       seg_index :=1;
5138     ELSIF ((catsegs IS NULL) AND (sepchar IS NOT NULL)) THEN
5139       segs(1) := NULL;
5140       seg_index := 2;
5141     ELSIF ((catsegs IS NOT NULL) AND (sepchar IS NULL)) THEN
5142       seg_index := 1;
5143    END IF;
5144    RETURN(To_number(seg_index - 1));
5145 END to_stringarray2;
5146 
5147 /* ----------------------------------------------------------------------- */
5148 /*               Converts segment array to concatenated segments           */
5149 /*      Segment array is 1-based containing entries for 1 <= i <= nsegs    */
5150 /* ----------------------------------------------------------------------- */
5151 FUNCTION from_stringarray2(nsegs   IN NUMBER,
5152                            segs    IN StringArray,
5153                            sepchar IN VARCHAR2) RETURN VARCHAR2
5154   IS
5155      l_return VARCHAR2(2000) := NULL;
5156 BEGIN
5157    IF (fnd_flex_server1.g_debug_level > 0) THEN
5158       fnd_flex_server1.add_debug('CALL SV1.from_stringarray2()');
5159    END IF;
5160    --
5161    -- Concatenate the segment values. No separator after the last value.
5162    --
5163    IF (nsegs > 0) THEN
5164       FOR i IN 1..(nsegs-1) LOOP
5165          l_return := l_return || REPLACE(segs(i), sepchar, NEWLINE) || sepchar;
5166       END LOOP;
5167       l_return := l_return || REPLACE(segs(nsegs), sepchar, NEWLINE);
5168    END IF;
5169    RETURN(l_return);
5170 END from_stringarray2;
5171 
5172 
5173 --------------------------------------------------------------------------------
5174 -- This procedure parses a SQL string into following pieces:
5175 --   - bind               (i.e. :bind portion of a SQL statement)
5176 --   - single quoted      (i.e. string literal portion of a SQL statement)
5177 --   - sql                (i.e. rest of the sql statement)
5178 --
5179 --------------------------------------------------------------------------------
5180 procedure parse_sql_string(p_sql_string  in varchar2,
5181                            px_sql_pieces in out nocopy sql_pieces_tab_type)
5182   IS
5183      l_sql_string      varchar2(32000);
5184      l_sql_piece_count BINARY_INTEGER;
5185      l_first_chr       varchar2(1);
5186      l_tmp_string      varchar2(32000);
5187 
5188      l_quote_pos       number;
5189      l_quote2_pos      number;
5190      l_colon_pos       number;
5191      l_end_pos         number;
5192 begin
5193    l_sql_string := p_sql_string;
5194    l_sql_piece_count := 0;
5195    px_sql_pieces.DELETE;
5196 
5197    while (l_sql_string is not null) loop
5198 
5199       l_first_chr := substr(l_sql_string, 1, 1);
5200 
5201       if (l_first_chr = SSP_QUOTE) then
5202          --
5203          -- single quoted section, find the end
5204          --
5205          l_quote2_pos := 0;
5206          loop
5207             --
5208             -- Skip double single quotes
5209             --
5210             l_quote_pos := instr(l_sql_string, SSP_QUOTE, l_quote2_pos + 2);
5211             if (l_quote_pos = 0) then
5212                --
5213                -- Error, not terminated properly
5214                --
5215                FND_MESSAGE.set_name('FND', 'FLEX-SQL MISSING QUOTE');
5216                FND_MESSAGE.set_token('CLAUSE', p_sql_string);
5217 
5218                raise_application_error
5219                  (-20001,
5220                   'Error: Single Quote is not terminated properly. ' ||
5221                   'SQL: ' || p_sql_string);
5222             else
5223                l_quote2_pos := instr(l_sql_string, SSP_QUOTE2, l_quote_pos);
5224                if (l_quote2_pos = l_quote_pos) then
5225                   --
5226                   -- double single quote, skip it
5227                   --
5228                   null;
5229                else
5230                   --
5231                   -- end of single quoted section
5232                   --
5233                   exit;
5234                end if;
5235             end if;
5236          end loop;
5237 
5238          l_sql_piece_count := l_sql_piece_count + 1;
5239          px_sql_pieces(l_sql_piece_count).piece_type := SSP_PIECE_TYPE_QUOTED;
5240          px_sql_pieces(l_sql_piece_count).piece_text := substr(l_sql_string, 1, l_quote_pos);
5241 
5242          l_sql_string := substr(l_sql_string, l_quote_pos + 1);
5243 
5244       elsif (l_first_chr = SSP_COLON) then
5245          --
5246          -- bind section
5247          --
5248          l_tmp_string := ltrim(l_sql_string, SSP_BIND_CHARS);
5249 
5250          l_sql_piece_count := l_sql_piece_count + 1;
5251          px_sql_pieces(l_sql_piece_count).piece_type := SSP_PIECE_TYPE_BIND;
5252          px_sql_pieces(l_sql_piece_count).piece_text := substr(l_sql_string, 1, length(l_sql_string) - nvl(length(l_tmp_string), 0));
5253 
5254          l_sql_string := l_tmp_string;
5255 
5256       else
5257          --
5258          -- sql section, find the end
5259          --
5260          l_quote_pos := instr(l_sql_string, SSP_QUOTE);
5261          l_colon_pos := instr(l_sql_string, SSP_COLON);
5262 
5263          if ((l_quote_pos = 0) and (l_colon_pos = 0)) then
5264             --
5265             -- no quotes, no binds, the remaining section is just sql
5266             --
5267             l_end_pos := length(l_sql_string);
5268 
5269          elsif (l_quote_pos = 0) then
5270             --
5271             -- no quotes
5272             --
5273             l_end_pos := l_colon_pos - 1;
5274 
5275          elsif (l_colon_pos = 0) then
5276             --
5277             -- no binds
5278             --
5279             l_end_pos := l_quote_pos - 1;
5280 
5281          else
5282             --
5283             -- both quotes, and binds
5284             --
5285             l_end_pos := least(l_quote_pos, l_colon_pos) - 1;
5286 
5287          end if;
5288 
5289          l_sql_piece_count := l_sql_piece_count + 1;
5290          px_sql_pieces(l_sql_piece_count).piece_type := SSP_PIECE_TYPE_SQL;
5291          px_sql_pieces(l_sql_piece_count).piece_text := substr(l_sql_string, 1, l_end_pos);
5292 
5293          l_sql_string := substr(l_sql_string, l_end_pos + 1);
5294 
5295       end if;
5296    end loop;
5297 end parse_sql_string;
5298 
5299 BEGIN
5300    chr_newline := fnd_global.newline;
5301    NEWLINE     := fnd_global.newline;
5302    TAB         := fnd_global.tab;
5303    WHITESPACE  := ' ' || TAB || NEWLINE;
5304 
5305    fnd_plsql_cache.generic_1to1_init('SV1.VST',
5306                                      vst_cache_controller,
5307                                      vst_cache_storage);
5308 
5309    fnd_plsql_cache.generic_1to1_init('SV1.VSC',
5310                                      vsc_cache_controller,
5311                                      vsc_cache_storage);
5312 
5313    fnd_plsql_cache.generic_1to1_init('SV1.FVC',
5314                                      fvc_cache_controller,
5315                                      fvc_cache_storage);
5316 
5317    fnd_plsql_cache.generic_1tom_init('SV1.FSQ',
5318                                      fsq_cache_controller,
5319                                      fsq_cache_storage);
5320 
5321    fnd_plsql_cache.generic_1tom_init('SV1.VSQ',
5322                                      vsq_cache_controller,
5323                                      vsq_cache_storage);
5324 
5325    fnd_plsql_cache.custom_1tom_init('SV1.STR',
5326                                     str_cache_controller);
5327    str_cache_storage.DELETE;
5328 
5329    --
5330    -- Decimal separators.
5331    --
5332    IF (fnd_flex_val_util.get_mask('CANONICAL_NUMERIC_CHARS',tmp_varchar2)) THEN
5333       m_nc := Substr(tmp_varchar2,1,1);
5334     ELSE
5335       m_nc := '.';
5336    END IF;
5337 
5338    IF (fnd_flex_val_util.get_mask('DB_NUMERIC_CHARS',tmp_varchar2)) THEN
5339       m_nb := Substr(tmp_varchar2,1,1);
5340     ELSE
5341       m_nb := '.';
5342    END IF;
5343 
5344    IF (fnd_flex_val_util.get_mask('NLS_NUMERIC_CHARS_OUT',tmp_varchar2)) THEN
5345       m_nd := Substr(tmp_varchar2,1,1);
5346     ELSE
5347       m_nd := '.';
5348    END IF;
5349 END fnd_flex_server1;