Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package pg_cron for openSUSE:Factory checked 
in at 2021-12-14 22:01:51
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/pg_cron (Old)
 and      /work/SRC/openSUSE:Factory/.pg_cron.new.2520 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "pg_cron"

Tue Dec 14 22:01:51 2021 rev:8 rq:940416 version:1.4.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/pg_cron/pg_cron.changes  2021-07-02 
13:27:37.644685950 +0200
+++ /work/SRC/openSUSE:Factory/.pg_cron.new.2520/pg_cron.changes        
2021-12-14 22:02:02.827142828 +0100
@@ -1,0 +2,36 @@
+Thu Dec  2 11:47:08 UTC 2021 - Marcus Rueckert <mrueck...@suse.de>
+
+- fix postgresql_has_llvm usage
+
+-------------------------------------------------------------------
+Tue Nov 30 17:24:01 UTC 2021 - Marcus Rueckert <mrueck...@suse.de>
+
+- switch to %{pg_name}-llvmjit-devel
+
+-------------------------------------------------------------------
+Sun Nov 14 02:05:33 UTC 2021 - Marcus Rueckert <mrueck...@suse.de>
+
+- port to postgresql macros
+
+-------------------------------------------------------------------
+Sun Sep 26 08:00:49 UTC 2021 - Andrey Karepin <egdf...@opensuse.org>
+
+- update to 1.4.1
+  * Fixes PostgreSQL 11- support
+
+-------------------------------------------------------------------
+Sat Sep 18 17:42:49 UTC 2021 - Andrey Karepin <egdf...@opensuse.org>
+
+- update to 1.4.0
+  * Adds a cron.alter_job function to change job properties, by
+    Bertrand Drouvot
+  * Adds a cron.log_min_messages setting to control log_min_messages
+    in pg_cron launcher, by Bertrand Drouvot
+  * Adds a cron.enable_superuser_jobs setting to disallow superuser
+    jobs
+  * Fixes a bug that could cause jobs to hang when using
+    cron.use_background_workers, by Bertrand Drouvot
+  * Fixes a small memory allocation bug, by @mrdrivingduck
+  * PostgreSQL 14 is supported (no changes were needed)
+
+-------------------------------------------------------------------

Old:
----
  pg_cron-1.3.1.tar.gz

New:
----
  pg_cron-1.4.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ pg_cron.spec ++++++
--- /var/tmp/diff_new_pack.tL3x5N/_old  2021-12-14 22:02:03.295143095 +0100
+++ /var/tmp/diff_new_pack.tL3x5N/_new  2021-12-14 22:02:03.299143098 +0100
@@ -16,82 +16,54 @@
 #
 
 
-%define         pgversion @BUILD_FLAVOR@
-%define         priority %{pgversion}
-%define         sname pg_cron
-%define         pg_libdir %(pg_config --pkglibdir)
-%define         pg_share %(pg_config --sharedir)
-%if 0%{?is_opensuse} && ("%{pgversion}" == "postgresql11" || "%{pgversion}" == 
"postgresql12" || "%{pgversion}" == "postgresql13") && 0%{?suse_version} >= 1500
-%bcond_without  llvm
-%else
-%bcond_with     llvm
-%endif
-Name:           %{pgversion}-%{sname}
-Version:        1.3.1
+%define         pg_name @BUILD_FLAVOR@%{nil}
+%define         ext_name pg_cron
+%{pg_version_from_name}
+
+Name:           %{pg_name}-%{ext_name}
+Version:        1.4.1
 Release:        0
 Summary:        PostgreSQL module for simple job schedule
 License:        PostgreSQL
 Group:          Productivity/Databases/Servers
 URL:            https://github.com/citusdata/pg_cron
-Source:         %{sname}-%{version}.tar.gz
-BuildRequires:  %{pgversion}-server
-BuildRequires:  %{pgversion}-server-devel
-%requires_eq    %{pgversion}-server
-%if "%{pgversion}" == ""
-Name:           %{sname}
-ExclusiveArch:  do_not_build
-%endif
-%if ("%{pgversion}" == "postgresql95" || "%{pgversion}" == "postgresql96") && 
0%{?suse_version} >= 1550
+Source:         
https://github.com/citusdata/pg_cron/archive/refs/tags/v%{version}.tar.gz#/%{ext_name}-%{version}.tar.gz
+
+BuildRequires:  %{pg_name}-llvmjit-devel
+%pg_server_requires
+%if "%{pg_name}" == ""
+Name:           %{ext_name}
 ExclusiveArch:  do_not_build
 %endif
 
 %description
-%{sname} is a simple cron-based job scheduler for PostgreSQL (9.5 or higher)
+%{ext_name} is a simple cron-based job scheduler for PostgreSQL (9.5 or higher)
 that runs inside the database as an extension. It uses the same syntax as
 regular cron, but it allows you to schedule PostgreSQL commands directly from
 the database.
 
-%if %{with llvm}
-%package llvmjit
-Summary:        Just-in-time compilation support for PostgreSQL %{sname} 
extension
-Group:          Productivity/Databases/Servers
-Requires:       %{pgversion}-%{sname} = %{version}-%{release}
-Requires:       %{pgversion}-llvmjit
-Requires:       %{pgversion}-server
-Supplements:    packageand(%{pgversion}-llvmjit:%{name})
-
-%description llvmjit
-This package contains support for just-in-time compiling parts of
-PostgreSQL queries. Using LLVM it compiles e.g. expressions and tuple
-deforming into native code, with the goal of accelerating analytics
-queries.
-%endif
-
 %prep
-%setup -q -n %{sname}-%{version}
+%autosetup -p1 -n %{ext_name}-%{version}
 
 %build
-export PATH="$PATH:%{_libexecdir}/%{pgname}/bin"
-make %{?_smp_mflags}
+%make_pgxs
 
 %install
 %make_install
 
 %post
-%{_datadir}/postgresql/install-alternatives %{priority}
+%{_datadir}/postgresql/install-alternatives %{pg_version}
 
 %postun
-%{_datadir}/postgresql/install-alternatives %{priority}
+%{_datadir}/postgresql/install-alternatives %{pg_version}
 
 %files
 %license LICENSE
 %doc CHANGELOG.md README.md
