diff --git a/CHANGELOG.md b/CHANGELOG.md index e310388f991..e8ffee7c3d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -104,3 +104,4 @@ - option to reload remote schemas in 'reload_metadata' API (fix #3792, #4117) - console: disable selecting roles without permissions for bulk actions (close #4178) (#4195) - console: show remote schema / event trigger intro sections always (#4044) +- server: fix postgres query error when computed fields included in mutation response (fix #4035) \ No newline at end of file diff --git a/server/src-lib/Hasura/GraphQL/Resolve/Insert.hs b/server/src-lib/Hasura/GraphQL/Resolve/Insert.hs index 34ae37c38b7..7b0d614ff4d 100644 --- a/server/src-lib/Hasura/GraphQL/Resolve/Insert.hs +++ b/server/src-lib/Hasura/GraphQL/Resolve/Insert.hs @@ -457,7 +457,7 @@ insertMultipleObjects strfyNum role tn multiObjIns addCols mutOutput errP = let affRows = sum $ map fst insResps columnValues = catMaybes $ map snd insResps cteExp <- mkSelCTEFromColVals tn tableColInfos columnValues - let sql = toSQL $ RR.mkMutationOutputExp tn (Just affRows) cteExp mutOutput strfyNum + let sql = toSQL $ RR.mkMutationOutputExp tn tableColInfos (Just affRows) cteExp mutOutput strfyNum runIdentity . Q.getRow <$> Q.rawQE dmlTxErrorHandler (Q.fromBuilder sql) [] False diff --git a/server/src-lib/Hasura/RQL/DML/Mutation.hs b/server/src-lib/Hasura/RQL/DML/Mutation.hs index c201f7fcebd..9438880a09f 100644 --- a/server/src-lib/Hasura/RQL/DML/Mutation.hs +++ b/server/src-lib/Hasura/RQL/DML/Mutation.hs @@ -38,19 +38,19 @@ runMutation mut = hasNestedFld $ _mOutput mut mutateAndReturn :: Mutation -> Q.TxE QErr EncJSON -mutateAndReturn (Mutation qt (cte, p) mutationOutput _ strfyNum) = +mutateAndReturn (Mutation qt (cte, p) mutationOutput allCols strfyNum) = encJFromBS . runIdentity . Q.getRow <$> Q.rawQE dmlTxErrorHandler (Q.fromBuilder $ toSQL selWith) (toList p) True where - selWith = mkMutationOutputExp qt Nothing cte mutationOutput strfyNum + selWith = mkMutationOutputExp qt allCols Nothing cte mutationOutput strfyNum mutateAndSel :: Mutation -> Q.TxE QErr EncJSON mutateAndSel (Mutation qt q mutationOutput allCols strfyNum) = do -- Perform mutation and fetch unique columns MutateResp _ columnVals <- mutateAndFetchCols qt allCols q strfyNum selCTE <- mkSelCTEFromColVals qt allCols columnVals - let selWith = mkMutationOutputExp qt Nothing selCTE mutationOutput strfyNum + let selWith = mkMutationOutputExp qt allCols Nothing selCTE mutationOutput strfyNum -- Perform select query and fetch returning fields encJFromBS . runIdentity . Q.getRow <$> Q.rawQE dmlTxErrorHandler (Q.fromBuilder $ toSQL selWith) [] True @@ -108,8 +108,7 @@ mkSelCTEFromColVals qt allCols colVals = where rowAlias = Iden "row" extractor = S.selectStar' $ S.QualIden rowAlias $ Just $ S.TypeAnn $ toSQLTxt qt - sortedCols = flip sortBy allCols $ \lCol rCol -> - compare (pgiPosition lCol) (pgiPosition rCol) + sortedCols = sortCols allCols mkTupsFromColVal colVal = fmap S.TupleExp $ forM sortedCols $ \ci -> do let pgCol = pgiColumn ci diff --git a/server/src-lib/Hasura/RQL/DML/Returning.hs b/server/src-lib/Hasura/RQL/DML/Returning.hs index a65d5e248a4..344fc79426a 100644 --- a/server/src-lib/Hasura/RQL/DML/Returning.hs +++ b/server/src-lib/Hasura/RQL/DML/Returning.hs @@ -93,12 +93,8 @@ mkDefaultMutFlds = MOutMultirowFields . \case where mutFlds = [("affected_rows", MCount)] -qualTableToAliasIden :: QualifiedTable -> Iden -qualTableToAliasIden qt = - Iden $ snakeCaseTable qt <> "__mutation_result_alias" - -mkMutFldExp :: QualifiedTable -> Maybe Int -> Bool -> MutFld -> S.SQLExp -mkMutFldExp qt preCalAffRows strfyNum = \case +mkMutFldExp :: Iden -> Maybe Int -> Bool -> MutFld -> S.SQLExp +mkMutFldExp cteAlias preCalAffRows strfyNum = \case MCount -> let countExp = S.SESelect $ S.mkSelect @@ -112,28 +108,70 @@ mkMutFldExp qt preCalAffRows strfyNum = \case tabPerm = TablePerm annBoolExpTrue Nothing in S.SESelect $ mkSQLSelect JASMultipleRows $ AnnSelG selFlds tabFrom tabPerm noTableArgs strfyNum - where - cteAlias = qualTableToAliasIden qt +{- Note [Mutation output expression] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +An example output expression for INSERT mutation: + +WITH "__mutation_result_alias" AS ( + INSERT INTO ([..]) + VALUES + ([..]) + ON CONFLICT ON CONSTRAINT "" DO NOTHING RETURNING *, + -- An extra column expression which performs the 'CHECK' validation + CASE + WHEN () THEN NULL + ELSE "hdb_catalog"."check_violation"('insert check constraint failed') + END +), +"__all_columns_alias" AS ( + -- Only extract columns from mutated rows. Columns sorted by ordinal position so that + -- resulted rows can be casted to table type. + SELECT ([..]) + FROM + "__mutation_result_alias" +) +