pg_query 2.0.1 → 2.1.1
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 +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)
|