pg_query 2.0.1 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +220 -114
  3. data/README.md +12 -0
  4. data/Rakefile +6 -21
  5. data/ext/pg_query/extconf.rb +5 -2
  6. data/ext/pg_query/include/c.h +12 -0
  7. data/ext/pg_query/include/executor/executor.h +6 -0
  8. data/ext/pg_query/include/nodes/execnodes.h +9 -6
  9. data/ext/pg_query/include/nodes/pathnodes.h +1 -1
  10. data/ext/pg_query/include/optimizer/paths.h +8 -0
  11. data/ext/pg_query/include/pg_config.h +10 -6
  12. data/ext/pg_query/include/pg_config_manual.h +7 -0
  13. data/ext/pg_query/include/pg_query.h +2 -2
  14. data/ext/pg_query/include/pg_query_outfuncs_defs.c +1 -0
  15. data/ext/pg_query/include/pg_query_readfuncs_defs.c +1 -0
  16. data/ext/pg_query/include/protobuf/pg_query.pb-c.h +472 -467
  17. data/ext/pg_query/include/protobuf-c/protobuf-c.h +7 -3
  18. data/ext/pg_query/include/protobuf-c.h +7 -3
  19. data/ext/pg_query/include/utils/array.h +1 -0
  20. data/ext/pg_query/include/utils/lsyscache.h +1 -0
  21. data/ext/pg_query/include/utils/probes.h +57 -57
  22. data/ext/pg_query/pg_query.pb-c.c +502 -487
  23. data/ext/pg_query/pg_query_deparse.c +33 -21
  24. data/ext/pg_query/pg_query_fingerprint.c +123 -33
  25. data/ext/pg_query/pg_query_fingerprint.h +3 -1
  26. data/ext/pg_query/pg_query_normalize.c +222 -61
  27. data/ext/pg_query/pg_query_parse_plpgsql.c +21 -1
  28. data/ext/pg_query/pg_query_ruby.sym +1 -0
  29. data/ext/pg_query/protobuf-c.c +34 -27
  30. data/ext/pg_query/src_backend_utils_mmgr_mcxt.c +36 -0
  31. data/ext/pg_query/src_common_hashfn.c +420 -0
  32. data/ext/pg_query/src_pl_plpgsql_src_pl_gram.c +1 -1
  33. data/lib/pg_query/filter_columns.rb +3 -1
  34. data/lib/pg_query/fingerprint.rb +1 -3
  35. data/lib/pg_query/parse.rb +101 -46
  36. data/lib/pg_query/pg_query_pb.rb +1385 -1383
  37. data/lib/pg_query/truncate.rb +12 -4
  38. data/lib/pg_query/version.rb +1 -1
  39. data/lib/pg_query.rb +0 -1
  40. metadata +8 -8
  41. data/lib/pg_query/json_field_names.rb +0 -1402
@@ -1,5 +1,6 @@
1
1
  #include "pg_query.h"
2
2
  #include "pg_query_internal.h"
3
+ #include "pg_query_fingerprint.h"
3
4
 
4
5
  #include "parser/parser.h"
5
6
  #include "parser/scanner.h"
@@ -14,6 +15,7 @@ typedef struct pgssLocationLen
14
15
  {
15
16
  int location; /* start offset in query text */
16
17
  int length; /* length in bytes, or -1 to ignore */
18
+ int param_id; /* Param id to use - if negative prefix, need to abs(..) and add highest_extern_param_id */
17
19
  } pgssLocationLen;
18
20
 
19
21
  /*
@@ -30,14 +32,32 @@ typedef struct pgssConstLocations
30
32
  /* Current number of valid entries in clocations array */
31
33
  int clocations_count;
32
34
 
35
+ /* highest Param id we have assigned, not yet taking into account external param refs */
36
+ int highest_normalize_param_id;
37
+
33
38
  /* highest Param id we've seen, in order to start normalization correctly */
34
39
  int highest_extern_param_id;
35
40
 
36
41
  /* query text */
37
42
  const char * query;
38
43
  int query_len;
