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.96) (envelope-from ) id 1wCWBL-0023wV-0B for pgsql-hackers@arkaria.postgresql.org; Tue, 14 Apr 2026 05:19:27 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wCWBJ-009tj3-0z for pgsql-hackers@arkaria.postgresql.org; Tue, 14 Apr 2026 05:19:26 +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.96) (envelope-from ) id 1wCWBI-009tiv-2t for pgsql-hackers@lists.postgresql.org; Tue, 14 Apr 2026 05:19:25 +0000 Received: from mail-wr1-x430.google.com ([2a00:1450:4864:20::430]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wCWBH-00000000y8m-2E5L for pgsql-hackers@lists.postgresql.org; Tue, 14 Apr 2026 05:19:25 +0000 Received: by mail-wr1-x430.google.com with SMTP id ffacd0b85a97d-43d77f6092eso1244771f8f.2 for ; Mon, 13 Apr 2026 22:19:23 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1776143961; cv=none; d=google.com; s=arc-20240605; b=kB/FzPmE3ZpGJFWgJoJkN+TelS0gPrde9HYJkCpvyDWOoK8yDq52UubgCHmKXGRryP q5odl2Fe96KR25O5bm3sj0pl11ncKvS9Rc19qClyIrY4VFNhujw4CZUwR3geOwEkGgZP aYNT/lUzYxHmoc+vYOtYmotZC7obJ0qGne2mK9v5WJSe33Jne2HdxhRk56+CJG0u4lfo qAaMf4KqHeR+mDPEk9k13q2DV+TZn9Q5TKZuHavZ0g91Y9d7nJzoXAi/khfnkhgES8eM SQUqPD/n+toC/6t0Cajk8zRwyxKFIH55HFBmEiL80igqSseQr2kveBDlOAKkFPXcc9w+ /yjw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:dkim-signature; bh=EyMC0gCcJLsHFIwK38LJwjB2C8zpt4D5zVYMib+FP5U=; fh=PKVT6GwFJYPfOT9vi2CeMd2kmjAm7pCXEWy7wLfDMkc=; b=Ugy/FAJBYEFqExE+wtGbzb5QKqw6XE/bHgv5NG1q2OiWrhXjsLuM2a09Tila6JigW1 VNttZfS38UXMrTju2Q4+BvC2D9yYJr5Ph34roTF3wPk4oYXcEA5pvCzP9nGC+2gjkioi EkCfWlvUsf2/D0Mgr/OOBu+0oITSRpY6hO4O8byFUC1stkySMZXrMoWSZY5nF0OP4t6f 5QCwaualdc69y1AHmYdxqC4eTFpgzK0RPxcId46NabthjzvWVPYc8SMhwVO9tHjJHlEs lqkXhvMcHlzDZHOIV3WhdeukOMGup6A1vc9BPy0OLbsdcZ6EgLbcdHfrJZXcFB3vIqOn rOjw==; darn=lists.postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1776143961; x=1776748761; darn=lists.postgresql.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=EyMC0gCcJLsHFIwK38LJwjB2C8zpt4D5zVYMib+FP5U=; b=TLxwCbSSKKj+/OGCq2B1A2J/xzttdtlc3Li4KnBHPNCh2scuCHrS5ENAAwoFYFvG2q lI0oJq36Rh6eO8cYB1osLzG1J9y64ZzEKNSRoFYHKx+l87239oef95oA+Z3LfzvJ/E6y ZYwVX31NhBfNQI3xCMH9weQN5NfoMAqBFr5IuJ3/8RMZmp8lq4P03A1ETxLKQTQVylRF YdS7tPReGx1dhQjOpLgSt/TBoZ4UAfZefNNepCzwRSFsCId6LzMpzZUdRRSJA4Iq2uQL dGGMGdZyEFSqR0rxjY6KuGb94S4l87+QfW3WeHuPHLF1q0tnkL8IU2e2bi0KWyVpvBxq JbNA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776143961; x=1776748761; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=EyMC0gCcJLsHFIwK38LJwjB2C8zpt4D5zVYMib+FP5U=; b=BF1d7lJmu4pUPLnW9VULrgiS62mfQBLRVDlGaRhUmnXWoAkdS4gkLKUnQ5fSG2YX4y EJ7jusUOcZrpcaDf9xpINgZ1HqrP2ydvmo0PMliCEoTaGQGZbZCwh6HXs2cDQHYcoqjs gtinzxcMNbcYQPdRqXloaQpAXjD1vj2cyuQNm+6w7ZUaPaU0yumxJlVzqQPaaaCR/EQz nTrJvgrM+BvYjN/vsur4EVqenH7oenshRU+5sKDC/vyKADEBC8xp4krYQNCGOGhhCdcS hO4DXCo9S8ZqxdltU/bIQJzhDPnFnSO9m9WjMlVheXDlLhVx7tMusZQiVUlijwJctiq+ pPJQ== X-Gm-Message-State: AOJu0Yw4EDk2DI8v+dDTRSqBnAjZhe2+19tLUHViWh3TUKTxQwkQEYfm V0CYjO/rsVm8cNuBXIsXYxT8RLjZ5Vyt1lxFk9ehKEHpQezSI4Hvj2Bn8irqwZmHqqjnao8Mk4W mKh6QmIkx7COLRR9sseo44r60f2fIHMROEVyL X-Gm-Gg: AeBDiet7wtDS/Oi6U+Td0DTj+FM7jM0Nj+RvvL3719OK7J2DWdASWKxw+ThlhjRSBfA BqHB9101EH7ciQSNhcW4jexkpxktitAjZDh6dauGABnAWs21ViqIFdBgabIuRcIz0k6igmZXibC MXqwFalb+A6EZ/JFrxveZ8jgUmvXAVgJ4Vohyb8yEXmO9jhVe3qYsFOIw8fpfqMca5+2fPlOFEj jSPMBtxjfkqqreoJus+NkaDPLLWVMnEpoeUlGN6ssnwJ5A6xN4zJm0ZtrUachEIxqTtNfBAqfmz dQRrO8gXhJwryow8rlHZZFjZwPH3JORru2WTHgsrdHlBY/JN5LN66di2ijkSYOvq2U/8+v0rrg= = X-Received: by 2002:a05:6000:40dd:b0:43d:7e5b:928c with SMTP id ffacd0b85a97d-43d7e5b9a32mr3973315f8f.47.1776143960904; Mon, 13 Apr 2026 22:19:20 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: From: David Rowley Date: Tue, 14 Apr 2026 17:19:08 +1200 X-Gm-Features: AQROBzDFqmb-OVXX6e2WPb_TN07QIPmj-gcNfvomcbik7lGSy4cBGDnwRJ4v3xk Message-ID: Subject: Re: POC: Comparison of partitioning key values To: John Mikk Cc: pgsql-hackers@lists.postgresql.org Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On Tue, 14 Apr 2026 at 09:11, John Mikk wrote: > ```sql > drop table if exists grid2 cascade; > > create table grid2(x bigint, y bigint) partition by range (x,y); > > create table g2_part1 partition of grid2 for values from (1,3) to (7,11); > create table g2_part2 partition of grid2 for values from (7,11) to (13,15= ); > create table g2_part3 partition of grid2 for values from (13,15) to (15,1= 7); > create table g2_part4 partition of grid2 for values from (15,17) to (19,2= 1); > -- > create table g2_part5 partition of grid2 for values from (5,15) to (13,17= ); > -- [42P17] ERROR: partition "g2_part5" would overlap partition "g2_part1" > ``` > > Why is that? Because (5,15) is between (1,3) (inclusive) and (7,11) (non-inclusive) > According to the documentation, the row comparison rule for tables applie= s (subsection 9.25.5). > However, in the case of row comparison, it is possible to override compar= ison operators, which is not the case when defining partitions. > There is no way to override the comparison operator for partition ranges.= And is this general approach always correct in the case of partitioning? You're free to create your own type and own btree opfamily, but I don't see how you're going to tell it that (5,15) isn't above or equal to (1,3), and separately, isn't below (7,11). This all works with the notion of sorting on a single dimention, where "y" is the tiebreaker for equal "x" values. There's just no way to map that into 2-dimentional space with table partitioning. Note the part of the documentation in [1]: "For example, given PARTITION BY RANGE (x,y), a partition bound FROM (1, 2) TO (3, 4) allows x=3D1 with any y>=3D2, x=3D2 with any non-null y, and x=3D3 with any y<4." > Let us provide a generalized reasoning: > > Suppose we have a range-partitioned table with a partitioning key consist= ing of n attributes. > Let us consider the from and to values of the partitioning key from the f= or values clause as points on the main diagonal of an n-dimensional paralle= lepiped of permissible key values for a specific partition. > Of course, our set is finite, but this perspective on the partitioning ke= y allows us to use a fact from multidimensional geometry: > > Let the first parallelepiped be defined by the main diagonal points > A =3D (a_1, a_2, ..., a_n) and A' =3D (a_1', a_2', ..., a_n'), where a_i = < a_i' for all i, > and the second parallelepiped be defined by the main diagonal points > B =3D (b_1, b_2, ..., b_n) and B' =3D (b_1', b_2', ..., b_n'), where b_i = < b_i' for all i. > > In this case, the following theorem (statement) holds true: So I think you must be thinking that another RANGE column adds another dimention. That's not the case. It's still 1 dimention, you just have more tiebreaker columns in the notion sorting by the partition bound. > Two parallelepipeds do not intersect if and only if there exists at least= one coordinate k (from 1 to n) for which the projection intervals on this = axis do not intersect; that is, the intersection of [a_k, a_k'] and [b_k, b= _k'] is an empty set, or equivalently, the condition (a_k' < b_k) OR (b_k' = < a_k) holds for one of the k values. > > In other words, this fact establishes: first, when two figures do not int= ersect and are separated by a hyperplane x_k =3D const; and second, the nec= essary and sufficient condition for the figures to intersect, given that al= l projections intersect. The latter remains valid for a parallelepiped redu= ced to a point and can determine whether a new key belongs to a particular = partition. > > The experimental patch I am proposing (v1-0001-partition-by-range.patch) = introduces changes to the source code based on the described approach, so t= hat the partition from the example can be created. > > Moreover, the algorithm for determining the partition of a new key during= an insert operation is even more mysterious in the current implementation;= my patch corrects this. It uses a binary search to determine if the partition key columns in the inserted tuple falls within a partition's bound. It's not clear to me what exactly isn't correct about that. > In the proposed patch, writing to output directly via fprintf is hardcode= d. This allows obtaining a plain text list of existing and added ranges aft= er each operation for the illustrative Python script. > > A segmentation fault will occur during update and delete operations. > > Or would adding an override for the range comparison operator be a more f= lexible and correct approach? > > I would like to hear your opinion, dear hackers! You can't change how RANGE partitioning works and not break things for everyone using RANGE partitioning when they upgrade. If your patch is proposing that, then it's going to fail. If you're proposing a new partitioning method, then that's different. It's still a hefty amount of work. If you're proposing that then do a detailed proposal here before doing too much work. Remember that with declarative partitioning, there can be only (at most) a single partition for any given tuple. The tuple routing done during INSERT and UPDATE requires that. Finding the correct partition must also be fast as INSERT/UPDATE performance needs to run that code for every affected tuple. David [1] https://www.postgresql.org/docs/current/sql-createtable.html