PostgreSQL Rule does not work with deferred constraint.

2022-09-21 Thread Louis Tian
Hi all,

Encountered a possible bug today. In short, it appears that the rule system is 
not deferring the constraint checking as specified. Here is an example.
create table "parent" (
  "id" uuid primary key
);

create table "children" (
  "id" uuid primary key
  default gen_random_uuid()
   references parent("id")
deferrable
initially deferred
);

-- this works as expected.
begin;
  insert into "children" values ('74c247be-2fc3-43e5-94f8-d5e1af147a9b');
  insert into "parent" values ('74c247be-2fc3-43e5-94f8-d5e1af147a9b');
commit;

-- doing the same with a rule
create rule on_insert as on insert to "children" do also (
  insert into "parent" (id) values (new."id");
);

-- this fails with:
--    ERROR:  insert or update on table "children" violates foreign key 
constraint "children_id_fkey"
--    DETAIL:  Key (id)=(40513132-f9fa-4e5a-aa46-20c8185b3e58) is not present 
in table "parent".
--    SQL state: 23503
insert into "children" values (default);
The rules system supposedly transforms the insert statement and executed the 
rule action in the same transaction. So I think it should work.
But I got the same error on both pg13 and pg14.

Is there something I missed here? or is my understanding of the rule system 
just simply wrong?

Regards,

Louis Tian
louis.t...@aquamonix.com.au



Row Level Security Policy Name in Error Message

2023-03-06 Thread Louis Tian
Hi All,

Wondering whether there is a way to get the row-level security policy name in 
the error message when it's violated.
I am only getting a more generic error message like this.
ERROR:  new row violates row-level security policy for table "table_name"

Thanks for your help.

Regards,
Louis Tian


UPSERT in Postgres

2023-04-06 Thread Louis Tian
This is a question/feature request. 

Virtually all references on the internet today suggests one can "upsert" in 
PostgreSQL using the "insert ... on conflict do update ..." statement. 
But this is not complete true. 