44
+
45
+ /* optional recording of assigned or discovered param refs, only active if param_refs is not NULL */
46
+ int *param_refs;
47
+ int param_refs_buf_size;
48
+ int param_refs_count;
39
49
  } pgssConstLocations;
40
50
 
51
+ /*
52
+ * Intermediate working state struct to remember param refs for individual target list elements
53
+ */
54
+ typedef struct FpAndParamRefs
55
+ {
56
+ uint64_t fp;
57
+ int* param_refs;
58
+ int param_refs_count;
59
+ } FpAndParamRefs;
60
+
41
61
  /*
42
62
  * comp_location: comparator for qsorting pgssLocationLen structs by location
43
63
  */
@@ -230,7 +250,8 @@ generate_normalized_query(pgssConstLocations *jstate, int query_loc, int* query_
230
250
  for (i = 0; i < jstate->clocations_count; i++)
231
251
  {
232
252
  int off, /* Offset from start for cur tok */
233
- tok_len; /* Length (in bytes) of that tok */
253
+ tok_len, /* Length (in bytes) of that tok */
254
+ param_id; /* Param ID to be assigned */
234
255
 
235
256
  off = jstate->clocations[i].location;
236
257
  /* Adjust recorded location if we're dealing with partial string */
@@ -250,8 +271,10 @@ generate_normalized_query(pgssConstLocations *jstate, int query_loc, int* query_
250
271
  n_quer_loc += len_to_wrt;
251
272
 
252
273
  /* And insert a param symbol in place of the constant token */
253
- n_quer_loc += sprintf(norm_query + n_quer_loc, "$%d",
254
- i + 1 + jstate->highest_extern_param_id);
274
+ param_id = (jstate->clocations[i].param_id < 0) ?
275
+ jstate->highest_extern_param_id + abs(jstate->clocations[i].param_id) :
276
+ jstate->clocations[i].param_id;
277
+ n_quer_loc += sprintf(norm_query + n_quer_loc, "$%d", param_id);
255
278
 
256
279
  quer_loc = off + tok_len;
257
280
  last_off = off;
@@ -292,6 +315,18 @@ static void RecordConstLocation(pgssConstLocations *jstate, int location)
292
315
  jstate->clocations[jstate->clocations_count].location = location;
293
316
  /* initialize lengths to -1 to simplify fill_in_constant_lengths */
294
317
  jstate->clocations[jstate->clocations_count].length = -1;
318
+ /* by default we assume that we need a new param ref */
319
+ jstate->clocations[jstate->clocations_count].param_id = - jstate->highest_normalize_param_id;
320
+ jstate->highest_normalize_param_id++;
321
+ /* record param ref number if requested */
322
+ if (jstate->param_refs != NULL) {
323
+ jstate->param_refs[jstate->param_refs_count] = jstate->clocations[jstate->clocations_count].param_id;
324
+ jstate->param_refs_count++;
325
+ if (jstate->param_refs_count >= jstate->param_refs_buf_size) {
326
+ jstate->param_refs_buf_size *= 2;
327
+ jstate->param_refs = (int *) repalloc(jstate->param_refs, jstate->param_refs_buf_size * sizeof(int));
328
+ }
329
+ }
295
330
  jstate->clocations_count++;
296
331
  }
297
332
  }
@@ -303,69 +338,188 @@ static bool const_record_walker(Node *node, pgssConstLocations *jstate)
303
338
 
304
339
  if (node == NULL) return false;
305
340
 
306
- if (IsA(node, A_Const))
341
+ switch (nodeTag(node))
307
342
  {
308
- RecordConstLocation(jstate, castNode(A_Const, node)->location);
309
- }
310
- else if (IsA(node, ParamRef))
311
- {
312
- /* Track the highest ParamRef number */
313
- if (((ParamRef *) node)->number > jstate->highest_extern_param_id)
314
- jstate->highest_extern_param_id = castNode(ParamRef, node)->number;
315
- }
316
- else if (IsA(node, DefElem))
317
- {
318
- DefElem * defElem = (DefElem *) node;
319
- if (defElem->arg != NULL && IsA(defElem->arg, String)) {
320
- for (int i = defElem->location; i < jstate->query_len; i++) {
321
- if (jstate->query[i] == '\'')
322
- RecordConstLocation(jstate, i);
343
+ case T_A_Const:
344
+ RecordConstLocation(jstate, castNode(A_Const, node)->location);
345
+ break;
346
+ case T_ParamRef:
347
+ {
348
+ /* Track the highest ParamRef number */
349
+ if (((ParamRef *) node)->number > jstate->highest_extern_param_id)
350
+ jstate->highest_extern_param_id = castNode(ParamRef, node)->number;
351
+
352
+ if (jstate->param_refs != NULL) {
353
+ jstate->param_refs[jstate->param_refs_count] = ((ParamRef *) node)->number;
354
+ jstate->param_refs_count++;
355
+ if (jstate->param_refs_count >= jstate->param_refs_buf_size) {
356
+ jstate->param_refs_buf_size *= 2;
357
+ jstate->param_refs = (int *) repalloc(jstate->param_refs, jstate->param_refs_buf_size * sizeof(int));
358
+ }
359
+ }
323
360
  }
324
- }
325
- return const_record_walker((Node *) ((DefElem *) node)->arg, jstate);
326
- }
327
- else if (IsA(node, RawStmt))
328
- {
329
- return const_record_walker((Node *) ((RawStmt *) node)->stmt, jstate);
330
- }
331
- else if (IsA(node, VariableSetStmt))
332
- {
333
- return const_record_walker((Node *) ((VariableSetStmt *) node)->args, jstate);
334
- }
335
- else if (IsA(node, CopyStmt))
336
- {
337
- return const_record_walker((Node *) ((CopyStmt *) node)->query, jstate);
338
- }
339
- else if (IsA(node, ExplainStmt))
340
- {
341
- return const_record_walker((Node *) ((ExplainStmt *) node)->query, jstate);
342
- }
343
- else if (IsA(node, CreateRoleStmt))
344
- {
345
- return const_record_walker((Node *) ((CreateRoleStmt *) node)->options, jstate);
346
- }
347
- else if (IsA(node, AlterRoleStmt))
348
- {
349
- return const_record_walker((Node *) ((AlterRoleStmt *) node)->options, jstate);
350
- }
351
- else if (IsA(node, DeclareCursorStmt))
352
- {
353
- return const_record_walker((Node *) ((DeclareCursorStmt *) node)->query, jstate);
354
- }
361
+ break;
362
+ case T_DefElem:
363
+ {
364
+ DefElem * defElem = (DefElem *) node;
365
+ if (defElem->arg != NULL && IsA(defElem->arg, String)) {
366
+ for (int i = defElem->location; i < jstate->query_len; i++) {
367
+ if (jstate->query[i] == '\'') {
368
+ RecordConstLocation(jstate, i);
369
+ break;
370
+ }
371
+ }
372
+ }
373
+ return const_record_walker((Node *) ((DefElem *) node)->arg, jstate);
374
+ }
375
+ break;
376
+ case T_RawStmt:
377
+ return const_record_walker((Node *) ((RawStmt *) node)->stmt, jstate);
378
+ case T_VariableSetStmt:
379
+ return const_record_walker((Node *) ((VariableSetStmt *) node)->args, jstate);
380
+ case T_CopyStmt:
381
+ return const_record_walker((Node *) ((CopyStmt *) node)->query, jstate);
382
+ case T_ExplainStmt:
383
+ return const_record_walker((Node *) ((ExplainStmt *) node)->query, jstate);
384
+ case T_CreateRoleStmt:
385
+ return const_record_walker((Node *) ((CreateRoleStmt *) node)->options, jstate);
386
+ case T_AlterRoleStmt:
387
+ return const_record_walker((Node *) ((AlterRoleStmt *) node)->options, jstate);
388
+ case T_DeclareCursorStmt:
389
+ return const_record_walker((Node *) ((DeclareCursorStmt *) node)->query, jstate);
390
+ case T_TypeName:
391
+ /* Don't normalize constants in typmods or arrayBounds */
392
+ return false;
393
+ case T_SelectStmt:
394
+ {
395
+ SelectStmt *stmt = (SelectStmt *) node;
396
+ ListCell *lc;
397
+ List *fp_and_param_refs_list = NIL;
398
+
399
+ if (const_record_walker((Node *) stmt->distinctClause, jstate))
400
+ return true;
401
+ if (const_record_walker((Node *) stmt->intoClause, jstate))
402
+ return true;
403
+ foreach(lc, stmt->targetList)
404
+ {
405
+ ResTarget *res_target = lfirst_node(ResTarget, lc);
406
+ FpAndParamRefs *fp_and_param_refs = palloc0(sizeof(FpAndParamRefs));
407
+
408
+ /* Save all param refs we encounter or assign */
409
+ jstate->param_refs = palloc0(1 * sizeof(int));
410
+ jstate->param_refs_buf_size = 1;
411
+ jstate->param_refs_count = 0;
412
+
413
+ /* Walk the element */
414
+ if (const_record_walker((Node *) res_target, jstate))
415
+ return true;
416
+
417
+ /* Remember fingerprint and param refs for later */
418
+ fp_and_param_refs->fp = pg_query_fingerprint_node(res_target->val);
419
+ fp_and_param_refs->param_refs = jstate->param_refs;
420
+ fp_and_param_refs->param_refs_count = jstate->param_refs_count;
421
+ fp_and_param_refs_list = lappend(fp_and_param_refs_list, fp_and_param_refs);
422
+
423
+ /* Reset for next element, or stop recording if this is the last element */
424
+ jstate->param_refs = NULL;
425
+ jstate->param_refs_buf_size = 0;
426
+ jstate->param_refs_count = 0;
427
+ }
428
+ if (const_record_walker((Node *) stmt->fromClause, jstate))
429
+ return true;
430
+ if (const_record_walker((Node *) stmt->whereClause, jstate))
431
+ return true;
355
432
 
356
- PG_TRY();
357
- {
358
- result = raw_expression_tree_walker(node, const_record_walker, (void*) jstate);
359
- }
360
- PG_CATCH();
361
- {
362
- MemoryContextSwitchTo(normalize_context);
363
- result = false;
364
- FlushErrorState();
433
+ /*
434
+ * Instead of walking all of groupClause (like raw_expression_tree_walker does),
435
+ * only walk certain items.
436
+ */
437
+ foreach(lc, stmt->groupClause)
438
+ {
439
+ /*
440
+ * Do not walk A_Const values that are simple integers, this avoids
441
+ * turning "GROUP BY 1" into "GROUP BY $n", which obscures an important
442
+ * semantic meaning. This matches how pg_stat_statements handles the
443
+ * GROUP BY clause (i.e. it doesn't touch these constants)
444
+ */
445
+ if (IsA(lfirst(lc), A_Const) && IsA(&castNode(A_Const, lfirst(lc))->val, Integer))
446
+ continue;
447
+
448
+ /*
449
+ * Match up GROUP BY clauses against the target list, to assign the same
450
+ * param refs as used in the target list - this ensures the query is valid,
451
+ * instead of throwing a bogus "columns ... must appear in the GROUP BY
452
+ * clause or be used in an aggregate function" error
453
+ */
454
+ uint64_t fp = pg_query_fingerprint_node(lfirst(lc));
455
+ FpAndParamRefs *fppr = NULL;
456
+ ListCell *lc2;
457
+ foreach(lc2, fp_and_param_refs_list) {
458
+ if (fp == ((FpAndParamRefs *) lfirst(lc2))->fp) {
459
+ fppr = (FpAndParamRefs *) lfirst(lc2);
460
+ foreach_delete_current(fp_and_param_refs_list, lc2);
461
+ break;
462
+ }
463
+ }
464
+
465
+ int prev_cloc_count = jstate->clocations_count;
466
+ if (const_record_walker((Node *) lfirst(lc), jstate))
467
+ return true;
468
+
469
+ if (fppr != NULL && fppr->param_refs_count == jstate->clocations_count - prev_cloc_count) {
470
+ for (int i = prev_cloc_count; i < jstate->clocations_count; i++) {
471
+ jstate->clocations[i].param_id = fppr->param_refs[i - prev_cloc_count];
472
+ }
473
+ jstate->highest_normalize_param_id -= fppr->param_refs_count;
474
+ }
475
+ }
476
+ foreach(lc, stmt->sortClause)
477
+ {
478
+ /* Similarly, don't turn "ORDER BY 1" into "ORDER BY $n" */
479
+ if (IsA(lfirst(lc), SortBy) && IsA(castNode(SortBy, lfirst(lc))->node, A_Const) &&
480
+ IsA(&castNode(A_Const, castNode(SortBy, lfirst(lc))->node)->val, Integer))
481
+ continue;
482
+
483
+ if (const_record_walker((Node *) lfirst(lc), jstate))
484
+ return true;
485
+ }
486
+ if (const_record_walker((Node *) stmt->havingClause, jstate))
487
+ return true;
488
+ if (const_record_walker((Node *) stmt->windowClause, jstate))
489
+ return true;
490
+ if (const_record_walker((Node *) stmt->valuesLists, jstate))
491
+ return true;
492
+ if (const_record_walker((Node *) stmt->limitOffset, jstate))
493
+ return true;
494
+ if (const_record_walker((Node *) stmt->limitCount, jstate))
495
+ return true;
496
+ if (const_record_walker((Node *) stmt->lockingClause, jstate))
497
+ return true;
498
+ if (const_record_walker((Node *) stmt->withClause, jstate))
499
+ return true;
500
+ if (const_record_walker((Node *) stmt->larg, jstate))
501
+ return true;
502
+ if (const_record_walker((Node *) stmt->rarg, jstate))
503
+ return true;
504
+
505
+ return false;
506
+ }
507
+ default:
508
+ {
509
+ PG_TRY();
510
+ {
511
+ return raw_expression_tree_walker(node, const_record_walker, (void*) jstate);
512
+ }
513
+ PG_CATCH();
514
+ {
515
+ MemoryContextSwitchTo(normalize_context);
516
+ FlushErrorState();
517
+ }
518
+ PG_END_TRY();
519
+ }
365
520
  }
366
- PG_END_TRY();
367
521
 
368
- return result;
522
+ return false;
369
523
  }
370
524
 
371
525
  PgQueryNormalizeResult pg_query_normalize(const char* input)
@@ -391,9 +545,13 @@ PgQueryNormalizeResult pg_query_normalize(const char* input)
391
545
  jstate.clocations = (pgssLocationLen *)
392
546
  palloc(jstate.clocations_buf_size * sizeof(pgssLocationLen));
393
547
  jstate.clocations_count = 0;
548
+ jstate.highest_normalize_param_id = 1;
394
549
  jstate.highest_extern_param_id = 0;
395
550
  jstate.query = input;
396
551
  jstate.query_len = query_len;
552
+ jstate.param_refs = NULL;
553
+ jstate.param_refs_buf_size = 0;
554
+ jstate.param_refs_count = 0;
397
555
 
398
556
  /* Walk tree and record const locations */
399
557
  const_record_walker((Node *) tree, &jstate);
@@ -412,6 +570,8 @@ PgQueryNormalizeResult pg_query_normalize(const char* input)
412
570
  error = malloc(sizeof(PgQueryError));
413
571
  error->message = strdup(error_data->message);
414
572
  error->filename = strdup(error_data->filename);
573
+ error->funcname = strdup(error_data->funcname);
574
+ error->context = NULL;
415
575
  error->lineno = error_data->lineno;
416
576
  error->cursorpos = error_data->cursorpos;
417
577
 
@@ -430,6 +590,7 @@ void pg_query_free_normalize_result(PgQueryNormalizeResult result)
430
590
  if (result.error) {
431
591
  free(result.error->message);
432
592
  free(result.error->filename);
593
+ free(result.error->funcname);
433
594
  free(result.error);
434
595
  }
435
596
 
@@ -108,7 +108,7 @@ static PLpgSQL_function *compile_create_function_stmt(CreateFunctionStmt* stmt)
108
108
  }
