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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +220 -114
- data/README.md +12 -0
- data/Rakefile +6 -21
- data/ext/pg_query/extconf.rb +5 -2
- 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 +10 -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/pg_query.pb-c.h +472 -467
- data/ext/pg_query/include/protobuf-c/protobuf-c.h +7 -3
- data/ext/pg_query/include/protobuf-c.h +7 -3
- 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 +33 -21
- data/ext/pg_query/pg_query_fingerprint.c +123 -33
- data/ext/pg_query/pg_query_fingerprint.h +3 -1
- data/ext/pg_query/pg_query_normalize.c +222 -61
- data/ext/pg_query/pg_query_parse_plpgsql.c +21 -1
- data/ext/pg_query/pg_query_ruby.sym +1 -0
- 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/ext/pg_query/src_pl_plpgsql_src_pl_gram.c +1 -1
- data/lib/pg_query/filter_columns.rb +3 -1
- data/lib/pg_query/fingerprint.rb +1 -3
- data/lib/pg_query/parse.rb +101 -46
- data/lib/pg_query/pg_query_pb.rb +1385 -1383
- data/lib/pg_query/truncate.rb +12 -4
- data/lib/pg_query/version.rb +1 -1
- data/lib/pg_query.rb +0 -1
- metadata +8 -8
- 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
|
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
|
-
|
254
|
-
|
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
|
-
|
341
|
+
switch (nodeTag(node))
|
307
342
|
{
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
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
|
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;
|
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
|
+
}
|
@@ -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)
|