1 /*
2 
3 -Procedure ekpsel_c ( EK, parse SELECT clause )
4 
5 -Abstract
6 
7    Parse the SELECT clause of an EK query, returning full particulars
8    concerning each selected item.
9 
10 -Disclaimer
11 
12    THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE
13    CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S.
14    GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE
15    ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE
16    PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS"
17    TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY
18    WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A
19    PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC
20    SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE
21    SOFTWARE AND RELATED MATERIALS, HOWEVER USED.
22 
23    IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA
24    BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT
25    LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND,
26    INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS,
27    REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE
28    REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY.
29 
30    RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF
31    THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY
32    CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE
33    ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE.
34 
35 -Required_Reading
36 
37    None.
38 
39 -Keywords
40 
41    PRIVATE
42 
43 */
44 
45    #include "SpiceUsr.h"
46    #include "SpiceZfc.h"
47    #include "SpiceZst.h"
48    #include "SpiceZmc.h"
49 
50 
ekpsel_c(ConstSpiceChar * query,SpiceInt msglen,SpiceInt tablen,SpiceInt collen,SpiceInt * n,SpiceInt * xbegs,SpiceInt * xends,SpiceEKDataType * xtypes,SpiceEKExprClass * xclass,void * tabs,void * cols,SpiceBoolean * error,SpiceChar * errmsg)51    void ekpsel_c ( ConstSpiceChar        * query,
52                    SpiceInt                msglen,
53                    SpiceInt                tablen,
54                    SpiceInt                collen,
55                    SpiceInt              * n,
56                    SpiceInt              * xbegs,
57                    SpiceInt              * xends,
58                    SpiceEKDataType       * xtypes,
59                    SpiceEKExprClass      * xclass,
60                    void                  * tabs,
61                    void                  * cols,
62                    SpiceBoolean          * error,
63                    SpiceChar             * errmsg  )
64 /*
65 
66 -Brief_I/O
67 
68    Variable  I/O  Description
69    --------  ---  --------------------------------------------------
70    query      I   EK query.
71    msglen     I   Available space in the output error message string.
72    tablen     I   Length of strings in `tabs' output array.
73    collen     I   Length of strings in `cols' output array.
74    n          O   Number of items in SELECT clause of query.
75    xbegs      O   Begin positions of expressions in SELECT clause.
76    xends      O   End positions of expressions in SELECT clause.
77    xtypes     O   Data types of expressions.
78    xclass     O   Classes of expressions.
79    tabs       O   Names of tables qualifying SELECT columns.
80    cols       O   Names of columns in SELECT clause of query.
81    error      O   Error flag.
82    errmsg     O   Parse error message.
83 
84 -Detailed_Input
85 
86    query          is a character string containing an EK query.
87                   EK queries have the general form
88 
89                      SELECT <select expr>, <select expr>, ...
90                      FROM <table spec>, <table spec>, ...
91                      [WHERE <constraint list>]
92                      [ORDER BY <order-by column list>]
93 
94                   Here the symbol <select expr> indicates any
95                   expression representing an entity that can be
96                   selected.  Commonly, the selected items are
97                   columns, with or without qualifying table names,
98                   having the form
99 
100                      <column name>
101                      <table name>.<column name>
102                      <table alias>.<column name>
103 
104                   but more general expressions may also be selected.
105                   Examples are functions, such as
106 
107                      COUNT(*)
108                      COUNT( <table name>.<column name> )
109                      MAX  ( <table name>.<column name> )
110 
111                   or expressions involving constants, such as
112 
113                      2 * <column name>
114 
115 
116    msglen         The allowed length for the output message string.
117                   This length must large enough to hold the output
118                   string plus the terminator.  If the output string is
119                   expected to have x characters, msglen needs to be
120                   x + 1.
121 
122    tablen         The length of the strings in the output table array.
123                   This length must large enough to hold the output
124                   strings plus the terminator.  If the output strings
125                   are expected to have x characters, tablen needs to be
126                   x + 1.  The parameter SPICE_EK_TSTRLN defines a string
127                   length sufficient to hold any table name.  This
128                   parameter is defined by SpiceUsr.h.
129 
130    collen         The length of the strings in the output column array.
131                   This length must large enough to hold the output
132                   strings plus the terminator.  If the output strings
133                   are expected to have x characters, collen needs to be
134                   x + 1.  The parameter SPICE_EK_CSTRLN defines a string
135                   length sufficient to hold any table name.  This
136                   parameter is defined by SpiceUsr.h.
137 
138 -Detailed_Output
139 
140    n              is the number of items specified in the
141                   SELECT clause of the input query.
142 
143    xbegs,
144    xends          are, respectively, arrays of begin and end
145                   positions of expressions designating items in the
146                   SELECT clause of the input query.  The ith
147                   expression is located in the substring
148 
149                      query[ xbegs[i] ]...query[ xends[i] ]
150 
151 
152    xtypes         is an array of values of type SpiceEKDataType giving
153                   types of the expressions in the SELECT clause.
154                   Values and meanings of xtypes are:
155 
156                      SPICE_CHR     Character type
157                      SPICE_DP      Double precision type
158                      SPICE_INT     Integer type
159                      SPICE_TIME    Time type
160 
161                   The ith element of xtypes refers to the ith
162                   selected item.
163 
164                   The data type of an expression indicates which
165                   fetch routine to use to obtain values of the
166                   selected expression.  The mapping of data types
167                   to fetch routines is shown below:
168 
169                      SPICE_CHR      ekgc_c
170                      SPICE_DP       ekgd_c
171                      SPICE_INT      ekgi_c
172                      SPICE_TIME     ekgd_c
173 
174                   Note that time values are stored as d.p. numbers.
175 
176 
177    xclass         is an array of values of type SpiceEKExprClass giving
178                   the classes of the expressions occurring in the SELECT
179                   clause of the input query.  Values and meanings of
180                   xclass are:
181 
182                      SPICE_EK_EXP_COL     Selected item was a column.
183                                           The column may qualified by a
184                                           table name.
185 
186                      SPICE_EK_EXP_FUNC    Selected item was a simple
187                                           function invocation of the
188                                           form
189 
190                                              F ( <column> )
191 
192                                           or else was
193 
194                                              COUNT(*)
195 
196                      SPICE_EK_EXP_EXPR    Selected item was a more
197                                           general expression than those
198                                           shown above.
199 
200                   The Ith element of xclass refers to the Ith
201                   selected item.
202 
203                   When a selected item is a column, the values of
204                   the arguments tabs and cols (discussed below) are
205                   defined.
206 
207 
208    tabs           is an array of names of tables corresponding to
209                   the columns in the SELECT clause.  The ith element
210                   of tabs corresponds to the table containing the
211                   ith SELECT column.  Table names returned in tabs
212                   are the actual names of tables in loaded EKs, not
213                   aliases supplied in the input query.  Table names
214                   are supplied even if the corresponding column was
215                   unqualified in the input query, as long as the
216                   column name was unambiguous.
217 
218                   The contents of tabs[i] are defined if and only if
219                   the returned value of xclass[i] is SPICE_EK_EXP_COL.
220 
221                   The caller should declare `tabs' as an array of strings
222                   of length
223 
224                      SPICE_EK_TSTRLN
225 
226                   for example
227 
228                      SpiceChar     tabs[SPICE_EK_MAXQSEL][SPICE_EK_TSTRLN];
229 
230 
231 
232    cols           is an array containing the columns of the SELECT
233                   clause.  The contents of cols[i] are defined if and
234                   only if the returned value of xclass[i] is
235                   SPICE_EK_EXP_COL.
236 
237                   The caller should declare `cols' as an array of strings
238                   of length
239 
240                      SPICE_EK_CSTRLN
241 
242                   for example
243 
244                      SpiceChar     tabs[SPICE_EK_MAXQSEL][SPICE_EK_CSTRLN];
245 
246 
247    error          is a logical flag indicating whether the input
248                   query parsed correctly.  The other outputs of this
249                   routine, except for errmsg, are undefined if a
250                   parse error occurred.  error is returned SPICETRUE if
251                   a parse error occurred, SPICEFALSE otherwise.
252 
253    errmsg         is a character string describing the cause of a
254                   parse error, if such an error occurred.  Otherwise,
255                   errmsg is returned empty.
256 
257 -Parameters
258 
259    None.
260 
261 -Exceptions
262 
263    1)  Parse failures do not cause this routine to signal errors;
264        instead, the error and errmsg outputs indicate invalid
265        QUERIES.
266 
267    2)  Queries cannot be parsed correctly unless at least one EK
268        is loaded.
269 
270 -Files
271 
272    None.
273 
274 -Particulars
275 
276    This routine allows callers of the EK fetch routines to determine
277    at run time the attributes of the columns from which data is to be
278    fetched.
279 
280 -Examples
281 
282    1)  Use of ekpsel_c to assist in fetching rows matching queries
283        supplied at run time.
284 
285        The code fragment shown here does not rely on advance
286        knowledge of the input query or the contents of any loaded EK
287        files.
288 
289        To simplify the example, we assume that all columns are scalar-
290        valued.
291 
292 
293           #include "SpiceUsr.h"
294           #include <stdio.h>
295           #include <string.h>
296 
297 
298           void main()
299        {
300           /.
301           The kernel names that appear here are examples; to use this
302           program, you would have to replace these names with those of
303           kernels available on your own system.
304           ./
305           #define EK              "/kernels/galileo/ek/EK97148A.BSE"
306           #define LSK             "/kernels/gen/lsk/leapseconds.ker"
307           #define MSGLEN          320
308           #define LNSIZE          80
309           #define TIMELEN         25
310 
311           SpiceBoolean            error;
312           SpiceBoolean            found;
313           SpiceBoolean            null;
314 
315           SpiceChar               cdata  [LNSIZE];
316           SpiceChar               cols   [SPICE_EK_MAXQSEL]
317                                          [SPICE_EK_CSTRLN];
318           SpiceChar               errmsg [MSGLEN];
319           SpiceChar               outstr [LNSIZE];
320           SpiceChar             * query;
321           SpiceChar               tabs   [SPICE_EK_MAXQSEL]
322                                          [SPICE_EK_TSTRLN];
323           SpiceChar               utc    [TIMELEN];
324 
325           SpiceDouble             ddata;
326           SpiceDouble             tdata;
327 
328           SpiceEKDataType         xtypes [SPICE_EK_MAXQSEL];
329           SpiceEKExprClass        xclass [SPICE_EK_MAXQSEL];
330 
331           SpiceInt                col;
332           SpiceInt                exprlen;
333           SpiceInt                handle;
334           SpiceInt                idata;
335           SpiceInt                n;
336           SpiceInt                nmrows;
337           SpiceInt                row;
338 
339           SpiceInt                xbegs  [SPICE_EK_MAXQSEL];
340           SpiceInt                xends  [SPICE_EK_MAXQSEL];
341 
342 
343 
344           /.
345           Load leapseconds and E-kernels.
346           ./
347           furnsh_c ( LSK );
348           eklef_c  ( EK, &handle );
349 
350 
351           while ( SPICETRUE )
352           {
353 
354              /.
355              Prompt for query.  Parse the SELECT clause using ekpsel_c.
356              ./
357              query = prompt_c ( "Enter query > " );
358 
359              ekpsel_c ( query,
360                         MSGLEN,
361                         &n,
362                         xbegs,
363                         xends,
364                         xtypes,
365                         xclass,
366                         tabs,
367                         cols,
368                         &error,
369                         errmsg );
370 
371              if ( error )
372              {
373                 printf ( "Error: <%s>\n", errmsg );
374              }
375 
376              else
377              {
378                 /.
379                 Submit query to the EK query system.
380                 ./
381 
382                 ekfind_c ( query, MSGLEN, &nmrows, &error, errmsg );
383 
384                 if ( error )
385                 {
386                    printf ( "Error found: %s\n", errmsg );
387                 }
388 
389                 else
390                 {
391                    printf ( "Number of matching rows = %d\n", nmrows );
392 
393                    /.
394                    Fetch the rows that matched the query.
395                    ./
396 
397                    for ( row = 0;  row < nmrows;  row++ )
398                    {
399                       /.
400                       Fetch data from the current row.
401                       ./
402 
403                       printf ( "\nROW = %d\n", row );
404 
405 
406                       for ( col = 0;  col < n;  col++ )
407                       {
408                          /.
409                          Fetch data from the current selected column.
410                          ./
411 
412                          if ( xclass[col] == SPICE_EK_EXP_COL )
413                          {
414                              printf ( "COLUMN = %s.%s\n",
415                                        tabs[col],
416                                        cols[col] );
417                          }
418                          else
419                          {
420                             exprlen = xends[col] - xbegs[col] + 1;
421 
422                             strncpy ( outstr, query+xbegs[col],
423                                       exprlen                    );
424 
425                             outstr[exprlen] = (char)0;
426 
427                             printf ( "%s\n", outstr );
428                          }
429 
430 
431                          /.
432                          Write out the data.
433                          ./
434 
435                          switch ( xtypes[col] )
436                          {
437                             case SPICE_CHR:
438 
439                                ekgc_c ( col,   row,   0,     LNSIZE,
440                                         cdata, &null, &found         );
441 
442                                if ( !null )
443                                {
444                                   printf ( "%s\n", cdata );
445                                }
446 
447                                break;
448 
449 
450                             case SPICE_DP:
451 
452                                ekgd_c ( col,    row,   0,
453                                         &ddata, &null, &found );
454 
455                                if ( !null )
456                                {
457                                   printf ( "%f\n", ddata );
458                                }
459 
460                                break;
461 
462 
463                             case SPICE_INT:
464 
465                                ekgi_c ( col,    row,   0,
466                                         &idata, &null, &found );
467 
468                                if ( !null )
469                                {
470                                   printf ( "%d\n", cdata );
471                                }
472 
473                                break;
474 
475 
476                             case SPICE_TIME:
477 
478                                /.
479                                The item is a time value.  Convert it
480                                to UTC for output.
481                                ./
482 
483                                ekgd_c ( col,    row,   0,
484                                         &tdata, &null, &found );
485 
486                                if ( !null )
487                                {
488                                   et2utc_c ( tdata,   "C", 3,
489                                              TIMELEN, utc    );
490 
491                                   printf ( "%s\n", utc );
492                                }
493 
494                                break;
495 
496 
497                             default:
498 
499                                ;
500                          }
501 
502                          /.
503                          Handle null values here.
504                          ./
505 
506                          if ( null )
507                          {
508                             printf ( "%s\n", "<Null>" );
509                          }
510 
511                          /.
512                          End of data type switch.
513                          ./
514 
515                       }
516                       /.
517                       We're done with the column having index col.
518                       ./
519                    }
520                    /.
521                    We're done with the row having index row.
522                    ./
523                 }
524                 /.
525                 We either processed the query or ekfind_c detected an
526                 error.
527                 ./
528              }
529              /.
530              We either parsed the SELECT clause or ekpsel_c detected an
531              error.
532              ./
533 
534           }
535 
536        }
537 
538 
539 
540 
541 -Restrictions
542 
543    1)  Currently, column names are the only supported expressions.
544 
545 -Literature_References
546 
547    None.
548 
549 -Author_and_Institution
550 
551    N.J. Bachman       (JPL)
552 
553 -Version
554 
555    -CSPICE Version 2.1.2, 22-MAR-2016   (NJB)
556 
557       Updated brief I/O to describe inputs `tablen' and `collen'.
558       Also added to Detailed_Output descriptions of declarations
559       of the outputs `tabs' and 'cols'.
560 
561    -CSPICE Version 2.1.1, 14-AUG-2006   (EDW)
562 
563       Replace mention of ldpool_c with furnsh_c.
564 
565    -CSPICE Version 2.1.0, 02-SEP-1999 (NJB)
566 
567       Local type logical variable now used for error flag used in
568       interface of ekpsel_.
569 
570    -CSPICE Version 2.0.0, 19-JUL-1999 (NJB)
571 
572       The data types of the tabs and cols arguments were changed
573       to (void *), and associated string length arguments were added.
574       This style of interface for string arrays is now standard within
575       CSPICE.
576 
577       Some corrections of the header comments were made.
578 
579    -CSPICE Version 1.0.0, 21-FEB-1999 (NJB)
580 
581 -Index_Entries
582 
583    parse select clause of EK query
584 
585 -&
586 */
587 
588 { /* Begin ekpsel_c */
589 
590 
591    /*
592    Local constants
593 
594 
595    XCLASSLEN is the maximum length of a short string indicating the
596    class of a SELECT clause item in a QUERY.  The set of expected
597    strings is defined by the Fortran SPICELIB routine EKPSEL.  The
598    current set of strings is {"COL", "FUNC", "EXPR"}.
599    */
600    #define XCLASSLEN       4
601 
602 
603    /*
604    TYPSIZ is the string length associated with the array locXtypes.
605    */
606    #define TYPSIZ          ( SPICE_EK_TYPLEN + 1 )
607 
608 
609    /*
610    EXPSIZ is the string length associated with the array locXclass.
611    */
612    #define EXPSIZ          ( XCLASSLEN + 1 )
613 
614 
615    /*
616    Local variables
617    */
618    logical                 err;
619 
620    SpiceChar               locXtypes[SPICE_EK_MXCLSG][TYPSIZ];
621    SpiceChar               locXclass[SPICE_EK_MXCLSG][EXPSIZ];
622    SpiceChar             * strptr;
623 
624    SpiceInt                i;
625    SpiceInt                lastnb;
626 
627 
628 
629    /*
630    Participate in error tracing.
631    */
632 
633    chkin_c ( "ekpsel_c" );
634 
635    /*
636    Check the input query string to make sure the pointer is non-null and
637    the string length is non-zero.
638    */
639    CHKFSTR ( CHK_STANDARD, "ekpsel_c", query );
640 
641 
642    /*
643    Make sure the output error message string has at least enough room
644    for one output character and a null terminator.  Also check for a
645    null pointer.
646    */
647    CHKOSTR ( CHK_STANDARD, "ekpsel_c", errmsg, msglen );
648 
649 
650    /*
651    Call the f2c'd function.
652    */
653    ekpsel_ ( ( char    * ) query,
654              ( integer * ) n,
655              ( integer * ) xbegs,
656              ( integer * ) xends,
657              ( char    * ) locXtypes,
658              ( char    * ) locXclass,
659              ( char    * ) tabs,
660              ( char    * ) cols,
661              ( logical * ) &err,
662              ( char    * ) errmsg,
663              ( ftnlen    ) strlen(query),
664              ( ftnlen    ) SPICE_EK_TYPLEN,
665              ( ftnlen    ) XCLASSLEN,
666              ( ftnlen    ) tablen-1,
667              ( ftnlen    ) collen-1,
668              ( ftnlen    ) msglen-1          );
669 
670 
671    /*
672    Assign the SpiceBoolean error flag.
673    */
674 
675    *error = err;
676 
677 
678    if ( failed_c() )
679    {
680       chkout_c ( "ekpsel_c" );
681       return;
682    }
683 
684 
685    /*
686    Convert the error message to a C style string.
687    */
688    F2C_ConvertStr ( msglen, errmsg );
689 
690 
691    /*
692    If there was a parse error, the other outputs are undefined.
693    */
694    if ( *error )
695    {
696       chkout_c ( "ekpsel_c" );
697       return;
698    }
699 
700 
701    /*
702    Map the token begin and end indices from Fortran to C style.
703    */
704    for ( i = 0;  i < *n;  i++ )
705    {
706       xbegs[i]--;
707       xends[i]--;
708    }
709 
710 
711    /*
712    Map the expression data types from strings to SpiceEKDataType values.
713    First, map the Fortran-style strings returned by ekpsel_ to C
714    style strings.
715    */
716    F2C_ConvertStrArr ( *n, TYPSIZ, (SpiceChar *)locXtypes );
717 
718 
719    for ( i = 0;  i < *n;  i++ )
720    {
721       if (  eqstr_c( locXtypes[i], "CHR" )  )
722       {
723          xtypes[i] = SPICE_CHR;
724       }
725 
726       else if (  eqstr_c( locXtypes[i], "DP" )  )
727       {
728          xtypes[i] = SPICE_DP;
729       }
730 
731       else if (  eqstr_c( locXtypes[i], "INT" )  )
732       {
733          xtypes[i] = SPICE_INT;
734       }
735 
736       else if (  eqstr_c( locXtypes[i], "TIME" )  )
737       {
738          xtypes[i] = SPICE_TIME;
739       }
740 
741       else
742       {
743          setmsg_c ( "Unrecognized data type string <#> returned "
744                     "by ekpsel_ for item #."                     );
745          errch_c  ( "#",  locXtypes[i]                           );
746          errint_c ( "#",  i                                      );
747          sigerr_c ( "SPICE(BUG)"                                 );
748          chkout_c ( "ekpsel_c"                                   );
749          return;
750       }
751    }
752 
753    /*
754    Map the expression classes from strings to SpiceEKExprClass values.
755    First, map the Fortran-style strings returned by ekpsel_ to C
756    style strings.
757    */
758    F2C_ConvertStrArr ( *n, EXPSIZ, (SpiceChar *)locXclass );
759 
760    for ( i = 0;  i < *n;  i++ )
761    {
762       if (  eqstr_c( locXclass[i], "COL" )  )
763       {
764          xclass[i] = SPICE_EK_EXP_COL;
765       }
766 
767       else if (  eqstr_c( locXclass[i], "FUNC" )  )
768       {
769          xclass[i] = SPICE_EK_EXP_FUNC;
770       }
771 
772       else if (  eqstr_c( locXclass[i], "EXPR" )  )
773       {
774          xclass[i] = SPICE_EK_EXP_EXPR;
775       }
776 
777       else
778       {
779          setmsg_c ( "Unrecognized item class string <#> returned "
780                     "by ekpsel_ for item #."                     );
781          errch_c  ( "#",  locXclass[i]                           );
782          errint_c ( "#",  i                                      );
783          sigerr_c ( "SPICE(BUG)"                                 );
784          chkout_c ( "ekpsel_c"                                   );
785          return;
786       }
787    }
788 
789 
790    /*
791    Convert the array of table names to a C style array of strings.
792    Null-terminate each string so as to eliminate trailing blanks.
793    */
794    F2C_ConvertStrArr ( *n, tablen, (SpiceChar *)tabs );
795 
796    for ( i = 0;  i < *n;  i++ )
797    {
798       strptr = ((SpiceChar *)tabs) + i*tablen;
799 
800       lastnb = F_StrLen ( tablen-1, strptr );
801 
802       *( strptr + lastnb ) = (char)0;
803    }
804 
805    /*
806    Convert the array of column names to a C style array of strings.
807    Null-terminate each string so as to eliminate trailing blanks.
808    */
809    F2C_ConvertStrArr ( *n, collen, (SpiceChar *)cols );
810 
811    for ( i = 0;  i < *n;  i++ )
812    {
813       strptr = ((SpiceChar *)cols) + i*collen;
814 
815       lastnb = F_StrLen ( collen-1, strptr );
816 
817       *( strptr + lastnb ) = (char)0;
818    }
819 
820 
821    chkout_c ( "ekpsel_c" );
822 
823 } /* End ekpsel_c */
824