-%{_datadir}/%{pgversion}/extension/%{sname}*
-%{pg_libdir}/%{sname}.so
-
-%if %{with llvm}
-%files llvmjit
-%{pg_libdir}/bitcode/*
+%{pg_config_sharedir}/extension/%{ext_name}*
+%{pg_config_pkglibdir}/%{ext_name}.so
+%if %{postgresql_has_llvm}
+%{pg_config_pkglibdir}/bitcode/*
 %endif
 
 %changelog

++++++ _multibuild ++++++
--- /var/tmp/diff_new_pack.tL3x5N/_old  2021-12-14 22:02:03.327143113 +0100
+++ /var/tmp/diff_new_pack.tL3x5N/_new  2021-12-14 22:02:03.327143113 +0100
@@ -1,9 +1,8 @@
 <multibuild>
-  <package>postgresql95</package>
-  <package>postgresql96</package>
   <package>postgresql10</package>
   <package>postgresql11</package>
   <package>postgresql12</package>
   <package>postgresql13</package>
+  <package>postgresql14</package>
 </multibuild>
 

++++++ pg_cron-1.3.1.tar.gz -> pg_cron-1.4.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pg_cron-1.3.1/CHANGELOG.md 
new/pg_cron-1.4.1/CHANGELOG.md
--- old/pg_cron-1.3.1/CHANGELOG.md      2021-03-29 12:17:31.000000000 +0200
+++ new/pg_cron-1.4.1/CHANGELOG.md      2021-09-25 18:55:16.000000000 +0200
@@ -1,3 +1,17 @@
+### pg_cron v1.4.1 (September 25, 2021) ###
+
+* Fixes PostgreSQL 11- support
+
+### pg_cron v1.4.0 (September 16, 2021) ###
+
+* Adds a cron.alter_job function to change job properties, by Bertrand Drouvot
+* Adds a cron.schedule_in_database function to schedule in a custom database, 
by Bertrand Drouvot
+* Adds a cron.log_min_messages setting to control log_min_messages in pg_cron 
launcher, by Bertrand Drouvot
+* Adds a cron.enable_superuser_jobs setting to disallow superuser jobs
+* Fixes a bug that could cause jobs to hang when using 
cron.use_background_workers, by Bertrand Drouvot
+* Fixes a small memory allocation bug, by @mrdrivingduck
+* PostgreSQL 14 is supported (no changes were needed)
+
 ### pg_cron v1.3.1 (March 29, 2021) ###
 
 * Fixes a memory leak
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pg_cron-1.3.1/Makefile new/pg_cron-1.4.1/Makefile
--- old/pg_cron-1.3.1/Makefile  2021-03-29 12:17:31.000000000 +0200
+++ new/pg_cron-1.4.1/Makefile  2021-09-25 18:55:16.000000000 +0200
@@ -18,7 +18,7 @@
 SHLIB_LINK = $(libpq)
 EXTRA_CLEAN += $(addprefix src/,*.gcno *.gcda) # clean up after profiling runs
 
-PG_CONFIG = pg_config
+PG_CONFIG ?= pg_config
 PGXS := $(shell $(PG_CONFIG) --pgxs)
 include $(PGXS)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pg_cron-1.3.1/README.md new/pg_cron-1.4.1/README.md
--- old/pg_cron-1.3.1/README.md 2021-03-29 12:17:31.000000000 +0200
+++ new/pg_cron-1.4.1/README.md 2021-09-25 18:55:16.000000000 +0200
@@ -14,13 +14,25 @@
        42
 
 -- Vacuum every day at 10:00am (GMT)
-SELECT cron.schedule('0 10 * * *', 'VACUUM');
+SELECT cron.schedule('nightly-vacuum', '0 10 * * *', 'VACUUM');
  schedule
 ----------
        43
 
--- Stop scheduling a job
-SELECT cron.unschedule(43);
+-- Change to vacuum at 3:00am (GMT)
+SELECT cron.schedule('nightly-vacuum', '0 3 * * *', 'VACUUM');
+ schedule
+----------
+       43
+
+-- Stop scheduling jobs
+SELECT cron.unschedule('nightly-vacuum' );
+ unschedule 
+------------
+ t
+(1 row)
+
+SELECT cron.unschedule(42);
  unschedule
 ------------
           t
@@ -48,21 +60,18 @@
 
 ## Installing pg_cron
 
-Install on Red Hat, CentOS, Fedora, Amazon Linux with PostgreSQL 11:
+Install on Red Hat, CentOS, Fedora, Amazon Linux with PostgreSQL 12 using 
[PGDG](https://yum.postgresql.org/repopackages/):
 
 ```bash
-# Add Citus Data package repository
-curl https://install.citusdata.com/community/rpm.sh | sudo bash
-
 # Install the pg_cron extension
-sudo yum install -y pg_cron_11
+sudo yum install -y pg_cron_12
 ```
 
-Install on Debian, Ubuntu with PostgreSQL 11 using 
[apt.postgresql.org](https://wiki.postgresql.org/wiki/Apt):
+Install on Debian, Ubuntu with PostgreSQL 12 using 
[apt.postgresql.org](https://wiki.postgresql.org/wiki/Apt):
 
 ```bash
 # Install the pg_cron extension
-sudo apt-get -y install postgresql-11-cron
+sudo apt-get -y install postgresql-12-cron
 ```
 
 You can also install pg_cron by building it from source:
@@ -71,7 +80,7 @@
 git clone https://github.com/citusdata/pg_cron.git
 cd pg_cron
 # Ensure pg_config is in your path, e.g.
-export PATH=/usr/pgsql-11/bin:$PATH
+export PATH=/usr/pgsql-12/bin:$PATH
 make && sudo PATH=$PATH make install
 ```
 
@@ -117,11 +126,15 @@
 
 | Service       | Supported     |
 | ------------- |:-------------:|
+| [Aiven](https://aiven.io/postgresql) | :heavy_check_mark: |
 | [Alibaba Cloud](https://www.alibabacloud.com/help/doc-detail/150355.htm) | 
:heavy_check_mark: |
-| [Amazon RDS](https://aws.amazon.com/rds/postgresql/)     | :x:      |        
  |
+| [Amazon RDS](https://aws.amazon.com/rds/postgresql/)     | 
:heavy_check_mark:      |          |
 | [Azure](https://azure.microsoft.com/en-us/services/postgresql/) | 
:heavy_check_mark:  |
 | [Citus Cloud](https://www.citusdata.com/product/cloud)  | :heavy_check_mark: 
|
 | [Crunchy 
Bridge](https://www.crunchydata.com/products/crunchy-bridge/?ref=producthunt) | 
:heavy_check_mark: |
 | [DigitalOcean](https://www.digitalocean.com/products/managed-databases/) | 
:heavy_check_mark: |
 | [Google Cloud](https://cloud.google.com/sql/docs/postgres/) | :x:      |
 | [Heroku](https://elements.heroku.com/addons/heroku-postgresql) | :x: | |
+| [ScaleGrid](https://scalegrid.io/postgresql.html) | :heavy_check_mark:  |
+| [Scaleway](https://www.scaleway.com/en/database/) | :heavy_check_mark:  |
+| [Supabase](https://supabase.io/docs/guides/database) | :heavy_check_mark:  |
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pg_cron-1.3.1/expected/pg_cron-test.out 
new/pg_cron-1.4.1/expected/pg_cron-test.out
--- old/pg_cron-1.3.1/expected/pg_cron-test.out 2021-03-29 12:17:31.000000000 
+0200
+++ new/pg_cron-1.4.1/expected/pg_cron-test.out 2021-09-25 18:55:16.000000000 
+0200
@@ -5,13 +5,14 @@
  1.0
 (1 row)
 
-ALTER EXTENSION pg_cron UPDATE TO '1.3';
+ALTER EXTENSION pg_cron UPDATE TO '1.4';
 SELECT extversion FROM pg_extension WHERE extname='pg_cron';
  extversion 
 ------------
- 1.3
+ 1.4
 (1 row)
 
+SET cron.enable_superuser_jobs TO on;
 -- Vacuum every day at 10:00am (GMT)
 SELECT cron.schedule('0 10 * * *', 'VACUUM');
  schedule 
@@ -93,4 +94,125 @@
      2 |         | @restart | ALTER EXTENSION pg_cron UPDATE
 (1 row)
 
+-- Testing version >= 1.4 new APIs
+-- First as superuser
+-- Update a job without one job attribute to change
+SELECT cron.alter_job(2);
+ERROR:  no updates specified
+HINT:  You must specify at least one job attribute to change when calling 
alter_job
+-- Update to a non existing database
+select cron.alter_job(job_id:=2,database:='hopedoesnotexist');
+ERROR:  database "hopedoesnotexist" does not exist
+-- Create a database that does not allow connection
+create database pgcron_dbno;
+revoke connect on database pgcron_dbno from public;
+-- create a test user
+create user pgcron_cront with password 'pwd';
+GRANT USAGE ON SCHEMA cron TO pgcron_cront;
+-- Schedule a job for this user on the database that does not accept 
connections
+SELECT cron.schedule_in_database(job_name:='can not connect', schedule:='0 11 
* * *', command:='VACUUM',database:='pgcron_dbno',username:='pgcron_cront');
+ERROR:  User pgcron_cront does not have CONNECT privilege on pgcron_dbno
+-- Create a database that does allow connections
+create database pgcron_dbyes;
+-- Schedule a job on the database that does accept connections for a non 
existing user
+SELECT cron.schedule_in_database(job_name:='user does not exist', schedule:='0 
11 * * *', 
command:='VACUUM',database:='pgcron_dbyes',username:='pgcron_useraqwxszedc');
+ERROR:  role "pgcron_useraqwxszedc" does not exist
+-- Alter an existing job on a database that does not accept connections
+SELECT 
cron.alter_job(job_id:=2,database:='pgcron_dbno',username:='pgcron_cront');
+ERROR:  User pgcron_cront does not have CONNECT privilege on pgcron_dbno
+-- Make sure pgcron_cront can execute alter_job
+GRANT EXECUTE ON FUNCTION cron.alter_job(bigint,text,text,text,text,boolean) 
TO public;
+-- Second as non superuser
+SET SESSION AUTHORIZATION pgcron_cront;
+-- Create a job
+SELECT cron.schedule('My vacuum', '0 11 * * *', 'VACUUM');
+ schedule 
+----------
+        6
+(1 row)
+
+-- Create a job for another user
+SELECT cron.schedule_in_database(job_name:='his vacuum', schedule:='0 11 * * 
*', command:='VACUUM',database:=current_database(),username:='anotheruser');
+ERROR:  permission denied for function schedule_in_database
+-- Change the username of an existing job that the user own
+select cron.alter_job(job_id:=6,username:='anotheruser');
+ERROR:  must be superuser to alter username
+-- Update a job that the user does not own
+select cron.alter_job(job_id:=2,database:='pgcron_dbyes');
+ERROR:  Job 2 does not exist or you don't own it
+-- change the database for a job that the user own and can connect to
+select cron.alter_job(job_id:=6,database:='pgcron_dbyes');
+ alter_job 
+-----------
+ 
+(1 row)
+
+SELECT database FROM cron.job;
+   database   
+--------------
+ pgcron_dbyes
+(1 row)
+
+-- change the database for a job that the user own but can not connect to
+select cron.alter_job(job_id:=6,database:='pgcron_dbno');
+ERROR:  User pgcron_cront does not have CONNECT privilege on pgcron_dbno
+SELECT database FROM cron.job;
+   database   
+--------------
+ pgcron_dbyes
+(1 row)
+
+-- back to superuser
+RESET SESSION AUTHORIZATION;
+-- Change the username of an existing job
+select cron.alter_job(job_id:=2,username:='pgcron_cront');
+ alter_job 
+-----------
+ 
+(1 row)
+
+SELECT username FROM cron.job where jobid=2;
+   username   
+--------------
+ pgcron_cront
+(1 row)
+
+-- Create a job for another user
+SELECT cron.schedule_in_database(job_name:='his vacuum', schedule:='0 11 * * 
*', command:='VACUUM',database:=current_database(), username:='pgcron_cront');
+ schedule_in_database 
+----------------------
+                    7
+(1 row)
+
+SELECT username FROM cron.job where jobid=7;
+   username   
+--------------
+ pgcron_cront
+(1 row)
+
+-- Try to schedule a job as superuser when it is not allowed
+SET cron.enable_superuser_jobs TO off;
+SELECT cron.schedule(job_name:='disallowed-superuser', schedule:='* * * * *', 
command:='drop database pg_crondbno');
+ERROR:  cannot schedule jobs as superuser
+DETAIL:  Scheduling jobs as superuser is disallowed when 
cron.enable_superuser_jobs is set to off.
+SELECT cron.alter_job(7, username := current_user);
+ERROR:  cannot schedule jobs as superuser
+DETAIL:  Scheduling jobs as superuser is disallowed when 
cron.enable_superuser_jobs is set to off.
+-- Scheduling as other users is allowed as superuser
+SELECT cron.schedule_in_database(job_name:='more vacuum', schedule:='0 12 * * 
*', command:='VACUUM', database:=current_database(), username:='pgcron_cront');
+ schedule_in_database 
+----------------------
+                    8
+(1 row)
+
+SELECT cron.alter_job(7, username := 'pgcron_cront');
+ alter_job 
+-----------
+ 
+(1 row)
+
+-- cleaning
 DROP EXTENSION pg_cron;
+drop user pgcron_cront;
+drop database pgcron_dbno;
+drop database pgcron_dbyes;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pg_cron-1.3.1/include/job_metadata.h 
new/pg_cron-1.4.1/include/job_metadata.h
--- old/pg_cron-1.3.1/include/job_metadata.h    2021-03-29 12:17:31.000000000 
+0200
+++ new/pg_cron-1.4.1/include/job_metadata.h    2021-09-25 18:55:16.000000000 
+0200
@@ -46,6 +46,7 @@
 /* global settings */
 extern char *CronHost;
 extern bool CronJobCacheValid;