The PostgreSQL's own wiki page 
(https://wiki.postgresql.org/wiki/UPSERT#.22UPSERT.22_definition) defines 
UPSERT as
 "UPSERT" is a DBMS feature that allows a DML statement's author to atomically 
either insert a row, or on the basis of the row already existing, UPDATE that 
existing row instead,
I believe this definition is correct and consistent with defintion elsewhere 
(https://en.wiktionary.org/wiki/upsert).

An implicit assumption behind this definition is that table must have a primary 
key for the upsert operation to make sense since it's the primary key that 
uniquely identifies a row. 
let's say we have a very simple table

```
create table person (
  id int primary key,
  name text not null,
           is_active boolean
)
``` 

Given the definition of upsert, I'd expect an upsert command to do the 
following.
- `upsert into person (id, name) values (0, 'foo')` to insert a new row 
- `upsert into person (id, is_active) values (0, true)` updates the is_active 
column for the row inserted above

Naturally, since there isn't a real upsert command in PostgreSQL this won't 
work today. 
But can we achieve the same effect with "INSERT ... ON CONFLICT DO UPDATE" like 
a lot of references on the internet seems to suggest. 

insert into person (id, name) values (0, 'foo') on conflict ("id") do update 
set id=excluded.id, name=excluded.name
insert into person (id, is_active) values (0, true) on conflict ("id") do 
update set id=excluded.id, is_active=excluded.is_active 

Unfortunately. the second statement will fail due to violation of the not null 
constraint on the "name" column. 
PostgreSQL will always try to insert the row into the table first. and only 
fallback to update when the uniqueness constraint is violated. 
Is this behavior wrong? maybe not, I think it is doing what it reads quite 
literally. 
That being said, I have never had a need for the ON CONFLICT DO UPDATE 
statement other than where I need upsert. 
But using it as "upsert" is only valid when the table is absent of any NOT NULL 
constraint on it's non primary key columns. 
So, if my experience/use case is typical (meaning the main purpose / use case 
for ON CONFLICT DO UPDATE is to support upsert) then it can be argue the 
current behavior is incorrect?  

This has been a source confusion to say at least. 
https://stackoverflow.com/questions/48816629/on-conflict-do-nothing-in-postgres-with-a-not-null-constraint
 
https://www.postgresql.org/message-id/flat/1996438.1604952901%40sss.pgh.pa.us#ace8adc1354265aca5672028faea0c0f

The MERGE command introduced in PG15 in theory can be used to do UPSERT 
properly that is void of the aforementioned limitation. 
The downside is it is rather verbose. 

*Question*
This there a way to do an upsert proper prior to PG15?

*Feature Request*
Given that UPSERT is an *idempotent* operator it is extremely useful.  
Would love to see an UPSERT command in PostgreSQL so one can 'upsert' properly 
and easily. 


Regards,
Louis Tian











Re: [EXTERNAL]: Re: UPSERT in Postgres

2023-04-08 Thread Louis Tian
Hi Adrian,

Thank you. I think this is a better approach than trigger-based solution, at 
least for my taste.
That being said, it does require some logic to push to the client side 
(figuring out which required column value is missing and set it value to the 
existing one via reference of the table name).
Still wish there would be UPSERT statement that can handle this and make dev 
experience better.

Cheers,
Louis Tian

From: Adrian Klaver 
Sent: Friday, April 7, 2023 7:00 AM
To: Louis Tian ; 
pgsql-general@lists.postgresql.org 
Subject: [EXTERNAL]: Re: UPSERT in Postgres

CAUTION: This email originated from outside of Envirada. Do not click links or 
open attachments unless you recognize the sender and know the content is safe.


On 4/5/23 23:21, Louis Tian wrote:
> This is a question/feature request.
>

> Given the definition of upsert, I'd expect an upsert command to do the 
> following.
> - `upsert into person (id, name) values (0, 'foo')` to insert a new row
> - `upsert into person (id, is_active) values (0, true)` updates the is_active 
> column for the row inserted above
>
> Naturally, since there isn't a real upsert command in PostgreSQL this won't 
> work today.
> But can we achieve the same effect with "INSERT ... ON CONFLICT DO UPDATE" 
> like a lot of references on the internet seems to suggest.
>
> insert into person (id, name) values (0, 'foo') on conflict ("id") do update 
> set id=excluded.id, name=excluded.name
> insert into person (id, is_active) values (0, true) on conflict ("id") do 
> update set id=excluded.id, is_active=excluded.is_active

insert into person (id, name, is_active) values (0, '', true) on
conflict ("id") do update set id=excluded.id, name=person.name,
is_active=excluded.is_active ;
INSERT 0 1

select * from person;
  id | name | is_active
+--+---
   0 | foo  | t

>
> Unfortunately. the second statement will fail due to violation of the not 
> null constraint on the "name" column.
> PostgreSQL will always try to insert the row into the table first. and only 
> fallback to update when the uniqueness constraint is violated.
> Is this behavior wrong? maybe not, I think it is doing what it reads quite 
> literally.
> That being said, I have never had a need for the ON CONFLICT DO UPDATE 
> statement other than where I need upsert.
> But using it as "upsert" is only valid when the table is absent of any NOT 
> NULL constraint on it's non primary key columns.
> So, if my experience/use case is typical (meaning the main purpose / use case 
> for ON CONFLICT DO UPDATE is to support upsert) then it can be argue the 
> current behavior is incorrect?
>
> This has been a source confusion to say at least.
> https://stackoverflow.com/questions/48816629/on-conflict-do-nothing-in-postgres-with-a-not-null-constraint
> https://www.postgresql.org/message-id/flat/1996438.1604952901%40sss.pgh.pa.us#ace8adc1354265aca5672028faea0c0f
>
> The MERGE command introduced in PG15 in theory can be used to do UPSERT 
> properly that is void of the aforementioned limitation.
> The downside is it is rather verbose.
>
> *Question*
> This there a way to do an upsert proper prior to PG15?
>
> *Feature Request*
> Given that UPSERT is an *idempotent* operator it is extremely useful.
> Would love to see an UPSERT command in PostgreSQL so one can 'upsert' 
> properly and easily.
>
>
> Regards,
> Louis Tian
>
>
>
>
>
>
>
>
>

--
Adrian Klaver
adrian.kla...@aklaver.com

--
Message  protected by MailGuard: e-mail anti-virus, anti-spam and content 
filtering.https://www.mailguard.com.au/mg
Click here to report this message as spam:
https://console.mailguard.com.au/ras/259w94L3yw/5Vb4QHWbRwfP3KeOMAvzU8/-2.1



Re: [EXTERNAL]: Re: UPSERT in Postgres

2023-04-08 Thread Louis Tian
Hi Peter,

Thanks for your reply. Appreciate the help and discussion.

> In general UPSERT (or any definition of it that I can think of) does
> not imply idempotency.

"Idempotence is the property of certain operations in mathematics and computer 
science whereby they can be applied multiple times without changing the result 
beyond the initial application." from Wikipedia.
the concept of Idempotence when applies to HTTP is consistent with the above. 
https://developer.mozilla.org/en-US/docs/Glossary/Idempotent. Or are you going 
by a different defintion that I am not aware of?
If you execute the same upsert multiple times, the state of the database 
remains the same as if only execute once. 
If a row already exists, the first statement will update the row so does any 
subsequent statements. executing the same update multiple time is the same as 
executing it only once.
If the row doesn't exist, the first statement will insert that row and any 
subsequent will try to update, but the update has no real effect since it the 
value is exactly the same as the insert. 
So by defintion, upsert is idempotent.

> It could just be a unique index or a unique constraint. So you can
> upsert on any individual unique constraint/index, or the primary key.
> Of course there might be several on a given table, but you can only
> use one as the "conflict arbiter" per statement.

Understand that I can use any unique constraint with on conflict. 
But semantically the only correct one is the primary key, since that's what 
identifies a row logically.
In that sense, any unique column(s) is a potential candidate for primary key.
It's more of a pedantic point rather than pragmatic one.
It's less of a problem for PostgreSQL where the semantic importance of primary 
key is not manifested at implementation level, since all index points to the 
tuple directly
Whereas it is more import for Databaes like MySQL where the secondary index 
points to the primary key index. 

> It sort of has to work that way, though. In general your example might
> *not* fail, due to a row-level before trigger in the insert path.

Do you mean having the trigger to check whether new."name" is set if not use 
the old."name" as fallback ?

> Why doesn't your proposed upsert syntax have the same problem? I mean,
> how could it not? I guess it doesn't if you assume that it'll never
> take the insert path with your not NULL constraint example?

Use some pesudo code might be helpful here to explain the difference. 

How on conflict works at the moment.

try {
 insert row
} catch (duplicated key error) {
  update row
}

How I think it upsert should work

if (new.id exists) {
 update row 
} else {
 insert row
}

I would argue that later is a correct form of upsert given it's definition. 
The two are not equivalent when there is not null constraint on any non primary 
key column.

> But if you know that for sure, why not just use a regular update statement? 
Yes, in general it is not know whether the insert or update path should be 
taken. 

> On the other hand, if you're not sure if the insert path can be taken,
> then why is it actually helpful to not just throw an error at the
> earliest opportunity?
I am not expecting an error here. The problem is with no conflict it always go 
down the insert path first and results in a not null constraint error.
While I am expecting the insert is never executed in the first place when that 
row already exist (as identified by it primary key). So the update execute 
without error.
I hope the pesudo code above is enough to clarify the difference? 

> The MERGE command has various race conditions that are particularly
> relevant to UPSERT type use cases. See the wiki page you referenced
> for a huge amount of information on this.
Thanks for the pointer. Reading into it.

Cheers,
Louis Tian


From: Peter Geoghegan 
Sent: Friday, April 7, 2023 6:58 AM
To: Louis Tian 
Cc: pgsql-general@lists.postgresql.org 
Subject: [EXTERNAL]: Re: UPSERT in Postgres 
 
CAUTION: This email originated from outside of Envirada. Do not click links or 
open attachments unless you recognize the sender and know the content is safe.


On Thu, Apr 6, 2023 at 1:21 PM Louis Tian  wrote:
> An implicit assumption behind this definition is that table must have a 
> primary key for the upsert operation to make sense since it's the primary key 
> that uniquely identifies a row.

It could just be a unique index or a unique constraint. So you can
upsert on any individual unique constraint/index, or the primary key.
Of course there might be several on a given table, but you can only
use one as the "conflict arbiter" per statement.

> But can we achieve the same effect with "INSERT ... ON CONFLICT DO UPDATE" 
> like a lot of references on the internet seems to suggest.
>
> insert in

Re: [EXTERNAL]: Re: [EXTERNAL]: Re: UPSERT in Postgres

2023-04-09 Thread Louis Tian



From: Israel Brewster 
Sent: Sunday, April 9, 2023 3:09 AM
To: Louis Tian 
Cc: Peter Geoghegan ; pgsql-general@lists.postgresql.org 

Subject: [EXTERNAL]: Re: [EXTERNAL]: Re: UPSERT in Postgres

Thanks Israel. Your example really helped me to understand where we differ.

> Not necessarily. Consider the following UPSERT statement:
> INSERT INTO customer_order_counts (customer_id,order_count) VALUES (123456, 
> 1) ON CONFLICT (customer_id) DO UPDATE SET 
> order_count=customer_order_counts.order_count+1;

Yes, you are 100% right that is not idempotent statement. But that's not 
because UPSERT is idempotent ​*operation*. I am making a distinction between an 
operation and statement here.
This statement is not idempotent is not because UPSERT operation is not 
idempotent, it is because the value being upsert is different in the statement 
each time you run that statement.

> Not really. Generally when I am doing an UPSERT, I am NOT using the primary 
> key, but rather some other UNIQUE-ly indexed column(s). My primary key is 
> typically an ID column that is defined as a serial, > and automatically 
> generated by the database. The unique column I use for the upset, however, is 
> generally something that would identify the row to a human - such as Station 
> ID and timestamp
> columns in a database I have of seismic readings. Each reading gets a unique 
> ID (the primary key) that identifies it to the database and is used in joins. 
> However, occasionally a reading gets updated, so I > update the row, based 
> not on the primary key (which I don’t know for incoming data), but on the 
> station and timestamp. UPSERT, but not based on the primary key.

I am using "primary key" to refer to the "row identifier" in a conceptual way.
Definition from Wiki, "In the relational 
model<https://en.wikipedia.org/wiki/Relational_model> of 
databases<https://en.wikipedia.org/wiki/Database>, a primary key is a specific 
choice of a minimal set of attributes 
(columns<https://en.wikipedia.org/wiki/Column_(database)>) that uniquely 
specify a tuple (row<https://en.wikipedia.org/wiki/Row_(database)>) in a 
relation<https://en.wikipedia.org/wiki/Relation_(database)> 
(table<https://en.wikipedia.org/wiki/Table_(database)>)."
So, it's not necessarily the primary key you declared on the table (for 
example, the id column in your example).
To put it in another way, the Station ID and timestamp columns work in the 
capability of a primary key.
I was merely setting a scene in my orginal email. What I was trying to say is 
"UPSERT only makes sense when each row is uniquely identifiable".
So please don't get me wrong there, I am not arguing that being able to do on 
conflict on any unique index is wrong or bad.

Cheers,
Louis Tian

> On Apr 6, 2023, at 4:49 PM, Louis Tian  wrote:
>
> Hi Peter,
>
> Thanks for your reply. Appreciate the help and discussion.
>
>>  In general UPSERT (or any definition of it that I can think of) does
>> not imply idempotency.
>
> "Idempotence is the property of certain operations in mathematics and 
> computer science whereby they can be applied multiple times without changing 
> the result beyond the initial application." from Wikipedia.
> the concept of Idempotence when applies to HTTP is consistent with the above. 
> https://developer.mozilla.org/en-US/docs/Glossary/Idempotent. Or are you 
> going by a different defintion that I am not aware of?
> If you execute the same upsert multiple times, the state of the database 
> remains the same as if only execute once.

Not necessarily. Consider the following UPSERT statement:

INSERT INTO customer_order_counts (customer_id,order_count) VALUES (123456, 1) 
ON CONFLICT (customer_id) DO UPDATE SET 
order_count=customer_order_counts.order_count+1;

That is completely valid (I tested it), and actually makes sense as something 
you might want to do - keep track of how many orders a customer has placed, for 
example if you only keep the order records for 6 months, but still want to know 
the total number of orders the customer has placed. If it is a new customer, 
you insert a record for the customer with an order count of 1. Otherwise, you 
update the record to increment the order count. Clearly this is NOT an 
idempotent operation - every time you run it, it changes the order count, so 
the state of the database does NOT remain the same as if you only execute it 
once.

> If a row already exists, the first statement will update the row so does any 
> subsequent statements. executing the same update multiple time is the same as 
> executing it only once.
> If the row doesn't exist, the first statement will insert that row and any 
> subsequent will try to update, but the update has no real effect since it

Re: [EXTERNAL]: Re: [EXTERNAL]: Re: UPSERT in Postgres

2023-04-09 Thread Louis Tian
Hi Adrian, 

> No it is not as Israel Brewster pointed out.
I think we need make a distinction between an operation and a statement here
The examples Israel presented and yours are both non-idempotent statements 
because the different value being upserted each time the statement is executed. 
Not because upsert as an operation is not idempotent. 
Likewise, In HTTP, PUT method is defined as idempotent. No one would expect 
different PUT requests with different payload to be idempotent. 

Also, I don't think I am not the only one who think upsert is logically 
idempotent. Just a few seconds of searching on google.
- "The upsert action is a combination of insert and update. It allows us to 
write idempotent statements". 
(https://jonmeyers.io/blog/use-on-conflict-to-upsert-in-postgresql. )
-"One common example of an idempotent operation is an upsert (update or insert) 
statement in a database." 
(https://www.arecadata.com/core-data-engineering-concepts-idempotency)
- "A POST request means that the request is not idempotent, but an "upsert" 
request is idempotent." 
(https://softwareengineering.stackexchange.com/questions/426225/rest-how-to-upsert-a-resource-without-an-specific-resource-url#:~:text=A%20POST%20request%20means%20that,%22upsert%22%20request%20is%20idempotent.)
While no as direct as the article above, but the issue reported in those places 
are essentially stem from the same understanding. 
- 
https://stackoverflow.com/questions/48816629/on-conflict-do-nothing-in-postgres-with-a-not-null-constraint
- 
https://www.postgresql.org/message-id/flat/1996438.1604952901%40sss.pgh.pa.us#ace8adc1354265aca5672028faea0c0f
So at least I am not only one imaging things?
- "a ready made statement for idempotent data like Mongo's upsert" 
(https://www.compose.com/articles/the-potency-of-idempotent-with-rabbitmq-and-mongodb-upsert/)

> And therein lies your problem, you are imagining something that does not
> exist and more to the point will most likely not exist as it would break all 
> code that depends on above behavior.
I never argue the way postgresql does for insert ... on conflict is wrong and 
need to change. 
I said "I think it is doing what it reads quite literally" just like in your 
words "It does what is advertised on the tin". So there is no disagreement 
here. So I am not saying "insert on conflict" need to change. 
What I am point out here is, the "insert...on conflict do update" is not a true 
"upsert". 
I am saying in my opinion it would be nice see UPSERT statement to be added to 
PostgreSQL so upsert can work "out of box" even when there're not null 
constraints on that table.

It might never happen judging from the replies I am getting but that's fine. 
The solution you have showed me is good enough as a workaround (to not 
depreciate it's value, just not as easy/bullet proof as it could be in my 
opinion). 
It was just a question just to confirm my understanding so I got what I need, 
so thank you all for that. 


Cheers,
Louis Tian


From: Adrian Klaver 
Sent: Sunday, April 9, 2023 7:51 AM
To: Louis Tian ; Peter Geoghegan 
Cc: pgsql-general@lists.postgresql.org 
Subject: [EXTERNAL]: Re: [EXTERNAL]: Re: UPSERT in Postgres 
 
CAUTION: This email originated from outside of Envirada. Do not click links or 
open attachments unless you recognize the sender and know the content is safe.


On 4/6/23 17:49, Louis Tian wrote:
> Hi Peter,
>
> Thanks for your reply. Appreciate the help and discussion.
>
>>   In general UPSERT (or any definition of it that I can think of) does
>> not imply idempotency.
>
> "Idempotence is the property of certain operations in mathematics and 
> computer science whereby they can be applied multiple times without changing 
> the result beyond the initial application." from Wikipedia.
> the concept of Idempotence when applies to HTTP is consistent with the above. 
> https://developer.mozilla.org/en-US/docs/Glossary/Idempotent. Or are you 
> going by a different defintion that I am not aware of?
> If you execute the same upsert multiple times, the state of the database 
> remains the same as if only execute once.
> If a row already exists, the first statement will update the row so does any 
> subsequent statements. executing the same update multiple time is the same as 
> executing it only once.
> If the row doesn't exist, the first statement will insert that row and any 
> subsequent will try to update, but the update has no real effect since it the 
> value is exactly the same as the insert.
> So by defintion, upsert is idempotent.

No it is not as Israel Brewster pointed out.

To his example I would add:

alter some_table add column ts_upsert_update timestamptz;

insert into some_table values('foo', 'bar') on conflict(

RE: [EXTERNAL]: Re: [EXTERNAL]: Re: UPSERT in Postgres

2023-04-09 Thread Louis Tian
Hi Francisco, 

I think we need to make a distinction between an "operation" and a "statement".
The concept of idempotency applies to an "operation" not an entire statement. 
Like how HTTP "PUT" method is defined as "idempotent", you don't say actual 
HTTP PUT request is idempotent. 
With the "current_datetime" and "access_count+1", you are effectively changing 
the value passing to the UPSERT operator. 
Just like how you changed the payload of a PUT, then obviously there is no 
reason to expect the state of the database to remain the same. 

Cheers,
Louis Tian


-Original Message-----
From: Francisco Olarte  
Sent: Sunday, April 9, 2023 7:32 PM
To: Louis Tian 
Cc: Peter Geoghegan ; pgsql-general@lists.postgresql.org
Subject: [EXTERNAL]: Re: [EXTERNAL]: Re: UPSERT in Postgres

CAUTION: This email originated from outside of Envirada. Do not click links or 
open attachments unless you recognize the sender and know the content is safe.


(not the OP on idempotency)

On Sat, 8 Apr 2023 at 18:33, Louis Tian  wrote:
> > In general UPSERT (or any definition of it that I can think of) does 
> > not imply idempotency.
> "Idempotence is the property of certain operations in mathematics and 
> computer science whereby they can be applied multiple times without changing 
> the result beyond the initial application." from Wikipedia.
> the concept of Idempotence when applies to HTTP is consistent with the above. 
> https://developer.mozilla.org/en-US/docs/Glossary/Idempotent. Or are you 
> going by a different defintion that I am not aware of?
> If you execute the same upsert multiple times, the state of the database 
> remains the same as if only execute once.
> If a row already exists, the first statement will update the row so does any 
> subsequent statements. executing the same update multiple time is the same as 
> executing it only once.
> If the row doesn't exist, the first statement will insert that row and any 
> subsequent will try to update, but the update has no real effect since it the 
> value is exactly the same as the insert.
> So by defintion, upsert is idempotent.

Only on a narrow definition of upsert.

You are thinking on a narrow ( but very frequent ) use of "upsert"
statements, something like:

insert on users(id,name) values (1,'x') on conflict(id) update set name='x'

But upsert can be used for things like:

   insert into last_access(id,cuando) values (1,current_timestamp) on
conflict(id) set cuando=current_timestamp

   insert into access_count(id, access_count) values (1,1) on
conflict(id) set access_count=access_count+1

Which are not idempotent ( and also frequent, I use both variants )

Francisco Olarte.
--
Message  protected by MailGuard: e-mail anti-virus, anti-spam and content 
filtering.https://www.mailguard.com.au/mg
Click here to report this message as spam:
https://console.mailguard.com.au/ras/25ayvBFOMd/7rJjrYVDtTx03A1wSEIfeL/0.1



RE: [EXTERNAL]: Re: [EXTERNAL]: Re: UPSERT in Postgres

2023-04-09 Thread Louis Tian
Hi Alban, 

"I am not expecting an error here", by "here" I means when doing a TRUE UPSERT 
(an upsert current does not exist in Postgres). 
I am NOT referring to an "Insert on conflict do update" (which despite its 
intention and wide acceptance is not fully equivalent to a true upsert).
I understand the error I am getting now is due to not null constraint given how 
"insert on conflict" works. 

An UPSERT checks whether a row exists, if so, it does an update, if not it does 
an insert. This is the literal definition.
An UPSERT is NOT defined as try do an INSERT first, if violate uniqueness 
constraint, do update. This is what on conflict do update is doing. 
We cannot define UPSERT with what "ON CONFLICT DO UPDATE" is doing. That is a 
logical fallacy.
 UPSERT is a higher-level abstract concept. ON CONFLICT DO UPDATE is an 
implementation of UPSERT. not the other way around.

When doing a true UPSERT, if a row already exists, there is no need provide an 
(not null) column, since I am doing an update. 

With `UPSERT person (id, is_active)` VALUES (0, true). Is it necessary to 
provide the not null "name" column here logically? 
Not really, I already specified the row with the `id` column, then I specify 
the column I want to update `is_active`. 
* the id does exist; the update can be executed without any issue or assumptions
* the id does not exit; then I am expecting a violate not null constraint. 

On contrast, with `INSERT person (id, is_active) value (0, true) ON CONFLICT DO 
UPDATE set is_active=true`,
this statement will always fail regardless of whether the id exists or not. 
So the behavior of ON CONFLICT DO UPDATE differs from a UPSERT with the 
presence of a not null column. 
Hence why ON CONFLICT DO UPDATE is not complete equivalent to a TRUE upsert.

Cheers,
Louis Tian


-Original Message-
From: Alban Hertroys  
Sent: Sunday, April 9, 2023 7:26 PM
To: Louis Tian 
Cc: Peter Geoghegan ; pgsql-general@lists.postgresql.org
Subject: [EXTERNAL]: Re: [EXTERNAL]: Re: UPSERT in Postgres

CAUTION: This email originated from outside of Envirada. Do not click links or 
open attachments unless you recognize the sender and know the content is safe.


> On 7 Apr 2023, at 2:49, Louis Tian  wrote:

(…)

> I am not expecting an error here. The problem is with no conflict it always 
> go down the insert path first and results in a not null constraint error.
> While I am expecting the insert is never executed in the first place when 
> that row already exist (as identified by it primary key). So the update 
> execute without error.
> I hope the pesudo code above is enough to clarify the difference?

Your assumption on what the problem is, is not correct. The problem is not with 
the conflict resolution, it is with your statement violating a not null 
constraint.

It doesn’t matter whether you insert first or update first, either operation is 
going to violate that constraint. You’re specifying a NULL value for a column 
that doesn’t accept that because it has a NOT NULL constraint. That is your 
problem.

Alban Hertroys
--
There is always an exception to always.




--
Message  protected by MailGuard: e-mail anti-virus, anti-spam and content 
filtering.https://www.mailguard.com.au/mg
Click here to report this message as spam:
https://console.mailguard.com.au/ras/25ayougcIv/4FIia1zrtWT2nnuHlesEOS/1.8