Skip to content

Commit 1ad8c54

Browse files
committed
Add PostgreSQL index access method reflection support
This adds the ability to reflect PostgreSQL index access methods (gin, gist, spgist, brin, hash) when describing indexes. Changes: - Add `accessMethod` property to Index class with constants for PostgreSQL access methods (GIN, GIST, SPGIST, BRIN, HASH) - Update describeIndexQuery() to join pg_am and fetch amname - Update describeIndexes() and convertIndexDescription() to include accessMethod in result for non-btree indexes - Update indexSql() to generate USING clause for non-btree indexes This enables migrations to properly reflect and regenerate indexes that use specialized PostgreSQL access methods. Refs cakephp/migrations#1053
1 parent cef6ba0 commit 1ad8c54

File tree

2 files changed

+64
-3
lines changed

2 files changed

+64
-3
lines changed

src/Database/Schema/Index.php

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,17 @@ class Index
3838
*/
3939
public const FULLTEXT = 'fulltext';
4040

41+
/**
42+
* PostgreSQL index access methods
43+
*
44+
* @var string
45+
*/
46+
public const GIN = 'gin';
47+
public const GIST = 'gist';
48+
public const SPGIST = 'spgist';
49+
public const BRIN = 'brin';
50+
public const HASH = 'hash';
51+
4152
/**
4253
* Constructor
4354
*
@@ -48,6 +59,7 @@ class Index
4859
* @param array<string>|null $order The sort order of the index columns.
4960
* @param array<string>|null $include The included columns for covering indexes.
5061
* @param ?string $where The where clause for partial indexes.
62+
* @param ?string $accessMethod The index access method for PostgreSQL (gin, gist, spgist, brin, hash).
5163
*/
5264
public function __construct(
5365
protected string $name,
@@ -57,6 +69,7 @@ public function __construct(
5769
protected ?array $order = null,
5870
protected ?array $include = null,
5971
protected ?string $where = null,
72+
protected ?string $accessMethod = null,
6073
) {
6174
}
6275

@@ -231,6 +244,32 @@ public function getWhere(): ?string
231244
return $this->where;
232245
}
233246

247+
/**
248+
* Set the index access method for PostgreSQL.
249+
*
250+
* PostgreSQL supports multiple index access methods: btree (default),
251+
* gin, gist, spgist, brin, and hash.
252+
*
253+
* @param ?string $accessMethod The access method (gin, gist, spgist, brin, hash).
254+
* @return $this
255+
*/
256+
public function setAccessMethod(?string $accessMethod)
257+
{
258+
$this->accessMethod = $accessMethod;
259+
260+
return $this;
261+
}
262+
263+
/**
264+
* Get the index access method for PostgreSQL.
265+
*
266+
* @return ?string
267+
*/
268+
public function getAccessMethod(): ?string
269+
{
270+
return $this->accessMethod;
271+
}
272+
234273
/**
235274
* Utility method that maps an array of index options to this object's methods.
236275
*
@@ -241,7 +280,7 @@ public function getWhere(): ?string
241280
public function setAttributes(array $attributes)
242281
{
243282
// Valid Options
244-
$validOptions = ['columns', 'type', 'name', 'length', 'order', 'include', 'where'];
283+
$validOptions = ['columns', 'type', 'name', 'length', 'order', 'include', 'where', 'accessMethod'];
245284
foreach ($attributes as $attr => $value) {
246285
if (!in_array($attr, $validOptions, true)) {
247286
throw new RuntimeException(sprintf('"%s" is not a valid index option.', $attr));
@@ -268,6 +307,7 @@ public function toArray(): array
268307
'order' => $this->getOrder(),
269308
'include' => $this->getInclude(),
270309
'where' => $this->getWhere(),
310+
'accessMethod' => $this->getAccessMethod(),
271311
];
272312
}
273313
}

src/Database/Schema/PostgresSchemaDialect.php

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -375,12 +375,14 @@ private function describeIndexQuery(): string
375375
a.attname,
376376
i.indisprimary,
377377
i.indisunique,
378-
i.indnkeyatts
378+
i.indnkeyatts,
379+
am.amname
379380
FROM pg_catalog.pg_namespace n
380381
INNER JOIN pg_catalog.pg_class c ON (n.oid = c.relnamespace)
381382
INNER JOIN pg_catalog.pg_index i ON (c.oid = i.indrelid)
382383
INNER JOIN pg_catalog.pg_class c2 ON (c2.oid = i.indexrelid)
383384
INNER JOIN pg_catalog.pg_attribute a ON (a.attrelid = c.oid AND i.indrelid::regclass = a.attrelid::regclass)
385+
INNER JOIN pg_catalog.pg_am am ON (c2.relam = am.oid)
384386
WHERE n.nspname = ?
385387
AND a.attnum = ANY(i.indkey)
386388
AND c.relname = ?
@@ -423,6 +425,11 @@ public function convertIndexDescription(TableSchema $schema, array $row): void
423425
'type' => $type,
424426
'columns' => [],
425427
];
428+
// Include access method for non-btree indexes
429+
$accessMethod = $row['amname'] ?? 'btree';
430+
if ($accessMethod !== 'btree') {
431+
$index['accessMethod'] = $accessMethod;
432+
}
426433
}
427434
$index['columns'][] = $row['attname'];
428435
$schema->addIndex($name, $index);
@@ -458,6 +465,11 @@ public function describeIndexes(string $tableName): array
458465
'columns' => [],
459466
'length' => [],
460467
];
468+
// Include access method for non-btree indexes
469+
$accessMethod = $row['amname'] ?? 'btree';
470+
if ($accessMethod !== 'btree') {
471+
$indexes[$name]['accessMethod'] = $accessMethod;
472+
}
461473
}
462474
if ($constraint) {
463475
$indexes[$name]['constraint'] = $constraint;
@@ -917,6 +929,14 @@ public function indexSql(TableSchema $schema, string $name): string
917929
$this->_driver->quoteIdentifier(...),
918930
(array)$index->getColumns(),
919931
);
932+
933+
// Build USING clause for non-btree access methods (gin, gist, spgist, brin, hash)
934+
$using = '';
935+
$accessMethod = $index->getAccessMethod();
936+
if ($accessMethod !== null) {
937+
$using = ' USING ' . $accessMethod;
938+
}
939+
920940
$include = '';
921941
if ($index->getInclude()) {
922942
$included = array_map(
@@ -927,9 +947,10 @@ public function indexSql(TableSchema $schema, string $name): string
927947
}
928948

929949
return sprintf(
930-
'CREATE INDEX %s ON %s (%s)%s',
950+
'CREATE INDEX %s ON %s%s (%s)%s',
931951
$this->_driver->quoteIdentifier($name),
932952
$this->_driver->quoteIdentifier($schema->name()),
953+
$using,
933954
implode(', ', $columns),
934955
$include,
935956
);

0 commit comments

Comments
 (0)