+extern bool EnableSuperuserJobs;
 
 
 /* functions for retrieving job metadata */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pg_cron-1.3.1/pg_cron--1.3--1.4.sql 
new/pg_cron-1.4.1/pg_cron--1.3--1.4.sql
--- old/pg_cron-1.3.1/pg_cron--1.3--1.4.sql     1970-01-01 01:00:00.000000000 
+0100
+++ new/pg_cron-1.4.1/pg_cron--1.3--1.4.sql     2021-09-25 18:55:16.000000000 
+0200
@@ -0,0 +1,44 @@
+/* pg_cron--1.3--1.4.sql */
+
+/* cron_schedule_named expects job name to be text */
+DROP FUNCTION cron.schedule(name,text,text);
+CREATE FUNCTION cron.schedule(job_name text,
+                              schedule text,
+                              command text)
+RETURNS bigint
+LANGUAGE C
+AS 'MODULE_PATHNAME', $$cron_schedule_named$$;
+COMMENT ON FUNCTION cron.schedule(text,text,text)
+IS 'schedule a pg_cron job';
+
+CREATE FUNCTION cron.alter_job(job_id bigint,
+                                                               schedule text 
default null,
+                                                               command text 
default null,
+                                                               database text 
default null,
+                                                               username text 
default null,
+                                                               active boolean 
default null)
+RETURNS void
+LANGUAGE C
+AS 'MODULE_PATHNAME', $$cron_alter_job$$;
+
+COMMENT ON FUNCTION cron.alter_job(bigint,text,text,text,text,boolean)
+IS 'Alter the job identified by job_id. Any option left as NULL will not be 
modified.';
+
+/* admin should decide whether alter_job is safe by explicitly granting 
execute */
+REVOKE ALL ON FUNCTION cron.alter_job(bigint,text,text,text,text,boolean) FROM 
public;
+
+CREATE FUNCTION cron.schedule_in_database(job_name text,
+                                                                               
  schedule text,
+                                                                               
  command text,
+                                                                               
  database text,
+                                                                               
  username text default null,
+                                                                               
  active boolean default 'true')
