From e0b35e463349a8dc8bdce3139ba7b20d4d4b3ca1 Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Tue, 2 Jun 2020 16:47:26 -0700 Subject: [PATCH v3 08/10] wip: make in/out send/recv calls in copy.c cheaper Author: Reviewed-By: Discussion: https://postgr.es/m/ Backpatch: --- src/include/commands/copyfrom_internal.h | 22 +++++- src/backend/access/common/printtup.c | 2 +- src/backend/commands/copyfrom.c | 35 +++++---- src/backend/commands/copyfromparse.c | 96 ++++++++++++++++-------- src/backend/commands/copyto.c | 83 ++++++++++++++++---- src/tools/pgindent/typedefs.list | 70 ++++++++--------- 6 files changed, 212 insertions(+), 96 deletions(-) diff --git a/src/include/commands/copyfrom_internal.h b/src/include/commands/copyfrom_internal.h index cad52fcc783..1bc51d8a0fc 100644 --- a/src/include/commands/copyfrom_internal.h +++ b/src/include/commands/copyfrom_internal.h @@ -52,6 +52,23 @@ typedef enum CopyInsertMethod * ExecForeignBatchInsert only if valid */ } CopyInsertMethod; +typedef struct CopyInAttributeInfo +{ + AttrNumber num; + const char *name; + + Oid typioparam; + int32 typmod; + + FmgrInfo in_finfo; + union + { + FunctionCallInfoBaseData fcinfo; + char fcinfo_data[SizeForFunctionCallInfo(3)]; + } in_fcinfo; + +} CopyInAttributeInfo; + /* * This struct contains all the state variables used throughout a COPY FROM * operation. @@ -93,9 +110,8 @@ typedef struct CopyFromStateData AttrNumber num_defaults; /* count of att that are missing and have * default value */ - FmgrInfo *in_functions; /* array of input functions for each attrs */ - Oid *typioparams; /* array of element types for in_functions */ - ErrorSaveContext *escontext; /* soft error trapper during in_functions + CopyInAttributeInfo *in_attributes; + ErrorSaveContext *escontext; /* soft error trapper during in_attributes * execution */ uint64 num_errors; /* total number of rows which contained soft * errors */ diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c index b4c031f67e7..bee3fc26220 100644 --- a/src/backend/access/common/printtup.c +++ b/src/backend/access/common/printtup.c @@ -394,7 +394,7 @@ printtup(TupleTableSlot *slot, DestReceiver *self) outputbytes = DatumGetByteaP(result); outputlen = VARSIZE(outputbytes) - VARHDRSZ; - Assert(outputlen > 0); + Assert(outputlen >= 0); pq_sendint32(buf, outputlen); pq_sendbytes(buf, VARDATA(outputbytes), outputlen); diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c index 1fe70b91338..96e56d3c128 100644 --- a/src/backend/commands/copyfrom.c +++ b/src/backend/commands/copyfrom.c @@ -1384,8 +1384,7 @@ BeginCopyFrom(ParseState *pstate, TupleDesc tupDesc; AttrNumber num_phys_attrs, num_defaults; - FmgrInfo *in_functions; - Oid *typioparams; + CopyInAttributeInfo *in_attributes; Oid in_func_oid; int *defmap; ExprState **defexprs; @@ -1608,27 +1607,36 @@ BeginCopyFrom(ParseState *pstate, * the input function), and info about defaults and constraints. (Which * input function we use depends on text/binary format choice.) */ - in_functions = (FmgrInfo *) palloc(num_phys_attrs * sizeof(FmgrInfo)); - typioparams = (Oid *) palloc(num_phys_attrs * sizeof(Oid)); + in_attributes = (CopyInAttributeInfo *) + palloc0(num_phys_attrs * sizeof(CopyInAttributeInfo)); defmap = (int *) palloc(num_phys_attrs * sizeof(int)); defexprs = (ExprState **) palloc(num_phys_attrs * sizeof(ExprState *)); for (int attnum = 1; attnum <= num_phys_attrs; attnum++) { - Form_pg_attribute att = TupleDescAttr(tupDesc, attnum - 1); + CopyInAttributeInfo *attr = &in_attributes[attnum - 1]; + Form_pg_attribute pgatt = TupleDescAttr(tupDesc, attnum - 1); /* We don't need info for dropped attributes */ - if (att->attisdropped) + if (pgatt->attisdropped) continue; + attr->num = attnum; + attr->typmod = pgatt->atttypmod; + attr->name = NameStr(pgatt->attname); + /* Fetch the input function and typioparam info */ if (cstate->opts.binary) - getTypeBinaryInputInfo(att->atttypid, - &in_func_oid, &typioparams[attnum - 1]); + getTypeBinaryInputInfo(pgatt->atttypid, + &in_func_oid, &attr->typioparam); else - getTypeInputInfo(att->atttypid, - &in_func_oid, &typioparams[attnum - 1]); - fmgr_info(in_func_oid, &in_functions[attnum - 1]); + getTypeInputInfo(pgatt->atttypid, + &in_func_oid, &attr->typioparam); + fmgr_info(in_func_oid, &attr->in_finfo); + InitFunctionCallInfoData(attr->in_fcinfo.fcinfo, &attr->in_finfo, 3, + InvalidOid, (fmNodePtr) cstate->escontext, + NULL); + /* Get default info if available */ defexprs[attnum - 1] = NULL; @@ -1640,7 +1648,7 @@ BeginCopyFrom(ParseState *pstate, */ if ((cstate->opts.default_print != NULL || !list_member_int(cstate->attnumlist, attnum)) && - !att->attgenerated) + !pgatt->attgenerated) { Expr *defexpr = (Expr *) build_column_default(cstate->rel, attnum); @@ -1689,8 +1697,7 @@ BeginCopyFrom(ParseState *pstate, cstate->bytes_processed = 0; /* We keep those variables in cstate. */ - cstate->in_functions = in_functions; - cstate->typioparams = typioparams; + cstate->in_attributes = in_attributes; cstate->defmap = defmap; cstate->defexprs = defexprs; cstate->volatile_defexprs = volatile_defexprs; diff --git a/src/backend/commands/copyfromparse.c b/src/backend/commands/copyfromparse.c index 7cacd0b752c..7cf9d10e7ae 100644 --- a/src/backend/commands/copyfromparse.c +++ b/src/backend/commands/copyfromparse.c @@ -154,8 +154,8 @@ static bool CopyReadLine(CopyFromState cstate); static bool CopyReadLineText(CopyFromState cstate); static int CopyReadAttributesText(CopyFromState cstate); static int CopyReadAttributesCSV(CopyFromState cstate); -static Datum CopyReadBinaryAttribute(CopyFromState cstate, FmgrInfo *flinfo, - Oid typioparam, int32 typmod, +static Datum CopyReadBinaryAttribute(CopyFromState cstate, + CopyInAttributeInfo *att, bool *isnull); @@ -859,8 +859,7 @@ NextCopyFrom(CopyFromState cstate, ExprContext *econtext, AttrNumber num_phys_attrs, attr_count, num_defaults = cstate->num_defaults; - FmgrInfo *in_functions = cstate->in_functions; - Oid *typioparams = cstate->typioparams; + CopyInAttributeInfo *in_attributes = cstate->in_attributes; int i; int *defmap = cstate->defmap; ExprState **defexprs = cstate->defexprs; @@ -899,13 +898,14 @@ NextCopyFrom(CopyFromState cstate, ExprContext *econtext, { int attnum = lfirst_int(cur); int m = attnum - 1; - Form_pg_attribute att = TupleDescAttr(tupDesc, m); + CopyInAttributeInfo *attr = &in_attributes[m]; + FunctionCallInfo fcinfo = &attr->in_fcinfo.fcinfo; if (fieldno >= fldct) ereport(ERROR, (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), errmsg("missing data for column \"%s\"", - NameStr(att->attname)))); + attr->name))); string = field_strings[fieldno++]; if (cstate->convert_select_flags && @@ -939,7 +939,7 @@ NextCopyFrom(CopyFromState cstate, ExprContext *econtext, } } - cstate->cur_attname = NameStr(att->attname); + cstate->cur_attname = attr->name; cstate->cur_attval = string; if (string != NULL) @@ -956,20 +956,47 @@ NextCopyFrom(CopyFromState cstate, ExprContext *econtext, values[m] = ExecEvalExpr(defexprs[m], econtext, &nulls[m]); } - - /* - * If ON_ERROR is specified with IGNORE, skip rows with soft - * errors - */ - else if (!InputFunctionCallSafe(&in_functions[m], - string, - typioparams[m], - att->atttypmod, - (Node *) cstate->escontext, - &values[m])) + else if (string == NULL && fcinfo->flinfo->fn_strict) { - cstate->num_errors++; - return true; + /* FIXME: shouldn't be reachable */ + nulls[m] = true; + } + else + { + fcinfo->args[0].value = CStringGetDatum(string); + fcinfo->args[0].isnull = false; + fcinfo->args[1].value = ObjectIdGetDatum(attr->typioparam); + fcinfo->args[1].isnull = false; + fcinfo->args[2].value = Int32GetDatum(attr->typmod); + fcinfo->args[2].isnull = false; + + values[m] = FunctionCallInvoke(fcinfo); + + if (SOFT_ERROR_OCCURRED(cstate->escontext)) + { + /* + * If ON_ERROR is specified with IGNORE, skip rows with + * soft errors + */ + cstate->num_errors++; + return true; + } + + /* Should get null result if and only if str is NULL */ + if (string == NULL) + { + if (unlikely(!fcinfo->isnull)) + elog(ERROR, "input function %u returned non-NULL", + fcinfo->flinfo->fn_oid); + } + else + { + if (unlikely(fcinfo->isnull)) + elog(ERROR, "input function %u returned NULL", + fcinfo->flinfo->fn_oid); + } + + nulls[m] = string == NULL; } cstate->cur_attname = NULL; @@ -1021,13 +1048,11 @@ NextCopyFrom(CopyFromState cstate, ExprContext *econtext, { int attnum = lfirst_int(cur); int m = attnum - 1; - Form_pg_attribute att = TupleDescAttr(tupDesc, m); + CopyInAttributeInfo *attr = &in_attributes[m]; - cstate->cur_attname = NameStr(att->attname); + cstate->cur_attname = attr->name; values[m] = CopyReadBinaryAttribute(cstate, - &in_functions[m], - typioparams[m], - att->atttypmod, + attr, &nulls[m]); cstate->cur_attname = NULL; } @@ -1952,12 +1977,13 @@ endfield: * Read a binary attribute */ static Datum -CopyReadBinaryAttribute(CopyFromState cstate, FmgrInfo *flinfo, - Oid typioparam, int32 typmod, +CopyReadBinaryAttribute(CopyFromState cstate, + CopyInAttributeInfo *attr, bool *isnull) { int32 fld_size; Datum result; + FunctionCallInfo fcinfo = &attr->in_fcinfo.fcinfo; if (!CopyGetInt32(cstate, &fld_size)) ereport(ERROR, @@ -1966,7 +1992,7 @@ CopyReadBinaryAttribute(CopyFromState cstate, FmgrInfo *flinfo, if (fld_size == -1) { *isnull = true; - return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod); + return ReceiveFunctionCall(fcinfo->flinfo, NULL, attr->typioparam, attr->typmod); } if (fld_size < 0) ereport(ERROR, @@ -1987,8 +2013,18 @@ CopyReadBinaryAttribute(CopyFromState cstate, FmgrInfo *flinfo, cstate->attribute_buf.data[fld_size] = '\0'; /* Call the column type's binary input converter */ - result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf, - typioparam, typmod); + fcinfo->args[0].value = PointerGetDatum(&cstate->attribute_buf); + fcinfo->args[0].isnull = false; + fcinfo->args[1].value = ObjectIdGetDatum(attr->typioparam); + fcinfo->args[1].isnull = false; + fcinfo->args[2].value = Int32GetDatum(attr->typmod); + fcinfo->args[2].isnull = false; + + result = FunctionCallInvoke(fcinfo); + + if (unlikely(fcinfo->isnull)) + elog(ERROR, "receive function %u returned NULL", + fcinfo->flinfo->fn_oid); /* Trouble if it didn't eat the whole buffer */ if (cstate->attribute_buf.cursor != cstate->attribute_buf.len) diff --git a/src/backend/commands/copyto.c b/src/backend/commands/copyto.c index 5857532f54e..b5cada5cb75 100644 --- a/src/backend/commands/copyto.c +++ b/src/backend/commands/copyto.c @@ -54,6 +54,20 @@ typedef enum CopyDest COPY_CALLBACK, /* to callback function */ } CopyDest; +typedef struct CopyOutAttributeInfo +{ + AttrNumber num; + const char *name; + int32 typid; + + FmgrInfo out_finfo; + union + { + FunctionCallInfoBaseData fcinfo; + char fcinfo_data[SizeForFunctionCallInfo(1)]; + } out_fcinfo; +} CopyOutAttributeInfo; + /* * This struct contains all the state variables used throughout a COPY TO * operation. @@ -96,7 +110,8 @@ typedef struct CopyToStateData */ MemoryContext copycontext; /* per-copy execution context */ - FmgrInfo *out_functions; /* lookup info for output functions */ + CopyOutAttributeInfo *out_attributes; + MemoryContext rowcontext; /* per-row evaluation context */ uint64 bytes_processed; /* number of bytes processed so far */ } CopyToStateData; @@ -768,23 +783,34 @@ DoCopyTo(CopyToState cstate) cstate->fe_msgbuf = makeStringInfo(); /* Get info about the columns we need to process. */ - cstate->out_functions = (FmgrInfo *) palloc(num_phys_attrs * sizeof(FmgrInfo)); + cstate->out_attributes = + (CopyOutAttributeInfo *) palloc(num_phys_attrs * sizeof(CopyOutAttributeInfo)); foreach(cur, cstate->attnumlist) { int attnum = lfirst_int(cur); + CopyOutAttributeInfo *attr = &cstate->out_attributes[attnum - 1]; + Form_pg_attribute pgatt; Oid out_func_oid; bool isvarlena; - Form_pg_attribute attr = TupleDescAttr(tupDesc, attnum - 1); + + pgatt = TupleDescAttr(tupDesc, attnum - 1); + attr->num = attnum; + attr->name = NameStr(pgatt->attname); + attr->typid = pgatt->atttypid; if (cstate->opts.binary) - getTypeBinaryOutputInfo(attr->atttypid, + getTypeBinaryOutputInfo(attr->typid, &out_func_oid, &isvarlena); else - getTypeOutputInfo(attr->atttypid, + getTypeOutputInfo(attr->typid, &out_func_oid, &isvarlena); - fmgr_info(out_func_oid, &cstate->out_functions[attnum - 1]); + + fmgr_info(out_func_oid, &attr->out_finfo); + InitFunctionCallInfoData(attr->out_fcinfo.fcinfo, &attr->out_finfo, + 1, InvalidOid, + NULL, NULL); } /* @@ -908,7 +934,7 @@ static void CopyOneRowTo(CopyToState cstate, TupleTableSlot *slot) { bool need_delim = false; - FmgrInfo *out_functions = cstate->out_functions; + CopyOutAttributeInfo *out_attributes = cstate->out_attributes; MemoryContext oldcontext; ListCell *cur; char *string; @@ -928,6 +954,8 @@ CopyOneRowTo(CopyToState cstate, TupleTableSlot *slot) foreach(cur, cstate->attnumlist) { int attnum = lfirst_int(cur); + CopyOutAttributeInfo *attr = &out_attributes[attnum - 1]; + FunctionCallInfo fcinfo = &attr->out_fcinfo.fcinfo; Datum value = slot->tts_values[attnum - 1]; bool isnull = slot->tts_isnull[attnum - 1]; @@ -949,8 +977,22 @@ CopyOneRowTo(CopyToState cstate, TupleTableSlot *slot) { if (!cstate->opts.binary) { - string = OutputFunctionCall(&out_functions[attnum - 1], - value); + Datum result; + + fcinfo->args[0].value = value; + fcinfo->args[0].isnull = false; + + result = FunctionCallInvoke(fcinfo); + + /* + * Check for null result, since caller is clearly not + * expecting one + */ + if (unlikely(fcinfo->isnull)) + elog(ERROR, "send function return null"); + + string = DatumGetCString(result); + if (cstate->opts.csv_mode) CopyAttributeOutCSV(cstate, string, cstate->opts.force_quote_flags[attnum - 1]); @@ -959,13 +1001,26 @@ CopyOneRowTo(CopyToState cstate, TupleTableSlot *slot) } else { + int outputlen; + Datum result; bytea *outputbytes; - outputbytes = SendFunctionCall(&out_functions[attnum - 1], - value); - CopySendInt32(cstate, VARSIZE(outputbytes) - VARHDRSZ); - CopySendData(cstate, VARDATA(outputbytes), - VARSIZE(outputbytes) - VARHDRSZ); + fcinfo->args[0].value = value; + fcinfo->args[0].isnull = false; + result = FunctionCallInvoke(fcinfo); + + /* + * Check for null result, since caller is clearly not + * expecting one + */ + if (unlikely(fcinfo->isnull)) + elog(ERROR, "send function return null"); + + outputbytes = DatumGetByteaP(result); + outputlen = VARSIZE(outputbytes) - VARHDRSZ; + + CopySendInt32(cstate, outputlen); + CopySendData(cstate, VARDATA(outputbytes), outputlen); } } } diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index d808aad8b05..2bd1028a5f4 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -273,6 +273,13 @@ BlockId BlockIdData BlockInfoRecord BlockNumber +BlockRefTable +BlockRefTableBuffer +BlockRefTableEntry +BlockRefTableKey +BlockRefTableReader +BlockRefTableSerializedEntry +BlockRefTableWriter BlockSampler BlockSamplerData BlockedProcData @@ -373,7 +380,6 @@ CatalogId CatalogIdMapEntry CatalogIndexState ChangeVarNodes_context -ReplaceVarnoContext CheckPoint CheckPointStmt CheckpointStatsData @@ -476,10 +482,12 @@ CopyFormatOptions CopyFromState CopyFromStateData CopyHeaderChoice +CopyInAttributeInfo CopyInsertMethod CopyMultiInsertBuffer CopyMultiInsertInfo CopyOnErrorChoice +CopyOutAttributeInfo CopySource CopyStmt CopyToState @@ -552,6 +560,8 @@ DR_intorel DR_printtup DR_sqlfunction DR_transientrel +DSMRegistryCtxStruct +DSMRegistryEntry DWORD DataDirSyncMethod DataDumperPtr @@ -612,8 +622,6 @@ DropSubscriptionStmt DropTableSpaceStmt DropUserMappingStmt DropdbStmt -DSMRegistryCtxStruct -DSMRegistryEntry DumpComponents DumpId DumpOptions @@ -748,6 +756,7 @@ FetchStmt FieldSelect FieldStore File +FileBackupMethod FileFdwExecutionState FileFdwPlanState FileNameMap @@ -1157,6 +1166,7 @@ InProgressEnt IncludeWal InclusionOpaque IncrementVarSublevelsUp_context +IncrementalBackupInfo IncrementalSort IncrementalSortExecutionStatus IncrementalSortGroupInfo @@ -1291,9 +1301,9 @@ JsonManifestWALRangeField JsonObjectAgg JsonObjectConstructor JsonOutput -JsonParseExpr JsonParseContext JsonParseErrorType +JsonParseExpr JsonPath JsonPathBool JsonPathExecContext @@ -2008,6 +2018,7 @@ PathClauseUsage PathCostComparison PathHashStack PathKey +PathKeyInfo PathKeysComparison PathTarget PatternInfo @@ -2359,6 +2370,7 @@ ReorderBufferUpdateProgressTxnCB ReorderTuple RepOriginId ReparameterizeForeignPathByChild_function +ReplaceVarnoContext ReplaceVarsFromTargetList_context ReplaceVarsNoMatchOption ReplicaIdentityStmt @@ -2697,6 +2709,7 @@ SubscriptingRefState Subscription SubscriptionInfo SubscriptionRelState +SummarizerReadLocalXLogPrivate SupportRequestCost SupportRequestIndexCondition SupportRequestOptimizeWindowClause @@ -2846,7 +2859,6 @@ TocEntry TokenAuxData TokenizedAuthLine TrackItem -TransamVariablesData TransApplyAction TransInvalidationInfo TransState @@ -2855,6 +2867,7 @@ TransactionState TransactionStateData TransactionStmt TransactionStmtKind +TransamVariablesData TransformInfo TransformJsonStringValuesState TransitionCaptureState @@ -2898,8 +2911,8 @@ TupleTableSlotOps TuplesortClusterArg TuplesortDatumArg TuplesortIndexArg -TuplesortIndexBrinArg TuplesortIndexBTreeArg +TuplesortIndexBrinArg TuplesortIndexHashArg TuplesortInstrumentation TuplesortMethod @@ -2945,12 +2958,14 @@ UnicodeNormalizationQC Unique UniquePath UniquePathMethod +UniqueRelInfo UniqueState UnlistenStmt UnresolvedTup UnresolvedTupData UpdateContext UpdateStmt +UploadManifestCmd UpperRelationKind UpperUniquePath UserAuth @@ -2999,7 +3014,6 @@ VolatileFunctionStatus Vsrt WAIT_ORDER WALAvailability -WalInsertClass WALInsertLock WALInsertLockPadded WALOpenSegment @@ -3032,6 +3046,7 @@ WaitEventTimeout WaitPMResult WalCloseMethod WalCompression +WalInsertClass WalLevel WalRcvData WalRcvExecResult @@ -3045,6 +3060,9 @@ WalSnd WalSndCtlData WalSndSendDataCallback WalSndState +WalSummarizerData +WalSummaryFile +WalSummaryIO WalSyncMethod WalTimeSample WalUsage @@ -3201,8 +3219,10 @@ avl_node avl_tree avw_dbase backslashResult +backup_file_entry backup_manifest_info backup_manifest_option +backup_wal_range base_yy_extra_type basebackup_options bbsink @@ -3245,6 +3265,10 @@ cached_re_str canonicalize_state cashKEY catalogid_hash +cb_cleanup_dir +cb_options +cb_tablespace +cb_tablespace_mapping check_agg_arguments_context check_function_callback check_network_data @@ -3498,10 +3522,12 @@ macKEY macaddr macaddr8 macaddr_sortsupport_state +manifest_data manifest_file manifest_files_hash manifest_files_iterator manifest_wal_range +manifest_writer map_variable_attnos_context max_parallel_hazard_context mb2wchar_with_len_converter @@ -3733,6 +3759,7 @@ ret_type rewind_source rewrite_event rf_context +rfile rm_detail_t role_auth_extra rolename_hash @@ -3866,7 +3893,6 @@ unicodeStyleColumnFormat unicodeStyleFormat unicodeStyleRowFormat unicode_linestyle -UniqueRelInfo unit_conversion unlogged_relation_entry utf_local_conversion_func @@ -3907,6 +3933,8 @@ worker_spi_state worker_state worktable wrap +ws_file_info +ws_options xl_brin_createidx xl_brin_desummarize xl_brin_insert @@ -4026,29 +4054,3 @@ yyscan_t z_stream z_streamp zic_t -BlockRefTable -BlockRefTableBuffer -BlockRefTableEntry -BlockRefTableKey -BlockRefTableReader -BlockRefTableSerializedEntry -BlockRefTableWriter -SummarizerReadLocalXLogPrivate -WalSummarizerData -WalSummaryFile -WalSummaryIO -FileBackupMethod -IncrementalBackupInfo -UploadManifestCmd -backup_file_entry -backup_wal_range -cb_cleanup_dir -cb_options -cb_tablespace -cb_tablespace_mapping -manifest_data -manifest_writer -rfile -ws_options -ws_file_info -PathKeyInfo -- 2.38.0