pg_query 2.0.3 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -0
  3. data/README.md +12 -0
  4. data/Rakefile +5 -19
  5. data/ext/pg_query/extconf.rb +3 -1
  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 +6 -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-c.h +7 -3
  17. data/ext/pg_query/include/protobuf-c/protobuf-c.h +7 -3
  18. data/ext/pg_query/include/protobuf/pg_query.pb-c.h +472 -467
  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 +6 -0
  24. data/ext/pg_query/pg_query_fingerprint.c +104 -32
  25. data/ext/pg_query/pg_query_normalize.c +112 -60
  26. data/ext/pg_query/protobuf-c.c +34 -27
  27. data/ext/pg_query/src_backend_utils_mmgr_mcxt.c +36 -0
  28. data/ext/pg_query/src_common_hashfn.c +420 -0
  29. data/lib/pg_query.rb +0 -1
  30. data/lib/pg_query/filter_columns.rb +1 -1
  31. data/lib/pg_query/fingerprint.rb +1 -3
  32. data/lib/pg_query/parse.rb +60 -5
  33. data/lib/pg_query/pg_query_pb.rb +1385 -1383
  34. data/lib/pg_query/version.rb +1 -1
  35. metadata +7 -7
  36. data/lib/pg_query/json_field_names.rb +0 -1402
@@ -2247,6 +2247,12 @@ static void deparseRangeVar(StringInfo str, RangeVar *range_var, DeparseNodeCont
2247
2247
  if (!range_var->inh && context != DEPARSE_NODE_CONTEXT_CREATE_TYPE && context != DEPARSE_NODE_CONTEXT_ALTER_TYPE)
2248
2248
  appendStringInfoString(str, "ONLY ");
2249
2249
 
2250
+ if (range_var->catalogname != NULL)
2251
+ {
2252
+ appendStringInfoString(str, quote_identifier(range_var->catalogname));
2253
+ appendStringInfoChar(str, '.');
2254
+ }
2255
+
2250
2256
  if (range_var->schemaname != NULL)
2251
2257
  {
2252
2258
  appendStringInfoString(str, quote_identifier(range_var->schemaname));
@@ -17,6 +17,8 @@
17
17
  #include "nodes/parsenodes.h"
18
18
  #include "nodes/value.h"
19
19
 
20
+ #include "common/hashfn.h"
21
+
20
22
  #include <unistd.h>
21
23
  #include <fcntl.h>
22
24
 
@@ -26,15 +28,41 @@ typedef struct FingerprintContext
26
28
  {
27
29
  XXH3_state_t *xxh_state;
28
30
 
31
+ struct listsort_cache_hash *listsort_cache;
32
+
29
33
  bool write_tokens;
30
34
  dlist_head tokens;
31
35
  } FingerprintContext;
32
36
 
33
- typedef struct FingerprintListContext
37
+ typedef struct FingerprintListsortItem
34
38
  {
35
39
  XXH64_hash_t hash;
36
40
  size_t list_pos;
37
- } FingerprintListContext;
41
+ } FingerprintListsortItem;
42
+
43
+ typedef struct FingerprintListsortItemCacheEntry
44
+ {
45
+ /* List node this cache entry is for */
46
+ uintptr_t node;
47
+
48
+ /* Hashes of all list items -- this is expensive to calculate */
49
+ FingerprintListsortItem **listsort_items;
50
+ size_t listsort_items_size;
51
+
52
+ /* hash entry status */
53
+ char status;
54
+ } FingerprintListsortItemCacheEntry;
55
+
56
+ #define SH_PREFIX listsort_cache
57
+ #define SH_ELEMENT_TYPE FingerprintListsortItemCacheEntry
58
+ #define SH_KEY_TYPE uintptr_t
59
+ #define SH_KEY node
60
+ #define SH_HASH_KEY(tb, key) hash_bytes((const unsigned char *) &key, sizeof(uintptr_t))
61
+ #define SH_EQUAL(tb, a, b) a == b
62
+ #define SH_SCOPE static inline
63
+ #define SH_DEFINE
64
+ #define SH_DECLARE
65
+ #include "lib/simplehash.h"
38
66
 
39
67
  typedef struct FingerprintToken
40
68
  {
@@ -43,7 +71,7 @@ typedef struct FingerprintToken
43
71
  } FingerprintToken;
44
72
 
45
73
  static void _fingerprintNode(FingerprintContext *ctx, const void *obj, const void *parent, char *parent_field_name, unsigned int depth);
46
- static void _fingerprintInitContext(FingerprintContext *ctx, bool write_tokens);
74
+ static void _fingerprintInitContext(FingerprintContext *ctx, FingerprintContext *parent, bool write_tokens);
47
75
  static void _fingerprintFreeContext(FingerprintContext *ctx);
48
76
 
49
77
  #define PG_QUERY_FINGERPRINT_VERSION 3
@@ -96,10 +124,10 @@ _fingerprintBitString(FingerprintContext *ctx, const Value *node)
96
124
  }
