mirror of https://github.com/citusdata/citus.git
Support for deferred error messages.
It can be useful, e.g. in the upcoming prepared statement support, to be able to return an error from a function that is not raised immediately, but can later be thrown. That allows e.g. to attempt to plan a statment using different methods and to create good error messages in each planner, but to only error out after all planners have been run. To enable that create support for deferred error messages that can be created (supporting errorcode, message, detail, hint) in one function, and then thrown in different place.pull/1134/head
parent
9a82e8f06b
commit
557ccc6fda
|
@ -13,6 +13,7 @@
|
|||
#include "catalog/pg_type.h"
|
||||
#include "distributed/citus_nodes.h"
|
||||
#include "distributed/citus_nodefuncs.h"
|
||||
#include "distributed/errormessage.h"
|
||||
#include "distributed/metadata_cache.h"
|
||||
#include "distributed/multi_planner.h"
|
||||
|
||||
|
@ -33,7 +34,8 @@ static const char *CitusNodeTagNamesD[] = {
|
|||
"Task",
|
||||
"ShardInterval",
|
||||
"ShardPlacement",
|
||||
"RelationShard"
|
||||
"RelationShard",
|
||||
"DeferredErrorMessage"
|
||||
};
|
||||
|
||||
const char **CitusNodeTagNames = CitusNodeTagNamesD;
|
||||
|
@ -383,6 +385,7 @@ const ExtensibleNodeMethods nodeMethods[] =
|
|||
DEFINE_NODE_METHODS(ShardPlacement),
|
||||
DEFINE_NODE_METHODS(RelationShard),
|
||||
DEFINE_NODE_METHODS(Task),
|
||||
DEFINE_NODE_METHODS(DeferredErrorMessage),
|
||||
|
||||
/* nodes with only output support */
|
||||
DEFINE_NODE_METHODS_NO_READ(MultiNode),
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "distributed/citus_nodefuncs.h"
|
||||
#include "distributed/citus_nodes.h"
|
||||
#include "distributed/errormessage.h"
|
||||
#include "distributed/multi_logical_planner.h"
|
||||
#include "distributed/multi_physical_planner.h"
|
||||
#include "distributed/multi_planner.h"
|
||||
|
@ -515,6 +516,23 @@ OutTask(OUTFUNC_ARGS)
|
|||
WRITE_NODE_FIELD(relationShardList);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
OutDeferredErrorMessage(OUTFUNC_ARGS)
|
||||
{
|
||||
WRITE_LOCALS(DeferredErrorMessage);
|
||||
WRITE_NODE_TYPE("DEFERREDERRORMESSAGE");
|
||||
|
||||
WRITE_INT_FIELD(code);
|
||||
WRITE_STRING_FIELD(message);
|
||||
WRITE_STRING_FIELD(detail);
|
||||
WRITE_STRING_FIELD(hint);
|
||||
WRITE_STRING_FIELD(filename);
|
||||
WRITE_INT_FIELD(linenumber);
|
||||
WRITE_STRING_FIELD(functionname);
|
||||
}
|
||||
|
||||
|
||||
#if (PG_VERSION_NUM < 90600)
|
||||
|
||||
/*
|
||||
|
@ -635,6 +653,12 @@ outNode(StringInfo str, const void *obj)
|
|||
appendStringInfoChar(str, '}');
|
||||
break;
|
||||
|
||||
case T_DeferredErrorMessage:
|
||||
appendStringInfoChar(str, '{');
|
||||
OutDeferredErrorMessage(str, obj);
|
||||
appendStringInfoChar(str, '}');
|
||||
break;
|
||||
|
||||
default:
|
||||
/* fall back into postgres' normal nodeToString machinery */
|
||||
appendStringInfoString(str, nodeToString(obj));
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <math.h>
|
||||
|
||||
#include "distributed/citus_nodefuncs.h"
|
||||
#include "distributed/errormessage.h"
|
||||
#include "distributed/multi_planner.h"
|
||||
#include "nodes/parsenodes.h"
|
||||
#include "nodes/readfuncs.h"
|
||||
|
@ -314,6 +315,24 @@ ReadTask(READFUNC_ARGS)
|
|||
READ_DONE();
|
||||
}
|
||||
|
||||
|
||||
READFUNC_RET
|
||||
ReadDeferredErrorMessage(READFUNC_ARGS)
|
||||
{
|
||||
READ_LOCALS(DeferredErrorMessage);
|
||||
|
||||
READ_INT_FIELD(code);
|
||||
READ_STRING_FIELD(message);
|
||||
READ_STRING_FIELD(detail);
|
||||
READ_STRING_FIELD(hint);
|
||||
READ_STRING_FIELD(filename);
|
||||
READ_INT_FIELD(linenumber);
|
||||
READ_STRING_FIELD(functionname);
|
||||
|
||||
READ_DONE();
|
||||
}
|
||||
|
||||
|
||||
READFUNC_RET
|
||||
ReadUnsupportedCitusNode(READFUNC_ARGS)
|
||||
{
|
||||
|
|
|
@ -1519,6 +1519,8 @@ CitusParseNodeString(void)
|
|||
return_value = ReadRelationShard();
|
||||
else if (MATCH("TASK", 4))
|
||||
return_value = ReadTask();
|
||||
else if (MATCH("DEFERREDERRORMESSAGE", 20))
|
||||
return_value = ReadDeferredErrorMessage();
|
||||
/* XXX: END Citus Nodes */
|
||||
else
|
||||
{
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* errormessage.c
|
||||
* Error handling related support functionality.
|
||||
*
|
||||
* Copyright (c) 2017, Citus Data, Inc.
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "distributed/citus_nodes.h"
|
||||
#include "distributed/errormessage.h"
|
||||
|
||||
|
||||
/*
|
||||
* DeferredErrorInternal is a helper function for DeferredError().
|
||||
*/
|
||||
DeferredErrorMessage *
|
||||
DeferredErrorInternal(int code, const char *message, const char *detail, const char *hint,
|
||||
const char *filename, int linenumber, const char *functionname)
|
||||
{
|
||||
DeferredErrorMessage *error = CitusMakeNode(DeferredErrorMessage);
|
||||
|
||||
error->code = code;
|
||||
error->message = message;
|
||||
error->detail = detail;
|
||||
error->hint = hint;
|
||||
error->filename = filename;
|
||||
error->linenumber = linenumber;
|
||||
error->functionname = functionname;
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* RaiseDeferredErrorInternal is a helper function for RaiseDeferredError().
|
||||
*/
|
||||
void
|
||||
RaiseDeferredErrorInternal(DeferredErrorMessage *error, int elevel)
|
||||
{
|
||||
ErrorData *errorData = palloc0(sizeof(ErrorData));
|
||||
|
||||
errorData->sqlerrcode = error->code;
|
||||
errorData->elevel = elevel;
|
||||
errorData->message = pstrdup(error->message);
|
||||
if (error->detail)
|
||||
{
|
||||
errorData->detail = pstrdup(error->detail);
|
||||
}
|
||||
if (error->hint)
|
||||
{
|
||||
errorData->hint = pstrdup(error->hint);
|
||||
}
|
||||
errorData->filename = pstrdup(error->filename);
|
||||
errorData->lineno = error->linenumber;
|
||||
errorData->funcname = error->functionname;
|
||||
|
||||
ThrowErrorData(errorData);
|
||||
}
|
|
@ -68,6 +68,7 @@ extern READFUNC_RET ReadMapMergeJob(READFUNC_ARGS);
|
|||
extern READFUNC_RET ReadShardPlacement(READFUNC_ARGS);
|
||||
extern READFUNC_RET ReadRelationShard(READFUNC_ARGS);
|
||||
extern READFUNC_RET ReadTask(READFUNC_ARGS);
|
||||
extern READFUNC_RET ReadDeferredErrorMessage(READFUNC_ARGS);
|
||||
|
||||
extern READFUNC_RET ReadUnsupportedCitusNode(READFUNC_ARGS);
|
||||
|
||||
|
@ -78,6 +79,7 @@ extern void OutMapMergeJob(OUTFUNC_ARGS);
|
|||
extern void OutShardPlacement(OUTFUNC_ARGS);
|
||||
extern void OutRelationShard(OUTFUNC_ARGS);
|
||||
extern void OutTask(OUTFUNC_ARGS);
|
||||
extern void OutDeferredErrorMessage(OUTFUNC_ARGS);
|
||||
|
||||
extern void OutMultiNode(OUTFUNC_ARGS);
|
||||
extern void OutMultiTreeRoot(OUTFUNC_ARGS);
|
||||
|
|
|
@ -56,7 +56,8 @@ typedef enum CitusNodeTag
|
|||
T_Task,
|
||||
T_ShardInterval,
|
||||
T_ShardPlacement,
|
||||
T_RelationShard
|
||||
T_RelationShard,
|
||||
T_DeferredErrorMessage
|
||||
} CitusNodeTag;
|
||||
|
||||
|
||||
|
@ -99,6 +100,8 @@ CitusNodeTagI(Node *node)
|
|||
|
||||
#else
|
||||
|
||||
#include "nodes/nodes.h"
|
||||
|
||||
typedef CitusNodeTag CitusNode;
|
||||
/*
|
||||
* nodeTag equivalent that returns the node tag for both citus and postgres
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* errormessage.h
|
||||
* Error handling related support functionality.
|
||||
*
|
||||
* Copyright (c) 2017, Citus Data, Inc.
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef ERRORMESSAGE_H
|
||||
#define ERRORMESSAGE_H
|
||||
|
||||
|
||||
#include "distributed/citus_nodes.h"
|
||||
|
||||
|
||||
typedef struct DeferredErrorMessage
|
||||
{
|
||||
CitusNode tag;
|
||||
|
||||
int code;
|
||||
const char *message;
|
||||
const char *detail;
|
||||
const char *hint;
|
||||
const char *filename;
|
||||
int linenumber;
|
||||
const char *functionname;
|
||||
} DeferredErrorMessage;
|
||||
|
||||
|
||||
/*
|
||||
* DeferredError allocates a deferred error message, that can later be emitted
|
||||
* using RaiseDeferredError(). These error messages can be
|
||||
* serialized/copied/deserialized, i.e. can be embedded in plans and such.
|
||||
*/
|
||||
#define DeferredError(code, message, detail, hint) \
|
||||
DeferredErrorInternal(code, message, detail, hint, __FILE__, __LINE__, __func__)
|
||||
|
||||
DeferredErrorMessage * DeferredErrorInternal(int code, const char *message, const
|
||||
char *detail, const char *hint,
|
||||
const char *filename, int linenumber, const
|
||||
char *functionname);
|
||||
|
||||
/*
|
||||
* RaiseDeferredError emits a previously allocated error using the specified
|
||||
* severity.
|
||||
*
|
||||
* The trickery with __builtin_constant_p/pg_unreachable aims to have the
|
||||
* compiler understand that the function will not return if elevel >= ERROR.
|
||||
*/
|
||||
#define RaiseDeferredError(error, elevel) \
|
||||
do { \
|
||||
RaiseDeferredErrorInternal(error, elevel); \
|
||||
if (__builtin_constant_p(elevel) && (elevel) >= ERROR) { \
|
||||
pg_unreachable(); } \
|
||||
} while (0)
|
||||
|
||||
void RaiseDeferredErrorInternal(DeferredErrorMessage *error, int elevel);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue