home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / utils / adt / arrayfuncs.c next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  11.0 KB  |  475 lines

  1. /*
  2.  * arrayfuncs.c --
  3.  *     Special array in and out functions for arrays.
  4.  *
  5.  *
  6.  * RcsId("$Header: /private/postgres/src/utils/adt/RCS/arrayfuncs.c,v 1.19 1992/08/07 02:31:23 mer Exp $");
  7.  */
  8.  
  9. #include <ctype.h>
  10. #include "tmp/postgres.h"
  11. #include "tmp/align.h"
  12.  
  13. #include "catalog/pg_type.h"
  14. #include "catalog/syscache.h"
  15.  
  16. #include "utils/palloc.h"
  17. #include "utils/fmgr.h"
  18. #include "utils/log.h"
  19.  
  20. /*
  21.  * Function prototypes - contained in this file as no one outside should
  22.  * be calling these except the function manager.
  23.  */
  24.  
  25. int array_count ARGS((char *string , char delimiter ));
  26. int system_cache_lookup ARGS((
  27.     ObjectId
  28.     element_type ,
  29.     Boolean input ,
  30.     int *typlen ,
  31.     bool *typbyval ,
  32.     char *typdelim ,
  33.     ObjectId *typelem ,
  34.     ObjectId *proc
  35. ));
  36.  
  37. /*
  38.  *    array_count - counts the number of elements in an array.
  39.  */
  40.  
  41. int
  42. array_count(string, delimiter)
  43.  
  44. char *string;
  45. char delimiter;
  46.  
  47. {
  48.     int i = 1, nelems = 0;
  49.     bool scanning_string = false;
  50.     int nest_level = 1;
  51.  
  52.     while (nest_level >= 1)
  53.     {
  54.         switch (string[i])
  55.         {
  56.             case '\\':
  57.                 i++;
  58.                 break;
  59.             case '{':
  60.                 if (!scanning_string) nest_level++;
  61.                 break;
  62.             case '}':
  63.                 if (!scanning_string) nest_level--;
  64.                 break;
  65.             case '\"':
  66.                 scanning_string = !scanning_string;
  67.                 break;
  68.         case 0:
  69.         elog(WARN, "array constant is missing a closing bracket");
  70.         break;
  71.             default:
  72.                 if (!scanning_string
  73.                   && nest_level == 1
  74.                   && string[i] == delimiter)
  75.                 {
  76.                     nelems++;
  77.                 }
  78.                 break;
  79.         }
  80.         i++;
  81.     }
  82.  
  83.     /*
  84.      * account for last element in list.
  85.      *
  86.      * Careful! If the array string is "{}" there is no 'last element'
  87.      */
  88.  
  89.     return(((nelems > 0) ? (nelems + 1) : 0));
  90. }
  91.  
  92. /*
  93.  *    array_in - takes an array surrounded by {...} and returns it in
  94.  *    VARLENA format:
  95.  */
  96.  
  97. char *
  98. array_in(string, element_type)
  99.  
  100. char *string;
  101. ObjectId element_type;
  102.  
  103. {
  104.     static ObjectId charTypid = InvalidObjectId;
  105.     int typlen;
  106.     bool typbyval;
  107.     char typdelim;
  108.     ObjectId typinput;
  109.     ObjectId typelem;
  110.     char *string_save, *p, *q, *r;
  111.     char **values;
  112.     func_ptr inputproc;
  113.     int i, nitems, dummy;
  114.     int32 nbytes;
  115.     char *retval;
  116.     bool scanning_string = false;
  117.  
  118.     if (charTypid == InvalidObjectId)
  119.     {
  120.     HeapTuple tup;
  121.  
  122.     tup = (HeapTuple)SearchSysCacheTuple(TYPNAME, "char");
  123.     if ((charTypid = tup->t_oid) == InvalidObjectId)
  124.         elog(WARN, "type lookup on char failed");
  125.     }
  126.  
  127.     system_cache_lookup(element_type, true, &typlen, &typbyval,
  128.                         &typdelim, &typelem, &typinput);
  129.  
  130.     fmgr_info(typinput, & inputproc, &dummy);
  131.  
  132.     string_save = (char *) palloc(strlen(string) + 3);
  133.  
  134.     if (string[0] != '{')
  135.     {
  136.     if (element_type == charTypid)
  137.     {
  138.         /*
  139.          * this is a hack to allow char arrays to have a { in the
  140.          * first position.  Of course now \{ can never be the first
  141.          * two characters, but what else can we do?
  142.          */
  143.         string =
  144.         (*string == '\\' && *(string+1) == '{') ? &string[1] : string;
  145.         return (char *)textin(string);
  146.     }
  147.     else
  148.         elog(WARN, "array_in:  malformed array constant");
  149.     }
  150.     else
  151.     {
  152.         strcpy(string_save, string);
  153.     }
  154.  
  155.     if ((nitems = array_count(string, typdelim)) == 0)
  156.     {
  157.     char *emptyArray = palloc(sizeof(int32));
  158.  
  159.     * (int32 *) emptyArray = sizeof(int32);
  160.     return emptyArray;
  161.     }
  162.  
  163.     values        = (char **) palloc(nitems * sizeof(char *));
  164.  
  165.     p = q = string_save;
  166.  
  167.     p++; q++; /* get past leading '{' */
  168.  
  169.     for (i = 0; i < nitems; i++)
  170.     {
  171.         int nest_level = 0;
  172.         bool done = false;
  173.     bool eoArray = false;
  174.  
  175.         while (!done)
  176.         {
  177.             switch (*q)
  178.             {
  179.                 case '\\':
  180.                     /* Crunch the string on top of the backslash. */
  181.                     for (r = q; *r != '\0'; r++) *r = *(r+1);
  182.                     break;
  183.                 case '\"':
  184.                     if (!scanning_string && nest_level == 0)
  185.                     {
  186.                         scanning_string = true;
  187.                         while (p != q) p++;
  188.                         p++; /* get p past first doublequote */
  189.                         break;
  190.                     }
  191.                     else if (nest_level == 0)
  192.                     {
  193.                         scanning_string = false;
  194.                         *q = '\0';
  195.                     }
  196.                     break;
  197.                 case '{':
  198.                     if (!scanning_string) nest_level++;
  199.                     break;
  200.                 case '}':
  201.                     if (nest_level == 0 && !scanning_string)
  202.             {
  203.                         done = true;
  204.             eoArray = true;
  205.             }
  206.                     else if (!scanning_string) nest_level--;
  207.                     break;
  208.                 default:
  209.                     if (*q == typdelim && !scanning_string && nest_level == 0)
  210.             done = true;
  211.                     break;
  212.             }
  213.             if (!done) q++;
  214.         }
  215.         *q = '\0';                    /* Put a null at the end of it */
  216.         values[i] = (*inputproc) (p, typelem);
  217.     if (!typbyval && !values[i])
  218.     {
  219.         elog(NOTICE, "pass by reference array element is NULL, you may");
  220.         elog(WARN, "need to quote each individual element in the constant");
  221.     }
  222.     p = ++q;    /* p goes past q */
  223.     if (!eoArray)    /* if not at the end of the array skip white space */
  224.         while (isspace(*q))
  225.         {
  226.         p++;
  227.         q++;
  228.         }
  229.     }
  230.  
  231.     if (typlen > 0)
  232.     {
  233.         nbytes = nitems * typlen + sizeof(int32);
  234.     }
  235.     else
  236.     {
  237.         for (i = 0, nbytes = 0;
  238.              i < nitems;
  239.              nbytes += LONGALIGN(* (int32 *) values[i]), i++);
  240.         nbytes += sizeof(int32);
  241.     }
  242.  
  243.     retval = (char *) palloc(nbytes);
  244.     p = retval + 4;
  245.  
  246.     bcopy(&nbytes, retval, sizeof(int4));
  247.  
  248.     for (i = 0; i < nitems; i++)
  249.     {
  250.         if (typlen > 0)
  251.         {
  252.             if (typbyval)
  253.             {
  254.         char oneByte;
  255.         short twoBytes;
  256.         switch(typlen) {
  257.             case 1: 
  258.             *p = DatumGetChar(values[i]);
  259.             break;
  260.             case 2: 
  261.             * (int16 *) p = DatumGetInt16(values[i]);
  262.             break;
  263.             case 4:
  264.             * (int32 *) p = (int32)values[i];
  265.             break;
  266.         }
  267.             }
  268.             else
  269.                 bcopy(values[i], p, typlen);
  270.             p += typlen;
  271.         }
  272.         else
  273.         {
  274.             int len;
  275.  
  276.             len = LONGALIGN(* (int32 *) values[i]);
  277.             bcopy(values[i], p, * (int32 *) values[i]);
  278.             p += len;
  279.         }
  280.         if (!typbyval) pfree(values[i]);
  281.     }
  282.     pfree(string_save);
  283.     pfree((char *)values);
  284.     return(retval);
  285. }
  286.  
  287. char *
  288. array_out(items, element_type)
  289.  
  290. char *items;
  291. ObjectId element_type;
  292.  
  293. {
  294.     /*
  295.      * statics so we don't do excessive system cache lookups.
  296.      */
  297.  
  298.     int typlen;
  299.     bool typbyval;
  300.     char typdelim;
  301.     ObjectId typoutput;
  302.     ObjectId typelem;
  303.  
  304.     char *p;
  305.     char *retval;
  306.     char **values;
  307.     int32 nitems, nbytes, overall_length;
  308.     int i, dummy;
  309.     func_ptr outputproc;
  310.     char delim[2];
  311.  
  312.     system_cache_lookup(element_type, false, &typlen, &typbyval,
  313.                         &typdelim, &typelem, &typoutput);
  314.  
  315.     fmgr_info(typoutput, & outputproc, &dummy);
  316.     sprintf(delim, "%c", typdelim);
  317.  
  318.     /*
  319.      * It's an array of fixed-length things (either fixed-length arrays
  320.      * or non-array objects.  We can compute the number of items just by
  321.      * dividing the number of bytes in the blob of memory by the length
  322.      * of each element.
  323.      */
  324.  
  325.     if (typlen > 0)
  326.     {
  327.         nitems = (* (int32 *) items - 4)/ typlen;
  328.     }
  329.     else
  330.  
  331.     /*
  332.      * It's an array of variable length objects.  We have to manually walk
  333.      * through each variable length element to count the number of elements.
  334.      */
  335.  
  336.     {
  337.         nbytes = (* (int32 *) items) - sizeof(int32);
  338.         nitems = 0;
  339.         p = items + sizeof(int32);
  340.  
  341.         while (nbytes != 0)
  342.         {
  343.             nbytes -= LONGALIGN(* (int32 *) p);
  344.             p += LONGALIGN(* (int32 *) p);
  345.             nitems++;
  346.         }
  347.     }
  348.  
  349.     items += sizeof(int32);
  350.  
  351.     if (nitems == 0)
  352.     {
  353.     char *emptyArray = palloc(3);
  354.     emptyArray[0] = '{';
  355.     emptyArray[1] = '}';
  356.     emptyArray[2] = '\0';
  357.     return emptyArray;
  358.     }
  359.     values = (char **) palloc(nitems * sizeof (char *));
  360.     overall_length = 0;
  361.  
  362.     for (i = 0; i < nitems; i++)
  363.     {
  364.         if (typbyval)
  365.         {
  366.             switch(typlen)
  367.             {
  368.                 case 1:
  369.                     values[i] = (*outputproc) (*items, typelem);
  370.                     break;
  371.                 case 2:
  372.                     values[i] = (*outputproc) (* (int16 *) items, typelem);
  373.                     break;
  374.                 case 3:
  375.                 case 4:
  376.                     values[i] = (*outputproc) (* (int32 *) items, typelem);
  377.                     break;
  378.             }
  379.             items += typlen;
  380.         }
  381.         else
  382.         {
  383.             values[i] = (*outputproc) (items, typelem);
  384.             if (typlen > 0)
  385.                 items += typlen;
  386.             else
  387.                 items += LONGALIGN(* (int32 *) items);
  388.         /*
  389.          * For the pair of double quotes
  390.          */
  391.         overall_length += 2;
  392.         }
  393.         overall_length += strlen(values[i]);
  394.  
  395.         /*
  396.          * So that the mapping between input and output functions is preserved
  397.          * in the case of array_out(array_in(string)), we have to put double
  398.          * quotes around strings that look like text strings.  To be sure, and
  399.          * since it will not break anything, we will put double quotes around
  400.          * anything that is not passed by value.
  401.          */
  402.  
  403.         if (!typbyval) overall_length += 2;
  404.     }
  405.  
  406.     p = (char *) palloc(overall_length + 3);
  407.     retval = p;
  408.  
  409.     strcpy(p, "{");
  410.  
  411.     for (i = 0; i < nitems; i++)
  412.     {
  413.         /*
  414.          * Surround anything that is not passed by value in double quotes.
  415.          * See above for more details.
  416.          */
  417.  
  418.         if (!typbyval)
  419.         {
  420.             strcat(p, "\"");
  421.             strcat(p, values[i]);
  422.             strcat(p, "\"");
  423.         }
  424.         else
  425.         {
  426.             strcat(p, values[i]);
  427.         }
  428.  
  429.         if (i != nitems - 1) strcat(p, delim); else strcat(p, "}");
  430.         pfree(values[i]);
  431.     }
  432.  
  433.     pfree((char *)values);
  434.  
  435.     return(retval);
  436. }
  437.  
  438. system_cache_lookup(element_type, input, typlen, typbyval, typdelim,
  439.                     typelem, proc)
  440.  
  441. ObjectId element_type;
  442. Boolean input;
  443. int *typlen;
  444. bool *typbyval;
  445. char *typdelim;
  446. ObjectId *typelem;
  447. ObjectId *proc;
  448.  
  449. {
  450.     HeapTuple typeTuple;
  451.     TypeTupleForm typeStruct;
  452.  
  453.     typeTuple = SearchSysCacheTuple(TYPOID, element_type, NULL, NULL, NULL);
  454.  
  455.     if (!HeapTupleIsValid(typeTuple))
  456.     {
  457.         elog(WARN, "array_out: Cache lookup failed for type %d\n",
  458.              element_type);
  459.         return NULL;
  460.     }
  461.     typeStruct = (TypeTupleForm) GETSTRUCT(typeTuple);
  462.     *typlen    = typeStruct->typlen;
  463.     *typbyval  = typeStruct->typbyval;
  464.     *typdelim  = typeStruct->typdelim;
  465.     *typelem   = typeStruct->typelem;
  466.     if (input)
  467.     {
  468.         *proc = typeStruct->typinput;
  469.     }
  470.     else
  471.     {
  472.         *proc = typeStruct->typoutput;
  473.     }
  474. }
  475.