Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1tZ9R4-002By4-NZ for pgsql-general@arkaria.postgresql.org; Sat, 18 Jan 2025 14:04:27 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1tZ9R0-000SQx-Ti for pgsql-general@arkaria.postgresql.org; Sat, 18 Jan 2025 14:04:23 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1tZ9R0-000SQp-GN for pgsql-general@lists.postgresql.org; Sat, 18 Jan 2025 14:04:23 +0000 Received: from mail-ed1-x530.google.com ([2a00:1450:4864:20::530]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1tZ9Qx-000Cbk-2X for pgsql-general@postgresql.org; Sat, 18 Jan 2025 14:04:22 +0000 Received: by mail-ed1-x530.google.com with SMTP id 4fb4d7f45d1cf-5d7e3f1fc01so6007997a12.2 for ; Sat, 18 Jan 2025 06:04:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1737209058; x=1737813858; darn=postgresql.org; h=cc:subject:message-id:date:from:in-reply-to:references:mime-version :from:to:cc:subject:date:message-id:reply-to; bh=gldy0pzM4W1P0E8balv2FTfI5T1ugtmrfGuES5YETz8=; b=APfmqz/vQGwqOUYCGo+MelNNbzvsTi/snECUcpkAgd3Ka9OX98pAiLbOELRrNWQJ21 9cZivWDkb5QuXKY94JWnbMnOUeSxyk7pm4xFUi6cgfMfL0PkNnPstkoh7/Qd1JD9k9e7 7A+l31ffzteU1hF5bnutrL/BmAsSaSuLUa6CFMYueoJOZQh6acfznTH4a2kGWFO8pi1I ui4u7yAYbYtUjx2NWyUGT6XeddORMb08HPcasTs/HE14gQYozig78D2TdH9QWPqCXYtl TwCKqNm1Z7GRPHDMC+wmhQYEVRomVbLPq29OrDGRa7sVE9g3O1+bIIeVaAHQY/LelpeY 8MsQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1737209058; x=1737813858; h=cc:subject:message-id:date:from:in-reply-to:references:mime-version :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=gldy0pzM4W1P0E8balv2FTfI5T1ugtmrfGuES5YETz8=; b=AKKlmtg9+CNUfcVeUFLfWmfw8mYKcZwxB7w5N0KaXCHRbzOZhatuRg9tYHnHpdiPii pvC3b8IVpAM9UErK33Q3B4ZJKZ4Pt6RVySXZdx7TVYxhIFJqPE/HDaCUjmjeOXTf2ZnR kzvOpFBmgIxXpzDMs6cySZvI8mwjVZa+gxxPttyAqNCrAgUBTNlvVk+mqqYg1A0b7Dnr g/2SJZ8GdJXWNBwqdBlCD8v9cpByQMdW3LwpVD1hFpe16BFFTQn4ml6wHK6d4h/mBHNR SNFdQIx9GpUKE7C7pXr0A4OvBUhBDpX2zndFzI6ahVA6Zw2Gv5m2jtePoEnLjy1+Z32y WPtg== X-Gm-Message-State: AOJu0Yy/fZm69/pljICsSmlqZpwTjsGhu7SDbMZBZgmovoK39tyTO8ny kJBS1fIIv8i4gj2uAnJS+Vs8cMpycN2nASbY2mrw2yQbFfSTLEupO0dii1wQBJe0GB4CUv0/y2k vhf6REzOX9bAODj4r0obHQmwMj0HXH9WEjcY= X-Gm-Gg: ASbGncvuLtDTzlbQfVfk66zhqa5SBlx5lGS7GpCTdq9kav1xLTAnKI7jkUVaOBb5D6I poH9MXrOGk/r9pfelJLvSlsSQONGabWcM2NA/CcP/gR2ZguYwMvru X-Google-Smtp-Source: AGHT+IGgKxTE9mwzjaD36AUeSGnO33ZJvNyVLF3fIaeEPGv+gid27RSI00VETR9X1kCE4NLOZECPbiIMtWyyFkG7QXQ= X-Received: by 2002:a05:6402:84c:b0:5d1:f009:925e with SMTP id 4fb4d7f45d1cf-5db7d31bae9mr5880443a12.16.1737209058221; Sat, 18 Jan 2025 06:04:18 -0800 (PST) MIME-Version: 1.0 References: In-Reply-To: From: Alexander Farber Date: Sat, 18 Jan 2025 15:04:07 +0100 X-Gm-Features: AbW1kvYtXpSvrhQlCeZK-YMKG7BGCivCHcGXsciyK_3OAHoKgSYSQOJ1qPDYNdc Message-ID: Subject: Re: Why is DELETE FROM vehicle_data WHERE NOW, > expires_at, failing in my stored function? Cc: pgsql-general Content-Type: multipart/alternative; boundary="000000000000d0ea59062bfb800a" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --000000000000d0ea59062bfb800a Content-Type: text/plain; charset="UTF-8" Thank you Giovanni, I did not expect this from NOW() and that is why I was stuck. I have decided to keep NOW() in my stored function in the hope it has better performance. To fix the issue I have rewritten my smoke tests to be plain SQL without any transaction: CREATE OR REPLACE FUNCTION test_store_vehicle_data( num_runs INTEGER, OUT count_true INTEGER, OUT count_false INTEGER ) RETURNS RECORD AS $$ DECLARE test_result BOOLEAN; BEGIN count_true := 0; count_false := 0; FOR i IN 1..num_runs LOOP -- Store OSM node ids (2 are same, 2 are changing) -- with node limit 10 and retention time 5 seconds test_result := store_vehicle_data( 100 + i, ARRAY[1000, 2000, 3000 + i, 4000 + i], 1, 5, 10, INTERVAL '5 seconds' ); IF test_result THEN count_true := count_true + 1; ELSE count_false := count_false + 1; END IF; END LOOP; RETURN; END $$ LANGUAGE plpgsql; -- Test 1: Run the test_store_vehicle_data function -- to insert 15x4 records (node_limit 10, expiring -- in 5 seconds) into the vehicle_data table and -- finally store the result in a temporary table CREATE TEMP TABLE temp_test_result AS SELECT * FROM test_store_vehicle_data(15); -- The temp_test_result has just 1 record, check it SELECT CASE WHEN count_true != 10 OR count_false != 5 THEN 'Test 1 failed: expected 10 TRUE, 5 FALSE' ELSE 'Test 1 passed' END AS test_result FROM temp_test_result; -- Drop the temporary table to clean up DROP TABLE temp_test_result; -- Pause execution for 10 seconds so that all records expire SELECT pg_sleep(10); -- Test 2: Run the test_store_vehicle_data function -- to insert 15x4 records (node_limit 10, expiring -- in 5 seconds) into the vehicle_data table and -- finally store the result in a temporary table CREATE TEMP TABLE temp_test_result AS SELECT * FROM test_store_vehicle_data(15); -- The temp_test_result has just 1 record, check it SELECT CASE WHEN count_true != 10 OR count_false != 5 THEN 'Test 1 failed: expected 10 TRUE, 5 FALSE' ELSE 'Test 1 passed' END AS test_result FROM temp_test_result; -- Drop the temporary table to clean up DROP TABLE temp_test_result; -- Print all records in the vehicle_data table SELECT expires_at < NOW() AS is_expired, * FROM vehicle_data ORDER BY container_id; --000000000000d0ea59062bfb800a Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Thank you Giovanni, I did not expect this= from NOW() and that is why I was stuck.

I have decided to keep NOW(= ) in my stored function in the hope it has better performance.

To fi= x the issue I have rewritten my smoke tests to be plain SQL without any tra= nsaction:

CREATE OR REPLACE FUNCTION test_store_vehicle_data(
=C2=A0 =C2=A0 num_runs INTEGER,
=C2=A0 =C2=A0 OUT count_= true INTEGER,
=C2=A0 =C2=A0 OUT count_false INTEGER
)
RETURNS RECORD AS $$
DECLARE
=C2=A0 =C2=A0 tes= t_result BOOLEAN;
BEGIN
=C2=A0 =C2=A0 count_true :=3D 0= ;
=C2=A0 =C2=A0 count_false :=3D 0;

=C2= =A0 =C2=A0 FOR i IN 1..num_runs LOOP
=C2=A0 =C2=A0 =C2=A0 =C2=A0 = -- Store OSM node ids (2 are same, 2 are changing)
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 -- with node limit 10 and retention time 5 seconds
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 test_result :=3D store_vehicle_data(
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 100 + i,=C2=A0
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ARRAY[1000, 2000, 3000 + i, 4000 + i],
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 1,=C2=A0
=C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 5,=C2=A0
=C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 10,=C2=A0
=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 INTERVAL '5 seconds'
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 );

=C2=A0 =C2=A0 =C2=A0 =C2=A0 IF test_resu= lt THEN
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 count_true :=3D= count_true + 1;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 ELSE
=C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 count_false :=3D count_false + 1;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 END IF;
=C2=A0 =C2=A0 END LOO= P;

=C2=A0 =C2=A0 RETURN;
END $$ LANGUAGE= plpgsql;

-- Test 1: Run the test_store_vehicle_da= ta function
-- to insert 15x4 records (node_limit 10, expiring
-- in 5 seconds) into the vehicle_data table and
-- final= ly store the result in a temporary table
CREATE TEMP TABLE temp_t= est_result AS
SELECT * FROM test_store_vehicle_data(15);

-- The temp_test_result has just 1 record, check it
<= div>SELECT=C2=A0
=C2=A0 =C2=A0 CASE=C2=A0
=C2=A0 =C2=A0= =C2=A0 =C2=A0 WHEN count_true !=3D 10 OR count_false !=3D 5=C2=A0
=C2=A0 =C2=A0 =C2=A0 =C2=A0 THEN 'Test 1 failed: expected 10 TRUE, 5 = FALSE'=C2=A0
=C2=A0 =C2=A0 =C2=A0 =C2=A0 ELSE 'Test 1 pas= sed'=C2=A0
=C2=A0 =C2=A0 END AS test_result
FROM te= mp_test_result;

-- Drop the temporary table to cle= an up
DROP TABLE temp_test_result;

-- Pa= use execution for 10 seconds so that all records expire
SELECT pg= _sleep(10);

-- Test 2: Run the test_store_vehicle_= data function
-- to insert 15x4 records (node_limit 10, expiring<= /div>
-- in 5 seconds) into the vehicle_data table and
-- fin= ally store the result in a temporary table
CREATE TEMP TABLE temp= _test_result AS
SELECT * FROM test_store_vehicle_data(15);
<= div>
-- The temp_test_result has just 1 record, check it
SELECT=C2=A0
=C2=A0 =C2=A0 CASE=C2=A0
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 WHEN count_true !=3D 10 OR count_false !=3D 5=C2=A0
=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 THEN 'Test 1 failed: expected 10 TRUE,= 5 FALSE'=C2=A0
=C2=A0 =C2=A0 =C2=A0 =C2=A0 ELSE 'Test 1 = passed'=C2=A0
=C2=A0 =C2=A0 END AS test_result
FROM= temp_test_result;

-- Drop the temporary table to = clean up
DROP TABLE temp_test_result;

--= Print all records in the vehicle_data table
SELECT expires_at &l= t; NOW() AS is_expired, *
FROM vehicle_data
ORDER BY co= ntainer_id;

--000000000000d0ea59062bfb800a--