aboutsummaryrefslogtreecommitdiff
path: root/src/pq/pq_result_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pq/pq_result_helper.c')
-rw-r--r--src/pq/pq_result_helper.c529
1 files changed, 529 insertions, 0 deletions
diff --git a/src/pq/pq_result_helper.c b/src/pq/pq_result_helper.c
index f945c5d2e..808445b3b 100644
--- a/src/pq/pq_result_helper.c
+++ b/src/pq/pq_result_helper.c
@@ -22,9 +22,12 @@
22 * @brief functions to extract result values 22 * @brief functions to extract result values
23 * @author Christian Grothoff 23 * @author Christian Grothoff
24 */ 24 */
25#include "gnunet_common.h"
26#include "gnunet_time_lib.h"
25#include "platform.h" 27#include "platform.h"
26#include "gnunet_util_lib.h" 28#include "gnunet_util_lib.h"
27#include "gnunet_pq_lib.h" 29#include "gnunet_pq_lib.h"
30#include "pq.h"
28 31
29 32
30struct GNUNET_PQ_ResultSpec 33struct GNUNET_PQ_ResultSpec
@@ -1117,4 +1120,530 @@ GNUNET_PQ_result_spec_uint64 (const char *name,
1117} 1120}
1118 1121
1119 1122
1123/**
1124 * Closure for the array result specifications. Contains type information
1125 * for the generic parser extract_array_generic and out-pointers for the results.
1126 */
1127struct array_result_cls
1128{
1129 /* Oid of the expected type, must match the oid in the header of the PQResult struct */
1130 Oid oid;
1131
1132 /* Target type */
1133 enum array_types typ;
1134
1135 /* If not 0, defines the expected size of each entry */
1136 size_t same_size;
1137
1138 /* Out-pointer to write the number of elements in the array */
1139 size_t *num;
1140
1141 /* Out-pointer. If @a typ is array_of_byte and @a same_size is 0,
1142 * allocate and put the array of @a num sizes here. NULL otherwise */
1143 size_t **sizes;
1144};
1145
1146
1147/**
1148 * Extract data from a Postgres database @a result as array of a specific type
1149 * from row @a row. The type information and optionally additional
1150 * out-parameters are given in @a cls which is of type array_result_cls.
1151 *
1152 * @param cls closure of type array_result_cls
1153 * @param result where to extract data from
1154 * @param row row to extract data from
1155 * @param fname name (or prefix) of the fields to extract from
1156 * @param[in,out] dst_size where to store size of result, may be NULL
1157 * @param[out] dst where to store the result
1158 * @return
1159 * #GNUNET_YES if all results could be extracted
1160 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
1161 */
1162static enum GNUNET_GenericReturnValue
1163extract_array_generic (
1164 void *cls,
1165 PGresult *result,
1166 int row,
1167 const char *fname,
1168 size_t *dst_size,
1169 void *dst)
1170{
1171 const struct array_result_cls *info = cls;
1172 int data_sz;
1173 char *data;
1174 void *out = NULL;
1175 struct pq_array_header header;
1176 int col_num;
1177
1178 GNUNET_assert (NULL != dst);
1179 *((void **) dst) = NULL;
1180
1181 #define FAIL_IF(cond) \
1182 do { \
1183 if ((cond)) \
1184 { \
1185 GNUNET_break (! (cond)); \
1186 goto FAIL; \
1187 } \
1188 } while(0)
1189
1190 col_num = PQfnumber (result, fname);
1191 FAIL_IF (0 > col_num);
1192
1193 data_sz = PQgetlength (result, row, col_num);
1194 FAIL_IF (0 > data_sz);
1195 FAIL_IF (sizeof(header) > (size_t) data_sz);
1196
1197 data = PQgetvalue (result, row, col_num);
1198 FAIL_IF (NULL == data);
1199
1200 {
1201 struct pq_array_header *h =
1202 (struct pq_array_header *) data;
1203
1204 header.ndim = ntohl (h->ndim);
1205 header.has_null = ntohl (h->has_null);
1206 header.oid = ntohl (h->oid);
1207 header.dim = ntohl (h->dim);
1208 header.lbound = ntohl (h->lbound);
1209
1210 FAIL_IF (1 != header.ndim);
1211 FAIL_IF ((0 > header.dim) || (INT_MAX == header.dim));
1212 FAIL_IF (0 != header.has_null);
1213 FAIL_IF (1 != header.lbound);
1214 FAIL_IF (info->oid != header.oid);
1215 }
1216
1217 *info->num = header.dim;
1218 switch (info->typ)
1219 {
1220 case array_of_bool:
1221 if (NULL != dst_size)
1222 *dst_size = sizeof(bool) * (*info->num);
1223 out = GNUNET_new_array (*info->num, bool);
1224 break;
1225 case array_of_uint16:
1226 if (NULL != dst_size)
1227 *dst_size = sizeof(uint16_t) * (*info->num);
1228 out = GNUNET_new_array (*info->num, uint16_t);
1229 break;
1230 case array_of_uint32:
1231 if (NULL != dst_size)
1232 *dst_size = sizeof(uint32_t) * (*info->num);
1233 out = GNUNET_new_array (*info->num, uint32_t);
1234 break;
1235 case array_of_uint64:
1236 if (NULL != dst_size)
1237 *dst_size = sizeof(uint64_t) * (*info->num);
1238 out = GNUNET_new_array (*info->num, uint64_t);
1239 break;
1240 case array_of_abs_time:
1241 if (NULL != dst_size)
1242 *dst_size = sizeof(struct GNUNET_TIME_Absolute) * (*info->num);
1243 out = GNUNET_new_array (*info->num, struct GNUNET_TIME_Absolute);
1244 break;
1245 case array_of_rel_time:
1246 if (NULL != dst_size)
1247 *dst_size = sizeof(struct GNUNET_TIME_Relative) * (*info->num);
1248 out = GNUNET_new_array (*info->num, struct GNUNET_TIME_Relative);
1249 break;
1250 case array_of_timestamp:
1251 if (NULL != dst_size)
1252 *dst_size = sizeof(struct GNUNET_TIME_Timestamp) * (*info->num);
1253 out = GNUNET_new_array (*info->num, struct GNUNET_TIME_Timestamp);
1254 break;
1255 case array_of_byte:
1256 if (0 == info->same_size)
1257 *info->sizes = GNUNET_new_array (header.dim, size_t);
1258 /* fallthrough */
1259 case array_of_string:
1260 {
1261 size_t total = 0;
1262 bool is_string = (array_of_string == info->typ);
1263
1264 /* first, calculate total size required for allocation */
1265 {
1266 char *ptr = data + sizeof(header);
1267 for (uint32_t i = 0; i < header.dim; i++)
1268 {
1269 uint32_t sz;
1270
1271 sz = ntohl (*(uint32_t *) ptr);
1272 sz += is_string ? 1 : 0;
1273 total += sz;
1274 ptr += sizeof(uint32_t);
1275 ptr += sz;
1276
1277 if ((! is_string) &&
1278 (0 == info->same_size))
1279 (*info->sizes)[i] = sz;
1280
1281 FAIL_IF ((0 != info->same_size) &&
1282 (sz != info->same_size));
1283 FAIL_IF (total < sz);
1284 }
1285 }
1286
1287 if (NULL != dst_size)
1288 *dst_size = total;
1289
1290 if (0 < total)
1291 out = GNUNET_malloc (total);
1292
1293 break;
1294 }
1295 default:
1296 FAIL_IF (1 != 0);
1297 }
1298
1299 *((void **) dst) = out;
1300
1301 /* copy data */
1302 {
1303 char *in = data + sizeof(header);
1304
1305 for (uint32_t i = 0; i < header.dim; i++)
1306 {
1307 size_t sz = ntohl (*(uint32_t *) in);
1308 in += sizeof(uint32_t);
1309
1310 switch (info->typ)
1311 {
1312 case array_of_bool:
1313 FAIL_IF (sz != sizeof(bool));
1314 *(bool *) out = *(bool *) in;
1315 break;
1316 case array_of_uint16:
1317 FAIL_IF (sz != sizeof(uint16_t));
1318 *(uint16_t *) out = ntohs (*(uint16_t *) in);
1319 break;
1320 case array_of_uint32:
1321 FAIL_IF (sz != sizeof(uint32_t));
1322 *(uint32_t *) out = ntohl (*(uint32_t *) in);
1323 break;
1324 case array_of_uint64:
1325 FAIL_IF (sz != sizeof(uint64_t));
1326 *(uint64_t *) out = GNUNET_ntohll (*(uint64_t *) in);
1327 break;
1328 case array_of_abs_time:
1329 case array_of_rel_time:
1330 case array_of_timestamp:
1331 FAIL_IF (sz != sizeof(uint64_t));
1332 {
1333 uint64_t val = GNUNET_ntohll (*(uint64_t *) in);
1334 switch (info->typ)
1335 {
1336 case array_of_abs_time:
1337 ((struct GNUNET_TIME_Absolute *) out)->abs_value_us = val;
1338 break;
1339 case array_of_rel_time:
1340 ((struct GNUNET_TIME_Relative *) out)->rel_value_us = val;
1341 break;
1342 case array_of_timestamp:
1343 ((struct GNUNET_TIME_Timestamp *) out)->abs_time.abs_value_us = val;
1344 break;
1345 default:
1346 FAIL_IF (1 != 0);
1347 }
1348 }
1349 break;
1350 case array_of_byte:
1351 case array_of_string:
1352 GNUNET_memcpy (out, in, sz);
1353 break;
1354 default:
1355 FAIL_IF (1 != 0);
1356 }
1357
1358 in += sz;
1359 out += sz;
1360 out += (array_of_string == info->typ) ? 1 : 0;
1361 }
1362 }
1363
1364 return GNUNET_OK;
1365
1366FAIL:
1367 GNUNET_free (*(void **) dst);
1368 return GNUNET_SYSERR;
1369 #undef FAIL_IF
1370}
1371
1372
1373/**
1374 * Cleanup of the data and closure of an array spec.
1375 */
1376static void
1377array_cleanup (void *cls,
1378 void *rd)
1379{
1380
1381 struct array_result_cls *info = cls;
1382 void **dst = rd;
1383
1384 if ((array_of_byte == info->typ) &&
1385 (0 == info->same_size) &&
1386 (NULL != info->sizes))
1387 GNUNET_free (*(info->sizes));
1388
1389 GNUNET_free (cls);
1390 GNUNET_free (*dst);
1391 *dst = NULL;
1392}
1393
1394
1395struct GNUNET_PQ_ResultSpec
1396GNUNET_PQ_result_spec_array_bool (
1397 const struct GNUNET_PQ_Context *db,
1398 const char *name,
1399 size_t *num,
1400 bool **dst)
1401{
1402 struct array_result_cls *info =
1403 GNUNET_new (struct array_result_cls);
1404
1405 info->num = num;
1406 info->typ = array_of_bool;
1407 info->oid = db->oids[GNUNET_PQ_DATATYPE_BOOL];
1408
1409 struct GNUNET_PQ_ResultSpec res = {
1410 .conv = extract_array_generic,
1411 .cleaner = array_cleanup,
1412 .dst = (void *) dst,
1413 .fname = name,
1414 .cls = info
1415 };
1416 return res;
1417}
1418
1419
1420struct GNUNET_PQ_ResultSpec
1421GNUNET_PQ_result_spec_array_uint16 (
1422 const struct GNUNET_PQ_Context *db,
1423 const char *name,
1424 size_t *num,
1425 uint16_t **dst)
1426{
1427 struct array_result_cls *info =
1428 GNUNET_new (struct array_result_cls);
1429
1430 info->num = num;
1431 info->typ = array_of_uint16;
1432 info->oid = db->oids[GNUNET_PQ_DATATYPE_INT2];
1433
1434 struct GNUNET_PQ_ResultSpec res = {
1435 .conv = extract_array_generic,
1436 .cleaner = array_cleanup,
1437 .dst = (void *) dst,
1438 .fname = name,
1439 .cls = info
1440 };
1441 return res;
1442}
1443
1444
1445struct GNUNET_PQ_ResultSpec
1446GNUNET_PQ_result_spec_array_uint32 (
1447 const struct GNUNET_PQ_Context *db,
1448 const char *name,
1449 size_t *num,
1450 uint32_t **dst)
1451{
1452 struct array_result_cls *info =
1453 GNUNET_new (struct array_result_cls);
1454
1455 info->num = num;
1456 info->typ = array_of_uint32;
1457 info->oid = db->oids[GNUNET_PQ_DATATYPE_INT4];
1458
1459 struct GNUNET_PQ_ResultSpec res = {
1460 .conv = extract_array_generic,
1461 .cleaner = array_cleanup,
1462 .dst = (void *) dst,
1463 .fname = name,
1464 .cls = info
1465 };
1466 return res;
1467}
1468
1469
1470struct GNUNET_PQ_ResultSpec
1471GNUNET_PQ_result_spec_array_uint64 (
1472 const struct GNUNET_PQ_Context *db,
1473 const char *name,
1474 size_t *num,
1475 uint64_t **dst)
1476{
1477 struct array_result_cls *info =
1478 GNUNET_new (struct array_result_cls);
1479
1480 info->num = num;
1481 info->typ = array_of_uint64;
1482 info->oid = db->oids[GNUNET_PQ_DATATYPE_INT8];
1483
1484 struct GNUNET_PQ_ResultSpec res = {
1485 .conv = extract_array_generic,
1486 .cleaner = array_cleanup,
1487 .dst = (void *) dst,
1488 .fname = name,
1489 .cls = info
1490 };
1491 return res;
1492}
1493
1494
1495struct GNUNET_PQ_ResultSpec
1496GNUNET_PQ_result_spec_array_abs_time (
1497 const struct GNUNET_PQ_Context *db,
1498 const char *name,
1499 size_t *num,
1500 struct GNUNET_TIME_Absolute **dst)
1501{
1502 struct array_result_cls *info =
1503 GNUNET_new (struct array_result_cls);
1504
1505 info->num = num;
1506 info->typ = array_of_abs_time;
1507 info->oid = db->oids[GNUNET_PQ_DATATYPE_INT8];
1508
1509 struct GNUNET_PQ_ResultSpec res = {
1510 .conv = extract_array_generic,
1511 .cleaner = array_cleanup,
1512 .dst = (void *) dst,
1513 .fname = name,
1514 .cls = info
1515 };
1516 return res;
1517}
1518
1519
1520struct GNUNET_PQ_ResultSpec
1521GNUNET_PQ_result_spec_array_rel_time (
1522 const struct GNUNET_PQ_Context *db,
1523 const char *name,
1524 size_t *num,
1525 struct GNUNET_TIME_Relative **dst)
1526{
1527 struct array_result_cls *info =
1528 GNUNET_new (struct array_result_cls);
1529
1530 info->num = num;
1531 info->typ = array_of_rel_time;
1532 info->oid = db->oids[GNUNET_PQ_DATATYPE_INT8];
1533
1534 struct GNUNET_PQ_ResultSpec res = {
1535 .conv = extract_array_generic,
1536 .cleaner = array_cleanup,
1537 .dst = (void *) dst,
1538 .fname = name,
1539 .cls = info
1540 };
1541 return res;
1542}
1543
1544
1545struct GNUNET_PQ_ResultSpec
1546GNUNET_PQ_result_spec_array_timestamp (
1547 const struct GNUNET_PQ_Context *db,
1548 const char *name,
1549 size_t *num,
1550 struct GNUNET_TIME_Timestamp **dst)
1551{
1552 struct array_result_cls *info =
1553 GNUNET_new (struct array_result_cls);
1554
1555 info->num = num;
1556 info->typ = array_of_timestamp;
1557 info->oid = db->oids[GNUNET_PQ_DATATYPE_INT8];
1558
1559 struct GNUNET_PQ_ResultSpec res = {
1560 .conv = extract_array_generic,
1561 .cleaner = array_cleanup,
1562 .dst = (void *) dst,
1563 .fname = name,
1564 .cls = info
1565 };
1566 return res;
1567}
1568
1569
1570struct GNUNET_PQ_ResultSpec
1571GNUNET_PQ_result_spec_array_variable_size (
1572 const struct GNUNET_PQ_Context *db,
1573 const char *name,
1574 size_t *num,
1575 size_t **sizes,
1576 void **dst)
1577{
1578 struct array_result_cls *info =
1579 GNUNET_new (struct array_result_cls);
1580
1581 info->num = num;
1582 info->sizes = sizes;
1583 info->typ = array_of_byte;
1584 info->oid = db->oids[GNUNET_PQ_DATATYPE_BYTEA];
1585
1586 struct GNUNET_PQ_ResultSpec res = {
1587 .conv = extract_array_generic,
1588 .cleaner = array_cleanup,
1589 .dst = (void *) dst,
1590 .fname = name,
1591 .cls = info
1592 };
1593 return res;
1594}
1595
1596
1597struct GNUNET_PQ_ResultSpec
1598GNUNET_PQ_result_spec_array_fixed_size (
1599 const struct GNUNET_PQ_Context *db,
1600 const char *name,
1601 size_t size,
1602 size_t *num,
1603 void **dst)
1604{
1605 struct array_result_cls *info =
1606 GNUNET_new (struct array_result_cls);
1607
1608 info->num = num;
1609 info->same_size = size;
1610 info->typ = array_of_byte;
1611 info->oid = db->oids[GNUNET_PQ_DATATYPE_BYTEA];
1612
1613 struct GNUNET_PQ_ResultSpec res = {
1614 .conv = extract_array_generic,
1615 .cleaner = array_cleanup,
1616 .dst = (void *) dst,
1617 .fname = name,
1618 .cls = info
1619 };
1620 return res;
1621}
1622
1623
1624struct GNUNET_PQ_ResultSpec
1625GNUNET_PQ_result_spec_array_string (
1626 const struct GNUNET_PQ_Context *db,
1627 const char *name,
1628 size_t *num,
1629 char **dst)
1630{
1631 struct array_result_cls *info =
1632 GNUNET_new (struct array_result_cls);
1633
1634 info->num = num;
1635 info->typ = array_of_string;
1636 info->oid = db->oids[GNUNET_PQ_DATATYPE_VARCHAR];
1637
1638 struct GNUNET_PQ_ResultSpec res = {
1639 .conv = extract_array_generic,
1640 .cleaner = array_cleanup,
1641 .dst = (void *) dst,
1642 .fname = name,
1643 .cls = info
1644 };
1645 return res;
1646}
1647
1648
1120/* end of pq_result_helper.c */ 1649/* end of pq_result_helper.c */