public inbox for [email protected]help / color / mirror / Atom feed
[PATCH v1] Change pg_attribute_noreturn() to pg_noreturn, move to before return type. 3+ messages / 3 participants [nested] [flat]
* [PATCH v1] Change pg_attribute_noreturn() to pg_noreturn, move to before return type. @ 2019-11-12 21:55 Andres Freund <[email protected]> 0 siblings, 0 replies; 3+ messages in thread From: Andres Freund @ 2019-11-12 21:55 UTC (permalink / raw) --- contrib/cube/cubedata.h | 2 +- contrib/dblink/dblink.c | 6 ++---- contrib/pgcrypto/px.h | 2 +- contrib/seg/segdata.h | 2 +- src/backend/postmaster/autovacuum.c | 4 ++-- src/backend/postmaster/pgarch.c | 2 +- src/backend/postmaster/pgstat.c | 2 +- src/backend/postmaster/postmaster.c | 4 ++-- src/backend/postmaster/syslogger.c | 2 +- src/backend/replication/logical/tablesync.c | 3 +-- src/backend/replication/walsender.c | 2 +- src/backend/utils/adt/json.c | 4 ++-- src/backend/utils/adt/ri_triggers.c | 8 ++++---- src/backend/utils/fmgr/dfmgr.c | 4 ++-- src/backend/utils/misc/guc.c | 3 +-- src/bin/pg_dump/pg_backup_utils.h | 2 +- src/bin/pg_upgrade/pg_upgrade.h | 2 +- src/bin/pgbench/pgbench.h | 12 ++++++------ src/include/bootstrap/bootstrap.h | 4 ++-- src/include/c.h | 10 +++++----- src/include/mb/pg_wchar.h | 6 +++--- src/include/parser/parse_relation.h | 6 +++--- src/include/parser/scanner.h | 2 +- src/include/pgstat.h | 2 +- src/include/postmaster/autovacuum.h | 4 ++-- src/include/postmaster/bgworker_internals.h | 2 +- src/include/postmaster/bgwriter.h | 4 ++-- src/include/postmaster/pgarch.h | 2 +- src/include/postmaster/postmaster.h | 4 ++-- src/include/postmaster/startup.h | 2 +- src/include/postmaster/syslogger.h | 2 +- src/include/postmaster/walwriter.h | 2 +- src/include/replication/walreceiver.h | 2 +- src/include/replication/walsender_private.h | 2 +- src/include/storage/ipc.h | 2 +- src/include/storage/lock.h | 2 +- src/include/tcop/tcopprot.h | 10 +++++----- src/include/utils/datetime.h | 4 ++-- src/include/utils/elog.h | 8 ++++---- src/include/utils/help_config.h | 2 +- src/interfaces/ecpg/preproc/preproc_extern.h | 2 +- src/pl/plpgsql/src/plpgsql.h | 2 +- src/test/modules/test_shm_mq/test_shm_mq.h | 2 +- src/test/modules/worker_spi/worker_spi.c | 2 +- src/timezone/zic.c | 4 ++-- 45 files changed, 79 insertions(+), 83 deletions(-) diff --git a/contrib/cube/cubedata.h b/contrib/cube/cubedata.h index dbe7d4f7429..178fb46f217 100644 --- a/contrib/cube/cubedata.h +++ b/contrib/cube/cubedata.h @@ -61,7 +61,7 @@ typedef struct NDBOX /* in cubescan.l */ extern int cube_yylex(void); -extern void cube_yyerror(NDBOX **result, const char *message) pg_attribute_noreturn(); +extern pg_noreturn void cube_yyerror(NDBOX **result, const char *message); extern void cube_scanner_init(const char *str); extern void cube_scanner_finish(void); diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c index 7e225589a9b..371b89383d9 100644 --- a/contrib/dblink/dblink.c +++ b/contrib/dblink/dblink.c @@ -152,8 +152,7 @@ xpstrdup(const char *in) return pstrdup(in); } -static void -pg_attribute_noreturn() +static pg_noreturn void dblink_res_internalerror(PGconn *conn, PGresult *res, const char *p2) { char *msg = pchomp(PQerrorMessage(conn)); @@ -163,8 +162,7 @@ dblink_res_internalerror(PGconn *conn, PGresult *res, const char *p2) elog(ERROR, "%s: %s", p2, msg); } -static void -pg_attribute_noreturn() +static pg_noreturn void dblink_conn_not_avail(const char *conname) { if (conname) diff --git a/contrib/pgcrypto/px.h b/contrib/pgcrypto/px.h index 0d4722a04a0..a3f3a182a66 100644 --- a/contrib/pgcrypto/px.h +++ b/contrib/pgcrypto/px.h @@ -184,7 +184,7 @@ int px_find_hmac(const char *name, PX_HMAC **res); int px_find_cipher(const char *name, PX_Cipher **res); int px_find_combo(const char *name, PX_Combo **res); -void px_THROW_ERROR(int err) pg_attribute_noreturn(); +pg_noreturn void px_THROW_ERROR(int err); const char *px_strerror(int err); const char *px_resolve_alias(const PX_Alias *aliases, const char *name); diff --git a/contrib/seg/segdata.h b/contrib/seg/segdata.h index 9488bf3a81a..a5d8ac3f591 100644 --- a/contrib/seg/segdata.h +++ b/contrib/seg/segdata.h @@ -16,7 +16,7 @@ extern int significant_digits(const char *str); /* in segscan.l */ extern int seg_yylex(void); -extern void seg_yyerror(SEG *result, const char *message) pg_attribute_noreturn(); +extern pg_noreturn void seg_yyerror(SEG *result, const char *message); extern void seg_scanner_init(const char *str); extern void seg_scanner_finish(void); diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index c1dd8168caf..a266bdeb1ae 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -307,8 +307,8 @@ int AutovacuumLauncherPid = 0; static pid_t avlauncher_forkexec(void); static pid_t avworker_forkexec(void); #endif -NON_EXEC_STATIC void AutoVacWorkerMain(int argc, char *argv[]) pg_attribute_noreturn(); -NON_EXEC_STATIC void AutoVacLauncherMain(int argc, char *argv[]) pg_attribute_noreturn(); +NON_EXEC_STATIC pg_noreturn void AutoVacWorkerMain(int argc, char *argv[]); +NON_EXEC_STATIC pg_noreturn void AutoVacLauncherMain(int argc, char *argv[]); static Oid do_start_worker(void); static void launcher_determine_sleep(bool canlaunch, bool recursing, diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c index f84f882c4cb..5b8460e4d0f 100644 --- a/src/backend/postmaster/pgarch.c +++ b/src/backend/postmaster/pgarch.c @@ -96,7 +96,7 @@ static volatile sig_atomic_t ready_to_stop = false; static pid_t pgarch_forkexec(void); #endif -NON_EXEC_STATIC void PgArchiverMain(int argc, char *argv[]) pg_attribute_noreturn(); +NON_EXEC_STATIC pg_noreturn void PgArchiverMain(int argc, char *argv[]); static void pgarch_exit(SIGNAL_ARGS); static void ArchSigHupHandler(SIGNAL_ARGS); static void ArchSigTermHandler(SIGNAL_ARGS); diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 011076c3e3e..c0641ce6123 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -284,7 +284,7 @@ static instr_time total_func_time; static pid_t pgstat_forkexec(void); #endif -NON_EXEC_STATIC void PgstatCollectorMain(int argc, char *argv[]) pg_attribute_noreturn(); +NON_EXEC_STATIC pg_noreturn void PgstatCollectorMain(int argc, char *argv[]); static void pgstat_exit(SIGNAL_ARGS); static void pgstat_beshutdown_hook(int code, Datum arg); static void pgstat_sighup_handler(SIGNAL_ARGS); diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 5f303591652..1f5c6ab403e 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -400,8 +400,8 @@ static void LogChildExit(int lev, const char *procname, int pid, int exitstatus); static void PostmasterStateMachine(void); static void BackendInitialize(Port *port); -static void BackendRun(Port *port) pg_attribute_noreturn(); -static void ExitPostmaster(int status) pg_attribute_noreturn(); +static pg_noreturn void BackendRun(Port *port); +static pg_noreturn void ExitPostmaster(int status); static int ServerLoop(void); static int BackendStartup(Port *port); static int ProcessStartupPacket(Port *port, bool secure_done); diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c index bb2baff7631..cda31f10546 100644 --- a/src/backend/postmaster/syslogger.c +++ b/src/backend/postmaster/syslogger.c @@ -137,7 +137,7 @@ static volatile sig_atomic_t rotation_requested = false; static pid_t syslogger_forkexec(void); static void syslogger_parseArgs(int argc, char *argv[]); #endif -NON_EXEC_STATIC void SysLoggerMain(int argc, char *argv[]) pg_attribute_noreturn(); +NON_EXEC_STATIC pg_noreturn void SysLoggerMain(int argc, char *argv[]); static void process_pipe_input(char *logbuffer, int *bytes_in_logbuffer); static void flush_pipe_input(char *logbuffer, int *bytes_in_logbuffer); static FILE *logfile_open(const char *filename, const char *mode, diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c index 7881079e96b..a3302e12663 100644 --- a/src/backend/replication/logical/tablesync.c +++ b/src/backend/replication/logical/tablesync.c @@ -117,8 +117,7 @@ StringInfo copybuf = NULL; /* * Exit routine for synchronization worker. */ -static void -pg_attribute_noreturn() +static pg_noreturn void finish_sync_worker(void) { /* diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index 7f5671504f7..6ab7966818f 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -222,7 +222,7 @@ typedef void (*WalSndSendDataCallback) (void); static void WalSndLoop(WalSndSendDataCallback send_data); static void InitWalSenderSlot(void); static void WalSndKill(int code, Datum arg); -static void WalSndShutdown(void) pg_attribute_noreturn(); +static pg_noreturn void WalSndShutdown(void); static void XLogSendPhysical(void); static void XLogSendLogical(void); static void WalSndDone(WalSndSendDataCallback send_data); diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c index d4ba3bd87db..fd03c0315c5 100644 --- a/src/backend/utils/adt/json.c +++ b/src/backend/utils/adt/json.c @@ -84,8 +84,8 @@ static void parse_object_field(JsonLexContext *lex, JsonSemAction *sem); static void parse_object(JsonLexContext *lex, JsonSemAction *sem); static void parse_array_element(JsonLexContext *lex, JsonSemAction *sem); static void parse_array(JsonLexContext *lex, JsonSemAction *sem); -static void report_parse_error(JsonParseContext ctx, JsonLexContext *lex) pg_attribute_noreturn(); -static void report_invalid_token(JsonLexContext *lex) pg_attribute_noreturn(); +static pg_noreturn void report_parse_error(JsonParseContext ctx, JsonLexContext *lex); +static pg_noreturn void report_invalid_token(JsonLexContext *lex); static int report_json_context(JsonLexContext *lex); static char *extract_mb_char(char *s); static void composite_to_json(Datum composite, StringInfo result, diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index caf27f8bcb4..bd94f22507e 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -218,10 +218,10 @@ static bool ri_PerformCheck(const RI_ConstraintInfo *riinfo, static void ri_ExtractValues(Relation rel, TupleTableSlot *slot, const RI_ConstraintInfo *riinfo, bool rel_is_pk, Datum *vals, char *nulls); -static void ri_ReportViolation(const RI_ConstraintInfo *riinfo, - Relation pk_rel, Relation fk_rel, - TupleTableSlot *violatorslot, TupleDesc tupdesc, - int queryno, bool partgone) pg_attribute_noreturn(); +static pg_noreturn void ri_ReportViolation(const RI_ConstraintInfo *riinfo, + Relation pk_rel, Relation fk_rel, + TupleTableSlot *violatorslot, TupleDesc tupdesc, + int queryno, bool partgone); /* diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c index be684786d64..88c4978f348 100644 --- a/src/backend/utils/fmgr/dfmgr.c +++ b/src/backend/utils/fmgr/dfmgr.c @@ -77,8 +77,8 @@ static DynamicFileList *file_tail = NULL; char *Dynamic_library_path; static void *internal_load_library(const char *libname); -static void incompatible_module_error(const char *libname, - const Pg_magic_struct *module_magic_data) pg_attribute_noreturn(); +static pg_noreturn void incompatible_module_error(const char *libname, + const Pg_magic_struct *module_magic_data); static void internal_unload_library(const char *libname); static bool file_exists(const char *name); static char *expand_dynamic_library_name(const char *name); diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 994bf37477a..92e84bda2ba 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -11624,8 +11624,7 @@ assign_recovery_target_timeline(const char *newval, void *extra) * string. */ -static void -pg_attribute_noreturn() +static pg_noreturn void error_multiple_recovery_targets(void) { ereport(ERROR, diff --git a/src/bin/pg_dump/pg_backup_utils.h b/src/bin/pg_dump/pg_backup_utils.h index 619c9fe08c8..c5c81b41a49 100644 --- a/src/bin/pg_dump/pg_backup_utils.h +++ b/src/bin/pg_dump/pg_backup_utils.h @@ -31,7 +31,7 @@ extern const char *progname; extern void set_dump_section(const char *arg, int *dumpSections); extern void on_exit_nicely(on_exit_nicely_callback function, void *arg); -extern void exit_nicely(int code) pg_attribute_noreturn(); +extern pg_noreturn void exit_nicely(int code); #define fatal(...) do { pg_log_error(__VA_ARGS__); exit_nicely(1); } while(0) diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h index 729f86aa32d..6150883a4ed 100644 --- a/src/bin/pg_upgrade/pg_upgrade.h +++ b/src/bin/pg_upgrade/pg_upgrade.h @@ -434,7 +434,7 @@ int get_user_info(char **user_name_p); void check_ok(void); void report_status(eLogType type, const char *fmt,...) pg_attribute_printf(2, 3); void pg_log(eLogType type, const char *fmt,...) pg_attribute_printf(2, 3); -void pg_fatal(const char *fmt,...) pg_attribute_printf(1, 2) pg_attribute_noreturn(); +pg_noreturn void pg_fatal(const char *fmt,...) pg_attribute_printf(1, 2); void end_progress_output(void); void prep_status(const char *fmt,...) pg_attribute_printf(1, 2); void check_ok(void); diff --git a/src/bin/pgbench/pgbench.h b/src/bin/pgbench/pgbench.h index c4a1e298e06..3759528e44d 100644 --- a/src/bin/pgbench/pgbench.h +++ b/src/bin/pgbench/pgbench.h @@ -141,9 +141,9 @@ extern PgBenchExpr *expr_parse_result; extern int expr_yyparse(yyscan_t yyscanner); extern int expr_yylex(union YYSTYPE *lvalp, yyscan_t yyscanner); -extern void expr_yyerror(yyscan_t yyscanner, const char *str) pg_attribute_noreturn(); -extern void expr_yyerror_more(yyscan_t yyscanner, const char *str, - const char *more) pg_attribute_noreturn(); +extern pg_noreturn void expr_yyerror(yyscan_t yyscanner, const char *str); +extern pg_noreturn void expr_yyerror_more(yyscan_t yyscanner, const char *str, + const char *more); extern bool expr_lex_one_word(PsqlScanState state, PQExpBuffer word_buf, int *offset); extern yyscan_t expr_scanner_init(PsqlScanState state, @@ -156,9 +156,9 @@ extern char *expr_scanner_get_substring(PsqlScanState state, bool chomp); extern int expr_scanner_get_lineno(PsqlScanState state, int offset); -extern void syntax_error(const char *source, int lineno, const char *line, - const char *cmd, const char *msg, - const char *more, int col) pg_attribute_noreturn(); +extern pg_noreturn void syntax_error(const char *source, int lineno, const char *line, + const char *cmd, const char *msg, + const char *more, int col); extern bool strtoint64(const char *str, bool errorOK, int64 *pi); extern bool strtodouble(const char *str, bool errorOK, double *pd); diff --git a/src/include/bootstrap/bootstrap.h b/src/include/bootstrap/bootstrap.h index 85705602cb3..151d0ab3557 100644 --- a/src/include/bootstrap/bootstrap.h +++ b/src/include/bootstrap/bootstrap.h @@ -32,7 +32,7 @@ extern Form_pg_attribute attrtypes[MAXATTR]; extern int numattr; -extern void AuxiliaryProcessMain(int argc, char *argv[]) pg_attribute_noreturn(); +extern pg_noreturn void AuxiliaryProcessMain(int argc, char *argv[]); extern void closerel(char *name); extern void boot_openrel(char *name); @@ -57,6 +57,6 @@ extern void boot_get_type_io_data(Oid typid, extern int boot_yyparse(void); extern int boot_yylex(void); -extern void boot_yyerror(const char *str) pg_attribute_noreturn(); +extern pg_noreturn void boot_yyerror(const char *str); #endif /* BOOTSTRAP_H */ diff --git a/src/include/c.h b/src/include/c.h index c95acd35f7f..d5000557c0e 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -135,7 +135,7 @@ /* GCC, Sunpro and XLC support aligned, packed and noreturn */ #if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__IBMC__) #define pg_attribute_aligned(a) __attribute__((aligned(a))) -#define pg_attribute_noreturn() __attribute__((noreturn)) +#define pg_noreturn __attribute__((noreturn)) #define pg_attribute_packed() __attribute__((packed)) #define HAVE_PG_ATTRIBUTE_NORETURN 1 #else @@ -144,7 +144,7 @@ * affect code functionality; they *must* be implemented by the compiler * if they are to be used. */ -#define pg_attribute_noreturn() +#define pg_noreturn #endif /* @@ -813,9 +813,9 @@ typedef NameData *Name; * we should declare it as long as !FRONTEND. */ #ifndef FRONTEND -extern void ExceptionalCondition(const char *conditionName, - const char *errorType, - const char *fileName, int lineNumber) pg_attribute_noreturn(); +extern pg_noreturn void ExceptionalCondition(const char *conditionName, + const char *errorType, + const char *fileName, int lineNumber); #endif /* diff --git a/src/include/mb/pg_wchar.h b/src/include/mb/pg_wchar.h index 3e3e6c470e9..05169fc87de 100644 --- a/src/include/mb/pg_wchar.h +++ b/src/include/mb/pg_wchar.h @@ -608,9 +608,9 @@ extern void check_encoding_conversion_args(int src_encoding, int expected_src_encoding, int expected_dest_encoding); -extern void report_invalid_encoding(int encoding, const char *mbstr, int len) pg_attribute_noreturn(); -extern void report_untranslatable_char(int src_encoding, int dest_encoding, - const char *mbstr, int len) pg_attribute_noreturn(); +extern pg_noreturn void report_invalid_encoding(int encoding, const char *mbstr, int len); +extern pg_noreturn void report_untranslatable_char(int src_encoding, int dest_encoding, + const char *mbstr, int len); extern void local2local(const unsigned char *l, unsigned char *p, int len, int src_encoding, int dest_encoding, const unsigned char *tab); diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h index f7e078172de..4859cce8d1e 100644 --- a/src/include/parser/parse_relation.h +++ b/src/include/parser/parse_relation.h @@ -116,9 +116,9 @@ extern bool isLockedRefname(ParseState *pstate, const char *refname); extern void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace); -extern void errorMissingRTE(ParseState *pstate, RangeVar *relation) pg_attribute_noreturn(); -extern void errorMissingColumn(ParseState *pstate, - const char *relname, const char *colname, int location) pg_attribute_noreturn(); +extern pg_noreturn void errorMissingRTE(ParseState *pstate, RangeVar *relation); +extern pg_noreturn void errorMissingColumn(ParseState *pstate, + const char *relname, const char *colname, int location); extern void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, int location, bool include_dropped, List **colnames, List **colvars); diff --git a/src/include/parser/scanner.h b/src/include/parser/scanner.h index 731a2bd264a..c10d42bf35a 100644 --- a/src/include/parser/scanner.h +++ b/src/include/parser/scanner.h @@ -128,6 +128,6 @@ extern void scanner_finish(core_yyscan_t yyscanner); extern int core_yylex(core_YYSTYPE *lvalp, YYLTYPE *llocp, core_yyscan_t yyscanner); extern int scanner_errposition(int location, core_yyscan_t yyscanner); -extern void scanner_yyerror(const char *message, core_yyscan_t yyscanner) pg_attribute_noreturn(); +extern pg_noreturn void scanner_yyerror(const char *message, core_yyscan_t yyscanner); #endif /* SCANNER_H */ diff --git a/src/include/pgstat.h b/src/include/pgstat.h index fe076d823db..58453faaaec 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -1240,7 +1240,7 @@ extern void pgstat_reset_all(void); extern void allow_immediate_pgstat_restart(void); #ifdef EXEC_BACKEND -extern void PgstatCollectorMain(int argc, char *argv[]) pg_attribute_noreturn(); +extern pg_noreturn void PgstatCollectorMain(int argc, char *argv[]); #endif diff --git a/src/include/postmaster/autovacuum.h b/src/include/postmaster/autovacuum.h index 8451e5d9e27..663ac67d04c 100644 --- a/src/include/postmaster/autovacuum.h +++ b/src/include/postmaster/autovacuum.h @@ -65,8 +65,8 @@ extern void AutoVacWorkerFailed(void); extern void AutoVacuumUpdateDelay(void); #ifdef EXEC_BACKEND -extern void AutoVacLauncherMain(int argc, char *argv[]) pg_attribute_noreturn(); -extern void AutoVacWorkerMain(int argc, char *argv[]) pg_attribute_noreturn(); +extern pg_noreturn void AutoVacLauncherMain(int argc, char *argv[]); +extern pg_noreturn void AutoVacWorkerMain(int argc, char *argv[]); extern void AutovacuumWorkerIAm(void); extern void AutovacuumLauncherIAm(void); #endif diff --git a/src/include/postmaster/bgworker_internals.h b/src/include/postmaster/bgworker_internals.h index 0809e0af538..db1358578cb 100644 --- a/src/include/postmaster/bgworker_internals.h +++ b/src/include/postmaster/bgworker_internals.h @@ -54,7 +54,7 @@ extern void BackgroundWorkerStopNotifications(pid_t pid); extern void ResetBackgroundWorkerCrashTimes(void); /* Function to start a background worker, called from postmaster.c */ -extern void StartBackgroundWorker(void) pg_attribute_noreturn(); +extern pg_noreturn void StartBackgroundWorker(void); #ifdef EXEC_BACKEND extern BackgroundWorker *BackgroundWorkerEntry(int slotno); diff --git a/src/include/postmaster/bgwriter.h b/src/include/postmaster/bgwriter.h index 630366f49ef..327bc4e784a 100644 --- a/src/include/postmaster/bgwriter.h +++ b/src/include/postmaster/bgwriter.h @@ -27,8 +27,8 @@ extern int CheckPointTimeout; extern int CheckPointWarning; extern double CheckPointCompletionTarget; -extern void BackgroundWriterMain(void) pg_attribute_noreturn(); -extern void CheckpointerMain(void) pg_attribute_noreturn(); +extern pg_noreturn void BackgroundWriterMain(void); +extern pg_noreturn void CheckpointerMain(void); extern void RequestCheckpoint(int flags); extern void CheckpointWriteDelay(int flags, double progress); diff --git a/src/include/postmaster/pgarch.h b/src/include/postmaster/pgarch.h index 2474eac26a5..d6f50650d5b 100644 --- a/src/include/postmaster/pgarch.h +++ b/src/include/postmaster/pgarch.h @@ -33,7 +33,7 @@ extern int pgarch_start(void); #ifdef EXEC_BACKEND -extern void PgArchiverMain(int argc, char *argv[]) pg_attribute_noreturn(); +extern pg_noreturn void PgArchiverMain(int argc, char *argv[]); #endif #endif /* _PGARCH_H */ diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h index b692d8be110..7f7ef1c58cf 100644 --- a/src/include/postmaster/postmaster.h +++ b/src/include/postmaster/postmaster.h @@ -46,7 +46,7 @@ extern int postmaster_alive_fds[2]; extern PGDLLIMPORT const char *progname; -extern void PostmasterMain(int argc, char *argv[]) pg_attribute_noreturn(); +extern pg_noreturn void PostmasterMain(int argc, char *argv[]); extern void ClosePostmasterPorts(bool am_syslogger); extern void InitProcessGlobals(void); @@ -56,7 +56,7 @@ extern bool PostmasterMarkPIDForWorkerNotify(int); #ifdef EXEC_BACKEND extern pid_t postmaster_forkexec(int argc, char *argv[]); -extern void SubPostmasterMain(int argc, char *argv[]) pg_attribute_noreturn(); +extern pg_noreturn void SubPostmasterMain(int argc, char *argv[]); extern Size ShmemBackendArraySize(void); extern void ShmemBackendArrayAllocation(void); diff --git a/src/include/postmaster/startup.h b/src/include/postmaster/startup.h index 7b3a089932e..771e1a1126b 100644 --- a/src/include/postmaster/startup.h +++ b/src/include/postmaster/startup.h @@ -13,7 +13,7 @@ #define _STARTUP_H extern void HandleStartupProcInterrupts(void); -extern void StartupProcessMain(void) pg_attribute_noreturn(); +extern pg_noreturn void StartupProcessMain(void); extern void PreRestoreCommand(void); extern void PostRestoreCommand(void); extern bool IsPromoteTriggered(void); diff --git a/src/include/postmaster/syslogger.h b/src/include/postmaster/syslogger.h index 3a611045736..17e0a22ec7b 100644 --- a/src/include/postmaster/syslogger.h +++ b/src/include/postmaster/syslogger.h @@ -84,7 +84,7 @@ extern int SysLogger_Start(void); extern void write_syslogger_file(const char *buffer, int count, int dest); #ifdef EXEC_BACKEND -extern void SysLoggerMain(int argc, char *argv[]) pg_attribute_noreturn(); +extern pg_noreturn void SysLoggerMain(int argc, char *argv[]); #endif extern bool CheckLogrotateSignal(void); diff --git a/src/include/postmaster/walwriter.h b/src/include/postmaster/walwriter.h index ae267d2411e..df73343ef9d 100644 --- a/src/include/postmaster/walwriter.h +++ b/src/include/postmaster/walwriter.h @@ -16,6 +16,6 @@ extern int WalWriterDelay; extern int WalWriterFlushAfter; -extern void WalWriterMain(void) pg_attribute_noreturn(); +extern pg_noreturn void WalWriterMain(void); #endif /* _WALWRITER_H */ diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h index e12a9349660..47a0f5a22ed 100644 --- a/src/include/replication/walreceiver.h +++ b/src/include/replication/walreceiver.h @@ -300,7 +300,7 @@ walrcv_clear_result(WalRcvExecResult *walres) } /* prototypes for functions in walreceiver.c */ -extern void WalReceiverMain(void) pg_attribute_noreturn(); +extern pg_noreturn void WalReceiverMain(void); extern void ProcessWalRcvInterrupts(void); /* prototypes for functions in walreceiverfuncs.c */ diff --git a/src/include/replication/walsender_private.h b/src/include/replication/walsender_private.h index 0dd6d1cf808..2eeee014933 100644 --- a/src/include/replication/walsender_private.h +++ b/src/include/replication/walsender_private.h @@ -120,7 +120,7 @@ extern void WalSndSetState(WalSndState state); */ extern int replication_yyparse(void); extern int replication_yylex(void); -extern void replication_yyerror(const char *str) pg_attribute_noreturn(); +extern pg_noreturn void replication_yyerror(const char *str); extern void replication_scanner_init(const char *query_string); extern void replication_scanner_finish(void); diff --git a/src/include/storage/ipc.h b/src/include/storage/ipc.h index d113813df32..cd75c79825b 100644 --- a/src/include/storage/ipc.h +++ b/src/include/storage/ipc.h @@ -65,7 +65,7 @@ typedef void (*shmem_startup_hook_type) (void); extern PGDLLIMPORT bool proc_exit_inprogress; extern PGDLLIMPORT bool shmem_exit_inprogress; -extern void proc_exit(int code) pg_attribute_noreturn(); +extern pg_noreturn void proc_exit(int code); extern void shmem_exit(int code); extern void on_proc_exit(pg_on_exit_callback function, Datum arg); extern void on_shmem_exit(pg_on_exit_callback function, Datum arg); diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h index 6efb7a96481..4bf0aa43f0e 100644 --- a/src/include/storage/lock.h +++ b/src/include/storage/lock.h @@ -575,7 +575,7 @@ extern void lock_twophase_standby_recover(TransactionId xid, uint16 info, extern DeadLockState DeadLockCheck(PGPROC *proc); extern PGPROC *GetBlockingAutoVacuumPgproc(void); -extern void DeadLockReport(void) pg_attribute_noreturn(); +extern pg_noreturn void DeadLockReport(void); extern void RememberSimpleDeadLock(PGPROC *proc1, LOCKMODE lockmode, LOCK *lock, diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h index ec21f7e45c5..b04d02b198c 100644 --- a/src/include/tcop/tcopprot.h +++ b/src/include/tcop/tcopprot.h @@ -61,9 +61,9 @@ extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); extern void assign_max_stack_depth(int newval, void *extra); extern void die(SIGNAL_ARGS); -extern void quickdie(SIGNAL_ARGS) pg_attribute_noreturn(); +extern pg_noreturn void quickdie(SIGNAL_ARGS); extern void StatementCancelHandler(SIGNAL_ARGS); -extern void FloatExceptionHandler(SIGNAL_ARGS) pg_attribute_noreturn(); +extern pg_noreturn void FloatExceptionHandler(SIGNAL_ARGS); extern void RecoveryConflictInterrupt(ProcSignalReason reason); /* called from SIGUSR1 * handler */ extern void ProcessClientReadInterrupt(bool blocked); @@ -71,9 +71,9 @@ extern void ProcessClientWriteInterrupt(bool blocked); extern void process_postgres_switches(int argc, char *argv[], GucContext ctx, const char **dbname); -extern void PostgresMain(int argc, char *argv[], - const char *dbname, - const char *username) pg_attribute_noreturn(); +extern pg_noreturn void PostgresMain(int argc, char *argv[], + const char *dbname, + const char *username); extern long get_stack_depth_rlimit(void); extern void ResetUsage(void); extern void ShowUsage(const char *title); diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h index 5ebf336071b..eba5f3c9a80 100644 --- a/src/include/utils/datetime.h +++ b/src/include/utils/datetime.h @@ -304,8 +304,8 @@ extern int DecodeInterval(char **field, int *ftype, int nf, int range, extern int DecodeISO8601Interval(char *str, int *dtype, struct pg_tm *tm, fsec_t *fsec); -extern void DateTimeParseError(int dterr, const char *str, - const char *datatype) pg_attribute_noreturn(); +extern pg_noreturn void DateTimeParseError(int dterr, const char *str, + const char *datatype); extern int DetermineTimeZoneOffset(struct pg_tm *tm, pg_tz *tzp); extern int DetermineTimeZoneAbbrevOffset(struct pg_tm *tm, const char *abbr, pg_tz *tzp); diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h index 9ab4b5470b7..9c3569e2719 100644 --- a/src/include/utils/elog.h +++ b/src/include/utils/elog.h @@ -353,8 +353,8 @@ extern PGDLLIMPORT ErrorContextCallback *error_context_stack; } while (0) /* - * Some compilers understand pg_attribute_noreturn(); for other compilers, - * insert pg_unreachable() so that the compiler gets the point. + * Some compilers understand pg_noreturn for other compilers, insert + * pg_unreachable() so that the compiler gets the point. */ #ifdef HAVE_PG_ATTRIBUTE_NORETURN #define PG_RE_THROW() \ @@ -414,9 +414,9 @@ extern void EmitErrorReport(void); extern ErrorData *CopyErrorData(void); extern void FreeErrorData(ErrorData *edata); extern void FlushErrorState(void); -extern void ReThrowError(ErrorData *edata) pg_attribute_noreturn(); +extern pg_noreturn void ReThrowError(ErrorData *edata); extern void ThrowErrorData(ErrorData *edata); -extern void pg_re_throw(void) pg_attribute_noreturn(); +extern pg_noreturn void pg_re_throw(void); extern char *GetErrorContextStack(void); diff --git a/src/include/utils/help_config.h b/src/include/utils/help_config.h index f0eace59f50..7858973968f 100644 --- a/src/include/utils/help_config.h +++ b/src/include/utils/help_config.h @@ -12,6 +12,6 @@ #ifndef HELP_CONFIG_H #define HELP_CONFIG_H 1 -extern void GucInfoMain(void) pg_attribute_noreturn(); +extern pg_noreturn void GucInfoMain(void); #endif diff --git a/src/interfaces/ecpg/preproc/preproc_extern.h b/src/interfaces/ecpg/preproc/preproc_extern.h index 323fd5c3c1a..2d83e3fefb9 100644 --- a/src/interfaces/ecpg/preproc/preproc_extern.h +++ b/src/interfaces/ecpg/preproc/preproc_extern.h @@ -76,7 +76,7 @@ extern void base_yyerror(const char *); extern void *mm_alloc(size_t); extern char *mm_strdup(const char *); extern void mmerror(int errorcode, enum errortype type, const char *error,...) pg_attribute_printf(3, 4); -extern void mmfatal(int errorcode, const char *error,...) pg_attribute_printf(2, 3) pg_attribute_noreturn(); +extern pg_noreturn void mmfatal(int errorcode, const char *error,...) pg_attribute_printf(2, 3); extern void output_get_descr_header(char *); extern void output_get_descr(char *, char *); extern void output_set_descr_header(char *); diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index f66b2baa70a..52e53c796e9 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -1318,7 +1318,7 @@ extern int plpgsql_peek(void); extern void plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc, int *tok2_loc); extern int plpgsql_scanner_errposition(int location); -extern void plpgsql_yyerror(const char *message) pg_attribute_noreturn(); +extern pg_noreturn void plpgsql_yyerror(const char *message); extern int plpgsql_location_to_lineno(int location); extern int plpgsql_latest_lineno(void); extern void plpgsql_scanner_init(const char *str); diff --git a/src/test/modules/test_shm_mq/test_shm_mq.h b/src/test/modules/test_shm_mq/test_shm_mq.h index 4c0722297e9..3ff8b5f17d8 100644 --- a/src/test/modules/test_shm_mq/test_shm_mq.h +++ b/src/test/modules/test_shm_mq/test_shm_mq.h @@ -40,6 +40,6 @@ extern void test_shm_mq_setup(int64 queue_size, int32 nworkers, shm_mq_handle **input); /* Main entrypoint for a worker. */ -extern void test_shm_mq_main(Datum) pg_attribute_noreturn(); +extern pg_noreturn void test_shm_mq_main(Datum); #endif diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c index bc9ef64a508..35583a70e72 100644 --- a/src/test/modules/worker_spi/worker_spi.c +++ b/src/test/modules/worker_spi/worker_spi.c @@ -46,7 +46,7 @@ PG_MODULE_MAGIC; PG_FUNCTION_INFO_V1(worker_spi_launch); void _PG_init(void); -void worker_spi_main(Datum) pg_attribute_noreturn(); +pg_noreturn void worker_spi_main(Datum); /* flags set by signal handlers */ static volatile sig_atomic_t got_sighup = false; diff --git a/src/timezone/zic.c b/src/timezone/zic.c index c27fb456d05..31f317d9cac 100644 --- a/src/timezone/zic.c +++ b/src/timezone/zic.c @@ -118,11 +118,11 @@ struct zone extern int link(const char *fromname, const char *toname); -static void memory_exhausted(const char *msg) pg_attribute_noreturn(); +static pg_noreturn void memory_exhausted(const char *msg); static void verror(const char *string, va_list args) pg_attribute_printf(1, 0); static void error(const char *string,...) pg_attribute_printf(1, 2); static void warning(const char *string,...) pg_attribute_printf(1, 2); -static void usage(FILE *stream, int status) pg_attribute_noreturn(); +static pg_noreturn void usage(FILE *stream, int status); static void addtt(zic_t starttime, int type); static int addtype(zic_t, char const *, bool, bool, bool); static void leapadd(zic_t, bool, int, int); -- 2.23.0.385.gbc12974a89 --k5olgh2lgulcruiy-- ^ permalink raw reply [nested|flat] 3+ messages in thread
* Re: Implementing Incremental View Maintenance @ 2022-04-28 06:40 Yugo NAGATA <[email protected]> 0 siblings, 0 replies; 3+ messages in thread From: Yugo NAGATA @ 2022-04-28 06:40 UTC (permalink / raw) To: Greg Stark <[email protected]>; +Cc: PostgreSQL Hackers <[email protected]>; Zhihong Yu <[email protected]>; Julien Rouhaud <[email protected]>; [email protected]; vignesh C <[email protected]>; Tom Lane <[email protected]>; Andrew Dunstan <[email protected]>; Andy Fan <[email protected]>; Tatsuo Ishii <[email protected]>; Thomas Munro <[email protected]> Hello Greg, On Sat, 23 Apr 2022 08:18:01 +0200 Greg Stark <[email protected]> wrote: > I'm trying to figure out how to get this feature more attention. Everyone > agrees it would be a huge help but it's a scary patch to review. > > I wonder if it would be helpful to have a kind of "readers guide" > explanation of the patches to help a reviewer understand what the point of > each patch is and how the whole system works? I think Andres and Robert > have both taken that approach before with big patches and it really helped > imho. Thank you very much for your suggestion! Following your advice, I am going to write a readers guide referring to the past posts of Andres and Rebert. Regards, Yugo Nagata -- Yugo NAGATA <[email protected]> ^ permalink raw reply [nested|flat] 3+ messages in thread
* [PATCH v2 4/7] Row pattern recognition patch (executor). @ 2023-06-26 08:05 Tatsuo Ishii <[email protected]> 0 siblings, 0 replies; 3+ messages in thread From: Tatsuo Ishii @ 2023-06-26 08:05 UTC (permalink / raw) --- src/backend/executor/nodeWindowAgg.c | 225 +++++++++++++++++++- src/backend/utils/adt/windowfuncs.c | 302 ++++++++++++++++++++++++++- src/include/catalog/pg_proc.dat | 9 + src/include/nodes/execnodes.h | 13 ++ src/include/windowapi.h | 9 + 5 files changed, 548 insertions(+), 10 deletions(-) diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index 310ac23e3a..bef2bc62b2 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -48,6 +48,7 @@ #include "utils/acl.h" #include "utils/builtins.h" #include "utils/datum.h" +#include "utils/fmgroids.h" #include "utils/expandeddatum.h" #include "utils/lsyscache.h" #include "utils/memutils.h" @@ -159,6 +160,14 @@ typedef struct WindowStatePerAggData bool restart; /* need to restart this agg in this cycle? */ } WindowStatePerAggData; +/* + * Map between Var attno in a target list and the parsed attno. + */ +typedef struct AttnoMap { + List *attno; /* att number in target list (list of AttNumber) */ + List *attnosyn; /* parsed att number (list of AttNumber) */ +} AttnoMap; + static void initialize_windowaggregate(WindowAggState *winstate, WindowStatePerFunc perfuncstate, WindowStatePerAgg peraggstate); @@ -195,9 +204,9 @@ static Datum GetAggInitVal(Datum textInitVal, Oid transtype); static bool are_peers(WindowAggState *winstate, TupleTableSlot *slot1, TupleTableSlot *slot2); -static bool window_gettupleslot(WindowObject winobj, int64 pos, - TupleTableSlot *slot); +static void attno_map(Node *node, AttnoMap *map); +static bool attno_map_walker(Node *node, void *context); /* * initialize_windowaggregate @@ -2388,6 +2397,12 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags) TupleDesc scanDesc; ListCell *l; + TargetEntry *te; + Expr *expr; + Var *var; + int nargs; + AttnoMap attnomap; + /* check for unsupported flags */ Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); @@ -2483,6 +2498,16 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags) winstate->temp_slot_2 = ExecInitExtraTupleSlot(estate, scanDesc, &TTSOpsMinimalTuple); + winstate->prev_slot = ExecInitExtraTupleSlot(estate, scanDesc, + &TTSOpsMinimalTuple); + + winstate->next_slot = ExecInitExtraTupleSlot(estate, scanDesc, + &TTSOpsMinimalTuple); + + winstate->null_slot = ExecInitExtraTupleSlot(estate, scanDesc, + &TTSOpsMinimalTuple); + winstate->null_slot = ExecStoreAllNullTuple(winstate->null_slot); + /* * create frame head and tail slots only if needed (must create slots in * exactly the same cases that update_frameheadpos and update_frametailpos @@ -2667,6 +2692,71 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags) winstate->inRangeAsc = node->inRangeAsc; winstate->inRangeNullsFirst = node->inRangeNullsFirst; + /* Set up SKIP TO type */ + winstate->rpSkipTo = node->rpSkipTo; + /* Set up row pattern recognition PATTERN clause */ + winstate->patternVariableList = node->patternVariable; + winstate->patternRegexpList = node->patternRegexp; + + /* Set up row pattern recognition DEFINE clause */ + + /* + * Collect mapping between varattno and varattnosyn in the targetlist. + * XXX: For now we only check RPR's argument. Eventually we have to + * recurse the targetlist to find out all mappings in Var nodes. + */ + attnomap.attno = NIL; + attnomap.attnosyn = NIL; + + foreach (l, node->plan.targetlist) + { + te = lfirst(l); + if (IsA(te->expr, WindowFunc)) + { + WindowFunc *func = (WindowFunc *)te->expr; + if (func->winfnoid != F_RPR) + continue; + + /* sanity check */ + nargs = list_length(func->args); + if (list_length(func->args) != 1) + elog(ERROR, "RPR must have 1 argument but function %d has %d args", func->winfnoid, nargs); + + expr = (Expr *) lfirst(list_head(func->args)); + if (!IsA(expr, Var)) + elog(ERROR, "RPR's arg is not Var"); + + var = (Var *)expr; + elog(DEBUG1, "resname: %s varattno: %d varattnosyn: %d", + te->resname, var->varattno, var->varattnosyn); + attnomap.attno = lappend_int(attnomap.attno, var->varattno); + attnomap.attnosyn = lappend_int(attnomap.attnosyn, var->varattnosyn); + } + } + + winstate->defineVariableList = NIL; + winstate->defineClauseList = NIL; + if (node->defineClause != NIL) + { + foreach(l, node->defineClause) + { + char *name; + ExprState *exps; + + te = lfirst(l); + name = te->resname; + expr = te->expr; + + elog(DEBUG1, "defineVariable name: %s", name); + winstate->defineVariableList = lappend(winstate->defineVariableList, + makeString(pstrdup(name))); + /* tweak expr so that it referes to outer slot */ + attno_map((Node *)expr, &attnomap); + exps = ExecInitExpr(expr, (PlanState *) winstate); + winstate->defineClauseList = lappend(winstate->defineClauseList, exps); + } + } + winstate->all_first = true; winstate->partition_spooled = false; winstate->more_partitions = false; @@ -2674,6 +2764,76 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags) return winstate; } +/* + * Rewrite Var node's varattno to the varattno which is used in the target + * list using AttnoMap. We also rewrite varno so that it sees outer tuple + * (PREV) or inner tuple (NEXT). + */ +static void +attno_map(Node *node, AttnoMap *map) +{ + (void) expression_tree_walker(node, attno_map_walker, (void *) map); +} + +static bool +attno_map_walker(Node *node, void *context) +{ + FuncExpr *func; + int nargs; + Expr *expr; + Var *var; + AttnoMap *attnomap; + ListCell *lc1, *lc2; + + if (node == NULL) + return false; + + attnomap = (AttnoMap *) context; + + if (IsA(node, FuncExpr)) + { + func = (FuncExpr *)node; + + if (func->funcid == F_PREV || func->funcid == F_NEXT) + { + /* sanity check */ + nargs = list_length(func->args); + if (list_length(func->args) != 1) + elog(ERROR, "PREV/NEXT must have 1 argument but function %d has %d args", func->funcid, nargs); + + expr = (Expr *) lfirst(list_head(func->args)); + if (!IsA(expr, Var)) + elog(ERROR, "PREV/NEXT's arg is not Var"); /* XXX: is it possible that arg type is Const? */ + var = (Var *)expr; + + if (func->funcid == F_PREV) + var->varno = OUTER_VAR; + else + var->varno = INNER_VAR; + } + return expression_tree_walker(node, attno_map_walker, (void *) context); + } + else if (IsA(node, Var)) + { + var = (Var *)node; + + elog(DEBUG1, "original varno: %d varattno: %d", var->varno, var->varattno); + + forboth(lc1, attnomap->attno, lc2, attnomap->attnosyn) + { + int attno = lfirst_int(lc1); + int attnosyn = lfirst_int(lc2); + + if (var->varattno == attnosyn) + { + elog(DEBUG1, "loc: %d rewrite varattno from: %d to %d", var->location, attnosyn, attno); + var->varattno = attno; + } + } + } + return expression_tree_walker(node, attno_map_walker, (void *) context); +} + /* ----------------- * ExecEndWindowAgg * ----------------- @@ -2691,6 +2851,8 @@ ExecEndWindowAgg(WindowAggState *node) ExecClearTuple(node->agg_row_slot); ExecClearTuple(node->temp_slot_1); ExecClearTuple(node->temp_slot_2); + ExecClearTuple(node->prev_slot); + ExecClearTuple(node->next_slot); if (node->framehead_slot) ExecClearTuple(node->framehead_slot); if (node->frametail_slot) @@ -2740,6 +2902,8 @@ ExecReScanWindowAgg(WindowAggState *node) ExecClearTuple(node->agg_row_slot); ExecClearTuple(node->temp_slot_1); ExecClearTuple(node->temp_slot_2); + ExecClearTuple(node->prev_slot); + ExecClearTuple(node->next_slot); if (node->framehead_slot) ExecClearTuple(node->framehead_slot); if (node->frametail_slot) @@ -3080,7 +3244,7 @@ are_peers(WindowAggState *winstate, TupleTableSlot *slot1, * * Returns true if successful, false if no such row */ -static bool +bool window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot) { WindowAggState *winstate = winobj->winstate; @@ -3420,14 +3584,53 @@ WinGetFuncArgInFrame(WindowObject winobj, int argno, WindowAggState *winstate; ExprContext *econtext; TupleTableSlot *slot; - int64 abs_pos; - int64 mark_pos; Assert(WindowObjectIsValid(winobj)); winstate = winobj->winstate; econtext = winstate->ss.ps.ps_ExprContext; slot = winstate->temp_slot_1; + if (WinGetSlotInFrame(winobj, slot, + relpos, seektype, set_mark, + isnull, isout) == 0) + { + econtext->ecxt_outertuple = slot; + return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno), + econtext, isnull); + } + + if (isout) + *isout = true; + *isnull = true; + return (Datum) 0; +} + +/* + * WinGetSlotInFrame + * slot: TupleTableSlot to store the result + * relpos: signed rowcount offset from the seek position + * seektype: WINDOW_SEEK_HEAD or WINDOW_SEEK_TAIL + * set_mark: If the row is found/in frame and set_mark is true, the mark is + * moved to the row as a side-effect. + * isnull: output argument, receives isnull status of result + * isout: output argument, set to indicate whether target row position + * is out of frame (can pass NULL if caller doesn't care about this) + * + * Returns 0 if we successfullt got the slot. false if out of frame. + * (also isout is set) + */ +int +WinGetSlotInFrame(WindowObject winobj, TupleTableSlot *slot, + int relpos, int seektype, bool set_mark, + bool *isnull, bool *isout) +{ + WindowAggState *winstate; + int64 abs_pos; + int64 mark_pos; + + Assert(WindowObjectIsValid(winobj)); + winstate = winobj->winstate; + switch (seektype) { case WINDOW_SEEK_CURRENT: @@ -3583,15 +3786,13 @@ WinGetFuncArgInFrame(WindowObject winobj, int argno, *isout = false; if (set_mark) WinSetMarkPosition(winobj, mark_pos); - econtext->ecxt_outertuple = slot; - return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno), - econtext, isnull); + return 0; out_of_frame: if (isout) *isout = true; *isnull = true; - return (Datum) 0; + return -1; } /* @@ -3622,3 +3823,9 @@ WinGetFuncArgCurrent(WindowObject winobj, int argno, bool *isnull) return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno), econtext, isnull); } + +WindowAggState * +WinGetAggState(WindowObject winobj) +{ + return winobj->winstate; +} diff --git a/src/backend/utils/adt/windowfuncs.c b/src/backend/utils/adt/windowfuncs.c index b87a624fb2..74ef11ce55 100644 --- a/src/backend/utils/adt/windowfuncs.c +++ b/src/backend/utils/adt/windowfuncs.c @@ -13,6 +13,9 @@ */ #include "postgres.h" +#include "catalog/pg_collation_d.h" +#include "executor/executor.h" +#include "nodes/execnodes.h" #include "nodes/supportnodes.h" #include "utils/builtins.h" #include "windowapi.h" @@ -36,10 +39,21 @@ typedef struct int64 remainder; /* (total rows) % (bucket num) */ } ntile_context; +/* + * rpr process information. + * Used for AFTER MATCH SKIP PAST LAST ROW + */ +typedef struct SkipContext +{ + int64 pos; /* last row absolute position */ +} SkipContext; + static bool rank_up(WindowObject winobj); static Datum leadlag_common(FunctionCallInfo fcinfo, bool forward, bool withoffset, bool withdefault); - +static bool get_slots(WindowObject winobj, WindowAggState *winstate, int current_pos); +static int evaluate_pattern(WindowObject winobj, WindowAggState *winstate, + int relpos, char *vname, char *quantifier, bool *result); /* * utility routine for *_rank functions. @@ -713,3 +727,289 @@ window_nth_value(PG_FUNCTION_ARGS) PG_RETURN_DATUM(result); } + +/* + * rpr + * allow to use "Row pattern recognition: WINDOW clause" (SQL:2016 R020) in + * the target list. + * Usage: SELECT rpr(colname) OVER (..) + * where colname is defined in PATTERN clause. + */ +Datum +window_rpr(PG_FUNCTION_ARGS) +{ +#define MAX_PATTERNS 16 /* max variables in PATTERN clause */ + + WindowObject winobj = PG_WINDOW_OBJECT(); + WindowAggState *winstate = WinGetAggState(winobj); + Datum result; + bool expression_result; + bool isnull; + int relpos; + int64 curr_pos, markpos; + ListCell *lc, *lc1; + SkipContext *context = NULL; + + curr_pos = WinGetCurrentPosition(winobj); + elog(DEBUG1, "rpr is called. row: " INT64_FORMAT, curr_pos); + + if (winstate->rpSkipTo == ST_PAST_LAST_ROW) + { + context = (SkipContext *) WinGetPartitionLocalMemory(winobj, sizeof(SkipContext)); + if (curr_pos < context->pos) + { + elog(DEBUG1, "skip this row: curr_pos: " INT64_FORMAT "context->pos: " INT64_FORMAT, + curr_pos, context->pos); + PG_RETURN_NULL(); + } + } + + /* + * Evaluate PATTERN until one of expressions is not true or out of frame. + */ + relpos = 0; + + forboth(lc, winstate->patternVariableList, lc1, winstate->patternRegexpList) + { + char *vname = strVal(lfirst(lc)); + char *quantifier = strVal(lfirst(lc1)); + + elog(DEBUG1, "relpos: %d pattern vname: %s quantifier: %s", relpos, vname, quantifier); + + /* evaluate row pattern against current row */ + relpos = evaluate_pattern(winobj, winstate, relpos, vname, quantifier, &expression_result); + + /* + * If the expression did not match, we are done. + */ + if (!expression_result) + break; + + /* out of frame? */ + if (relpos < 0) + break; + + /* count up relative row position */ + relpos++; + } + + elog(DEBUG1, "relpos: %d", relpos); + + /* + * If current row satified the pattern, return argument expression. + */ + if (expression_result) + { + result = WinGetFuncArgInFrame(winobj, 0, + 0, WINDOW_SEEK_HEAD, false, + &isnull, NULL); + } + + /* + * At this point we can set mark down to current pos -2. + */ + markpos = curr_pos -2; + elog(DEBUG1, "markpos: " INT64_FORMAT, markpos); + if (markpos >= 0) + WinSetMarkPosition(winobj, markpos); + + if (expression_result) + { + if (winstate->rpSkipTo == ST_PAST_LAST_ROW) + { + context->pos += relpos; + elog(DEBUG1, "context->pos: " INT64_FORMAT, context->pos); + } + PG_RETURN_DATUM(result); + } + + PG_RETURN_NULL(); +} + +/* + * Evaluate expression associated with PATTERN variable vname. + * relpos is relative row position in a frame (starting from 0). + * "quantifier" is the quatifier part of the PATTERN regular expression. + * Currently only '+' is allowed. + * result is out paramater representing the expression evaluation result + * is true of false. + * Return values are: + * >=0: the last match relative row position + * -1: current row is out of frame + */ +static +int evaluate_pattern(WindowObject winobj, WindowAggState *winstate, + int relpos, char *vname, char *quantifier, bool *result) +{ + ExprContext *econtext = winstate->ss.ps.ps_ExprContext; + ListCell *lc1, *lc2; + ExprState *pat; + Datum eval_result; + int sts; + bool out_of_frame = false; + bool isnull; + StringInfo encoded_str = makeStringInfo(); + char pattern_str[128]; + + forboth (lc1, winstate->defineVariableList, lc2, winstate->defineClauseList) + { + char *name = strVal(lfirst(lc1)); + bool second_try_match = false; + + if (strcmp(vname, name)) + continue; + + /* set expression to evaluate */ + pat = lfirst(lc2); + + for (;;) + { + if (!get_slots(winobj, winstate, relpos)) + { + out_of_frame = true; + break; /* current row is out of frame */ + } + + /* evaluate the expression */ + eval_result = ExecEvalExpr(pat, econtext, &isnull); + if (isnull) + { + /* expression is NULL */ + elog(DEBUG1, "expression for %s is NULL at row: %d", vname, relpos); + break; + } + else + { + if (!DatumGetBool(eval_result)) + { + /* expression is false */ + elog(DEBUG1, "expression for %s is false at row: %d", vname, relpos); + break; + } + else + { + /* expression is true */ + elog(DEBUG1, "expression for %s is true at row: %d", vname, relpos); + appendStringInfoChar(encoded_str, vname[0]); + + /* If quantifier is "+", we need to look for more matching row */ + if (quantifier && !strcmp(quantifier, "+")) + { + /* remember that we want to try another row */ + second_try_match = true; + relpos++; + } + else + break; + } + } + } + if (second_try_match) + relpos--; + + if (out_of_frame) + { + *result = false; + return -1; + } + + /* build regular expression */ + snprintf(pattern_str, sizeof(pattern_str), "%c%s", vname[0], quantifier); + + /* + * Do regular expression matching against sequence of rows satisfying + * the expression using regexp_instr(). + */ + sts = DatumGetInt32(DirectFunctionCall2Coll(regexp_instr, DEFAULT_COLLATION_OID, + PointerGetDatum(cstring_to_text(encoded_str->data)), + PointerGetDatum(cstring_to_text(pattern_str)))); + elog(DEBUG1, "regexp_instr returned: %d. str: %s regexp: %s", + sts, encoded_str->data, pattern_str); + *result = (sts > 0)? true : false; + } + return relpos; +} + +/* + * Get current, previous and next tuple. + * Returns true if still within frame. + */ +static bool +get_slots(WindowObject winobj, WindowAggState *winstate, int current_pos) +{ + TupleTableSlot *slot; + bool isnull, isout; + int sts; + ExprContext *econtext; + + econtext = winstate->ss.ps.ps_ExprContext; + + /* for current row */ + slot = winstate->temp_slot_1; + sts = WinGetSlotInFrame(winobj, slot, + current_pos, WINDOW_SEEK_HEAD, false, + &isnull, &isout); + if (sts < 0) + { + elog(DEBUG1, "current row is out of frame"); + econtext->ecxt_scantuple = winstate->null_slot; + return false; + } + else + econtext->ecxt_scantuple = slot; + + /* for PREV */ + if (current_pos > 0) + { + slot = winstate->prev_slot; + sts = WinGetSlotInFrame(winobj, slot, + current_pos - 1, WINDOW_SEEK_HEAD, false, + &isnull, &isout); + if (sts < 0) + { + elog(DEBUG1, "previous row out of frame at: %d", current_pos); + econtext->ecxt_outertuple = winstate->null_slot; + } + econtext->ecxt_outertuple = slot; + } + else + econtext->ecxt_outertuple = winstate->null_slot; + + /* for NEXT */ + slot = winstate->next_slot; + sts = WinGetSlotInFrame(winobj, slot, + current_pos + 1, WINDOW_SEEK_HEAD, false, + &isnull, &isout); + if (sts < 0) + { + elog(DEBUG1, "next row out of frame at: %d", current_pos); + econtext->ecxt_innertuple = winstate->null_slot; + } + else + econtext->ecxt_innertuple = slot; + + return true; +} + +/* + * prev + * Dummy function to invoke RPR's navigation operator "PREV". + * This is *not* a window function. + */ +Datum +window_prev(PG_FUNCTION_ARGS) +{ + PG_RETURN_DATUM(PG_GETARG_DATUM(0)); +} + +/* + * next + * Dummy function to invoke RPR's navigation operation "NEXT". + * This is *not* a window function. + */ +Datum +window_next(PG_FUNCTION_ARGS) +{ + PG_RETURN_DATUM(PG_GETARG_DATUM(0)); +} + diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 6996073989..e3a9e0ffeb 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -10397,6 +10397,15 @@ { oid => '3114', descr => 'fetch the Nth row value', proname => 'nth_value', prokind => 'w', prorettype => 'anyelement', proargtypes => 'anyelement int4', prosrc => 'window_nth_value' }, +{ oid => '6122', descr => 'row pattern recognition in window', + proname => 'rpr', prokind => 'w', prorettype => 'anyelement', + proargtypes => 'anyelement', prosrc => 'window_rpr' }, +{ oid => '6123', descr => 'previous value', + proname => 'prev', provolatile => 's', prorettype => 'anyelement', + proargtypes => 'anyelement', prosrc => 'window_prev' }, +{ oid => '6124', descr => 'next value', + proname => 'next', provolatile => 's', prorettype => 'anyelement', + proargtypes => 'anyelement', prosrc => 'window_next' }, # functions for range types { oid => '3832', descr => 'I/O', diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index cb714f4a19..1643eaa6f1 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -2519,6 +2519,14 @@ typedef struct WindowAggState int64 groupheadpos; /* current row's peer group head position */ int64 grouptailpos; /* " " " " tail position (group end+1) */ + /* these fields are used in Row pattern recognition: */ + RPSkipTo rpSkipTo; /* Row Pattern Skip To type */ + List *patternVariableList; /* list of row pattern variables names (list of String) */ + List *patternRegexpList; /* list of row pattern regular expressions ('+' or ''. list of String) */ + List *defineVariableList; /* list of row pattern definition variables (list of String) */ + List *defineClauseList; /* expression for row pattern definition + * search conditions ExprState list */ + MemoryContext partcontext; /* context for partition-lifespan data */ MemoryContext aggcontext; /* shared context for aggregate working data */ MemoryContext curaggcontext; /* current aggregate's working data */ @@ -2555,6 +2563,11 @@ typedef struct WindowAggState TupleTableSlot *agg_row_slot; TupleTableSlot *temp_slot_1; TupleTableSlot *temp_slot_2; + + /* temporary slots for RPR */ + TupleTableSlot *prev_slot; /* PREV row navigation operator */ + TupleTableSlot *next_slot; /* NEXT row navigation operator */ + TupleTableSlot *null_slot; /* all NULL slot */ } WindowAggState; /* ---------------- diff --git a/src/include/windowapi.h b/src/include/windowapi.h index b8c2c565d1..a0facf38fe 100644 --- a/src/include/windowapi.h +++ b/src/include/windowapi.h @@ -58,7 +58,16 @@ extern Datum WinGetFuncArgInFrame(WindowObject winobj, int argno, int relpos, int seektype, bool set_mark, bool *isnull, bool *isout); +extern int WinGetSlotInFrame(WindowObject winobj, TupleTableSlot *slot, + int relpos, int seektype, bool set_mark, + bool *isnull, bool *isout); + extern Datum WinGetFuncArgCurrent(WindowObject winobj, int argno, bool *isnull); +extern WindowAggState *WinGetAggState(WindowObject winobj); + +extern bool window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot); + + #endif /* WINDOWAPI_H */ -- 2.25.1 ----Next_Part(Mon_Jun_26_17_45_07_2023_724)-- Content-Type: Text/X-Patch; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="v2-0005-Row-pattern-recognition-patch-docs.patch" ^ permalink raw reply [nested|flat] 3+ messages in thread
end of thread, other threads:[~2023-06-26 08:05 UTC | newest] Thread overview: 3+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2019-11-12 21:55 [PATCH v1] Change pg_attribute_noreturn() to pg_noreturn, move to before return type. Andres Freund <[email protected]> 2022-04-28 06:40 Re: Implementing Incremental View Maintenance Yugo NAGATA <[email protected]> 2023-06-26 08:05 [PATCH v2 4/7] Row pattern recognition patch (executor). Tatsuo Ishii <[email protected]>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox