<!--
Les sources pour ce sujet sont :

* https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=1adf16b8fba45f77056d91573cd7138ed9da4ebf
* https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=87c21bb9412c8ba2727dec5ebcd74d44c2232d11

REVERT pour raison de sécurité :
  https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=84f594da358861cceeaeb7a97bb58f3765eeb284

Discussion :

* https://postgr.es/m/c73a1746-0cd0-6bdd-6b23-3ae0b7c0c582%40postgrespro.ru

Voir aussi :

https://www.depesz.com/2024/05/22/waiting-for-postgresql-17-merge-split-partitions/
-->


<!-- A GARDER POUR PG 18 ?

<div class="slide-content">

  * Nouvelles commandes `DDL` :
    + `ALTER TABLE ... MERGE PARTITIONS ...` fusionne plusieurs partitions en
      une
    + `ALTER TABLE ... SPLIT PARTITION ...` divise une partition en plusieurs
      partitions 
  * `ACCESS EXCLUSIVE LOCK` posé sur la table parent pendant l'opération
  * Opérations pas encore parallélisées

</div>

<div class="notes">

Deux nouvelles commandes permettent de manipuler les partitions plus finement.
La commande `ALTER TABLE ... MERGE PARTITIONS ...` permet de fusionner plusieurs
partitions tandis que la commande `ALTER TABLE ... SPLIT PARTITION` permet d'en
diviser une. Lorsque ces commandes sont exécutées, elles posent un verrou
exclusif (`ACCESS EXCLUSIVE LOCK`) sur la table parent. Faites attention si vous
utilisez cela sur une table volumineuse comme le verrou pourrait être posé
longuement sur la table parent.

Voyons cela avec un exemple d'une table partitionnée par intervalles.

```sql
postgres=# create table t1 (i int, t text) partition by range (i);
CREATE TABLE
```

Cette table est découpée en quatre partitions ...

```sql
postgres=# create table t1_250 partition of t1 for values from (1) to (250);
CREATE TABLE
postgres=# create table t1_500 partition of t1 for values from (250) to (500);
CREATE TABLE
postgres=# create table t1_750 partition of t1 for values from (500) to (750);
CREATE TABLE
postgres=# create table t1_1000 partition of t1 for values from (750) to (1000);
CREATE TABLE
```

... et est initialisée avec des valeurs générées :

```sql
postgres=# insert into t1 select generate_series(1,999) as value, 'text';
INSERT 0 999
```

On peut par exemple fusionner les deux premières partitions avec la commande
suivante :

```sql
postgres=# ALTER TABLE t1 MERGE PARTITIONS ( t1_250, t1_500 ) INTO t1_0_500;
ALTER TABLE
```

Et diviser cette nouvelle partition en plusieurs partitions selon une autre
répartition des données : 

```sql
postgres=# ALTER TABLE t1 SPLIT PARTITION t1_0_500 INTO ( PARTITION t1_0_150 FOR VALUES FROM (1) TO (150), PARTITION t1_150_300 FOR VALUES FROM (150) TO (300), PARTITION t1_300_500 FOR VALUES FROM (300) TO (500) );
ALTER TABLE
```

La table initiale `t1` a désormais cinq partitions.

```sql
postgres=# \d+ t1
                                      Partitioned table "public.t1"
 Column |  Type   | Collation | Nullable | Default | Storage  | Compression | Stats target | Description 
--------+---------+-----------+----------+---------+----------+-------------+--------------+-------------
 i      | integer |           |          |         | plain    |             |              | 
 t      | text    |           |          |         | extended |             |              | 
Partition key: RANGE (i)
Partitions: t1_0_150 FOR VALUES FROM (1) TO (150),
            t1_1000 FOR VALUES FROM (750) TO (1000),
            t1_150_300 FOR VALUES FROM (150) TO (300),
            t1_300_500 FOR VALUES FROM (300) TO (500),
            t1_750 FOR VALUES FROM (500) TO (750)
```

Des mécanismes de vérifications existent bien évidemment. Par exemple, si les
bornes des deux intervalles ne sont pas contiguës, un message d'erreur apparaît
:

```sql
postgres=# ALTER TABLE t1 MERGE PARTITIONS ( t1_0_150, t1_1000 ) INTO t1_tmp;
ERROR:  lower bound of partition "t1_1000" conflicts with upper bound of previous partition "t1_0_150"
postgres=# select min(i), max(i) from t1_0_150 ;
 min | max 
-----+-----
   1 | 149
(1 row)
```

</div>

--> 