+RETURNS bigint
+LANGUAGE C
+AS 'MODULE_PATHNAME', $$cron_schedule_named$$;
+
+COMMENT ON FUNCTION cron.schedule_in_database(text,text,text,text,text,boolean)
+IS 'schedule a pg_cron job';
+
+/* admin should decide whether cron.schedule_in_database is safe by explicitly 
granting execute */
+REVOKE ALL ON FUNCTION 
cron.schedule_in_database(text,text,text,text,text,boolean) FROM public;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pg_cron-1.3.1/pg_cron.control 
new/pg_cron-1.4.1/pg_cron.control
--- old/pg_cron-1.3.1/pg_cron.control   2021-03-29 12:17:31.000000000 +0200
+++ new/pg_cron-1.4.1/pg_cron.control   2021-09-25 18:55:16.000000000 +0200
@@ -1,4 +1,4 @@
 comment = 'Job scheduler for PostgreSQL'
-default_version = '1.3'
+default_version = '1.4'
 module_pathname = '$libdir/pg_cron'
 relocatable = false
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pg_cron-1.3.1/sql/pg_cron-test.sql 
new/pg_cron-1.4.1/sql/pg_cron-test.sql
--- old/pg_cron-1.3.1/sql/pg_cron-test.sql      2021-03-29 12:17:31.000000000 
+0200
+++ new/pg_cron-1.4.1/sql/pg_cron-test.sql      2021-09-25 18:55:16.000000000 
+0200
@@ -1,8 +1,10 @@
 CREATE EXTENSION pg_cron VERSION '1.0';
 SELECT extversion FROM pg_extension WHERE extname='pg_cron';
-ALTER EXTENSION pg_cron UPDATE TO '1.3';
+ALTER EXTENSION pg_cron UPDATE TO '1.4';
 SELECT extversion FROM pg_extension WHERE extname='pg_cron';
 
+SET cron.enable_superuser_jobs TO on;
+
 -- Vacuum every day at 10:00am (GMT)
 SELECT cron.schedule('0 10 * * *', 'VACUUM');
 
@@ -37,4 +39,84 @@
 
 SELECT jobid, jobname, schedule, command FROM cron.job ORDER BY jobid;
 
