Veil
veil_serialise.c
Go to the documentation of this file.
1 /**
2  * @file veil_serialise.c
3  * \code
4  * Author: Marc Munro
5  * Copyright (c) 2009 - 2011 Marc Munro
6  * License: BSD
7  *
8  * \endcode
9  * @brief
10  * Functions serialising and de-serialising session variables. The
11  * purpose of this is to allow the contents of session variables to be
12  * saved for later re-use. They may be saved in files, temporary tables
13  * or using some smart cache such as memcached (thru the pgmemcache
14  * add-in).
15  *
16  */
17 
18 /*TODO: Provide a patch to postgres to make b64_encode and
19  * b64_decode extern functions and to elimiate the
20  * redundant copies from pgcrypto
21  */
22 
23 #include "postgres.h"
24 #include "veil_version.h"
25 #include "veil_funcs.h"
26 #include "veil_datatypes.h"
27 
28 #ifndef DOXYGEN_SHOULD_SKIP_THIS
29 
30 #define INT4VAR_HDR 'V'
31 #define INT8VAR_HDR '8'
32 #define RANGE_HDR 'R'
33 #ifdef USE_64_BIT
34 #define BITMAP_HDR 'B'
35 #else
36 #define BITMAP_HDR 'M'
37 #endif
38 #define BITMAP_ARRAY_HDR 'A'
39 #define BITMAP_HASH_HDR 'H'
40 #define INT4_ARRAY_HDR 'I'
41 #define BITMAP_HASH_MORE '>'
42 #define BITMAP_HASH_DONE '.'
43 
44 
45 #define HDRLEN 8 /* HDR field plus int32 for length of
46  * item */
47 #define INT32SIZE_B64 7 /* Actually 8 but the last char is
48  * always '=' so we forget it. */
49 #define INT64SIZE_B64 12
50 #define BOOLSIZE 1
51 
52 
53 /* BEGIN SECTION OF CODE COPIED FROM pgcrypto.c */
54 
55 static const char _base64[] =
56 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
57 
58 static const int8 b64lookup[128] = {
59  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
60  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
61  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
62  52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
63  -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
64  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
65  -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
66  41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
67 };
68 
69 static unsigned
70 b64_encode(const char *src, unsigned len, char *dst)
71 {
72  char *p,
73  *lend = dst + 76;
74  const char *s,
75  *end = src + len;
76  int pos = 2;
77  uint32 buf = 0;
78 
79  s = src;
80  p = dst;
81 
82  while (s < end)
83  {
84  buf |= (unsigned char) *s << (pos << 3);
85  pos--;
86  s++;
87 
88  /* write it out */
89  if (pos < 0)
90  {
91  *p++ = _base64[(buf >> 18) & 0x3f];
92  *p++ = _base64[(buf >> 12) & 0x3f];
93  *p++ = _base64[(buf >> 6) & 0x3f];
94  *p++ = _base64[buf & 0x3f];
95 
96  pos = 2;
97  buf = 0;
98  }
99  if (p >= lend)
100  {
101  *p++ = '\n';
102  lend = p + 76;
103  }
104  }
105  if (pos != 2)
106  {
107  *p++ = _base64[(buf >> 18) & 0x3f];
108  *p++ = _base64[(buf >> 12) & 0x3f];
109  *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '=';
110  *p++ = '=';
111  }
112 
113  return p - dst;
114 }
115 
116 static unsigned
117 b64_decode(const char *src, unsigned len, char *dst)
118 {
119  const char *srcend = src + len,
120  *s = src;
121  char *p = dst;
122  char c;
123  int b = 0;
124  uint32 buf = 0;
125  int pos = 0,
126  end = 0;
127 
128  while (s < srcend)
129  {
130  c = *s++;
131 
132  if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
133  continue;
134 
135  if (c == '=')
136  {
137  /* end sequence */
138  if (!end)
139  {
140  if (pos == 2)
141  end = 1;
142  else if (pos == 3)
143  end = 2;
144  else
145  ereport(ERROR,
146  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
147  errmsg("unexpected \"=\"")));
148  }
149  b = 0;
150  }
151  else
152  {
153  b = -1;
154  if (c > 0 && c < 127)
155  b = b64lookup[(unsigned char) c];
156  if (b < 0)
157  ereport(ERROR,
158  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
159  errmsg("invalid symbol")));
160  }
161  /* add it to buffer */
162  buf = (buf << 6) + b;
163  pos++;
164  if (pos == 4)
165  {
166  *p++ = (buf >> 16) & 255;
167  if (end == 0 || end > 1)
168  *p++ = (buf >> 8) & 255;
169  if (end == 0 || end > 2)
170  *p++ = buf & 255;
171  buf = 0;
172  pos = 0;
173  }
174  }
175 
176  if (pos != 0)
177  ereport(ERROR,
178  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
179  errmsg("invalid end sequence")));
180 
181  return p - dst;
182 }
183 
184 /* END SECTION OF CODE COPIED FROM pgcrypto.c */
185 
186 #endif
187 
188 /**
189  * Return the length of a base64 encoded stream for a binary stream of
190  * ::bytes length.
191  *
192  * @param bytes The length of the input binary stream in bytes
193  * @return The length of the base64 character stream required to
194  * represent the input stream.
195  */
196 static int
197 streamlen(int bytes)
198 {
199  return (4 * ((bytes + 2) / 3));
200 }
201 
202 /**
203  * Return the length of the header part of a serialised data stream for
204  * the given named variable. Note that the header contains the name and
205  * a base64 encode length indicator for the name.
206  *
207  * @param name The variable name to be recorded in the header
208  * @return The length of the base64 character stream required to
209  * hold the serialised header for the named variable.
210  */
211 static int
212 hdrlen(char *name)
213 {
214  return HDRLEN + INT32SIZE_B64 + strlen(name);
215 }
216 
217 
218 /**
219  * Serialise an int4 value as a base64 stream (truncated to save a
220  * byte) into *p_stream.
221  *
222  * @param p_stream Pointer into stream currently being written. This
223  * must be large enought to take the contents to be written. This
224  * pointer is updated to point to the next free slot in the stream after
225  * writing the int4 value, and is null terminated at that position.
226  * @param value The value to be written to the stream.
227  */
228 static void
229 serialise_int4(char **p_stream, int32 value)
230 {
231  int len = b64_encode((char *) &value, sizeof(int32), *p_stream);
232  (*p_stream) += (len - 1); /* X: dumb optimisation saves a byte */
233  (**p_stream) = '\0';
234 }
235 
236 
237 /**
238  * De-serialise an int4 value from a base64 character stream.
239  *
240  * @param p_stream Pointer into the stream currently being read.
241  * must be large enought to take the contents to be written. This
242  * pointer is updated to point to the next free slot in the stream after
243  * reading the int4 value.
244  * @return the int4 value read from the stream
245  */
246 static int32
247 deserialise_int4(char **p_stream)
248 {
249  int32 value;
250  char *endpos = (*p_stream) + INT32SIZE_B64;
251  char endchar = *endpos;
252  *endpos = '='; /* deal with dumb optimisation (X) above */
253  b64_decode(*p_stream, INT32SIZE_B64 + 1, (char *) &value);
254  *endpos = endchar;
255  (*p_stream) += INT32SIZE_B64;
256  return value;
257 }
258 
259 #ifdef UNUSED_BUT_WORKS
260 /**
261  * Serialise an int8 value as a base64 stream into *p_stream.
262  *
263  * @param p_stream Pointer into stream currently being written. This
264  * must be large enought to take the contents to be written. This
265  * pointer is updated to point to the next free slot in the stream after
266  * writing the int8 value, and is null terminated at that position.
267  * @param value The value to be written to the stream.
268  */
269 static void
270 serialise_int8(char **p_stream, int64 value)
271 {
272  int len = b64_encode((char *) &value, sizeof(int64), *p_stream);
273  (*p_stream) += len;
274  (**p_stream) = '\0';
275 }
276 
277 
278 /**
279  * De-serialise an int8 value from a base64 character stream.
280  *
281  * @param p_stream Pointer into the stream currently being read.
282  * must be large enought to take the contents to be written. This
283  * pointer is updated to point to the next free slot in the stream after
284  * reading the int8 value.
285  * @return the int8 value read from the stream
286  */
287 static int64
288 deserialise_int8(char **p_stream)
289 {
290  int64 value;
291  fprintf(stderr, "Deserialise %s\n", *p_stream);
292  b64_decode(*p_stream, INT64SIZE_B64, (char *) &value);
293  (*p_stream) += INT64SIZE_B64;
294  return value;
295 }
296 #endif
297 
298 /**
299  * Serialise a binary stream as a base64 stream into *p_stream.
300  *
301  * @param p_stream Pointer into stream currently being written. This
302  * pointer is updated to point to the next free slot in the stream after
303  * writing the contents of instream and is null terminated at that
304  * position.
305  * @param bytes The number of bytes to be written.
306  * @param instream The binary stream to be written.
307  */
308 static void
309 serialise_stream(char **p_stream, int32 bytes, char *instream)
310 {
311  int len = b64_encode(instream, bytes, *p_stream);
312  (*p_stream)[len] = '\0';
313  (*p_stream) += len;
314 }
315 
316 /**
317  * De-serialise a binary stream.
318  *
319  * @param p_stream Pointer into the stream currently being read.
320  * pointer is updated to point to the next free slot in the stream after
321  * reading the stream.
322  * @param bytes The number of bytes to be read
323  * @param outstream Pointer into the pre-allocated memory are into which
324  * the binary from p_stream is to be written.
325  */
326 static void
327 deserialise_stream(char **p_stream, int32 bytes, char *outstream)
328 {
329  int32 len = streamlen(bytes);
330  b64_decode(*p_stream, len, outstream);
331  (*p_stream) += len;
332 }
333 
334 
335 /**
336  * Serialise a boolean value into *p_stream.
337  *
338  * @param p_stream Pointer into stream currently being written. This
339  * pointer is updated to point to the next free slot in the stream after
340  * writing the contents of value and is null terminated at that
341  * position. A true value is written as 'T', and false as 'F'.
342  * @param value The boolean value to be written.
343  */
344 static void
345 serialise_bool(char **p_stream, bool value)
346 {
347  (**p_stream) = value? 'T': 'F';
348  (*p_stream)++;
349  (**p_stream) = '\0';
350 }
351 
352 /**
353  * De-serialise a boolean value.
354  *
355  * @param p_stream Pointer into the stream currently being read.
356  * pointer is updated to point to the next free slot in the stream after
357  * reading the stream.
358  * @return True or false depending on the contents of p_stream.
359  */
360 static bool
361 deserialise_bool(char **p_stream)
362 {
363  bool result = (**p_stream) == 'T';
364  (*p_stream)++;
365 
366  return result;
367 }
368 
369 /**
370  * Serialise a character value into *p_stream.
371  *
372  * @param p_stream Pointer into stream currently being written. This
373  * pointer is updated to point to the next free slot in the stream after
374  * writing the contents of value and is null terminated at that
375  * position. The character is written as a single byte character.
376  * @param value The character value to be written.
377  */
378 static void
379 serialise_char(char **p_stream, char value)
380 {
381  (**p_stream) = value;
382  (*p_stream)++;
383  (**p_stream) = '\0';
384 }
385 
386 /**
387  * De-serialise a character value.
388  *
389  * @param p_stream Pointer into the stream currently being read.
390  * pointer is updated to point to the next free slot in the stream after
391  * reading the stream.
392  * @return The value of the character read from p_stream.
393  */
394 static char
395 deserialise_char (char **p_stream)
396 {
397  char result = **p_stream;
398  (*p_stream)++;
399 
400  return result;
401 }
402 
403 /**
404  * Serialise a string (containing a name) into *p_stream.
405  *
406  * @param p_stream Pointer into stream currently being written. This
407  * pointer is updated to point to the next free slot in the stream after
408  * writing the contents of value and is null terminated at that
409  * position. The character is written as a single byte character.
410  * @param name The string to be written.
411  */
412 static void
413 serialise_name(char **p_stream, char *name)
414 {
415  static char *blank_name = "";
416  char *safe_name;
417  if (name) {
418  safe_name = name;
419  }
420  else {
421  safe_name = blank_name;
422  }
423 
424  serialise_int4(p_stream, strlen(safe_name));
425  strcpy((*p_stream), safe_name);
426  (*p_stream) += strlen(safe_name);
427  (**p_stream) = '\0';
428 }
429 
430 /**
431  * De-serialise a string returning a dynamically allocated string.
432  *
433  * @param p_stream Pointer into the stream currently being read.
434  * pointer is updated to point to the next free slot in the stream after
435  * reading the stream.
436  * @return Dynamically allocated copy of string read from *p_stream
437  */
438 static char *
439 deserialise_name(char **p_stream)
440 {
441  int32 name_len = deserialise_int4(p_stream);
442  char *result = palloc((name_len + 1) * sizeof(char));
443  strncpy(result, *p_stream, name_len);
444  result[name_len] = '\0';
445  (*p_stream) += name_len;
446  return result;
447 }
448 
449 /**
450  * Serialise a veil integer variable into a dynamically allocated string.
451  *
452  * @param var Pointer to the variable to be serialised
453  * @param name The name of the variable
454  * @return Dynamically allocated string containing the serialised
455  * variable
456  */
457 static char *
458 serialise_int4var(Int4Var *var, char *name)
459 {
460  int stream_len = hdrlen(name) + BOOLSIZE + INT32SIZE_B64 + 1;
461  char *stream = palloc(stream_len * sizeof(char));
462  char *streamstart = stream;
463 
464  serialise_char(&stream, INT4VAR_HDR);
465  serialise_name(&stream, name);
466  serialise_bool(&stream, var->isnull);
467  serialise_int4(&stream, var->value);
468  return streamstart;
469 }
470 
471 /**
472  * De-serialise a veil integer variable.
473  *
474  * @param **p_stream Pointer into the stream currently being read.
475  * pointer is updated to point to the next free slot in the stream after
476  * reading the stream
477  * @return Pointer to the variable created or updated from the stream.
478  */
479 static VarEntry *
480 deserialise_int4var(char **p_stream)
481 {
482  char *name = deserialise_name(p_stream);
483  VarEntry *var = vl_lookup_variable(name);
484  Int4Var *i4v = (Int4Var *) var->obj;
485 
486  if (i4v) {
487  if (i4v->type != OBJ_INT4) {
488  vl_type_mismatch(name, OBJ_INT4, i4v->type);
489  }
490  }
491  else {
492  var->obj = (Object *) vl_NewInt4(var->shared);
493  i4v = (Int4Var *) var->obj;
494  }
495  i4v->isnull = deserialise_bool(p_stream);
496  i4v->value = deserialise_int4(p_stream);
497  return var;
498 }
499 
500 /**
501  * Serialise a veil integer array variable into a dynamically allocated
502  * string.
503  *
504  * @param array Pointer to the variable to be serialised
505  * @param name The name of the variable
506  * @return Dynamically allocated string containing the serialised
507  * variable
508  */
509 static char *
510 serialise_int4array(Int4Array *array, char *name)
511 {
512  int elems = 1 + array->arraymax - array->arrayzero;
513  int stream_len = hdrlen(name) + (2 * INT32SIZE_B64) +
514  streamlen(elems * sizeof(int32)) + 1;
515  char *stream = palloc(stream_len * sizeof(char));
516  char *streamstart = stream;
517 
518  serialise_char(&stream, INT4_ARRAY_HDR);
519  serialise_name(&stream, name);
520  serialise_int4(&stream, array->arrayzero);
521  serialise_int4(&stream, array->arraymax);
522  serialise_stream(&stream, elems * sizeof(int32),
523  (char *) &(array->array[0]));
524 
525  return streamstart;
526 }
527 
528 /**
529  * De-serialise a veil integer array variable.
530  *
531  * @param **p_stream Pointer into the stream currently being read.
532  * pointer is updated to point to the next free slot in the stream after
533  * reading the stream
534  * @return Pointer to the variable created or updated from the stream.
535  */
536 static VarEntry *
537 deserialise_int4array(char **p_stream)
538 {
539  char *name = deserialise_name(p_stream);
540  int32 arrayzero;
541  int32 arraymax;
542  int32 elems;
543  VarEntry *var = vl_lookup_variable(name);
544  Int4Array *array = (Int4Array *) var->obj;
545 
546  arrayzero = deserialise_int4(p_stream);
547  arraymax = deserialise_int4(p_stream);
548  elems = 1 + arraymax - arrayzero;
549 
550  if (array) {
551  if (array->type != OBJ_INT4_ARRAY) {
552  vl_type_mismatch(name, OBJ_INT4_ARRAY, array->type);
553  }
554  }
555  array = vl_NewInt4Array(array, var->shared, arrayzero, arraymax);
556  var->obj = (Object *) array;
557 
558  deserialise_stream(p_stream, elems * sizeof(int32),
559  (char *) &(array->array[0]));
560  return var;
561 }
562 
563 /**
564  * Serialise a veil range variable into a dynamically allocated
565  * string.
566  *
567  * @param range Pointer to the variable to be serialised
568  * @param name The name of the variable
569  * @return Dynamically allocated string containing the serialised
570  * variable
571  */
572 static char *
573 serialise_range(Range *range, char *name)
574 {
575  int stream_len = hdrlen(name) + (INT32SIZE_B64 * 2) + 1;
576  char *stream = palloc(stream_len * sizeof(char));
577  char *streamstart = stream;
578 
579  serialise_char(&stream, RANGE_HDR);
580  serialise_name(&stream, name);
581  serialise_int4(&stream, range->min);
582  serialise_int4(&stream, range->max);
583  return streamstart;
584 }
585 
586 /**
587  * De-serialise a veil range variable.
588  *
589  * @param **p_stream Pointer into the stream currently being read.
590  * pointer is updated to point to the next free slot in the stream after
591  * reading the stream
592  * @return Pointer to the variable created or updated from the stream.
593  */
594 static VarEntry *
595 deserialise_range(char **p_stream)
596 {
597  char *name = deserialise_name(p_stream);
598  VarEntry *var = vl_lookup_variable(name);
599  Range *range = (Range *) var->obj;
600 
601  if (range) {
602  if (range->type != OBJ_RANGE) {
603  vl_type_mismatch(name, OBJ_RANGE, range->type);
604  }
605  }
606  else {
607  var->obj = (Object *) vl_NewRange(var->shared);
608  range = (Range *) var->obj;
609  }
610 
611  range->min = deserialise_int4(p_stream);
612  range->max = deserialise_int4(p_stream);
613  return var;
614 }
615 
616 /**
617  * Serialise a single bitmap from a veil bitmap array or bitmap hash.
618  *
619  * @param p_stream Pointer into the stream currently being read.
620  * pointer is updated to point to the next free slot in the stream after
621  * writing the stream.
622  * @param bitmap The bitmap to be serialised.
623  */
624 static void
625 serialise_one_bitmap(char **p_stream, Bitmap *bitmap)
626 {
627  int elems = ARRAYELEMS(bitmap->bitzero, bitmap->bitmax);
628  serialise_int4(p_stream, bitmap->bitzero);
629  serialise_int4(p_stream, bitmap->bitmax);
630  serialise_stream(p_stream, elems * sizeof(bm_int),
631  (char *) &(bitmap->bitset));
632 }
633 
634 /**
635  * Serialise a veil bitmap variable into a dynamically allocated
636  * string.
637  *
638  * @param bitmap Pointer to the variable to be serialised
639  * @param name The name of the variable
640  * @return Dynamically allocated string containing the serialised
641  * variable
642  */
643 static char *
644 serialise_bitmap(Bitmap *bitmap, char *name)
645 {
646  int elems = ARRAYELEMS(bitmap->bitzero, bitmap->bitmax);
647  int stream_len = hdrlen(name) + (INT32SIZE_B64 * 2) +
648  streamlen(sizeof(bm_int) * elems) + 1;
649  char *stream = palloc(stream_len * sizeof(char));
650  char *streamstart = stream;
651 
652  serialise_char(&stream, BITMAP_HDR);
653  serialise_name(&stream, name);
654  serialise_one_bitmap(&stream, bitmap);
655  return streamstart;
656 }
657 
658 /**
659  * De-serialise a single bitmap into a veil bitmap array or bitmap hash.
660  *
661  * @param p_bitmap Pointer to bitmap pointer. This may be updated to
662  * contain a dynamically allocated bitmap if none is already present.
663  * @param name The name of the variable, for error reporting purposes.
664  * @param shared Whether the bitmap is part of a shared rather than
665  * session variable.
666  * @param p_stream Pointer into the stream currently being read.
667  * pointer is updated to point to the next free slot in the stream after
668  * reading the stream.
669  */
670 static void
671 deserialise_one_bitmap(Bitmap **p_bitmap, char *name,
672  bool shared, char **p_stream)
673 {
674  Bitmap *bitmap = *p_bitmap;
675  int32 bitzero;
676  int32 bitmax;
677  int32 elems;
678 
679  bitzero = deserialise_int4(p_stream);
680  bitmax = deserialise_int4(p_stream);
681  elems = ARRAYELEMS(bitzero, bitmax);
682 
683  if (bitmap) {
684  if (bitmap->type != OBJ_BITMAP) {
685  vl_type_mismatch(name, OBJ_BITMAP, bitmap->type);
686  }
687  }
688  /* Check size and re-allocate memory if needed */
689  vl_NewBitmap(p_bitmap, shared, bitzero, bitmax);
690  bitmap = *p_bitmap;
691 
692  deserialise_stream(p_stream, elems * sizeof(bitmap->bitset[0]),
693  (char *) &(bitmap->bitset[0]));
694 
695 }
696 
697 /**
698  * De-serialise a veil bitmap variable.
699  *
700  * @param **p_stream Pointer into the stream currently being read.
701  * pointer is updated to point to the next free slot in the stream after
702  * reading the stream
703  * @return Pointer to the variable created or updated from the stream.
704  */
705 static VarEntry *
706 deserialise_bitmap(char **p_stream)
707 {
708  char *name = deserialise_name(p_stream);
709  VarEntry *var = vl_lookup_variable(name);
710  Bitmap *bitmap = (Bitmap *) var->obj;
711 
712  deserialise_one_bitmap(&bitmap, name, var->shared, p_stream);
713  var->obj = (Object *) bitmap;
714  return var;
715 }
716 
717 /**
718  * Serialise a veil bitmap array variable into a dynamically allocated
719  * string.
720  *
721  * @param bmarray Pointer to the variable to be serialised
722  * @param name The name of the variable
723  * @return Dynamically allocated string containing the serialised
724  * variable
725  */
726 static char *
727 serialise_bitmap_array(BitmapArray *bmarray, char *name)
728 {
729  int bitset_elems = ARRAYELEMS(bmarray->bitzero, bmarray->bitmax);
730  int array_elems = 1 + bmarray->arraymax - bmarray->arrayzero;
731  int bitmap_len = (INT32SIZE_B64 * 2) +
732  streamlen(sizeof(bm_int) * bitset_elems);
733  int stream_len = hdrlen(name) + (INT32SIZE_B64 * 4) +
734  (bitmap_len * array_elems) + 1;
735  int idx;
736  char *stream = palloc(stream_len * sizeof(char));
737  char *streamstart = stream;
738 
739  serialise_char(&stream, BITMAP_ARRAY_HDR);
740  serialise_name(&stream, name);
741  serialise_int4(&stream, bmarray->bitzero);
742  serialise_int4(&stream, bmarray->bitmax);
743  serialise_int4(&stream, bmarray->arrayzero);
744  serialise_int4(&stream, bmarray->arraymax);
745  for (idx = 0; idx < array_elems; idx++) {
746  serialise_one_bitmap(&stream, bmarray->bitmap[idx]);
747  }
748  return streamstart;
749 }
750 
751 /**
752  * De-serialise a veil bitmap array variable.
753  *
754  * @param **p_stream Pointer into the stream currently being read.
755  * pointer is updated to point to the next free slot in the stream after
756  * reading the stream
757  * @return Pointer to the variable created or updated from the stream.
758  */
759 static VarEntry *
760 deserialise_bitmap_array(char **p_stream)
761 {
762  char *name = deserialise_name(p_stream);
763  int32 bitzero;
764  int32 bitmax;
765  int32 arrayzero;
766  int32 arraymax;
767  int32 array_elems;
768  int32 idx;
769  VarEntry *var = vl_lookup_variable(name);
770  BitmapArray *bmarray = (BitmapArray *) var->obj;
771 
772  bitzero = deserialise_int4(p_stream);
773  bitmax = deserialise_int4(p_stream);
774  arrayzero = deserialise_int4(p_stream);
775  arraymax = deserialise_int4(p_stream);
776 
777  if (bmarray) {
778  if (bmarray->type != OBJ_BITMAP_ARRAY) {
779  vl_type_mismatch(name, OBJ_BITMAP_ARRAY, bmarray->type);
780  }
781  }
782  /* Check size and re-allocate memory if needed */
783  vl_NewBitmapArray(&bmarray, var->shared, arrayzero,
784  arraymax, bitzero, bitmax);
785  var->obj = (Object *) bmarray;
786 
787  array_elems = 1 + arraymax - arrayzero;
788  for (idx = 0; idx < array_elems; idx++) {
789  deserialise_one_bitmap(&(bmarray->bitmap[idx]), "",
790  var->shared, p_stream);
791 
792  }
793  return var;
794 }
795 
796 
797 /**
798  * Calculate the size needed for a base64 stream to contain all of the
799  * bitmaps in a bitmap hash including their keys.
800  *
801  * @param bmhash Pointer to the variable to be serialised
802  * @param bitset_size The size, in bytes, of each bitset in the bitmap
803  * hash.
804  * @return Number of bytes required to contain all of the bitmaps and
805  * keys in the bitmap_hash
806  */
807 static int
808 sizeof_bitmaps_in_hash(BitmapHash *bmhash, int bitset_size)
809 {
810  VarEntry *var = NULL;
811  int size = 1; /* Allow for final end of stream indicator */
812  while ((var = vl_NextHashEntry(bmhash->hash, var))) {
813  /* 1 byte below for record/end flag to precede each bitmap in
814  * the hash */
815  size += 1 + bitset_size + hdrlen(var->key);
816  }
817  return size;
818 }
819 
820 
821 /**
822  * Serialise a veil bitmap hash variable into a dynamically allocated
823  * string.
824  *
825  * @param bmhash Pointer to the variable to be serialised
826  * @param name The name of the variable
827  * @return Dynamically allocated string containing the serialised
828  * variable
829  */
830 static char *
831 serialise_bitmap_hash(BitmapHash *bmhash, char *name)
832 {
833  int bitset_elems = ARRAYELEMS(bmhash->bitzero, bmhash->bitmax);
834  int bitset_size = (INT32SIZE_B64 * 2) +
835  streamlen(sizeof(int32) * bitset_elems);
836  int all_bitmaps_size = sizeof_bitmaps_in_hash(bmhash, bitset_size);
837  int stream_len = hdrlen(name) + (INT32SIZE_B64 * 2) +
838  all_bitmaps_size + 1;
839  char *stream = palloc(stream_len * sizeof(char));
840  char *streamstart = stream;
841  VarEntry *var = NULL;
842 
843  serialise_char(&stream, BITMAP_HASH_HDR);
844  serialise_name(&stream, name);
845  serialise_int4(&stream, bmhash->bitzero);
846  serialise_int4(&stream, bmhash->bitmax);
847  while ((var = vl_NextHashEntry(bmhash->hash, var))) {
848  serialise_char(&stream, BITMAP_HASH_MORE);
849  serialise_name(&stream, var->key);
850  serialise_one_bitmap(&stream, (Bitmap *) var->obj);
851  }
852  serialise_char(&stream, BITMAP_HASH_DONE);
853 
854  return streamstart;
855 }
856 
857 /**
858  * De-serialise a veil bitmap hash variable.
859  *
860  * @param **p_stream Pointer into the stream currently being read.
861  * pointer is updated to point to the next free slot in the stream after
862  * reading the stream
863  * @return Pointer to the variable created or updated from the stream.
864  */
865 static VarEntry *
866 deserialise_bitmap_hash(char **p_stream)
867 {
868  char *name = deserialise_name(p_stream);
869  char *hashkey;
870  int32 bitzero;
871  int32 bitmax;
872  VarEntry *var = vl_lookup_variable(name);
873  BitmapHash *bmhash = (BitmapHash *) var->obj;
874  Bitmap *tmp_bitmap = NULL;
875  Bitmap *bitmap;
876 
877  bitzero = deserialise_int4(p_stream);
878  bitmax = deserialise_int4(p_stream);
879 
880  if (bmhash) {
881  if (bmhash->type != OBJ_BITMAP_HASH) {
882  vl_type_mismatch(name, OBJ_BITMAP_HASH, bmhash->type);
883  }
884  }
885  /* Check size and re-allocate memory if needed */
886  vl_NewBitmapHash(&bmhash, name, bitzero, bitmax);
887  var->obj = (Object *) bmhash;
888 
889  while (deserialise_char(p_stream) == BITMAP_HASH_MORE) {
890  hashkey = deserialise_name(p_stream);
891  deserialise_one_bitmap(&tmp_bitmap, "", var->shared, p_stream);
892  /* tmp_bitmap now contains a (dynamically allocated) bitmap
893  * Now we want to copy that into the bmhash. We don't worry
894  * about memory leaks here since this is allocated only once
895  * per call of this function, and the memory context will
896  * eventually be freed anyway.
897  */
898  bitmap = vl_AddBitmapToHash(bmhash, hashkey);
899  vl_BitmapUnion(bitmap, tmp_bitmap);
900  }
901  return var;
902 }
903 
904 /**
905  * Serialise a veil variable
906  *
907  * @param name The name of the variable to be serialised.
908  * @return Dynamically allocated string containing the serialised value.
909  */
910 extern char *
911 vl_serialise_var(char *name)
912 {
913  VarEntry *var;
914  char *result = NULL;
915 
916  var = vl_lookup_variable(name);
917  if (var && var->obj) {
918  switch (var->obj->type) {
919  case OBJ_INT4:
920  result = serialise_int4var((Int4Var *)var->obj, name);
921  break;
922  case OBJ_INT4_ARRAY:
923  result = serialise_int4array((Int4Array *)var->obj, name);
924  break;
925  case OBJ_RANGE:
926  result = serialise_range((Range *)var->obj, name);
927  break;
928  case OBJ_BITMAP:
929  result = serialise_bitmap((Bitmap *)var->obj, name);
930  break;
931  case OBJ_BITMAP_ARRAY:
932  result = serialise_bitmap_array((BitmapArray *)var->obj, name);
933  break;
934  case OBJ_BITMAP_HASH:
935  result = serialise_bitmap_hash((BitmapHash *)var->obj, name);
936  break;
937  default:
938  ereport(ERROR,
939  (errcode(ERRCODE_INTERNAL_ERROR),
940  errmsg("Unsupported type for variable serialisation"),
941  errdetail("Cannot serialise objects of type %d.",
942  (int32) var->obj->type)));
943 
944  }
945  }
946  return result;
947 }
948 
949 /**
950  * De-serialise the next veil variable from *p_stream
951  *
952  * @param **p_stream Pointer into the stream currently being read.
953  * pointer is updated to point to the next free slot in the stream after
954  * reading the stream
955  * @return The deserialised variable.
956  */
957 extern VarEntry *
958 vl_deserialise_next(char **p_stream)
959 {
960  VarEntry *var = NULL;
961  if ((**p_stream) != '\0') {
962  char type = deserialise_char(p_stream);
963  switch (type){
964  case INT4VAR_HDR: var = deserialise_int4var(p_stream);
965  break;
966  case INT4_ARRAY_HDR: var = deserialise_int4array(p_stream);
967  break;
968  case RANGE_HDR: var = deserialise_range(p_stream);
969  break;
970  case BITMAP_HDR: var = deserialise_bitmap(p_stream);
971  break;
972  case BITMAP_ARRAY_HDR: var = deserialise_bitmap_array(p_stream);
973  break;
974  case BITMAP_HASH_HDR: var = deserialise_bitmap_hash(p_stream);
975  break;
976  default:
977  ereport(ERROR,
978  (errcode(ERRCODE_INTERNAL_ERROR),
979  errmsg("Unsupported type for variable deserialisation"),
980  errdetail("Cannot deserialise objects of type %c.",
981  type)));
982 
983  }
984  }
985  return var;
986 }
987 
988 /**
989  * De-serialise a base64 string containing, possibly many, derialised
990  * veil variables.
991  *
992  * @param **p_stream Pointer into the stream currently being read.
993  * @return A count of the number of variables that have been de-serialised.
994  */
995 extern int32
996 vl_deserialise(char **p_stream)
997 {
998  int count = 0;
999  while ((**p_stream) != '\0') {
1000  (void) vl_deserialise_next(p_stream);
1001  count++;
1002  }
1003  return count;
1004 }
Subtype of Object for storing arrays of integers.
Subtype of Object for storing bitmaps.
static VarEntry * deserialise_bitmap_hash(char **p_stream)
De-serialise a veil bitmap hash variable.
int32 value
the integer value of the variable
void vl_NewBitmap(Bitmap **p_bitmap, bool shared, int32 min, int32 max)
Return a newly initialised (empty) Bitmap.
Definition: veil_bitmap.c:95
int32 bitzero
The index of the lowest bit each bitmap can store.
int32 bitmax
The index of the highest bit each bitmap can store.
Subtype of Object for storing simple int4 values.
ObjType type
This must have the value OBJ_BITMAP.
void vl_BitmapUnion(Bitmap *target, Bitmap *source)
Create the union of two bitmaps, updating the first with the result.
Definition: veil_bitmap.c:232
static char * serialise_bitmap_array(BitmapArray *bmarray, char *name)
Serialise a veil bitmap array variable into a dynamically allocated string.
ObjType type
This must have the value OBJ_BITMAP_ARRAY.
static int32 deserialise_int4(char **p_stream)
De-serialise an int4 value from a base64 character stream.
ObjType type
This must have the value OBJ_RANGE.
int32 bitmax
The index of the highest bit the bitmap can store.
static char deserialise_char(char **p_stream)
De-serialise a character value.
static int hdrlen(char *name)
Return the length of the header part of a serialised data stream for the given named variable...
ObjType type
This must have the value OBJ_INT4_ARRAY.
VarEntry * vl_lookup_variable(char *name)
Lookup a variable by name, creating it as as a session variable if it does not already exist...
int32 vl_deserialise(char **p_stream)
De-serialise a base64 string containing, possibly many, derialised veil variables.
static VarEntry * deserialise_range(char **p_stream)
De-serialise a veil range variable.
#define ARRAYELEMS(min, max)
Gives the number of array elements in a Bitmap that runs from element min to element max...
static void serialise_char(char **p_stream, char value)
Serialise a character value into *p_stream.
static char * deserialise_name(char **p_stream)
De-serialise a string returning a dynamically allocated string.
static void deserialise_one_bitmap(Bitmap **p_bitmap, char *name, bool shared, char **p_stream)
De-serialise a single bitmap into a veil bitmap array or bitmap hash.
static VarEntry * deserialise_bitmap(char **p_stream)
De-serialise a veil bitmap variable.
void vl_NewBitmapHash(BitmapHash **p_bmhash, char *name, int32 bitzero, int32 bitmax)
Return a newly initialised (empty) BitmapHash.
Definition: veil_bitmap.c:499
int32 arrayzero
The index of array element zero: the index of the lowest numbered bitmap in the array.
int32 arraymax
The index of the lowest numbered bitmap in the array.
static int sizeof_bitmaps_in_hash(BitmapHash *bmhash, int bitset_size)
Calculate the size needed for a base64 stream to contain all of the bitmaps in a bitmap hash includin...
char * vl_serialise_var(char *name)
Serialise a veil variable.
Provide definitions for all non-local C-callable Veil functions.
static char * serialise_bitmap(Bitmap *bitmap, char *name)
Serialise a veil bitmap variable into a dynamically allocated string.
bool shared
Whether this is a shared variable.
General purpose object-type.
Provides version information for veil.
int32 bitzero
The index of the lowest bit the bitmap can store.
Subtype of Object for storing bitmap hashes.
void vl_type_mismatch(char *name, ObjType expected, ObjType got)
Report, by raising an error, a type mismatch between the expected and actual type of a VarEntry varia...
static VarEntry * deserialise_int4var(char **p_stream)
De-serialise a veil integer variable.
HTAB * hash
Pointer to the (Postgresql dynahash) hash table.
A Veil variable.
static char * serialise_int4var(Int4Var *var, char *name)
Serialise a veil integer variable into a dynamically allocated string.
bm_int bitset[1]
Element zero of the array of int4 values comprising the bitmap.
Bitmap * vl_AddBitmapToHash(BitmapHash *bmhash, char *hashelem)
Create a newly allocated empty Bitmap to a BitmapHash.
Definition: veil_bitmap.c:588
VarEntry * vl_NextHashEntry(HTAB *hash, VarEntry *prev)
Utility function for scanning the hash table of a BitmapHash.
Definition: veil_bitmap.c:474
Int4Array * vl_NewInt4Array(Int4Array *current, bool shared, int32 min, int32 max)
Return a newly initialised (zeroed) Int4Array.
static int streamlen(int bytes)
Return the length of a base64 encoded stream for a binary stream of ::bytes length.
static char * serialise_int4array(Int4Array *array, char *name)
Serialise a veil integer array variable into a dynamically allocated string.
int32 arrayzero
The index of array element zero: the index of the lowest numbered bitmap in the array.
static void serialise_name(char **p_stream, char *name)
Serialise a string (containing a name) into *p_stream.
Subtype of Object for storing range values.
int32 max
Upper limit for range.
void vl_NewBitmapArray(BitmapArray **p_bmarray, bool shared, int32 arrayzero, int32 arraymax, int32 bitzero, int32 bitmax)
Return a newly initialised (empty) BitmapArray.
Definition: veil_bitmap.c:368
int32 bitzero
The index of the lowest bit each bitmap can store.
static char * serialise_range(Range *range, char *name)
Serialise a veil range variable into a dynamically allocated string.
static void serialise_one_bitmap(char **p_stream, Bitmap *bitmap)
Serialise a single bitmap from a veil bitmap array or bitmap hash.
ObjType type
Identifies the type of the object.
static bool deserialise_bool(char **p_stream)
De-serialise a boolean value.
int32 bitmax
The index of the highest bit each bitmap can store.
int32 arraymax
The index of the lowest numbered bitmap in the array.
static void serialise_stream(char **p_stream, int32 bytes, char *instream)
Serialise a binary stream as a base64 stream into *p_stream.
ObjType type
This must have the value OBJ_BITMAP_HASH.
Object * obj
Pointer to the contents of the variable.
static char * serialise_bitmap_hash(BitmapHash *bmhash, char *name)
Serialise a veil bitmap hash variable into a dynamically allocated string.
Subtype of Object for storing bitmap arrays.
Int4Var * vl_NewInt4(bool shared)
Create a new session or shared Int4Var object.
ObjType type
This must have the value OBJ_INT4.
int32 min
Lower limit for range.
static void serialise_bool(char **p_stream, bool value)
Serialise a boolean value into *p_stream.
bool isnull
if true, the value is null
int32 array[0]
Element zero of the array of integers.
Bitmap * bitmap[1]
Element zero of the array of Bitmap pointers comprising the array.
static VarEntry * deserialise_int4array(char **p_stream)
De-serialise a veil integer array variable.
static VarEntry * deserialise_bitmap_array(char **p_stream)
De-serialise a veil bitmap array variable.
static void serialise_int4(char **p_stream, int32 value)
Serialise an int4 value as a base64 stream (truncated to save a byte) into *p_stream.
VarEntry * vl_deserialise_next(char **p_stream)
De-serialise the next veil variable from *p_stream.
char key[60]
String containing variable name.
static void deserialise_stream(char **p_stream, int32 bytes, char *outstream)
De-serialise a binary stream.
Range * vl_NewRange(bool shared)
Create a new session or shared Range object.
Define all Veil public datatypes.