97
125
  }
98
126
 
99
- static int compareFingerprintListContext(const void *a, const void *b)
127
+ static int compareFingerprintListsortItem(const void *a, const void *b)
100
128
  {
101
- FingerprintListContext *ca = *(FingerprintListContext**) a;
102
- FingerprintListContext *cb = *(FingerprintListContext**) b;
129
+ FingerprintListsortItem *ca = *(FingerprintListsortItem**) a;
130
+ FingerprintListsortItem *cb = *(FingerprintListsortItem**) b;
103
131
  if (ca->hash > cb->hash)
104
132
  return 1;
105
133
  else if (ca->hash < cb->hash)
@@ -111,38 +139,69 @@ static void
111
139
  _fingerprintList(FingerprintContext *ctx, const List *node, const void *parent, char *field_name, unsigned int depth)
112
140
  {
113
141
  if (field_name != NULL && (strcmp(field_name, "fromClause") == 0 || strcmp(field_name, "targetList") == 0 ||
114
- strcmp(field_name, "cols") == 0 || strcmp(field_name, "rexpr") == 0 || strcmp(field_name, "valuesLists") == 0 ||
115
- strcmp(field_name, "args") == 0)) {
142
+ strcmp(field_name, "cols") == 0 || strcmp(field_name, "rexpr") == 0 || strcmp(field_name, "valuesLists") == 0 ||
143
+ strcmp(field_name, "args") == 0))
144
+ {
145
+ /*
146
+ * Check for cached values for the hashes of subnodes
147
+ *
148
+ * Note this cache is important so we avoid exponential runtime behavior,
149
+ * which would be the case if we fingerprinted each node twice, which
150
+ * then would also again have to fingerprint each of its subnodes twice,
151
+ * etc., leading to deep nodes to be fingerprinted many many times over.
152
+ *
153
+ * We have seen real-world problems with this logic here without
154
+ * a cache in place.
155
+ */
156
+ FingerprintListsortItem** listsort_items = NULL;
157
+ size_t listsort_items_size = 0;
158
+ FingerprintListsortItemCacheEntry *entry = listsort_cache_lookup(ctx->listsort_cache, (uintptr_t) node);
159
+ if (entry != NULL)
160
+ {
161
+ listsort_items = entry->listsort_items;
162
+ listsort_items_size = entry->listsort_items_size;
163
+ }
164
+ else
165
+ {
166
+ listsort_items = palloc0(node->length * sizeof(FingerprintListsortItem*));
167
+ listsort_items_size = 0;
168
+ ListCell *lc;
169
+ bool found;
116
170
 
117
- FingerprintListContext** listCtxArr = palloc0(node->length * sizeof(FingerprintListContext*));
118
- size_t listCtxCount = 0;
119
- const ListCell *lc;
171
+ foreach(lc, node)
172
+ {
173
+ FingerprintContext fctx;
174
+ FingerprintListsortItem* lctx = palloc0(sizeof(FingerprintListsortItem));
120
175
 
121
- foreach(lc, node)
122
- {
123
- FingerprintContext subCtx;
124
- FingerprintListContext* listCtx = palloc0(sizeof(FingerprintListContext));
176
+ _fingerprintInitContext(&fctx, ctx, false);
177
+ _fingerprintNode(&fctx, lfirst(lc), parent, field_name, depth + 1);
178
+ lctx->hash = XXH3_64bits_digest(fctx.xxh_state);
179
+ lctx->list_pos = listsort_items_size;
180
+ _fingerprintFreeContext(&fctx);
125
181
 
126
- _fingerprintInitContext(&subCtx, false);
127
- _fingerprintNode(&subCtx, lfirst(lc), parent, field_name, depth + 1);
128
- listCtx->hash = XXH3_64bits_digest(subCtx.xxh_state);
129
- listCtx->list_pos = listCtxCount;
130
- _fingerprintFreeContext(&subCtx);
182
+ listsort_items[listsort_items_size] = lctx;
183
+ listsort_items_size += 1;
184
+ }
131
185
 
132
- listCtxArr[listCtxCount] = listCtx;
133
- listCtxCount += 1;
134
- }
186
+ pg_qsort(listsort_items, listsort_items_size, sizeof(FingerprintListsortItem*), compareFingerprintListsortItem);
135
187
 
136
- pg_qsort(listCtxArr, listCtxCount, sizeof(FingerprintListContext*), compareFingerprintListContext);
188
+ FingerprintListsortItemCacheEntry *entry = listsort_cache_insert(ctx->listsort_cache, (uintptr_t) node, &found);
189
+ Assert(!found);
137
190
 
138
- for (size_t i = 0; i < listCtxCount; i++)
191
+ entry->listsort_items = listsort_items;
192
+ entry->listsort_items_size = listsort_items_size;
193
+ }
194
+
195
+ for (size_t i = 0; i < listsort_items_size; i++)
139
196
  {
140
- if (i > 0 && listCtxArr[i - 1]->hash == listCtxArr[i]->hash)
197
+ if (i > 0 && listsort_items[i - 1]->hash == listsort_items[i]->hash)
141
198
  continue; // Ignore duplicates
142
199
 
143
- _fingerprintNode(ctx, lfirst(list_nth_cell(node, listCtxArr[i]->list_pos)), parent, field_name, depth + 1);
200
+ _fingerprintNode(ctx, lfirst(list_nth_cell(node, listsort_items[i]->list_pos)), parent, field_name, depth + 1);
144
201
  }
145
- } else {
202
+ }
203
+ else
204
+ {
146
205
  const ListCell *lc;
147
206
 
148
207
  foreach(lc, node)
@@ -155,15 +214,28 @@ _fingerprintList(FingerprintContext *ctx, const List *node, const void *parent,
155
214
  }
156
215
 
157
216
  static void
158
- _fingerprintInitContext(FingerprintContext *ctx, bool write_tokens) {
217
+ _fingerprintInitContext(FingerprintContext *ctx, FingerprintContext *parent, bool write_tokens)
218
+ {
159
219
  ctx->xxh_state = XXH3_createState();
160
220
  if (ctx->xxh_state == NULL) abort();
161
221
  if (XXH3_64bits_reset_withSeed(ctx->xxh_state, PG_QUERY_FINGERPRINT_VERSION) == XXH_ERROR) abort();
162
222
 
163
- if (write_tokens) {
223
+ if (parent != NULL)
224
+ {
225
+ ctx->listsort_cache = parent->listsort_cache;
226
+ }
227
+ else
228
+ {
229
+ ctx->listsort_cache = listsort_cache_create(CurrentMemoryContext, 128, NULL);
230
+ }
231
+
232
+ if (write_tokens)
233
+ {
164
234
  ctx->write_tokens = true;
165
235
  dlist_init(&ctx->tokens);
166
- } else {
236
+ }
237
+ else
238
+ {
167
239
  ctx->write_tokens = false;
168
240
  }
169
241
  }
@@ -237,7 +309,7 @@ PgQueryFingerprintResult pg_query_fingerprint_with_opts(const char* input, bool
237
309
  FingerprintContext ctx;
238
310
  XXH64_canonical_t chash;
239
311
 
240
- _fingerprintInitContext(&ctx, printTokens);
312
+ _fingerprintInitContext(&ctx, NULL, printTokens);
241
313
 
242
314
  if (parsetree_and_error.tree != NULL) {
243
315
  _fingerprintNode(&ctx, parsetree_and_error.tree, NULL, NULL, 0);
@@ -303,71 +303,123 @@ static bool const_record_walker(Node *node, pgssConstLocations *jstate)
303
303
 
304
304
  if (node == NULL) return false;
305
305
 
306
- if (IsA(node, A_Const))
306
+ switch (nodeTag(node))
307
307
  {
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);
323
- break;
324
- }
308
+ case T_A_Const:
309
+ RecordConstLocation(jstate, castNode(A_Const, node)->location);
310
+ break;
311
+ case T_ParamRef:
312
+ {
313
+ /* Track the highest ParamRef number */
314
+ if (((ParamRef *) node)->number > jstate->highest_extern_param_id)
315
+ jstate->highest_extern_param_id = castNode(ParamRef, node)->number;
325
316
  }
326
- }
327
- return const_record_walker((Node *) ((DefElem *) node)->arg, jstate);
328
- }
329
- else if (IsA(node, RawStmt))
330
- {
331
- return const_record_walker((Node *) ((RawStmt *) node)->stmt, jstate);
332
- }
333
- else if (IsA(node, VariableSetStmt))
334
- {
335
- return const_record_walker((Node *) ((VariableSetStmt *) node)->args, jstate);
336
- }
337
- else if (IsA(node, CopyStmt))
338
- {
339
- return const_record_walker((Node *) ((CopyStmt *) node)->query, jstate);
340
- }
341
- else if (IsA(node, ExplainStmt))
342
- {
343
- return const_record_walker((Node *) ((ExplainStmt *) node)->query, jstate);
344
- }
345
- else if (IsA(node, CreateRoleStmt))
346
- {
347
- return const_record_walker((Node *) ((CreateRoleStmt *) node)->options, jstate);
348
- }
349
- else if (IsA(node, AlterRoleStmt))
350
- {
351
- return const_record_walker((Node *) ((AlterRoleStmt *) node)->options, jstate);
352
- }
353
- else if (IsA(node, DeclareCursorStmt))
354
- {
355
- return const_record_walker((Node *) ((DeclareCursorStmt *) node)->query, jstate);
356
- }
317
+ break;
318
+ case T_DefElem:
319
+ {
320
+ DefElem * defElem = (DefElem *) node;
321
+ if (defElem->arg != NULL && IsA(defElem->arg, String)) {
322
+ for (int i = defElem->location; i < jstate->query_len; i++) {
323
+ if (jstate->query[i] == '\'') {
324
+ RecordConstLocation(jstate, i);
325
+ break;
326
+ }
327
+ }
328
+ }
329
+ return const_record_walker((Node *) ((DefElem *) node)->arg, jstate);
330
+ }
331
+ break;
332
+ case T_RawStmt:
333
+ return const_record_walker((Node *) ((RawStmt *) node)->stmt, jstate);
334
+ case T_VariableSetStmt:
335
+ return const_record_walker((Node *) ((VariableSetStmt *) node)->args, jstate);
336
+ case T_CopyStmt:
337
+ return const_record_walker((Node *) ((CopyStmt *) node)->query, jstate);
338
+ case T_ExplainStmt:
339
+ return const_record_walker((Node *) ((ExplainStmt *) node)->query, jstate);
340
+ case T_CreateRoleStmt:
341
+ return const_record_walker((Node *) ((CreateRoleStmt *) node)->options, jstate);
342
+ case T_AlterRoleStmt:
343
+ return const_record_walker((Node *) ((AlterRoleStmt *) node)->options, jstate);
344
+ case T_DeclareCursorStmt:
345
+ return const_record_walker((Node *) ((DeclareCursorStmt *) node)->query, jstate);
346
+ case T_SelectStmt:
347
+ {
348
+ SelectStmt *stmt = (SelectStmt *) node;
349
+ ListCell *lc;
350
+
351
+ if (const_record_walker((Node *) stmt->distinctClause, jstate))
352
+ return true;
353
+ if (const_record_walker((Node *) stmt->intoClause, jstate))
354
+ return true;
355
+ if (const_record_walker((Node *) stmt->targetList, jstate))
356
+ return true;
357
+ if (const_record_walker((Node *) stmt->fromClause, jstate))
358
+ return true;
359
+ if (const_record_walker((Node *) stmt->whereClause, jstate))
360
+ return true;
361
+
362
+ // Instead of walking all of groupClause (like raw_expression_tree_walker does),
363
+ // only walk certain items.
364
+ foreach(lc, stmt->groupClause)
365
+ {
366
+ // Do not walk A_Const values that are simple integers, this avoids
367
+ // turning "GROUP BY 1" into "GROUP BY $n", which obscures an important
368
+ // semantic meaning. This matches how pg_stat_statements handles the
369
+ // GROUP BY clause (i.e. it doesn't touch these constants)
370
+ if (IsA(lfirst(lc), A_Const) && IsA(&castNode(A_Const, lfirst(lc))->val, Integer))
371
+ continue;
372
+
373
+ if (const_record_walker((Node *) lfirst(lc), jstate))
374
+ return true;
375
+ }
376
+ foreach(lc, stmt->sortClause)
377
+ {
378
+ // Similarly, don't turn "ORDER BY 1" into "ORDER BY $n"
379
+ if (IsA(lfirst(lc), SortBy) && IsA(castNode(SortBy, lfirst(lc))->node, A_Const) &&
380
+ IsA(&castNode(A_Const, castNode(SortBy, lfirst(lc))->node)->val, Integer))
381
+ continue;
357
382
 
358
- PG_TRY();
359
- {
360
- result = raw_expression_tree_walker(node, const_record_walker, (void*) jstate);
361
- }
362
- PG_CATCH();
363
- {
364
- MemoryContextSwitchTo(normalize_context);
365
- result = false;
366
- FlushErrorState();
383
+ if (const_record_walker((Node *) lfirst(lc), jstate))
384
+ return true;
385
+ }
386
+ if (const_record_walker((Node *) stmt->havingClause, jstate))
387
+ return true;
388
+ if (const_record_walker((Node *) stmt->windowClause, jstate))
389
+ return true;
390
+ if (const_record_walker((Node *) stmt->valuesLists, jstate))
391
+ return true;
392
+ if (const_record_walker((Node *) stmt->limitOffset, jstate))
393
+ return true;
394
+ if (const_record_walker((Node *) stmt->limitCount, jstate))
395
+ return true;
396
+ if (const_record_walker((Node *) stmt->lockingClause, jstate))
397
+ return true;
398
+ if (const_record_walker((Node *) stmt->withClause, jstate))
399
+ return true;
400
+ if (const_record_walker((Node *) stmt->larg, jstate))
401
+ return true;
402
+ if (const_record_walker((Node *) stmt->rarg, jstate))
403
+ return true;
404
+
405
+ return false;
406
+ }
407
+ default:
408
+ {
409
+ PG_TRY();
410
+ {
411
+ return raw_expression_tree_walker(node, const_record_walker, (void*) jstate);
412
+ }
413
+ PG_CATCH();
414
+ {
415
+ MemoryContextSwitchTo(normalize_context);
416
+ FlushErrorState();
417
+ }
418
+ PG_END_TRY();
419
+ }
367
420
  }
368
- PG_END_TRY();
369
421
 
370
- return result;
422
+ return false;
371
423
  }
372
424
 
373
425
  PgQueryNormalizeResult pg_query_normalize(const char* input)
@@ -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
+ }