+-- Testing version >= 1.4 new APIs
+-- First as superuser
+
+-- Update a job without one job attribute to change
+SELECT cron.alter_job(2);
+
+-- Update to a non existing database
+select cron.alter_job(job_id:=2,database:='hopedoesnotexist');
+
+-- Create a database that does not allow connection
+create database pgcron_dbno;
+revoke connect on database pgcron_dbno from public;
+
+-- create a test user
+create user pgcron_cront with password 'pwd';
+GRANT USAGE ON SCHEMA cron TO pgcron_cront;
+
+-- Schedule a job for this user on the database that does not accept 
connections
+SELECT cron.schedule_in_database(job_name:='can not connect', schedule:='0 11 
* * *', command:='VACUUM',database:='pgcron_dbno',username:='pgcron_cront');
+
+-- Create a database that does allow connections
+create database pgcron_dbyes;
+
+-- Schedule a job on the database that does accept connections for a non 
existing user
+SELECT cron.schedule_in_database(job_name:='user does not exist', schedule:='0 
11 * * *', 
command:='VACUUM',database:='pgcron_dbyes',username:='pgcron_useraqwxszedc');
+
+-- Alter an existing job on a database that does not accept connections
+SELECT 
cron.alter_job(job_id:=2,database:='pgcron_dbno',username:='pgcron_cront');
+
+-- Make sure pgcron_cront can execute alter_job
+GRANT EXECUTE ON FUNCTION cron.alter_job(bigint,text,text,text,text,boolean) 
TO public;
+
+-- Second as non superuser
+SET SESSION AUTHORIZATION pgcron_cront;
+
+-- Create a job
+SELECT cron.schedule('My vacuum', '0 11 * * *', 'VACUUM');
+
+-- Create a job for another user
+SELECT cron.schedule_in_database(job_name:='his vacuum', schedule:='0 11 * * 
*', command:='VACUUM',database:=current_database(),username:='anotheruser');
+
+-- Change the username of an existing job that the user own
+select cron.alter_job(job_id:=6,username:='anotheruser');
+
+-- Update a job that the user does not own
+select cron.alter_job(job_id:=2,database:='pgcron_dbyes');
+
+-- change the database for a job that the user own and can connect to
+select cron.alter_job(job_id:=6,database:='pgcron_dbyes');
+SELECT database FROM cron.job;
+
+-- change the database for a job that the user own but can not connect to
+select cron.alter_job(job_id:=6,database:='pgcron_dbno');
+SELECT database FROM cron.job;
+
+-- back to superuser
+RESET SESSION AUTHORIZATION;
+
+-- Change the username of an existing job
+select cron.alter_job(job_id:=2,username:='pgcron_cront');
+SELECT username FROM cron.job where jobid=2;
+
+-- Create a job for another user
+SELECT cron.schedule_in_database(job_name:='his vacuum', schedule:='0 11 * * 
*', command:='VACUUM',database:=current_database(), username:='pgcron_cront');
+SELECT username FROM cron.job where jobid=7;
+
+-- Try to schedule a job as superuser when it is not allowed
+SET cron.enable_superuser_jobs TO off;
+
+SELECT cron.schedule(job_name:='disallowed-superuser', schedule:='* * * * *', 
command:='drop database pg_crondbno');
+SELECT cron.alter_job(7, username := current_user);
+
+-- Scheduling as other users is allowed as superuser
+SELECT cron.schedule_in_database(job_name:='more vacuum', schedule:='0 12 * * 
*', command:='VACUUM', database:=current_database(), username:='pgcron_cront');
+SELECT cron.alter_job(7, username := 'pgcron_cront');
+
+-- cleaning
 DROP EXTENSION pg_cron;
+drop user pgcron_cront;
+drop database pgcron_dbno;
+drop database pgcron_dbyes;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pg_cron-1.3.1/src/entry.c 
new/pg_cron-1.4.1/src/entry.c
--- old/pg_cron-1.3.1/src/entry.c       2021-03-29 12:17:31.000000000 +0200
+++ new/pg_cron-1.4.1/src/entry.c       2021-09-25 18:55:16.000000000 +0200
@@ -381,7 +381,7 @@
        /* range. set all elements from num1 to num2, stepping
         * by num3.  (the step is a downward-compatible extension
         * proposed conceptually by bob@acornrc, syntactically
-        * designed then implmented by paul vixie).
+        * designed then implemented by paul vixie).
         */
        for (i = num1;  i <= num2;  i += num3)
                if (EOF == set_element(bits, low, high, i))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pg_cron-1.3.1/src/job_metadata.c 
new/pg_cron-1.4.1/src/job_metadata.c
--- old/pg_cron-1.3.1/src/job_metadata.c        2021-03-29 12:17:31.000000000 
+0200
+++ new/pg_cron-1.4.1/src/job_metadata.c        2021-09-25 18:55:16.000000000 
+0200
@@ -50,6 +50,8 @@
 
 #include "executor/spi.h"
 #include "catalog/pg_type.h"
+#include "commands/dbcommands.h"
+#include "catalog/pg_authid.h"
 
 #if (PG_VERSION_NUM < 120000)
 #define table_open(r, l) heap_open(r, l)
@@ -68,7 +70,9 @@
 /* forward declarations */
 static HTAB * CreateCronJobHash(void);
 
-static int64 ScheduleCronJob(Name jobName, char *schedule, char *command);
+static int64 ScheduleCronJob(text *scheduleText, text *commandText,
+                                                               text 
*databaseText, text *usernameText,
+                                                               bool active, 
text *jobnameText);
 static Oid CronExtensionOwner(void);
 static void EnsureDeletePermission(Relation cronJobsTable, HeapTuple 
heapTuple);
 static void InvalidateJobCacheCallback(Datum argument, Oid relationId);
@@ -78,7 +82,12 @@
 static CronJob * TupleToCronJob(TupleDesc tupleDescriptor, HeapTuple 
heapTuple);
 static bool PgCronHasBeenLoaded(void);
 static bool JobRunDetailsTableExists(void);
+static bool JobTableExists(void);
 
+static void AlterJob(int64 jobId, text *scheduleText, text *commandText,
+                                               text *databaseText, text 
*usernameText, bool *active);
+
+static Oid GetRoleOidIfCanLogin(char *username);
 
 /* SQL-callable functions */
 PG_FUNCTION_INFO_V1(cron_schedule);
@@ -86,6 +95,7 @@
 PG_FUNCTION_INFO_V1(cron_unschedule);
 PG_FUNCTION_INFO_V1(cron_unschedule_named);
 PG_FUNCTION_INFO_V1(cron_job_cache_invalidate);
+PG_FUNCTION_INFO_V1(cron_alter_job);
 
 
 /* global variables */
@@ -94,6 +104,7 @@
 static Oid CachedCronJobRelationId = InvalidOid;
 bool CronJobCacheValid = false;
 char *CronHost = "localhost";
+bool EnableSuperuserJobs = true;
 
 
 /*
@@ -167,59 +178,28 @@
        return job;
 }
 
-
-/*
- * cron_schedule schedules an unnamed cron job.
- */
-Datum
-cron_schedule(PG_FUNCTION_ARGS)
-{
-       text *scheduleText = PG_GETARG_TEXT_P(0);
-       text *commandText = PG_GETARG_TEXT_P(1);
-
-       Name jobName = NULL;
-       char *schedule = text_to_cstring(scheduleText);
-       char *command = text_to_cstring(commandText);
-
-       int64 jobId = ScheduleCronJob(jobName, schedule, command);
-
-       PG_RETURN_INT64(jobId);
-}
-
-
-/*
- * cron_schedule_named schedules a named cron job
- */
-Datum
-cron_schedule_named(PG_FUNCTION_ARGS)
-{
-       Name jobName = PG_GETARG_NAME(0);
-       text *scheduleText = PG_GETARG_TEXT_P(1);
-       text *commandText = PG_GETARG_TEXT_P(2);
-
-       char *schedule = text_to_cstring(scheduleText);
-       char *command = text_to_cstring(commandText);
-
-       int64 jobId = ScheduleCronJob(jobName, schedule, command);
-
-       PG_RETURN_INT64(jobId);
-}
-
-
 /*
  * ScheduleCronJob schedules a cron job with the given name.
  */
 static int64
-ScheduleCronJob(Name jobName, char *schedule, char *command)
+ScheduleCronJob(text *scheduleText, text *commandText, text *databaseText,
+                                       text *usernameText, bool active, text 
*jobnameText)
 {
        entry *parsedSchedule = NULL;
+       char *schedule;
+       char *command;
+       char *database_name;
+       char *jobName;
+       char *username;
+       AclResult aclresult;
+       Oid userIdcheckacl;
 
        int64 jobId = 0;
        Datum jobIdDatum = 0;
 
        StringInfoData querybuf;
-       Oid argTypes[7];
-       Datum argValues[7];
+       Oid argTypes[8];
+       Datum argValues[8];
        int argCount = 0;
 
        Oid savedUserId = InvalidOid;
@@ -230,9 +210,13 @@
        bool returnedJobIdIsNull = false;
 
        Oid userId = GetUserId();
-       char *userName = GetUserNameFromId(userId, false);
+       userIdcheckacl = GetUserId();
+       username = GetUserNameFromId(userId, false);
 
+       /* check schedule is valid */
+       schedule = text_to_cstring(scheduleText);
        parsedSchedule = parse_cron_entry(schedule);
+
        if (parsedSchedule == NULL)
        {
                ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -244,19 +228,19 @@
        initStringInfo(&querybuf);
 
        appendStringInfo(&querybuf,
-               "insert into %s (schedule, command, nodename, nodeport, 
database, username",
+               "insert into %s (schedule, command, nodename, nodeport, 
database, username, active",
                quote_qualified_identifier(CRON_SCHEMA_NAME, JOBS_TABLE_NAME));
 
-       if (jobName != NULL)
+       if (jobnameText != NULL)
        {
                appendStringInfo(&querybuf, ", jobname");
        }
 
-       appendStringInfo(&querybuf, ") values ($1, $2, $3, $4, $5, $6");
+       appendStringInfo(&querybuf, ") values ($1, $2, $3, $4, $5, $6, $7");
 
-       if (jobName != NULL)
+       if (jobnameText != NULL)
        {
-               appendStringInfo(&querybuf, ", $7) ");
+               appendStringInfo(&querybuf, ", $8) ");
                appendStringInfo(&querybuf, "on conflict on constraint 
jobname_username_uniq ");
                appendStringInfo(&querybuf, "do update set ");
                appendStringInfo(&querybuf, "schedule = EXCLUDED.schedule, ");
@@ -274,6 +258,7 @@
        argCount++;
 
        argTypes[1] = TEXTOID;
+       command = text_to_cstring(commandText);
        argValues[1] = CStringGetTextDatum(command);
        argCount++;
 
@@ -285,18 +270,57 @@
        argValues[3] = Int32GetDatum(PostPortNumber);
        argCount++;
 
+       /* username has been provided */
+       if (usernameText != NULL)
+       {
+               if (!superuser())
+                       elog(ERROR, "must be superuser to create a job for 
another role");
+
+               username = text_to_cstring(usernameText);
+               userIdcheckacl = GetRoleOidIfCanLogin(username);
+       }
+
+       /* database has been provided */
+       if (databaseText != NULL)
+               database_name = text_to_cstring(databaseText);
+       else
+       /* use the GUC */
+               database_name = CronTableDatabaseName;
+
+       /* first do a crude check to see whether superuser jobs are allowed */
+       if (!EnableSuperuserJobs && superuser_arg(userIdcheckacl))
+       {
+               ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                                               errmsg("cannot schedule jobs as 
superuser"),
+                                               errdetail("Scheduling jobs as 
superuser is disallowed when "
+                                                                 
"cron.enable_superuser_jobs is set to off.")));
+       }
+
+       /* ensure the user that is used in the job can connect to the database 
*/
+       aclresult = pg_database_aclcheck(get_database_oid(database_name, false),
+                                                                               
userIdcheckacl, ACL_CONNECT);
+
+       if (aclresult != ACLCHECK_OK)
+               elog(ERROR, "User %s does not have CONNECT privilege on %s",
+                               GetUserNameFromId(userIdcheckacl, false), 
database_name);
+
        argTypes[4] = TEXTOID;
-       argValues[4] = CStringGetTextDatum(CronTableDatabaseName);
+       argValues[4] = CStringGetTextDatum(database_name);
        argCount++;
 
        argTypes[5] = TEXTOID;
-       argValues[5] = CStringGetTextDatum(userName);
+       argValues[5] = CStringGetTextDatum(username);
+       argCount++;
+
+       argTypes[6] = BOOLOID;
+       argValues[6] = BoolGetDatum(active);
        argCount++;
 
-       if (jobName != NULL)
+       if (jobnameText != NULL)
        {
-               argTypes[6] = NAMEOID;
-               argValues[6] = NameGetDatum(jobName);
+               argTypes[7] = TEXTOID;
+               jobName = text_to_cstring(jobnameText);
+               argValues[7] = CStringGetTextDatum(jobName);
                argCount++;
        }
 
@@ -338,8 +362,154 @@
        return jobId;
 }
 
+/*
+ * GetRoleOidIfCanLogin
+ * Checks user exist and can log in
+ */
+static Oid
+GetRoleOidIfCanLogin(char *username)
+{
+       HeapTuple   roletup;
+       Form_pg_authid rform;
+       Oid roleOid = InvalidOid;
+
+       roletup = SearchSysCache1(AUTHNAME, PointerGetDatum(username));
+       if (!HeapTupleIsValid(roletup))
+               ereport(ERROR,
+                               (errmsg("role \"%s\" does not exist",
+                                               username)));
+
+       rform = (Form_pg_authid) GETSTRUCT(roletup);
+
+       if (!rform->rolcanlogin)
+               ereport(ERROR,
+                               (errmsg("role \"%s\" can not log in",
+                                               username),
+                                errdetail("Jobs may only be run by roles that 
have the LOGIN attribute.")));
+
+#if (PG_VERSION_NUM < 120000)
+       roleOid = HeapTupleGetOid(roletup);
+#else
+       roleOid = rform->oid;
+#endif
+
+       ReleaseSysCache(roletup);
+       return roleOid;
+}
+
+/*
+ * cron_alter_job alter a job
+ */
+Datum
+cron_alter_job(PG_FUNCTION_ARGS)
+{
+       int64 jobId;
+       text *scheduleText = NULL;
+       text *commandText = NULL;
+       text *databaseText = NULL;
+       text *usernameText = NULL;
+       bool active;
+
+       if (PG_ARGISNULL(0))
+               ereport(ERROR, (errmsg("job_id can not be NULL")));
+       else
+               jobId = PG_GETARG_INT64(0);
+
+       if (!PG_ARGISNULL(1))
+               scheduleText = PG_GETARG_TEXT_P(1);
+
+       if (!PG_ARGISNULL(2))
+               commandText = PG_GETARG_TEXT_P(2);
+
+       if (!PG_ARGISNULL(3))
+               databaseText = PG_GETARG_TEXT_P(3);
+
+       if (!PG_ARGISNULL(4))
+               usernameText = PG_GETARG_TEXT_P(4);
+
+       if (!PG_ARGISNULL(5))
+               active = PG_GETARG_BOOL(5);
+
+       AlterJob(jobId, scheduleText, commandText, databaseText, usernameText,
+                               PG_ARGISNULL(5) ? NULL : &active);
+
+       PG_RETURN_VOID();
+}
+
 
 /*
+ * cron_schedule schedule a job
+ */
+Datum
+cron_schedule(PG_FUNCTION_ARGS)
+{
+       text *scheduleText = NULL;
+       text *commandText = NULL;
+       int64 jobId;
+
+       if (PG_ARGISNULL(0))
+               ereport(ERROR, (errmsg("schedule can not be NULL")));
+       else
+               scheduleText = PG_GETARG_TEXT_P(0);
+
+       if (PG_ARGISNULL(1))
+               ereport(ERROR, (errmsg("command can not be NULL")));
+       else
+               commandText = PG_GETARG_TEXT_P(1);
+
+       jobId = ScheduleCronJob(scheduleText, commandText, NULL,
+                                                       NULL, true, NULL);
+
+       PG_RETURN_INT64(jobId);
+}
+
+/*
+ * cron_schedule schedule a named job
+ */
+Datum
+cron_schedule_named(PG_FUNCTION_ARGS)
+{
+       text *scheduleText = NULL;
+       text *commandText = NULL;
+       text *databaseText = NULL;
+       text *usernameText = NULL;
+       bool active = true;
+       text *jobnameText = NULL;
+       int64 jobId;
+
+       if (PG_ARGISNULL(0))
+               ereport(ERROR, (errmsg("job_name can not be NULL")));
+       else
+               jobnameText = PG_GETARG_TEXT_P(0);
+
+       if (PG_ARGISNULL(1))
+               ereport(ERROR, (errmsg("schedule can not be NULL")));
+       else
+               scheduleText = PG_GETARG_TEXT_P(1);
+
+       if (PG_ARGISNULL(2))
+               ereport(ERROR, (errmsg("command can not be NULL")));
+       else
+               commandText = PG_GETARG_TEXT_P(2);
+
+       if (PG_NARGS() > 3)
+       {
+               if (!PG_ARGISNULL(3))
+                       databaseText = PG_GETARG_TEXT_P(3);
+
+               if (!PG_ARGISNULL(4))
+                       usernameText = PG_GETARG_TEXT_P(4);
+
+               if (!PG_ARGISNULL(5))
+                       active = PG_GETARG_BOOL(5);
+       }
+
+       jobId = ScheduleCronJob(scheduleText, commandText, databaseText,
+                                                       usernameText, active, 
jobnameText);
+
+       PG_RETURN_INT64(jobId);
+}
+/*
  * NextRunId draws a new run ID from cron.runid_seq.
  */
 int64
@@ -692,11 +862,29 @@
        {
                MemoryContext oldContext = NULL;
                CronJob *job = NULL;
+               Oid jobOwnerId = InvalidOid;
 
                oldContext = MemoryContextSwitchTo(CronJobContext);
 
                job = TupleToCronJob(tupleDescriptor, heapTuple);
-               jobList = lappend(jobList, job);
+
+               jobOwnerId = get_role_oid(job->userName, false);
+               if (!EnableSuperuserJobs && superuser_arg(jobOwnerId))
+               {
+                       /*
+                        * Someone inserted a superuser into the metadata. Skip 
over the
+                        * job when cron.enable_superuser_jobs is disabled. The 
memory
+                        * will be cleaned up when CronJobContext is reset.
+                        */
+                       ereport(WARNING, 
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                                                         errmsg("skipping job 
" INT64_FORMAT " since superuser jobs "
+                                                                        "are 
currently disallowed",
+                                                                        
job->jobId)));
+               }
+               else
+               {
+                       jobList = lappend(jobList, job);
+               }
 
                MemoryContextSwitchTo(oldContext);
 
@@ -1013,6 +1201,171 @@
        pgstat_report_activity(STATE_IDLE, NULL);
 }
 
+
+static void
+AlterJob(int64 jobId, text *scheduleText, text *commandText, text 
*databaseText, text *usernameText, bool *active)
+{
+       StringInfoData querybuf;
+       Oid argTypes[7];
+       Datum argValues[7];
+       int i;
+       AclResult aclresult;
+       Oid userId;
+       Oid userIdcheckacl;
+       Oid savedUserId;
+       int savedSecurityContext;
+       char *database_name;
+       char *schedule;
+       char *command;
+       char *username;
+       char *currentuser;
+       entry *parsedSchedule = NULL;
+
+       userId = GetUserId();
+       userIdcheckacl = GetUserId();
+
+       currentuser = GetUserNameFromId(userId, false);
+       savedUserId = InvalidOid;
+       savedSecurityContext = 0;
+
+       if (!PgCronHasBeenLoaded() || RecoveryInProgress() || !JobTableExists())
+       {
+               return;
+       }
+
+       initStringInfo(&querybuf);
+       i = 0;
+
+       appendStringInfo(&querybuf,
+               "update %s.%s set", CRON_SCHEMA_NAME, JOBS_TABLE_NAME);
+
+       /* username has been provided */
+       if (usernameText != NULL)
+       {
+               if (!superuser())
+                       elog(ERROR, "must be superuser to alter username");
+
+               username = text_to_cstring(usernameText);
+               userIdcheckacl = GetRoleOidIfCanLogin(username);
+       }
+       else
+       {
+               username = currentuser;
+       }
+
+       if (!EnableSuperuserJobs && superuser_arg(userIdcheckacl))
+       {
+               ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                                               errmsg("cannot schedule jobs as 
superuser"),
+                                               errdetail("Scheduling jobs as 
superuser is disallowed when "
+                                                                 
"cron.enable_superuser_jobs is set to off.")));
+       }
+
+       /* add the fields to be updated */
+       /* database has been provided */
+       if (databaseText != NULL)
+       {
+               database_name = text_to_cstring(databaseText);
+               /* ensure the user that is used in the job can connect to the 
database */
+               aclresult = 
pg_database_aclcheck(get_database_oid(database_name, false), userIdcheckacl, 
ACL_CONNECT);
+
+               if (aclresult != ACLCHECK_OK)
+                       elog(ERROR, "User %s does not have CONNECT privilege on 
%s", GetUserNameFromId(userIdcheckacl, false), database_name);
+
+               argTypes[i] = TEXTOID;
+               argValues[i] = CStringGetTextDatum(database_name);
+               i++;
+               appendStringInfo(&querybuf, " database = $%d,", i);
+       }
+
+       /* ensure schedule is valid */
+       if (scheduleText != NULL)
+       {
+               schedule = text_to_cstring(scheduleText);
+               parsedSchedule = parse_cron_entry(schedule);
+
+               if (parsedSchedule == NULL)
+               {
+                       ereport(ERROR, 
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                       errmsg("invalid schedule: %s", 
schedule)));
+               }
+
+               free_entry(parsedSchedule);
+
+               argTypes[i] = TEXTOID;
+               argValues[i] = CStringGetTextDatum(schedule);
+               i++;
+               appendStringInfo(&querybuf, " schedule = $%d,", i);
+       }
+
+       if (commandText != NULL)
+       {
+               argTypes[i] = TEXTOID;
+               command = text_to_cstring(commandText);
+               argValues[i] = CStringGetTextDatum(command);
+               i++;
+               appendStringInfo(&querybuf, " command = $%d,", i);
+       }
+
+       if (usernameText != NULL)
+       {
+               argTypes[i] = TEXTOID;
+               argValues[i] = CStringGetTextDatum(username);
+               i++;
+               appendStringInfo(&querybuf, " username = $%d,", i);
+       }
+
+       if (active != NULL)
+       {
+               argTypes[i] = BOOLOID;
+               argValues[i] = BoolGetDatum(*active);
+               i++;
+               appendStringInfo(&querybuf, " active = $%d,", i);
+       }
+
+       /* remove the last comma */
+       querybuf.len--;
+       querybuf.data[querybuf.len] = '\0';
+
+       /* and add the where clause */
+       argTypes[i] = INT8OID;
+       argValues[i] = Int64GetDatum(jobId);
+       i++;
+
+       appendStringInfo(&querybuf, " where jobid = $%d", i);
+
+       /* ensure the caller owns the row */
+       argTypes[i] = TEXTOID;
+       argValues[i] = CStringGetTextDatum(currentuser);
+       i++;
+
+       if (!superuser())
+               appendStringInfo(&querybuf, " and username = $%d", i);
+
+       if (i <= 2)
+               ereport(ERROR, (errmsg("no updates specified"),
+                                               errhint("You must specify at 
least one job attribute to change when calling alter_job")));
+
+       GetUserIdAndSecContext(&savedUserId, &savedSecurityContext);
+       SetUserIdAndSecContext(CronExtensionOwner(), 
SECURITY_LOCAL_USERID_CHANGE);
+
+       /* Open SPI context. */
+       if (SPI_connect() != SPI_OK_CONNECT)
+               elog(ERROR, "SPI_connect failed");
+       if(SPI_execute_with_args(querybuf.data,
+               i, argTypes, argValues, NULL, false, 1) != SPI_OK_UPDATE)
+               elog(ERROR, "SPI_exec failed: %s", querybuf.data);
+
+       pfree(querybuf.data);
+
+       if (SPI_processed <= 0)
+               elog(ERROR, "Job %ld does not exist or you don't own it", 
jobId);
+
+       SPI_finish();
+       SetUserIdAndSecContext(savedUserId, savedSecurityContext);
+       InvalidateJobCache();
+}
+
 void
 MarkPendingRunsAsFailed(void)
 {
@@ -1101,3 +1454,16 @@
 
        return jobRunDetailsTableOid != InvalidOid;
 }
+
+/*
+ * JobTableExists returns whether the job table exists.
+ */
+static bool
+JobTableExists(void)
+{
+       Oid cronSchemaId = get_namespace_oid(CRON_SCHEMA_NAME, false);
+       Oid jobTableOid = get_relname_relid(JOBS_TABLE_NAME,
+                                                                               
                cronSchemaId);
+
+       return jobTableOid != InvalidOid;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pg_cron-1.3.1/src/pg_cron.c 
new/pg_cron-1.4.1/src/pg_cron.c
--- old/pg_cron-1.3.1/src/pg_cron.c     2021-03-29 12:17:31.000000000 +0200
+++ new/pg_cron-1.4.1/src/pg_cron.c     2021-09-25 18:55:16.000000000 +0200
@@ -36,9 +36,14 @@
 #include "task_states.h"
 #include "job_metadata.h"
 
-#include "poll.h"
+
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#elif defined(HAVE_SYS_POLL_H)
+#include <sys/poll.h>
+#endif
+
 #include "sys/time.h"
-#include "sys/poll.h"
 #include "time.h"
 
 #include "access/genam.h"
@@ -133,7 +138,7 @@
 static void ManageCronTask(CronTask *task, TimestampTz currentTime);
 static void ExecuteSqlString(const char *sql);
 static void GetTaskFeedback(PGresult *result, CronTask *task);
-static void GetBgwTaskFeedback(shm_mq_handle *responseq, CronTask *task);
+static void GetBgwTaskFeedback(shm_mq_handle *responseq, CronTask *task, bool 
running);
 
 static bool jobCanceled(CronTask *task);
 static bool jobStartupTimeout(CronTask *task, TimestampTz currentTime);
@@ -144,6 +149,7 @@
 char *CronTableDatabaseName = "postgres";
 static bool CronLogStatement = true;
 static bool CronLogRun = true;
+static bool CronReloadConfig = false;
 
 /* flags set by signal handlers */
 static volatile sig_atomic_t got_sigterm = false;
@@ -154,8 +160,27 @@
 static bool RebootJobsScheduled = false;
 static int RunningTaskCount = 0;
 static int MaxRunningTasks = 0;
+static int CronLogMinMessages = WARNING;
 static bool UseBackgroundWorkers = false;
 
+static const struct config_enum_entry cron_message_level_options[] = {
+       {"debug5", DEBUG5, false},
+       {"debug4", DEBUG4, false},
+       {"debug3", DEBUG3, false},
+       {"debug2", DEBUG2, false},
+       {"debug1", DEBUG1, false},
+       {"debug", DEBUG2, true},
+       {"info", INFO, false},
+       {"notice", NOTICE, false},
+       {"warning", WARNING, false},
+       {"error", ERROR, false},
+       {"log", LOG, false},
+       {"fatal", FATAL, false},
+       {"panic", PANIC, false},
+       {NULL, 0, false}
+};
+
+static const char *cron_error_severity(int elevel);
 
 /*
  * _PG_init gets called when the extension is loaded.
@@ -207,6 +232,16 @@
                GUC_SUPERUSER_ONLY,
                NULL, NULL, NULL);
 
+       DefineCustomBoolVariable(
+               "cron.enable_superuser_jobs",
+               gettext_noop("Allow jobs to be scheduled as superuser"),
+               NULL,
+               &EnableSuperuserJobs,
+               true,
+               PGC_USERSET,
+               GUC_SUPERUSER_ONLY,
+               NULL, NULL, NULL);
+
        DefineCustomStringVariable(
                "cron.host",
                gettext_noop("Hostname to connect to postgres."),
@@ -252,6 +287,17 @@
                        GUC_SUPERUSER_ONLY,
                        NULL, NULL, NULL);
 
+       DefineCustomEnumVariable(
+               "cron.log_min_messages",
+               gettext_noop("log_min_messages for the launcher bgworker."),
+               NULL,
+               &CronLogMinMessages,
+               WARNING,
+               cron_message_level_options,
+               PGC_SIGHUP,
+               GUC_SUPERUSER_ONLY,
+               NULL, NULL, NULL);
+
        /* set up common data for all our workers */
        worker.bgw_flags = BGWORKER_SHMEM_ACCESS | 
BGWORKER_BACKEND_DATABASE_CONNECTION;
        worker.bgw_start_time = BgWorkerStart_RecoveryFinished;
@@ -297,6 +343,7 @@
 pg_cron_sighup(SIGNAL_ARGS)
 {
        CronJobCacheValid = false;
+       CronReloadConfig = true;
 
        if (MyProc != NULL)
        {
@@ -362,6 +409,60 @@
 }
 
 /*
+ * cron_error_severity --- get string representing elevel
+ */
+static const char *
+cron_error_severity(int elevel)
+{
+       const char *elevel_char;
+
+       switch (elevel)
+       {
+               case DEBUG1:
+                       elevel_char = "DEBUG1";
+                       break;
+               case DEBUG2:
+                       elevel_char = "DEBUG2";
+                       break;
+               case DEBUG3:
+                       elevel_char = "DEBUG3";
+                       break;
+               case DEBUG4:
+                       elevel_char = "DEBUG4";
+                       break;
+               case DEBUG5:
+                       elevel_char = "DEBUG5";
+                       break;
+               case LOG:
+                       elevel_char = "LOG";
+                       break;
+               case INFO:
+                       elevel_char = "INFO";
+                       break;
+               case NOTICE:
+                       elevel_char = "NOTICE";
+                       break;
+               case WARNING:
+                       elevel_char = "WARNING";
+                       break;
+               case ERROR:
+                       elevel_char = "ERROR";
+                       break;
+               case FATAL:
+                       elevel_char = "FATAL";
+                       break;
+               case PANIC:
+                       elevel_char = "PANIC";
+                       break;
+               default:
+                       elevel_char = "???";
+                       break;
+       }
+
+       return elevel_char;
+}
+
+/*
  * bgw_generate_returned_message -
  *      generates the message to be inserted into the job_run_details table
  *      first part is comming from error_severity (elog.c)
@@ -516,6 +617,10 @@
 
        ereport(LOG, (errmsg("pg_cron scheduler started")));
 
+       /* set the desired log_min_messages */
+       SetConfigOption("log_min_messages", 
cron_error_severity(CronLogMinMessages),
+                                                                               
PGC_POSTMASTER, PGC_S_OVERRIDE);
+
        MemoryContextSwitchTo(CronLoopContext);
 
        while (!got_sigterm)
@@ -530,6 +635,15 @@
                        RefreshTaskHash();
                }
 
+               if (CronReloadConfig)
+               {
+                       /* set the desired log_min_messages */
+                       ProcessConfigFile(PGC_SIGHUP);
+                       SetConfigOption("log_min_messages", 
cron_error_severity(CronLogMinMessages),
+                                                                               
                PGC_POSTMASTER, PGC_S_OVERRIDE);
+                       CronReloadConfig = false;
+               }
+
                taskList = CurrentTaskList();
                currentTime = GetCurrentTimestamp();
 
@@ -913,7 +1027,7 @@
        int activeTaskCount = 0;
        ListCell *taskCell = NULL;
 
-       polledTasks = (CronTask **) palloc0(taskCount * sizeof(CronTask));
+       polledTasks = (CronTask **) palloc0(taskCount * sizeof(CronTask *));
        pollFDs = (struct pollfd *) palloc0(taskCount * sizeof(struct pollfd));
 
        currentTime = GetCurrentTimestamp();
@@ -1560,10 +1674,6 @@
                                break;
                        }
 
-                       /* still waiting for job to complete */
-                       if (GetBackgroundWorkerPid(&task->handle, &pid) != 
BGWH_STOPPED)
-                               break;
-
                        toc = shm_toc_attach(PG_CRON_MAGIC, 
dsm_segment_address(task->seg));
                        #if PG_VERSION_NUM < 100000
                                mq = shm_toc_lookup(toc, PG_CRON_KEY_QUEUE);
@@ -1571,7 +1681,16 @@
                                mq = shm_toc_lookup(toc, PG_CRON_KEY_QUEUE, 
false);
                        #endif
                        responseq = shm_mq_attach(mq, task->seg, NULL);
-                       GetBgwTaskFeedback(responseq, task);
+
+                       /* still waiting for job to complete */
+                       if (GetBackgroundWorkerPid(&task->handle, &pid) != 
BGWH_STOPPED)
+                       {
+                               GetBgwTaskFeedback(responseq, task, true);
+                               shm_mq_detach(responseq);
+                               break;
+                       }
+
+                       GetBgwTaskFeedback(responseq, task, false);
 
                        task->state = CRON_TASK_DONE;
                        dsm_detach(task->seg);
@@ -1736,7 +1855,7 @@
 }
 
 static void
-GetBgwTaskFeedback(shm_mq_handle *responseq, CronTask *task)
+GetBgwTaskFeedback(shm_mq_handle *responseq, CronTask *task, bool running)
 {
 
        TimestampTz end_time;
@@ -1783,9 +1902,10 @@
 
                                                if (edata.elevel >= ERROR)
                                                        
UpdateJobRunDetail(task->runId, NULL, GetCronStatus(CRON_STATUS_FAILED), 
display_msg.data, NULL, &end_time);
+                                               else if (running)
+                                                       
UpdateJobRunDetail(task->runId, NULL, NULL, display_msg.data, NULL, NULL);
                                                else
                                                        
UpdateJobRunDetail(task->runId, NULL, GetCronStatus(CRON_STATUS_SUCCEEDED), 
display_msg.data, NULL, &end_time);
-
                                        }
 
                                        ereport(LOG, (errmsg("cron job " 
INT64_FORMAT ": %s",

Reply via email to