pg_query 2.0.1 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
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)