pg_query 2.0.3 → 2.1.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -0
- data/README.md +12 -0
- data/Rakefile +5 -19
- data/ext/pg_query/extconf.rb +3 -1
- data/ext/pg_query/include/c.h +12 -0
- data/ext/pg_query/include/executor/executor.h +6 -0
- data/ext/pg_query/include/nodes/execnodes.h +9 -6
- data/ext/pg_query/include/nodes/pathnodes.h +1 -1
- data/ext/pg_query/include/optimizer/paths.h +8 -0
- data/ext/pg_query/include/pg_config.h +6 -6
- data/ext/pg_query/include/pg_config_manual.h +7 -0
- data/ext/pg_query/include/pg_query.h +2 -2
- data/ext/pg_query/include/pg_query_outfuncs_defs.c +1 -0
- data/ext/pg_query/include/pg_query_readfuncs_defs.c +1 -0
- data/ext/pg_query/include/protobuf-c.h +7 -3
- data/ext/pg_query/include/protobuf-c/protobuf-c.h +7 -3
- data/ext/pg_query/include/protobuf/pg_query.pb-c.h +472 -467
- data/ext/pg_query/include/utils/array.h +1 -0
- data/ext/pg_query/include/utils/lsyscache.h +1 -0
- data/ext/pg_query/include/utils/probes.h +57 -57
- data/ext/pg_query/pg_query.pb-c.c +502 -487
- data/ext/pg_query/pg_query_deparse.c +6 -0
- data/ext/pg_query/pg_query_fingerprint.c +104 -32
- data/ext/pg_query/pg_query_normalize.c +112 -60
- data/ext/pg_query/protobuf-c.c +34 -27
- data/ext/pg_query/src_backend_utils_mmgr_mcxt.c +36 -0
- data/ext/pg_query/src_common_hashfn.c +420 -0
- data/lib/pg_query.rb +0 -1
- data/lib/pg_query/filter_columns.rb +1 -1
- data/lib/pg_query/fingerprint.rb +1 -3
- data/lib/pg_query/parse.rb +60 -5
- data/lib/pg_query/pg_query_pb.rb +1385 -1383
- data/lib/pg_query/version.rb +1 -1
- metadata +7 -7
- 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
|
37
|
+
typedef struct FingerprintListsortItem
|
34
38
|
{
|
35
39
|
XXH64_hash_t hash;
|
36
40
|
size_t list_pos;
|
37
|
-
}
|
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
|
127
|
+
static int compareFingerprintListsortItem(const void *a, const void *b)
|
100
128
|
{
|
101
|
-
|
102
|
-
|
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
|
-
|
115
|
-
|
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
|
-
|
118
|
-
|
119
|
-
|
171
|
+
foreach(lc, node)
|
172
|
+
{
|
173
|
+
FingerprintContext fctx;
|
174
|
+
FingerprintListsortItem* lctx = palloc0(sizeof(FingerprintListsortItem));
|
120
175
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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
|
-
|
127
|
-
|
128
|
-
|
129
|
-
listCtx->list_pos = listCtxCount;
|
130
|
-
_fingerprintFreeContext(&subCtx);
|
182
|
+
listsort_items[listsort_items_size] = lctx;
|
183
|
+
listsort_items_size += 1;
|
184
|
+
}
|
131
185
|
|
132
|
-
|
133
|
-
listCtxCount += 1;
|
134
|
-
}
|
186
|
+
pg_qsort(listsort_items, listsort_items_size, sizeof(FingerprintListsortItem*), compareFingerprintListsortItem);
|
135
187
|
|
136
|
-
|
188
|
+
FingerprintListsortItemCacheEntry *entry = listsort_cache_insert(ctx->listsort_cache, (uintptr_t) node, &found);
|
189
|
+
Assert(!found);
|
137
190
|
|
138
|
-
|
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 &&
|
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,
|
200
|
+
_fingerprintNode(ctx, lfirst(list_nth_cell(node, listsort_items[i]->list_pos)), parent, field_name, depth + 1);
|
144
201
|
}
|
145
|
-
}
|
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 (
|
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
|
-
}
|
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
|
-
|
306
|
+
switch (nodeTag(node))
|
307
307
|
{
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
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
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
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
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
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
|
422
|
+
return false;
|
371
423
|
}
|
372
424
|
|
373
425
|
PgQueryNormalizeResult pg_query_normalize(const char* input)
|
data/ext/pg_query/protobuf-c.c
CHANGED
@@ -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
|
-
|
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
|
-
|
1630
|
-
|
1631
|
-
|
1632
|
-
|
1633
|
-
|
1634
|
-
|
1635
|
-
|
1636
|
-
|
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
|
-
|
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
|
2099
|
+
typedef struct ScannedMember ScannedMember;
|
2099
2100
|
/** Field as it's being read. */
|
2100
|
-
struct
|
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",
|
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",
|
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
|
-
|
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
|
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
|
-
|
2844
|
-
|
2845
|
-
if (
|
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)[
|
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
|
-
|
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
|
+
}
|