Skip to content

Commit

Permalink
server/postgres/citus: fix inserting values into columns with case se…
Browse files Browse the repository at this point in the history
…nsitive enum types

PR-URL: hasura/graphql-engine-mono#4196
GitOrigin-RevId: bbb9e565bc7143080eb1c50ade86b0e47b751387
  • Loading branch information
rakeshkky authored and hasura-bot committed Apr 11, 2022
1 parent 38c41b2 commit d561024
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 41 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Bug fixes and improvements

- server: fix inserting values into columns with case sensitive enum types for Postgres/Citus backends (fix #4014)
- server: remote relationships can be defined _on_ and _to_ SQLServer tables
- server: fix JSON key encoding issue for remote schemas (fixes #7543 and #8200)
- server: fix MSSQL insert mutation when relationships are used in check permissions (fix #8225)
Expand Down
1 change: 1 addition & 0 deletions server/graphql-engine.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -1103,6 +1103,7 @@ test-suite tests-hspec
Test.WhereSpec
Test.RunSQLSpec
Test.InsertCheckPermissionSpec
Test.InsertEnumColumnSpec

test-suite tests-gdw-api
import: common-all, common-exe
Expand Down
3 changes: 1 addition & 2 deletions server/src-lib/Hasura/Backends/Postgres/DDL/ComputedField.hs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import Hasura.RQL.Types.Common (Comment (..))
import Hasura.RQL.Types.ComputedField
import Hasura.RQL.Types.Function
import Hasura.SQL.Backend
import Hasura.SQL.Types
import Hasura.Server.Utils
import Language.GraphQL.Draft.Syntax qualified as G

Expand Down Expand Up @@ -61,7 +60,7 @@ showError qf = \case
CFVEInvalidSessionArgument (ISANotJSON functionArg) ->
showFunctionSessionArgument functionArg <> " is not of type JSON"
CFVENotBaseReturnType scalarType ->
"the function " <> qf <<> " returning type " <> toSQLTxt scalarType
"the function " <> qf <<> " returning type " <> pgScalarTypeToText scalarType
<> " is not a BASE type"
CFVEReturnTableNotFound table ->
"the function " <> qf <<> " returning set of table " <> table
Expand Down
91 changes: 55 additions & 36 deletions server/src-lib/Hasura/Backends/Postgres/SQL/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ module Hasura.Backends.Postgres.SQL.Types
qualifiedObjectToName,
PGScalarType (..),
textToPGScalarType,
pgScalarTypeToText,
PGTypeKind (..),
QualifiedPGType (..),
isBaseType,
Expand Down Expand Up @@ -317,6 +318,7 @@ data PGScalarType
| PGLtxtquery
| PGUnknown !Text
| PGCompositeScalar !Text
| PGEnumScalar !Text
deriving (Show, Eq, Ord, Generic, Data)

instance NFData PGScalarType
Expand All @@ -325,46 +327,55 @@ instance Hashable PGScalarType

instance Cacheable PGScalarType

pgScalarTypeToText :: PGScalarType -> Text
pgScalarTypeToText = \case
PGSmallInt -> "smallint"
PGInteger -> "integer"
PGBigInt -> "bigint"
PGSerial -> "serial"
PGBigSerial -> "bigserial"
PGFloat -> "real"
PGDouble -> "float8"
PGNumeric -> "numeric"
PGMoney -> "money"
PGBoolean -> "boolean"
PGChar -> "bpchar"
PGVarchar -> "varchar"
PGText -> "text"
PGCitext -> "citext"
PGDate -> "date"
PGTimeStamp -> "timestamp"
PGTimeStampTZ -> "timestamptz"
PGTimeTZ -> "timetz"
PGJSON -> "json"
PGJSONB -> "jsonb"
PGGeometry -> "geometry"
PGGeography -> "geography"
PGRaster -> "raster"
PGUUID -> "uuid"
PGLtree -> "ltree"
PGLquery -> "lquery"
PGLtxtquery -> "ltxtquery"
PGUnknown t -> t
PGCompositeScalar t -> t
PGEnumScalar t -> t

instance ToSQL PGScalarType where
toSQL = \case
PGSmallInt -> "smallint"
PGInteger -> "integer"
PGBigInt -> "bigint"
PGSerial -> "serial"
PGBigSerial -> "bigserial"
PGFloat -> "real"
PGDouble -> "float8"
PGNumeric -> "numeric"
PGMoney -> "money"
PGBoolean -> "boolean"
PGChar -> "bpchar"
PGVarchar -> "varchar"
PGText -> "text"
PGCitext -> "citext"
PGDate -> "date"
PGTimeStamp -> "timestamp"
PGTimeStampTZ -> "timestamptz"
PGTimeTZ -> "timetz"
PGJSON -> "json"
PGJSONB -> "jsonb"
PGGeometry -> "geometry"
PGGeography -> "geography"
PGRaster -> "raster"
PGUUID -> "uuid"
PGLtree -> "ltree"
PGLquery -> "lquery"
PGLtxtquery -> "ltxtquery"
PGUnknown t -> TB.text t
PGCompositeScalar t -> TB.text t
toSQL =
TB.text . \case
-- Format enum type names as identifiers to preserve case sensitivity
-- https://github.com/hasura/graphql-engine/issues/4014
PGEnumScalar t -> pgFmtIdentifier t
scalarType -> pgScalarTypeToText scalarType

instance ToJSON PGScalarType where
toJSON = String . toSQLTxt
toJSON = String . pgScalarTypeToText

instance ToJSONKey PGScalarType where
toJSONKey = toJSONKeyText toSQLTxt
toJSONKey = toJSONKeyText pgScalarTypeToText

instance ToTxt PGScalarType where
toTxt = toSQLTxt
toTxt = pgScalarTypeToText

textToPGScalarType :: Text -> PGScalarType
textToPGScalarType t = fromMaybe (PGUnknown t) (lookup t pgScalarTranslations)
Expand Down Expand Up @@ -418,7 +429,15 @@ pgScalarTranslations =

instance FromJSON PGScalarType where
parseJSON (String t) = return $ textToPGScalarType t
parseJSON _ = fail "Expecting a string for PGScalarType"
parseJSON (Object o) = do
typeType <- o .: "type"
typeName <- o .: "name"
pure $
case typeType of
PGKindEnum -> PGEnumScalar typeName
PGKindComposite -> PGCompositeScalar typeName
_ -> textToPGScalarType typeName
parseJSON _ = fail "Expecting a string or object for PGScalarType"

isNumType :: PGScalarType -> Bool
isNumType PGInteger = True
Expand Down Expand Up @@ -528,7 +547,7 @@ isBaseType (QualifiedPGType _ n ty) =

typeToTable :: QualifiedPGType -> QualifiedTable
typeToTable (QualifiedPGType sch n _) =
QualifiedObject sch $ TableName $ toSQLTxt n
QualifiedObject sch $ TableName $ pgScalarTypeToText n

mkFunctionArgScalarType :: QualifiedPGType -> PGScalarType
mkFunctionArgScalarType (QualifiedPGType _schema name type') =
Expand Down Expand Up @@ -582,7 +601,7 @@ mkScalarTypeName (PGCompositeScalar compositeScalarType) =
<> "valid GraphQL identifier"
)
mkScalarTypeName scalarType =
G.mkName (toSQLTxt scalarType)
G.mkName (pgScalarTypeToText scalarType)
`onNothing` throw400
ValidationFailed
( "cannot use SQL type " <> scalarType <<> " in the GraphQL schema because its name is not a "
Expand Down
5 changes: 4 additions & 1 deletion server/src-lib/Hasura/Backends/Postgres/SQL/Value.hs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ parsePGValue ty val = case (ty, val) of
fail $ "A string is expected for type: " ++ T.unpack tyName
PGCompositeScalar tyName ->
fail $ "A string is expected for type: " ++ T.unpack tyName
PGEnumScalar tyName ->
fail $ "A string is expected for type: " ++ T.unpack tyName

txtEncodedVal :: PGScalarValue -> TxtEncodedVal
txtEncodedVal = \case
Expand Down Expand Up @@ -284,8 +286,9 @@ pgTypeOid = \case
PGLtree -> PTI.text
PGLquery -> PTI.text
PGLtxtquery -> PTI.text
(PGUnknown _) -> PTI.auto
PGUnknown _ -> PTI.auto
PGCompositeScalar _ -> PTI.auto
PGEnumScalar _ -> PTI.auto

binEncoder :: PGScalarValue -> Q.PrepArg
binEncoder = \case
Expand Down
2 changes: 1 addition & 1 deletion server/src-rsr/citus_table_metadata.sql
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ LEFT JOIN LATERAL
( SELECT jsonb_agg(jsonb_build_object(
'name', "column".attname,
'position', "column".attnum,
'type', coalesce(base_type.typname, "type".typname),
'type', json_build_object('name', coalesce(base_type.typname, "type".typname), 'type', "type".typtype),
'is_nullable', NOT "column".attnotnull,
'description', pg_catalog.col_description("table".oid, "column".attnum),
'mutability', jsonb_build_object(
Expand Down
2 changes: 1 addition & 1 deletion server/src-rsr/pg_table_metadata.sql
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ LEFT JOIN LATERAL
( SELECT jsonb_agg(jsonb_build_object(
'name', "column".attname,
'position', "column".attnum,
'type', coalesce(base_type.typname, "type".typname),
'type', json_build_object('name', coalesce(base_type.typname, "type".typname), 'type', "type".typtype),
'is_nullable', NOT "column".attnotnull,
'description', pg_catalog.col_description("table".oid, "column".attnum),
'mutability', jsonb_build_object(
Expand Down
Loading

0 comments on commit d561024

Please sign in to comment.