libpqtypes - record.c

Home Page

array.c
datetime.c
error.c
events.c
exec.c
geo.c
getaddrinfo.h
handler.c
libpqtypes-int.h
libpqtypes.h
misc.c
network.c
numerics.c
param.c
port.c
record.c
regression-test.c
spec.c
utils.c
varlena.c
  1 
  2 /*
  3  * record.c
  4  *   Type handler for the record/composite data type.
  5  *
  6  * Copyright (c) 2011 eSilo, LLC. All rights reserved.
  7  * This is free software; see the source for copying conditions.  There is
  8  * NO warranty; not even for MERCHANTABILITY or  FITNESS FOR A  PARTICULAR
  9  * PURPOSE.
 10  */
 11 
 12 #include "libpqtypes-int.h"
 13 
 14 int
 15 pqt_put_record(PGtypeArgs *args)
 16 {
 17   int i;
 18   int len;
 19   char *out;
 20   PGparam *param = va_arg(args->ap, PGparam *);
 21 
 22   PUTNULLCHK(args, param);
 23 
 24   /* watch for invalidation issues */
 25   if (param->vcnt > args->typhandler->nattrs)
 26     return args->errorf(args,
 27       "param value count is %d but server says it's %d",
 28       param->vcnt, args->typhandler->nattrs);
 29 
 30   /* Auto-fill the remaining fields with SQL NULLs.  This feature was
 31    * added because it was needed (by eSilo).  We had a few cases where
 32    * we needed to append new fields to existing composites but wanted
 33    * to maintain backwards compatibility ... so some_func(mycomposite)
 34    * would continue to work even for older versions unaware of the
 35    * new composite fields.  I guess for some this is unwanted behavior,
 36    * but I think the cases for it are much more common.
 37    */
 38   if (param->vcnt < args->typhandler->nattrs)
 39   {
 40     int nattrs = args->typhandler->nattrs - param->vcnt;
 41     for (i=0; i < nattrs; i++)
 42       pqt_putparam(param, NULL, 0, 0, BINARYFMT,
 43         args->typhandler->attDescs[param->vcnt].attoid);
 44   }
 45 
 46   /* column count, 4-byte integer */
 47   len = 4;
 48 
 49   /* determine total byte count to ensure args->put.out is large enough */
 50   for (i=0; i < param->vcnt; i++)
 51   {
 52     len += (4 + 4); /* oid + len */
 53 
 54     if (param->vals[i].datal > 0)
 55       len += param->vals[i].datal;
 56   }
 57 
 58   /* ensure out buffer is large enough */
 59   if (args->put.expandBuffer(args, len) == -1)
 60     return -1;
 61 
 62   out = args->put.out;
 63 
 64   /* write column count */
 65   pqt_buf_putint4(out, param->vcnt);
 66   out += 4;
 67 
 68   for (i=0; i < param->vcnt; i++)
 69   {
 70     if (param->vals[i].format == 0)
 71       return args->errorf(args,
 72         "Cannot put composite attributes in text format");
 73 
 74     if (param->vals[i].datal == NULL_LEN)
 75       param->vals[i].oid = args->typhandler->attDescs[i].attoid;
 76 
 77     /* watch for invalidation issues */
 78     if (param->vals[i].oid != args->typhandler->attDescs[i].attoid)
 79       return args->errorf(args,
 80         "param value OID is %u but server says it's %u",
 81         param->vals[i].oid, args->typhandler->attDescs[i].attoid);
 82 
 83     /* write column oid */
 84     pqt_buf_putint4(out, param->vals[i].oid);
 85     out += 4;
 86 
 87     /* write column data length */
 88     pqt_buf_putint4(out, param->vals[i].datal);
 89     out += 4;
 90 
 91     /* write the column data */
 92     if (param->vals[i].data && param->vals[i].datal > 0)
 93     {
 94       memcpy(out, param->vals[i].data, param->vals[i].datal);
 95       out += param->vals[i].datal;
 96     }
 97   }
 98 
 99   return len;
100 }
101 
102 int
103 pqt_get_record(PGtypeArgs *args)
104 {
105   int i;
106   int nattrs;
107   int vlen;
108   Oid server_oid;
109   DECLVALUE(args);
110   PGresult *res;
111   PGresult **resultp = va_arg(args->ap, PGresult **);
112 
113   CHKGETVALS(args, resultp);
114 
115   if (args->format == TEXTFMT)
116     return args->errorf(args, "record does not support text results");
117 
118   /* get record column count, numAttributes */
119   nattrs = pqt_buf_getint4(value);
120   value += 4;
121 
122   /* watch for invalidation issues */
123   if (args->typhandler->nattrs != nattrs)
124     return args->errorf(args,
125       "type handler attribute count is %d but server says it's %d",
126       args->typhandler->nattrs, nattrs);
127 
128   if (!(res = pqt_copyresult(args, nattrs)))
129     RERR_MEM(args);
130 
131   for (i=0; i < nattrs; i++)
132   {
133     /* watch for invalidation issues */
134     server_oid = (Oid) pqt_buf_getint4(value);
135     if (server_oid != args->typhandler->attDescs[i].attoid)
136     {
137       args->errorf(args,
138         "type handler attribute OID is %u but server says it's %u",
139         args->typhandler->attDescs[i].attoid, server_oid);
140       PQclear(res);
141       return -1;
142     }
143 
144     /* move past Oid */
145     value += 4;
146 
147     /* get value length */
148     vlen = pqt_buf_getint4(value);
149     value += 4;
150 
151     if (!PQsetvalue(res, 0, i, value, vlen))
152     {
153       PQclear(res);
154       return -1;
155     }
156 
157     if (vlen > 0)
158       value += vlen;
159   }
160 
161   *resultp = res;
162   return 0;
163 }