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.
- 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
|
+
}
|