don't allow altering tracked SQL functions type to VOLATILE (fix #1546) (#1547)

This commit is contained in:
Rakesh Emmadi 2019-02-05 11:27:03 +05:30 committed by Vamshi Surabhi
parent 729ed5b22f
commit 96f8b05326
5 changed files with 71 additions and 19 deletions

View File

@ -32,7 +32,6 @@ import qualified Data.Text as T
import Hasura.GraphQL.Utils
import Hasura.Prelude
import Hasura.RQL.DDL.Utils
import Hasura.RQL.Types
import Hasura.SQL.Types

View File

@ -13,8 +13,10 @@ module Hasura.RQL.DDL.Schema.Diff
, getSchemaChangeDeps
, FunctionMeta(..)
, funcFromMeta
, fetchFunctionMeta
, getDroppedFuncs
, FunctionDiff(..)
, getFuncDiff
) where
import Hasura.Prelude
@ -227,24 +229,49 @@ getSchemaChangeDeps schemaDiff = do
data FunctionMeta
= FunctionMeta
{ fmOid :: !Int
, fmFunction :: !QualifiedFunction
, fmSchema :: !SchemaName
, fmName :: !FunctionName
, fmType :: !FunctionType
} deriving (Show, Eq)
$(deriveJSON (aesonDrop 2 snakeCase) ''FunctionMeta)
funcFromMeta :: FunctionMeta -> QualifiedFunction
funcFromMeta fm = QualifiedObject (fmSchema fm) (fmName fm)
fetchFunctionMeta :: Q.Tx [FunctionMeta]
fetchFunctionMeta = do
res <- Q.listQ [Q.sql|
map (Q.getAltJ . runIdentity) <$> Q.listQ [Q.sql|
SELECT
f.function_schema,
f.function_name,
p.oid
FROM hdb_catalog.hdb_function_agg f
json_build_object(
'oid', p.oid :: integer,
'schema', f.function_schema,
'name', f.function_name,
'type', f.function_type
) AS function_meta
FROM
hdb_catalog.hdb_function_agg f
JOIN pg_catalog.pg_proc p ON (p.proname = f.function_name)
JOIN pg_catalog.pg_namespace pn ON (
pn.oid = p.pronamespace
AND pn.nspname = f.function_schema
)
WHERE
f.function_schema <> 'hdb_catalog'
|] () False
forM res $ \(sn, fn, foid) ->
return $ FunctionMeta foid $ QualifiedObject sn fn
getDroppedFuncs :: [FunctionMeta] -> [FunctionMeta] -> [QualifiedFunction]
getDroppedFuncs oldMeta newMeta =
map fmFunction $ getDifference fmOid oldMeta newMeta
data FunctionDiff
= FunctionDiff
{ fdDropped :: ![QualifiedFunction]
, fdAltered :: ![(QualifiedFunction, FunctionType)]
} deriving (Show, Eq)
getFuncDiff :: [FunctionMeta] -> [FunctionMeta] -> FunctionDiff
getFuncDiff oldMeta newMeta =
FunctionDiff droppedFuncs alteredFuncs
where
droppedFuncs = map funcFromMeta $ getDifference fmOid oldMeta newMeta
alteredFuncs = mapMaybe mkAltered $ getOverlap fmOid oldMeta newMeta
mkAltered (oldfm, newfm) =
let isTypeAltered = fmType oldfm /= fmType newfm
alteredFunc = (funcFromMeta oldfm, fmType newfm)
in bool Nothing (Just alteredFunc) isTypeAltered

View File

@ -440,8 +440,8 @@ execWithMDCheck (RunSQL t cascade _) = do
oldMeta = flip filter oldMetaU $ \tm -> tmTable tm `elem` existingTables
schemaDiff = getSchemaDiff oldMeta newMeta
existingFuncs = M.keys $ scFunctions sc
oldFuncMeta = flip filter oldFuncMetaU $ \fm -> fmFunction fm `elem` existingFuncs
droppedFuncs = getDroppedFuncs oldFuncMeta newFuncMeta
oldFuncMeta = flip filter oldFuncMetaU $ \fm -> funcFromMeta fm `elem` existingFuncs
FunctionDiff droppedFuncs alteredFuncs = getFuncDiff oldFuncMeta newFuncMeta
indirectDeps <- getSchemaChangeDeps schemaDiff
@ -461,6 +461,12 @@ execWithMDCheck (RunSQL t cascade _) = do
liftTx $ delFunctionFromCatalog qf
delFunctionFromCache qf
-- Process altered functions
forM_ alteredFuncs $ \(qf, newTy) ->
when (newTy == FTVOLATILE) $
throw400 NotSupported $
"type of function " <> qf <<> " is altered to \"VOLATILE\" which is not supported now"
-- update the schema cache with the changes
processSchemaChanges schemaDiff

View File

@ -0,0 +1,17 @@
description: Alter SQL function to type VOLATILE (error)
url: /v1/query
status: 400
reponse:
path: "$.args"
error: type of function "search_posts" is altered to "VOLATILE" which is not supported
now
code: not-supported
query:
type: run_sql
args:
sql: |
create or replace function search_posts(search text)
returns setof post as $$
insert into post (title, content) values (search, search)
returning *
$$ language sql volatile;

View File

@ -339,6 +339,9 @@ class TestGraphQLQueryFunctions(DefaultTestSelectQueries):
def test_search_posts_aggregate(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + "/query_search_posts_aggregate.yaml")
def test_alter_function_error(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + '/alter_function_error.yaml')
@classmethod
def dir(cls):
return 'queries/graphql_query/functions'