veil_serialise.c

Go to the documentation of this file.
00001 /**
00002  * @file   veil_serialise.c
00003  * \code
00004  *     Author:       Marc Munro
00005  *     Copyright (c) 2009 - 2011 Marc Munro
00006  *     License:      BSD
00007  *
00008  * \endcode
00009  * @brief  
00010  * Functions serialising and de-serialising session variables.   The
00011  * purpose of this is to allow the contents of session variables to be
00012  * saved for later re-use.  They may be saved in files, temporary tables
00013  * or using some smart cache such as memcached (thru the pgmemcache
00014  * add-in).
00015  * 
00016  */
00017 
00018 /*TODO: Provide a patch to postgres to make b64_encode and
00019  *      b64_decode extern functions and to elimiate the 
00020  *      redundant copies from pgcrypto 
00021  */
00022 
00023 #include "postgres.h"
00024 #include "veil_version.h"
00025 #include "veil_funcs.h"
00026 #include "veil_datatypes.h"
00027 
00028 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00029 
00030 #define INT4VAR_HDR       'V'
00031 #define RANGE_HDR         'R'
00032 #define BITMAP_HDR        'B'
00033 #define BITMAP_ARRAY_HDR  'A'
00034 #define BITMAP_HASH_HDR   'H'
00035 #define INT4_ARRAY_HDR    'I'
00036 #define BITMAP_HASH_MORE  '>'
00037 #define BITMAP_HASH_DONE  '.'
00038 
00039 
00040 #define HDRLEN                 8   /* HDR field plus int32 for length of
00041                                     * item */
00042 #define INT32SIZE_B64          7
00043 #define BOOLSIZE               1
00044 
00045 
00046 /* BEGIN SECTION OF CODE COPIED FROM pgcrypto.c */
00047 
00048 static const char _base64[] =
00049 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00050 
00051 static const int8 b64lookup[128] = {
00052     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00053     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00054     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
00055     52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
00056     -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
00057     15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
00058     -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
00059     41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
00060 };
00061 
00062 static unsigned
00063 b64_encode(const char *src, unsigned len, char *dst)
00064 {
00065     char       *p,
00066                *lend = dst + 76;
00067     const char *s,
00068                *end = src + len;
00069     int         pos = 2;
00070     uint32      buf = 0;
00071 
00072     s = src;
00073     p = dst;
00074 
00075     while (s < end)
00076     {
00077         buf |= (unsigned char) *s << (pos << 3);
00078         pos--;
00079         s++;
00080 
00081         /* write it out */
00082         if (pos < 0)
00083         {
00084             *p++ = _base64[(buf >> 18) & 0x3f];
00085             *p++ = _base64[(buf >> 12) & 0x3f];
00086             *p++ = _base64[(buf >> 6) & 0x3f];
00087             *p++ = _base64[buf & 0x3f];
00088 
00089             pos = 2;
00090             buf = 0;
00091         }
00092         if (p >= lend)
00093         {
00094             *p++ = '\n';
00095             lend = p + 76;
00096         }
00097     }
00098     if (pos != 2)
00099     {
00100         *p++ = _base64[(buf >> 18) & 0x3f];
00101         *p++ = _base64[(buf >> 12) & 0x3f];
00102         *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '=';
00103         *p++ = '=';
00104     }
00105 
00106     return p - dst;
00107 }
00108 
00109 static unsigned
00110 b64_decode(const char *src, unsigned len, char *dst)
00111 {
00112     const char *srcend = src + len,
00113                *s = src;
00114     char       *p = dst;
00115     char        c;
00116     int         b = 0;
00117     uint32      buf = 0;
00118     int         pos = 0,
00119                 end = 0;
00120 
00121     while (s < srcend)
00122     {
00123         c = *s++;
00124 
00125         if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
00126             continue;
00127 
00128         if (c == '=')
00129         {
00130             /* end sequence */
00131             if (!end)
00132             {
00133                 if (pos == 2)
00134                     end = 1;
00135                 else if (pos == 3)
00136                     end = 2;
00137                 else
00138                     ereport(ERROR,
00139                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00140                              errmsg("unexpected \"=\"")));
00141             }
00142             b = 0;
00143         }
00144         else
00145         {
00146             b = -1;
00147             if (c > 0 && c < 127)
00148                 b = b64lookup[(unsigned char) c];
00149             if (b < 0)
00150                 ereport(ERROR,
00151                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00152                          errmsg("invalid symbol")));
00153         }
00154         /* add it to buffer */
00155         buf = (buf << 6) + b;
00156         pos++;
00157         if (pos == 4)
00158         {
00159             *p++ = (buf >> 16) & 255;
00160             if (end == 0 || end > 1)
00161                 *p++ = (buf >> 8) & 255;
00162             if (end == 0 || end > 2)
00163                 *p++ = buf & 255;
00164             buf = 0;
00165             pos = 0;
00166         }
00167     }
00168 
00169     if (pos != 0)
00170         ereport(ERROR,
00171                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00172                  errmsg("invalid end sequence")));
00173 
00174     return p - dst;
00175 }
00176 
00177 /* END SECTION OF CODE COPIED FROM pgcrypto.c */
00178 
00179 #endif
00180 
00181 /** 
00182  * Return the length of a base64 encoded stream for a binary stream of
00183  * ::bytes length.
00184  * 
00185  * @param bytes The length of the input binary stream in bytes
00186  * @return The length of the base64 character stream required to
00187  * represent the input stream.
00188  */
00189 static int
00190 streamlen(int bytes)
00191 {
00192     return (4 * ((bytes + 2) / 3));
00193 }
00194 
00195 /** 
00196  * Return the length of the header part of a serialised data stream for
00197  * the given named variable.  Note that the header contains the name and
00198  * a base64 encode length indicator for the name.
00199  * 
00200  * @param name The variable name to be recorded in the header
00201  * @return The length of the base64 character stream required to
00202  * hold the serialised header for the named variable.
00203  */
00204 static int
00205 hdrlen(char *name)
00206 {
00207     return HDRLEN + INT32SIZE_B64 + strlen(name);
00208 }
00209 
00210 
00211 /** 
00212  * Serialise an int4 value as a base64 stream (truncated to save a
00213  * byte) into *p_stream.
00214  *
00215  * @param p_stream Pointer into stream currently being written.  This
00216  * must be large enought to take the contents to be written.  This
00217  * pointer is updated to point to the next free slot in the stream after
00218  * writing the int4 value, and is null terminated at that position.
00219  * @param value The value to be written to the stream.
00220  */
00221 static void
00222 serialise_int4(char **p_stream, int4 value)
00223 {
00224     int len = b64_encode((char *) &value, sizeof(int32), *p_stream);
00225     (*p_stream) += (len - 1);  /* X: dumb optimisation saves a byte */
00226     (**p_stream) = '\0';
00227 }
00228 
00229 
00230 /** 
00231  * De-serialise an int4 value from a base64 character stream.
00232  *
00233  * @param p_stream Pointer into the stream currently being read.
00234  * must be large enought to take the contents to be written.  This
00235  * pointer is updated to point to the next free slot in the stream after
00236  * reading the int4 value.
00237  * @return the int4 value read from the stream
00238  */
00239 static int4
00240 deserialise_int4(char **p_stream)
00241 {
00242     int4 value;
00243     char *endpos = (*p_stream) + INT32SIZE_B64;
00244     char endchar = *endpos;
00245     *endpos = '=';  /* deal with dumb optimisation (X) above */
00246     b64_decode(*p_stream, INT32SIZE_B64 + 1, (char *) &value);
00247     *endpos = endchar;
00248     (*p_stream) += INT32SIZE_B64;
00249     return value;
00250 }
00251 
00252 /** 
00253  * Serialise a binary stream as a base64 stream into *p_stream.
00254  *
00255  * @param p_stream Pointer into stream currently being written.  This
00256  * pointer is updated to point to the next free slot in the stream after
00257  * writing the contents of instream and is null terminated at that
00258  * position.
00259  * @param bytes The number of bytes to be written.
00260  * @param instream The binary stream to be written.
00261  */
00262 static void
00263 serialise_stream(char **p_stream, int4 bytes, char *instream)
00264 {
00265     int len = b64_encode(instream, bytes, *p_stream);
00266     (*p_stream)[len] = '\0';
00267     (*p_stream) += len;
00268 }
00269 
00270 /** 
00271  * De-serialise a binary stream.
00272  *
00273  * @param p_stream Pointer into the stream currently being read.
00274  * pointer is updated to point to the next free slot in the stream after
00275  * reading the stream.
00276  * @param bytes The number of bytes to be read
00277  * @param outstream Pointer into the pre-allocated memory are into which
00278  * the binary from p_stream is to be written.
00279  */
00280 static void
00281 deserialise_stream(char **p_stream, int4 bytes, char *outstream)
00282 {
00283     int4 len = streamlen(bytes);
00284     b64_decode(*p_stream, len, outstream);
00285     (*p_stream) += len;
00286 }
00287 
00288 
00289 /** 
00290  * Serialise a boolean value into *p_stream.
00291  *
00292  * @param p_stream Pointer into stream currently being written.  This
00293  * pointer is updated to point to the next free slot in the stream after
00294  * writing the contents of value and is null terminated at that
00295  * position.  A true value is written as 'T', and false as 'F'.
00296  * @param value The boolean value to be written.
00297  */
00298 static void
00299 serialise_bool(char **p_stream, bool value)
00300 {
00301     (**p_stream) = value? 'T': 'F';
00302     (*p_stream)++;
00303     (**p_stream) = '\0';
00304 }
00305 
00306 /** 
00307  * De-serialise a boolean value.
00308  *
00309  * @param p_stream Pointer into the stream currently being read.
00310  * pointer is updated to point to the next free slot in the stream after
00311  * reading the stream.
00312  * @return True or false depending on the contents of p_stream.
00313  */
00314 static bool
00315 deserialise_bool(char **p_stream)
00316 {
00317     bool result = (**p_stream) == 'T';
00318     (*p_stream)++;
00319 
00320     return result;
00321 }
00322 
00323 /** 
00324  * Serialise a character value into *p_stream.
00325  *
00326  * @param p_stream Pointer into stream currently being written.  This
00327  * pointer is updated to point to the next free slot in the stream after
00328  * writing the contents of value and is null terminated at that
00329  * position.  The character is written as a single byte character.
00330  * @param value The character value to be written.
00331  */
00332 static void
00333 serialise_char(char **p_stream, char value)
00334 {
00335     (**p_stream) = value;
00336     (*p_stream)++;
00337     (**p_stream) = '\0';
00338 }
00339 
00340 /** 
00341  * De-serialise a character value.
00342  *
00343  * @param p_stream Pointer into the stream currently being read.
00344  * pointer is updated to point to the next free slot in the stream after
00345  * reading the stream.
00346  * @return The value of the character read from p_stream.
00347  */
00348 static char
00349 deserialise_char (char **p_stream)
00350 {
00351     char result = **p_stream;
00352     (*p_stream)++;
00353 
00354     return result;
00355 }
00356 
00357 /** 
00358  * Serialise a string (containing a name) into *p_stream.
00359  *
00360  * @param p_stream Pointer into stream currently being written.  This
00361  * pointer is updated to point to the next free slot in the stream after
00362  * writing the contents of value and is null terminated at that
00363  * position.  The character is written as a single byte character.
00364  * @param name The string to be written.
00365  */
00366 static void
00367 serialise_name(char **p_stream, char *name)
00368 {
00369     static char *blank_name = "";
00370     char *safe_name;
00371     if (name) {
00372         safe_name = name;
00373     }
00374     else {
00375         safe_name = blank_name;
00376     }
00377         
00378     serialise_int4(p_stream, strlen(safe_name));
00379     strcpy((*p_stream), safe_name);
00380     (*p_stream) += strlen(safe_name);
00381     (**p_stream) = '\0';
00382 }
00383 
00384 /** 
00385  * De-serialise a string returning a dynamically allocated string.
00386  *
00387  * @param p_stream Pointer into the stream currently being read.
00388  * pointer is updated to point to the next free slot in the stream after
00389  * reading the stream.
00390  * @return Dynamically allocated copy of string read from *p_stream
00391  */
00392 static char *
00393 deserialise_name(char **p_stream)
00394 {
00395     int32 name_len = deserialise_int4(p_stream);
00396     char *result = palloc((name_len + 1) * sizeof(char));
00397     strncpy(result, *p_stream, name_len);
00398     result[name_len] = '\0';
00399     (*p_stream) += name_len;
00400     return result;
00401 }
00402 
00403 /** 
00404  * Serialise a veil integer variable into a dynamically allocated string.
00405  *
00406  * @param var Pointer to the variable to be serialised
00407  * @param name The name of the variable
00408  * @return Dynamically allocated string containing the serialised
00409  * variable
00410  */
00411 static char *
00412 serialise_int4var(Int4Var *var, char *name)
00413 {
00414     int stream_len = hdrlen(name) + BOOLSIZE + INT32SIZE_B64 + 1;
00415     char *stream = palloc(stream_len * sizeof(char));
00416     char *streamstart = stream;
00417     
00418     serialise_char(&stream, INT4VAR_HDR);
00419     serialise_name(&stream, name);
00420     serialise_bool(&stream, var->isnull);
00421     serialise_int4(&stream, var->value);
00422     return streamstart;
00423 }
00424 
00425 /** 
00426  * De-serialise a veil integer variable.
00427  *
00428  * @param **p_stream Pointer into the stream currently being read.
00429  * pointer is updated to point to the next free slot in the stream after
00430  * reading the stream
00431  * @return Pointer to the variable created or updated from the stream.
00432  */
00433 static VarEntry *
00434 deserialise_int4var(char **p_stream)
00435 {
00436     char *name = deserialise_name(p_stream);
00437     VarEntry *var = vl_lookup_variable(name);
00438     Int4Var *i4v = (Int4Var *) var->obj;
00439 
00440     if (i4v) {
00441         if (i4v->type != OBJ_INT4) {
00442             vl_type_mismatch(name, OBJ_INT4, i4v->type);
00443         }
00444     }
00445     else {
00446         var->obj = (Object *) vl_NewInt4(var->shared);
00447         i4v = (Int4Var *) var->obj;
00448     }
00449     i4v->isnull = deserialise_bool(p_stream);
00450     i4v->value = deserialise_int4(p_stream);
00451     return var;
00452 }
00453 
00454 /** 
00455  * Serialise a veil integer array variable into a dynamically allocated
00456  * string.
00457  *
00458  * @param array Pointer to the variable to be serialised
00459  * @param name The name of the variable
00460  * @return Dynamically allocated string containing the serialised
00461  * variable
00462  */
00463 static char *
00464 serialise_int4array(Int4Array *array, char *name)
00465 {
00466     int elems = 1 + array->arraymax - array->arrayzero;
00467     int stream_len = hdrlen(name) + (2 * INT32SIZE_B64) +
00468         streamlen(elems * sizeof(int32)) + 1;
00469     char *stream = palloc(stream_len * sizeof(char));
00470     char *streamstart = stream;
00471 
00472     serialise_char(&stream, INT4_ARRAY_HDR);
00473     serialise_name(&stream, name);
00474     serialise_int4(&stream, array->arrayzero);
00475     serialise_int4(&stream, array->arraymax);
00476     serialise_stream(&stream, elems * sizeof(int32), 
00477                      (char *) &(array->array[0]));
00478 
00479     return streamstart;
00480 }
00481 
00482 /** 
00483  * De-serialise a veil integer array variable.
00484  *
00485  * @param **p_stream Pointer into the stream currently being read.
00486  * pointer is updated to point to the next free slot in the stream after
00487  * reading the stream
00488  * @return Pointer to the variable created or updated from the stream.
00489  */
00490 static VarEntry *
00491 deserialise_int4array(char **p_stream)
00492 {
00493     char *name = deserialise_name(p_stream);
00494     int4 arrayzero;
00495     int4 arraymax;
00496     int4 elems;
00497     VarEntry *var = vl_lookup_variable(name);
00498     Int4Array *array = (Int4Array *) var->obj;
00499 
00500     arrayzero = deserialise_int4(p_stream);
00501     arraymax = deserialise_int4(p_stream);
00502     elems = 1 + arraymax - arrayzero;
00503 
00504     if (array) {
00505         if (array->type != OBJ_INT4_ARRAY) {
00506             vl_type_mismatch(name, OBJ_INT4_ARRAY, array->type);
00507         }
00508     }
00509     array = vl_NewInt4Array(array, var->shared, arrayzero, arraymax);
00510     var->obj = (Object *) array;
00511 
00512     deserialise_stream(p_stream, elems * sizeof(int4), 
00513                        (char *) &(array->array[0]));
00514     return var;
00515 }
00516 
00517 /** 
00518  * Serialise a veil range variable into a dynamically allocated
00519  * string.
00520  *
00521  * @param range Pointer to the variable to be serialised
00522  * @param name The name of the variable
00523  * @return Dynamically allocated string containing the serialised
00524  * variable
00525  */
00526 static char *
00527 serialise_range(Range *range, char *name)
00528 {
00529     int stream_len = hdrlen(name) + (INT32SIZE_B64 * 2) + 1;
00530     char *stream = palloc(stream_len * sizeof(char));
00531     char *streamstart = stream;
00532 
00533     serialise_char(&stream, RANGE_HDR);
00534     serialise_name(&stream, name);
00535     serialise_int4(&stream, range->min);
00536     serialise_int4(&stream, range->max);
00537     return streamstart;
00538 }
00539 
00540 /** 
00541  * De-serialise a veil range variable.
00542  *
00543  * @param **p_stream Pointer into the stream currently being read.
00544  * pointer is updated to point to the next free slot in the stream after
00545  * reading the stream
00546  * @return Pointer to the variable created or updated from the stream.
00547  */
00548 static VarEntry *
00549 deserialise_range(char **p_stream)
00550 {
00551     char *name = deserialise_name(p_stream);
00552     VarEntry *var = vl_lookup_variable(name);
00553     Range *range = (Range *) var->obj;
00554 
00555     if (range) {
00556         if (range->type != OBJ_RANGE) {
00557             vl_type_mismatch(name, OBJ_RANGE, range->type);
00558         }
00559     }
00560     else {
00561         var->obj = (Object *) vl_NewRange(var->shared);
00562         range = (Range *) var->obj;
00563     }
00564 
00565     range->min = deserialise_int4(p_stream);
00566     range->max = deserialise_int4(p_stream);
00567     return var;
00568 }
00569 
00570 /** 
00571  * Serialise a single bitmap from a veil bitmap array or bitmap hash.
00572  *
00573  * @param p_stream Pointer into the stream currently being read.
00574  * pointer is updated to point to the next free slot in the stream after
00575  * writing the stream.
00576  * @param bitmap The bitmap to be serialised.
00577  */
00578 static void
00579 serialise_one_bitmap(char **p_stream, Bitmap *bitmap)
00580 {
00581     int elems = ARRAYELEMS(bitmap->bitzero, bitmap->bitmax);
00582     serialise_int4(p_stream, bitmap->bitzero);
00583     serialise_int4(p_stream, bitmap->bitmax);
00584     serialise_stream(p_stream, elems * sizeof(int32), 
00585                      (char *) &(bitmap->bitset));
00586 }
00587 
00588 /** 
00589  * Serialise a veil bitmap variable into a dynamically allocated
00590  * string.
00591  *
00592  * @param bitmap Pointer to the variable to be serialised
00593  * @param name The name of the variable
00594  * @return Dynamically allocated string containing the serialised
00595  * variable
00596  */
00597 static char *
00598 serialise_bitmap(Bitmap *bitmap, char *name)
00599 {
00600     int elems = ARRAYELEMS(bitmap->bitzero, bitmap->bitmax);
00601     int stream_len = hdrlen(name) + (INT32SIZE_B64 * 2) + 
00602                      streamlen(sizeof(int32) * elems) + 1;
00603     char *stream = palloc(stream_len * sizeof(char));
00604     char *streamstart = stream;
00605 
00606     serialise_char(&stream, BITMAP_HDR);
00607     serialise_name(&stream, name);
00608     serialise_one_bitmap(&stream, bitmap);
00609     return streamstart;
00610 }
00611 
00612 /** 
00613  * De-serialise a single bitmap into a veil bitmap array or bitmap hash.
00614  *
00615  * @param p_bitmap Pointer to bitmap pointer.  This may be updated to
00616  * contain a dynamically allocated bitmap if none is already present.
00617  * @param name  The name of the variable, for error reporting purposes.
00618  * @param shared Whether the bitmap is part of a shared rather than
00619  * session variable.
00620  * @param p_stream Pointer into the stream currently being read.
00621  * pointer is updated to point to the next free slot in the stream after
00622  * reading the stream.
00623  */
00624 static void
00625 deserialise_one_bitmap(Bitmap **p_bitmap, char *name, 
00626                        bool shared, char **p_stream)
00627 {
00628     Bitmap *bitmap = *p_bitmap;
00629     int4 bitzero;
00630     int4 bitmax;
00631     int4 elems;
00632 
00633     bitzero = deserialise_int4(p_stream);
00634     bitmax = deserialise_int4(p_stream);
00635     elems = ARRAYELEMS(bitzero, bitmax);
00636 
00637     if (bitmap) {
00638         if (bitmap->type != OBJ_BITMAP) {
00639             vl_type_mismatch(name, OBJ_BITMAP, bitmap->type);
00640         }
00641     }
00642     /* Check size and re-allocate memory if needed */
00643     vl_NewBitmap(p_bitmap, shared, bitzero, bitmax);
00644     bitmap = *p_bitmap;
00645 
00646     deserialise_stream(p_stream, elems * sizeof(bitmap->bitset[0]), 
00647                        (char *) &(bitmap->bitset[0]));
00648 
00649 }
00650 
00651 /** 
00652  * De-serialise a veil bitmap variable.
00653  *
00654  * @param **p_stream Pointer into the stream currently being read.
00655  * pointer is updated to point to the next free slot in the stream after
00656  * reading the stream
00657  * @return Pointer to the variable created or updated from the stream.
00658  */
00659 static VarEntry *
00660 deserialise_bitmap(char **p_stream)
00661 {
00662     char *name = deserialise_name(p_stream);
00663     VarEntry *var = vl_lookup_variable(name);
00664     Bitmap *bitmap = (Bitmap *) var->obj;
00665 
00666     deserialise_one_bitmap(&bitmap, name, var->shared, p_stream);
00667     var->obj = (Object *) bitmap;
00668     return var;
00669 }
00670 
00671 /** 
00672  * Serialise a veil bitmap array variable into a dynamically allocated
00673  * string.
00674  *
00675  * @param bmarray Pointer to the variable to be serialised
00676  * @param name The name of the variable
00677  * @return Dynamically allocated string containing the serialised
00678  * variable
00679  */
00680 static char *
00681 serialise_bitmap_array(BitmapArray *bmarray, char *name)
00682 {
00683     int bitset_elems = ARRAYELEMS(bmarray->bitzero, bmarray->bitmax);
00684     int array_elems = 1 + bmarray->arraymax - bmarray->arrayzero;
00685     int bitmap_len = (INT32SIZE_B64 * 2) + 
00686                      streamlen(sizeof(int32) * bitset_elems);
00687     int stream_len = hdrlen(name) + (INT32SIZE_B64 * 4) + 
00688                      (bitmap_len * array_elems) + 1;
00689     int idx;
00690     char *stream = palloc(stream_len * sizeof(char));
00691     char *streamstart = stream;
00692 
00693     serialise_char(&stream, BITMAP_ARRAY_HDR);
00694     serialise_name(&stream, name);
00695     serialise_int4(&stream, bmarray->bitzero);
00696     serialise_int4(&stream, bmarray->bitmax);
00697     serialise_int4(&stream, bmarray->arrayzero);
00698     serialise_int4(&stream, bmarray->arraymax);
00699     for (idx = 0; idx < array_elems; idx++) {
00700         serialise_one_bitmap(&stream, bmarray->bitmap[idx]);
00701     }
00702     return streamstart;
00703 }
00704 
00705 /** 
00706  * De-serialise a veil bitmap array variable.
00707  *
00708  * @param **p_stream Pointer into the stream currently being read.
00709  * pointer is updated to point to the next free slot in the stream after
00710  * reading the stream
00711  * @return Pointer to the variable created or updated from the stream.
00712  */
00713 static VarEntry *
00714 deserialise_bitmap_array(char **p_stream)
00715 {
00716     char *name = deserialise_name(p_stream);
00717     int4 bitzero;
00718     int4 bitmax;
00719     int4 arrayzero;
00720     int4 arraymax;
00721     int4 array_elems;
00722     int4 idx;
00723     VarEntry *var = vl_lookup_variable(name);
00724     BitmapArray *bmarray = (BitmapArray *) var->obj;
00725 
00726     bitzero = deserialise_int4(p_stream);
00727     bitmax = deserialise_int4(p_stream);
00728     arrayzero = deserialise_int4(p_stream);
00729     arraymax = deserialise_int4(p_stream);
00730 
00731     if (bmarray) {
00732         if (bmarray->type != OBJ_BITMAP_ARRAY) {
00733             vl_type_mismatch(name, OBJ_BITMAP_ARRAY, bmarray->type);
00734         }
00735     }
00736     /* Check size and re-allocate memory if needed */
00737     vl_NewBitmapArray(&bmarray, var->shared, arrayzero, 
00738                       arraymax, bitzero, bitmax);
00739     var->obj = (Object *) bmarray;
00740 
00741     array_elems = 1 + arraymax - arrayzero;
00742     for (idx = 0; idx < array_elems; idx++) {
00743         deserialise_one_bitmap(&(bmarray->bitmap[idx]), "", 
00744                                var->shared, p_stream);
00745         
00746     }
00747     return var;
00748 }
00749 
00750 
00751 /** 
00752  * Calculate the size needed for a base64 stream to contain all of the
00753  * bitmaps in a bitmap hash including their keys.
00754  *
00755  * @param bmhash Pointer to the variable to be serialised
00756  * @param bitset_size The size, in bytes, of each bitset in the bitmap
00757  * hash.
00758  * @return Number of bytes required to contain all of the bitmaps and
00759  * keys in the bitmap_hash
00760  */
00761 static int
00762 sizeof_bitmaps_in_hash(BitmapHash *bmhash, int bitset_size)
00763 {
00764     VarEntry *var = NULL;
00765     int size = 1;  /* Allow for final end of stream indicator */
00766     while ((var = vl_NextHashEntry(bmhash->hash, var))) {
00767         /* 1 byte below for record/end flag to precede each bitmap in
00768          * the hash */
00769         size += 1 + bitset_size + hdrlen(var->key); 
00770     }
00771     return size;
00772 }
00773 
00774 
00775 /** 
00776  * Serialise a veil bitmap hash variable into a dynamically allocated
00777  * string.
00778  *
00779  * @param bmhash Pointer to the variable to be serialised
00780  * @param name The name of the variable
00781  * @return Dynamically allocated string containing the serialised
00782  * variable
00783  */
00784 static char *
00785 serialise_bitmap_hash(BitmapHash *bmhash, char *name)
00786 {
00787     int bitset_elems = ARRAYELEMS(bmhash->bitzero, bmhash->bitmax);
00788     int bitset_size = (INT32SIZE_B64 * 2) + 
00789                       streamlen(sizeof(int32) * bitset_elems);
00790     int all_bitmaps_size = sizeof_bitmaps_in_hash(bmhash, bitset_size);
00791     int stream_len = hdrlen(name) + (INT32SIZE_B64 * 2) + 
00792                      all_bitmaps_size + 1;
00793     char *stream = palloc(stream_len * sizeof(char));
00794     char *streamstart = stream;
00795     VarEntry *var = NULL;
00796 
00797     serialise_char(&stream, BITMAP_HASH_HDR);
00798     serialise_name(&stream, name);
00799     serialise_int4(&stream, bmhash->bitzero);
00800     serialise_int4(&stream, bmhash->bitmax);
00801     while ((var = vl_NextHashEntry(bmhash->hash, var))) {
00802         serialise_char(&stream, BITMAP_HASH_MORE);
00803         serialise_name(&stream, var->key);
00804         serialise_one_bitmap(&stream, (Bitmap *) var->obj);
00805     }
00806     serialise_char(&stream, BITMAP_HASH_DONE);
00807 
00808     return streamstart;
00809 }
00810 
00811 /** 
00812  * De-serialise a veil bitmap hash variable.
00813  *
00814  * @param **p_stream Pointer into the stream currently being read.
00815  * pointer is updated to point to the next free slot in the stream after
00816  * reading the stream
00817  * @return Pointer to the variable created or updated from the stream.
00818  */
00819 static VarEntry *
00820 deserialise_bitmap_hash(char **p_stream)
00821 {
00822     char *name = deserialise_name(p_stream);
00823     char *hashkey;
00824     int4 bitzero;
00825     int4 bitmax;
00826     VarEntry *var = vl_lookup_variable(name);
00827     BitmapHash *bmhash = (BitmapHash *) var->obj;
00828     Bitmap *tmp_bitmap = NULL;
00829     Bitmap *bitmap;
00830 
00831     bitzero = deserialise_int4(p_stream);
00832     bitmax = deserialise_int4(p_stream);
00833 
00834     if (bmhash) {
00835         if (bmhash->type != OBJ_BITMAP_HASH) {
00836             vl_type_mismatch(name, OBJ_BITMAP_HASH, bmhash->type);
00837         }
00838     }
00839     /* Check size and re-allocate memory if needed */
00840     vl_NewBitmapHash(&bmhash, name, bitzero, bitmax);
00841     var->obj = (Object *) bmhash;
00842 
00843     while (deserialise_char(p_stream) == BITMAP_HASH_MORE) {
00844         hashkey = deserialise_name(p_stream);
00845         deserialise_one_bitmap(&tmp_bitmap, "", var->shared, p_stream);
00846         /* tmp_bitmap now contains a (dynamically allocated) bitmap
00847          * Now we want to copy that into the bmhash.  We don't worry
00848          * about memory leaks here since this is allocated only once
00849          * per call of this function, and the memory context will
00850          * eventually be freed anyway.
00851          */
00852         bitmap = vl_AddBitmapToHash(bmhash, hashkey);
00853         vl_BitmapUnion(bitmap, tmp_bitmap);
00854     }
00855     return var;
00856 }
00857 
00858 /** 
00859  * Serialise a veil variable
00860  *
00861  * @param name  The name of the variable to be serialised.
00862  * @return Dynamically allocated string containing the serialised value.
00863  */
00864 extern char *
00865 vl_serialise_var(char *name)
00866 {
00867     VarEntry *var;
00868     char *result = NULL;
00869 
00870     var = vl_lookup_variable(name);
00871     if (var && var->obj) {
00872         switch (var->obj->type) {
00873             case OBJ_INT4:
00874                 result = serialise_int4var((Int4Var *)var->obj, name);
00875                 break;
00876             case OBJ_INT4_ARRAY:
00877                 result = serialise_int4array((Int4Array *)var->obj, name);
00878                 break;
00879             case OBJ_RANGE:
00880                 result = serialise_range((Range *)var->obj, name);
00881                 break;
00882             case OBJ_BITMAP:
00883                 result = serialise_bitmap((Bitmap *)var->obj, name);
00884                 break;
00885             case OBJ_BITMAP_ARRAY:
00886                 result = serialise_bitmap_array((BitmapArray *)var->obj, name);
00887                 break;
00888             case OBJ_BITMAP_HASH:
00889                 result = serialise_bitmap_hash((BitmapHash *)var->obj, name);
00890                 break;
00891             default:
00892                 ereport(ERROR,
00893                         (errcode(ERRCODE_INTERNAL_ERROR),
00894                          errmsg("Unsupported type for variable serialisation"),
00895                          errdetail("Cannot serialise objects of type %d.", 
00896                                    (int4) var->obj->type)));
00897                 
00898         }
00899     }
00900     return result;
00901 }
00902 
00903 /** 
00904  * De-serialise the next veil variable from *p_stream
00905  *
00906  * @param **p_stream Pointer into the stream currently being read.
00907  * pointer is updated to point to the next free slot in the stream after
00908  * reading the stream
00909  * @return The deserialised variable.
00910  */
00911 extern VarEntry *
00912 vl_deserialise_next(char **p_stream)
00913 {
00914     VarEntry *var = NULL;
00915     if ((**p_stream) != '\0') {
00916         char type = deserialise_char(p_stream);
00917         switch (type){
00918             case INT4VAR_HDR: var = deserialise_int4var(p_stream);
00919                 break;
00920             case INT4_ARRAY_HDR: var = deserialise_int4array(p_stream);
00921                 break;
00922             case RANGE_HDR: var = deserialise_range(p_stream);
00923                 break;
00924             case BITMAP_HDR: var = deserialise_bitmap(p_stream);
00925                 break;
00926             case BITMAP_ARRAY_HDR: var = deserialise_bitmap_array(p_stream);
00927                 break;
00928             case BITMAP_HASH_HDR: var = deserialise_bitmap_hash(p_stream);
00929                 break;
00930             default:
00931                 ereport(ERROR,
00932                     (errcode(ERRCODE_INTERNAL_ERROR),
00933                      errmsg("Unsupported type for variable deserialisation"),
00934                      errdetail("Cannot deserialise objects of type %c.", 
00935                                type)));
00936                 
00937         }
00938     }
00939     return var;
00940 }
00941 
00942 /** 
00943  * De-serialise a base64 string containing, possibly many, derialised
00944  * veil variables.
00945  *
00946  * @param **p_stream Pointer into the stream currently being read.
00947  * @return A count of the number of variables that have been de-serialised.
00948  */
00949 extern int4
00950 vl_deserialise(char **p_stream)
00951 {
00952     int count = 0;
00953     while ((**p_stream) != '\0') {
00954         (void) vl_deserialise_next(p_stream);
00955         count++;
00956     }
00957     return count;
00958 }

Generated on Mon Sep 12 15:26:45 2011 for Veil by  doxygen 1.5.6