1 2 /* 3 * record.c 4 * Type handler for the record/composite data type. 5 * 6 * Copyright (c) 2009 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 } |