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 1tmTKN-006vty-GD for pgsql-general@arkaria.postgresql.org; Mon, 24 Feb 2025 07:56:36 +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 1tmTKL-00GmdY-4d for pgsql-general@arkaria.postgresql.org; Mon, 24 Feb 2025 07:56:33 +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 1tmTKK-00GmdP-Lz for pgsql-general@lists.postgresql.org; Mon, 24 Feb 2025 07:56:32 +0000 Received: from mail-il1-x144.google.com ([2607:f8b0:4864:20::144]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1tmTKH-000UgL-2Z for pgsql-general@lists.postgresql.org; Mon, 24 Feb 2025 07:56:32 +0000 Received: by mail-il1-x144.google.com with SMTP id e9e14a558f8ab-3d0465a8d34so36876885ab.0 for ; Sun, 23 Feb 2025 23:56:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1740383788; x=1740988588; darn=lists.postgresql.org; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=tYEs6z4fKOfxMFht04Mq111Wcbr+Kaa8u3Lw+EgTIPg=; b=UfelJ1/4LhHfM2gz3CqlF2VPiX8cK4WVE/6kpKUziuJTNYOfewKW+2RFXjuylWAy6I sanllnGc0w5A8RIoopMJ7OO9poYwTUVcX0L4FMeElfNKf4S9I9ci9xAao5Bj3bCbcxOZ gTC9An4CzEI9I/BgSgIq3Vy7JcObXW631nPmrlAN+xHNlcT4llMwC2YoDsYvbwgGZ0bv LFKvsjB4w2lLTQy9z3b+YlL9UDU2cnsr4QOr4BxPWtDK5CZxZztWDTeFQXlYVnywAzJQ f+2JTg+8xvix7vA1Rali5X7+GVcbkBpPpCrsrEJd1ySHo6gjrda7jiVHRfbWn2K+AFJd mhNg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1740383788; x=1740988588; h=to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=tYEs6z4fKOfxMFht04Mq111Wcbr+Kaa8u3Lw+EgTIPg=; b=pg+lusYh1RRLZPkHVrYTO0Y4/I2hPvZwMu64r1k7Sd5xiPuAUIyjBINMFF7qiLnUtN MKZ0zrZ0dWhx9/iLaZLAYsvSDeqM6xj+0fXLDhrQwsA+K7yW2xcGFWNo4HP6yW6q5bX/ EqsGZPsMVcDwqELmbAEmmr5eB0u/TgeN8CuxohZZgsoRaALIEOzoQGJ9OX63P72enzTY U49/lzx4/2kn+Jj9KeAMSghuJGp549KTQmrArY91e4eiYEejva9k6UPDeESyYqweaI+w nUDaPdfulGUI0i+dknB4SLuYEDo6Al8mZoZVlOwX5CL6QowSMBOWCW1lBFNAmot64NL2 BKow== X-Gm-Message-State: AOJu0YyqKQ9eR3U+J4DdqUKMXugC5EB1Uioo84yIPNZ4jn5+xL1rs7xR RdqaJVpAXT0xNMZ7C9YLNyKb1Z3PMGjBo98OYgMckiuBaSMfeNdArOEqWKzUwiUDZGdesLV13VL 9dphKVHkMq+AOFLl4BP7N888Ye9rpSdT/MPc= X-Gm-Gg: ASbGncsZKPijLwV4fU+KFfbVZmT14e99Ol71IlhxgDyv3yqadQ1OteOiWfVLARiPB5d q5pWIJxd5iSsnrwRTnwHQnyUWixZBh7I88IyVy21PTIuGecTRERh3gB2ix5lZkdtoG5S2Y2NHkc mFjEClembL X-Google-Smtp-Source: AGHT+IGC8yx5sC0qS1PYSjuPk469DsakJ6kvCRYOEVFdFcFP8kpr+eVWTSFHvyihc3r+kef9QSgftb7nFFk+YNB0QHk= X-Received: by 2002:a05:6e02:b49:b0:3ce:8ed9:ca94 with SMTP id e9e14a558f8ab-3d2caf01b16mr110960575ab.14.1740383787744; Sun, 23 Feb 2025 23:56:27 -0800 (PST) MIME-Version: 1.0 From: Marcelo Fernandes Date: Mon, 24 Feb 2025 20:56:16 +1300 X-Gm-Features: AWEUYZkQfdNgrIcKAZeZ4-R0cYZSNd18e8CU3NJKjB7HdI6YPYT4XA3c2fsjeEo Message-ID: Subject: Default Value Retention After Dropping Default To: pgsql-general@lists.postgresql.org Content-Type: text/plain; charset="UTF-8" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Hi folks, I am experiencing an interesting behavior in PostgreSQL and would like to seek some clarification. In the following snippet, I first add a column with a default value, then drop that default. However, when I query the table, the column still retains the dropped default for existing rows: SET client_min_messages=debug1; DROP TABLE IF EXISTS foo CASCADE; CREATE TABLE foo (id SERIAL PRIMARY KEY); INSERT INTO foo (id) SELECT generate_series(1, 10000); ALTER TABLE foo ADD COLUMN bar varchar(255) NOT NULL DEFAULT 'default'; ALTER TABLE foo ALTER COLUMN bar DROP DEFAULT; SELECT * from foo order by id desc limit 5; -- id | bar -- -------+--------- -- 10000 | default -- 9999 | default -- 9998 | default -- 9997 | default -- 9996 | default In this example, even after dropping the default value from the bar column, the rows that were previously inserted (prior to dropping the default) still show 'default' as their value in the bar column. It does not see that the table has been rewritten or rescanned, otherwise the debug1 messages would be triggered. Can anyone explain how PostgreSQL "knows about" the default value that has just been dropped and what is happened under the scenes? I am keen on a deep understanding on how Postgres achieves this. Here is what I could find in the docs, but it does not satisfy my question: > From PostgreSQL 11, adding a column with a constant default value no longer > means that each row of the table needs to be updated when the ALTER TABLE > statement is executed. Instead, the default value will be returned the next > time the row is accessed, and applied when the table is rewritten, making the > ALTER TABLE very fast even on large tables. https://www.postgresql.org/docs/current/ddl-alter.html#DDL-ALTER-ADDING-A-COLUMN