Skip to content

Commit dd8896e

Browse files
committed
fixup! Normalize index identifiers on construction
1 parent dda8104 commit dd8896e

2 files changed

Lines changed: 35 additions & 25 deletions

File tree

src/Database/PostgreSQL/PQTypes/Checks.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -752,7 +752,7 @@ checkDBStructure options tables = fmap mconcat . forM tables $ \(table, version)
752752
<> map localIndexInfo localIndexes
753753
where
754754
checkIndexName (idx, name)
755-
| name `elem` indexNames tblName idx = mempty
755+
| acceptsIndexName tblName idx name = mempty
756756
| otherwise =
757757
validationError . mconcat $
758758
[ "Property "

src/Database/PostgreSQL/PQTypes/Model/Index.hs

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ module Database.PostgreSQL.PQTypes.Model.Index
1414
, uniqueIndexOnColumnWithCondition
1515
, uniqueIndexOnColumns
1616
, indexName
17-
, indexNames
17+
, acceptsIndexName
1818
, IncludeColumn (unIncludeColumn)
1919
, includeColumn
2020
, sqlCreateIndexMaybeDowntime
@@ -185,34 +185,43 @@ uniqueIndexOnColumnWithCondition column whereC =
185185

186186
-- | Canonical auto-generated name for an index.
187187
indexName :: RawSQL () -> TableIndex -> RawSQL ()
188-
indexName = indexNameImpl id
189-
190-
-- | Index names accepted by 'Database.PostgreSQL.PQTypes.Checks.checkDatabase'.
191-
indexNames :: RawSQL () -> TableIndex -> [RawSQL ()]
192-
indexNames tname idx =
193-
[ indexName tname idx
194-
, -- The legacy entry, reconstructed the name that older versions produced for
195-
-- keyword columns.
196-
indexNameImpl (\t -> "\"" <> t <> "\"") tname idx
197-
]
198-
199-
indexNameImpl :: (T.Text -> T.Text) -> RawSQL () -> TableIndex -> RawSQL ()
200-
indexNameImpl preSanitize tname TableIndex {..} =
188+
indexName = indexNameWith []
189+
190+
-- | True if @dbName@ is an acceptable index name for @idx@ on @tname@.
191+
-- Also accepts the legacy form where quoted identifiers appeared as
192+
-- @$ident$@ in the name.
193+
acceptsIndexName :: RawSQL () -> TableIndex -> RawSQL () -> Bool
194+
acceptsIndexName tname idx@TableIndex {..} dbName =
195+
indexNameWith mask tname idx == dbName
196+
where
197+
dbNameText = unRawSQL dbName
198+
wasQuoted ident = T.isInfixOf ("$" <> unRawSQL ident <> "$") dbNameText
199+
mask =
200+
map (wasQuoted . indexColumnName) idxColumns
201+
++ map (wasQuoted . unIncludeColumn) idxInclude
202+
203+
-- | Generate an index name where each identifier (key columns first, then
204+
-- include columns) is wrapped in double quotes if the corresponding entry
205+
-- in the mask is 'True'. Positions beyond the mask default to bare.
206+
indexNameWith :: [Bool] -> RawSQL () -> TableIndex -> RawSQL ()
207+
indexNameWith mask tname TableIndex {..} =
201208
flip rawSQL () $
202209
T.take 63 . unRawSQL $
203210
mconcat
204211
[ if idxUnique then "unique_idx__" else "idx__"
205212
, tname
206213
, "__"
207-
, mintercalate "__" $ map (asText normalize . indexColumnName) idxColumns
214+
, mintercalate "__" $ zipWith renderIdent colMask (map indexColumnName idxColumns)
208215
, if null idxInclude
209216
then ""
210-
else "$$" <> mintercalate "__" (map (asText normalize . unIncludeColumn) idxInclude)
217+
else "$$" <> mintercalate "__" (zipWith renderIdent incMask (map unIncludeColumn idxInclude))
211218
, maybe "" (("__" <>) . hashWhere) idxWhere
212219
]
213220
where
214-
asText f = flip rawSQL () . f . unRawSQL
215-
normalize = sanitize . preSanitize
221+
(colMask, incMask) = splitAt (length idxColumns) (mask ++ repeat False)
222+
renderIdent quoted ident =
223+
flip rawSQL () . sanitize $
224+
if quoted then "\"" <> unRawSQL ident <> "\"" else unRawSQL ident
216225
-- See http://www.postgresql.org/docs/9.4/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS.
217226
-- Remove all unallowed characters and replace them by at most one adjacent dollar sign.
218227
sanitize = T.pack . foldr go [] . T.unpack
@@ -226,12 +235,13 @@ indexNameImpl preSanitize tname TableIndex {..} =
226235
-- hash WHERE clause and add it to index name so that indexes
227236
-- with the same columns, but different constraints can coexist
228237
hashWhere =
229-
asText $
230-
T.decodeUtf8
231-
. B16.encode
232-
. BS.take 10
233-
. RIPEMD160.hash
234-
. T.encodeUtf8
238+
flip rawSQL ()
239+
. T.decodeUtf8
240+
. B16.encode
241+
. BS.take 10
242+
. RIPEMD160.hash
243+
. T.encodeUtf8
244+
. unRawSQL
235245

236246
-- | Create an index. Warning: if the affected table is large, this will prevent
237247
-- the table from being modified during the creation. If this is not acceptable,

0 commit comments

Comments
 (0)