109
109
  }
110
110
 
111
- assert(proc_source);
111
+ assert(proc_source != NULL);
112
112
 
113
113
  if (stmt->returnType != NULL) {
114
114
  foreach(lc3, stmt->returnType->names)
@@ -179,6 +179,26 @@ static PLpgSQL_function *compile_create_function_stmt(CreateFunctionStmt* stmt)
179
179
  plpgsql_DumpExecTree = false;
180
180
  plpgsql_start_datums();
181
181
 
182
+ /* Setup parameter names */
183
+ foreach(lc, stmt->parameters)
184
+ {
185
+ FunctionParameter *param = lfirst_node(FunctionParameter, lc);
186
+ if (param->name != NULL)
187
+ {
188
+ char buf[32];
189
+ PLpgSQL_type *argdtype;
190
+ PLpgSQL_variable *argvariable;
191
+ PLpgSQL_nsitem_type argitemtype;
192
+ snprintf(buf, sizeof(buf), "$%d", foreach_current_index(lc) + 1);
193
+ argdtype = plpgsql_build_datatype(UNKNOWNOID, -1, InvalidOid, NULL);
194
+ argvariable = plpgsql_build_variable(param->name ? param->name : buf, 0, argdtype, false);
195
+ argitemtype = argvariable->dtype == PLPGSQL_DTYPE_VAR ? PLPGSQL_NSTYPE_VAR : PLPGSQL_NSTYPE_REC;
196
+ plpgsql_ns_additem(argitemtype, argvariable->dno, buf);
197
+ if (param->name != NULL)
198
+ plpgsql_ns_additem(argitemtype, argvariable->dno, param->name);
199
+ }
200
+ }
201
+
182
202
  /* Set up as though in a function returning VOID */
183
203
  function->fn_rettype = VOIDOID;
184
204
  function->fn_retset = is_setof;
@@ -1 +1,2 @@
1
1
  _Init_pg_query
2
+ Init_pg_query
@@ -84,7 +84,9 @@
84
84
  # define PROTOBUF_C_UNPACK_ERROR(...)
85
85
  #endif
86
86
 
87
+ #if !defined(_WIN32) || !defined(PROTOBUF_C_USE_SHARED_LIB)
87
88
  const char protobuf_c_empty_string[] = "";
89
+ #endif
88
90
 
89
91
  /**
90
92
  * Internal `ProtobufCMessage` manipulation macro.
@@ -148,12 +150,14 @@ protobuf_c_version_number(void)
148
150
  static void *
149
151
  system_alloc(void *allocator_data, size_t size)
150
152
  {
153
+ (void)allocator_data;
151
154
  return malloc(size);
152
155
  }
153
156
 
154
157
  static void
155
158
  system_free(void *allocator_data, void *data)
156
159
  {
160
+ (void)allocator_data;
157
161
  free(data);
158
162
  }
159
163
 
@@ -1618,22 +1622,19 @@ required_field_pack_to_buffer(const ProtobufCFieldDescriptor *field,
1618
1622
  break;
1619
1623
  }
1620
1624
  case PROTOBUF_C_TYPE_MESSAGE: {
1621
- uint8_t simple_buffer_scratch[256];
1622
- size_t sublen;
1623
1625
  const ProtobufCMessage *msg = *(ProtobufCMessage * const *) member;
1624
- ProtobufCBufferSimple simple_buffer =
1625
- PROTOBUF_C_BUFFER_SIMPLE_INIT(simple_buffer_scratch);
1626
-
1626
+
1627
1627
  scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;
1628
- if (msg == NULL)
1629
- sublen = 0;
1630
- else
1631
- sublen = protobuf_c_message_pack_to_buffer(msg, &simple_buffer.base);
1632
- rv += uint32_pack(sublen, scratch + rv);
1633
- buffer->append(buffer, rv, scratch);
1634
- buffer->append(buffer, sublen, simple_buffer.data);
1635
- rv += sublen;
1636
- PROTOBUF_C_BUFFER_SIMPLE_CLEAR(&simple_buffer);
1628
+ if (msg == NULL) {
1629
+ rv += uint32_pack(0, scratch + rv);
1630
+ buffer->append(buffer, rv, scratch);
1631
+ } else {
1632
+ size_t sublen = protobuf_c_message_get_packed_size(msg);
1633
+ rv += uint32_pack(sublen, scratch + rv);
1634
+ buffer->append(buffer, rv, scratch);
1635
+ protobuf_c_message_pack_to_buffer(msg, buffer);
1636
+ rv += sublen;
1637
+ }
1637
1638
  break;
1638
1639
  }
1639
1640
  default:
@@ -2063,7 +2064,7 @@ static size_t
2063
2064
  parse_tag_and_wiretype(size_t len,
2064
2065
  const uint8_t *data,
2065
2066
  uint32_t *tag_out,
2066
- ProtobufCWireType *wiretype_out)
2067
+ uint8_t *wiretype_out)
2067
2068
  {
2068
2069
  unsigned max_rv = len > 5 ? 5 : len;
2069
2070
  uint32_t tag = (data[0] & 0x7f) >> 3;
@@ -2095,9 +2096,9 @@ parse_tag_and_wiretype(size_t len,
2095
2096
 
2096
2097
  /* sizeof(ScannedMember) must be <= (1UL<<BOUND_SIZEOF_SCANNED_MEMBER_LOG2) */
2097
2098
  #define BOUND_SIZEOF_SCANNED_MEMBER_LOG2 5
2098
- typedef struct _ScannedMember ScannedMember;
2099
+ typedef struct ScannedMember ScannedMember;
2099
2100
  /** Field as it's being read. */
2100
- struct _ScannedMember {
2101
+ struct ScannedMember {
2101
2102
  uint32_t tag; /**< Field tag. */
2102
2103
  uint8_t wire_type; /**< Field type. */
2103
2104
  uint8_t length_prefix_len; /**< Prefix length. */
@@ -2132,11 +2133,13 @@ scan_length_prefixed_data(size_t len, const uint8_t *data,
2132
2133
  // Protobuf messages should always be less than 2 GiB in size.
2133
2134
  // We also want to return early here so that hdr_len + val does
2134
2135
  // not overflow on 32-bit systems.
2135
- PROTOBUF_C_UNPACK_ERROR("length prefix of %lu is too large", val);
2136
+ PROTOBUF_C_UNPACK_ERROR("length prefix of %lu is too large",
2137
+ (unsigned long int)val);
2136
2138
  return 0;
2137
2139
  }
2138
2140
  if (hdr_len + val > len) {
2139
- PROTOBUF_C_UNPACK_ERROR("data too short after length-prefix of %lu", val);
2141
+ PROTOBUF_C_UNPACK_ERROR("data too short after length-prefix of %lu",
2142
+ (unsigned long int)val);
2140
2143
  return 0;
2141
2144
  }
2142
2145
  return hdr_len + val;
@@ -2498,7 +2501,7 @@ parse_required_member(ScannedMember *scanned_member,
2498
2501
  {
2499
2502
  unsigned len = scanned_member->len;
2500
2503
  const uint8_t *data = scanned_member->data;
2501
- ProtobufCWireType wire_type = scanned_member->wire_type;
2504
+ uint8_t wire_type = scanned_member->wire_type;
2502
2505
 
2503
2506
  switch (scanned_member->field->type) {
2504
2507
  case PROTOBUF_C_TYPE_ENUM:
@@ -2579,7 +2582,7 @@ parse_required_member(ScannedMember *scanned_member,
2579
2582
  {
2580
2583
  do_free(allocator, bd->data);
2581
2584
  }
2582
- if (len - pref_len > 0) {
2585
+ if (len > pref_len) {
2583
2586
  bd->data = do_alloc(allocator, len - pref_len);
2584
2587
  if (bd->data == NULL)
2585
2588
  return FALSE;
@@ -2747,7 +2750,9 @@ parse_packed_repeated_member(ScannedMember *scanned_member,
2747
2750
  const uint8_t *at = scanned_member->data + scanned_member->length_prefix_len;
2748
2751
  size_t rem = scanned_member->len - scanned_member->length_prefix_len;
2749
2752
  size_t count = 0;
2753
+ #if defined(WORDS_BIGENDIAN)
2750
2754
  unsigned i;
2755
+ #endif
2751
2756
 
2752
2757
  switch (field->type) {
2753
2758
  case PROTOBUF_C_TYPE_SFIXED32:
@@ -2840,13 +2845,15 @@ parse_packed_repeated_member(ScannedMember *scanned_member,
2840
2845
  }
2841
2846
  break;
2842
2847
  case PROTOBUF_C_TYPE_BOOL:
2843
- count = rem;
2844
- for (i = 0; i < count; i++) {
2845
- if (at[i] > 1) {
2848
+ while (rem > 0) {
2849
+ unsigned s = scan_varint(rem, at);
2850
+ if (s == 0) {
2846
2851
  PROTOBUF_C_UNPACK_ERROR("bad packed-repeated boolean value");
2847
2852
  return FALSE;
2848
2853
  }
2849
- ((protobuf_c_boolean *) array)[i] = at[i];
2854
+ ((protobuf_c_boolean *) array)[count++] = parse_boolean(s, at);
2855
+ at += s;
2856
+ rem -= s;
2850
2857
  }
2851
2858
  break;
2852
2859
  default:
@@ -3080,7 +3087,7 @@ protobuf_c_message_unpack(const ProtobufCMessageDescriptor *desc,
3080
3087
 
3081
3088
  while (rem > 0) {
3082
3089
  uint32_t tag;
3083
- ProtobufCWireType wire_type;
3090
+ uint8_t wire_type;
3084
3091
  size_t used = parse_tag_and_wiretype(rem, at, &tag, &wire_type);
3085
3092
  const ProtobufCFieldDescriptor *field;
3086
3093
  ScannedMember tmp;
@@ -3657,4 +3664,4 @@ protobuf_c_service_descriptor_get_method_by_name(const ProtobufCServiceDescripto
3657
3664
  if (strcmp(desc->methods[desc->method_indices_by_name[start]].name, name) == 0)
3658
3665
  return desc->methods + desc->method_indices_by_name[start];
3659
3666
  return NULL;
3660
- }
3667
+ }
@@ -28,6 +28,7 @@
28
28
  * - CurrentMemoryContext
29
29
  * - MemoryContextDelete
30
30
  * - palloc0
31
+ * - MemoryContextAllocExtended
31
32
  *--------------------------------------------------------------------
32
33
  */
33
34
 
@@ -840,7 +841,42 @@ MemoryContextAllocZeroAligned(MemoryContext context, Size size)
840
841
  * MemoryContextAllocExtended
841
842
  * Allocate space within the specified context using the given flags.
842
843
  */
844
+ void *
845
+ MemoryContextAllocExtended(MemoryContext context, Size size, int flags)
846
+ {
847
+ void *ret;
848
+
849
+ AssertArg(MemoryContextIsValid(context));
850
+ AssertNotInCriticalSection(context);
851
+
852
+ if (((flags & MCXT_ALLOC_HUGE) != 0 && !AllocHugeSizeIsValid(size)) ||
853
+ ((flags & MCXT_ALLOC_HUGE) == 0 && !AllocSizeIsValid(size)))
854
+ elog(ERROR, "invalid memory alloc request size %zu", size);
855
+
856
+ context->isReset = false;
857
+
858
+ ret = context->methods->alloc(context, size);
859
+ if (unlikely(ret == NULL))
860
+ {
861
+ if ((flags & MCXT_ALLOC_NO_OOM) == 0)
862
+ {
863
+ MemoryContextStats(TopMemoryContext);
864
+ ereport(ERROR,
865
+ (errcode(ERRCODE_OUT_OF_MEMORY),
866
+ errmsg("out of memory"),
867
+ errdetail("Failed on request of size %zu in memory context \"%s\".",
868
+ size, context->name)));
869
+ }
870
+ return NULL;
871
+ }
843
872
 
873
+ VALGRIND_MEMPOOL_ALLOC(context, ret, size);
874
+
875
+ if ((flags & MCXT_ALLOC_ZERO) != 0)
876
+ MemSetAligned(ret, 0, size);
877
+
878
+ return ret;
879
+ }
844
880
 
845
881
  void *
846
882
  palloc(Size size)