Apenas esperando confirmar minha observação e obter uma explicação sobre por que isso está acontecendo.
Eu tenho uma função definida como:
CREATE OR REPLACE FUNCTION "public"."__post_users_id_coin" ("coins" integer, "userid" integer) RETURNS TABLE (id integer) AS '
UPDATE
users
SET
coin = coin + coins
WHERE
userid = users.id
RETURNING
users.id' LANGUAGE "sql" COST 100 ROWS 1000
VOLATILE
RETURNS NULL ON NULL INPUT
SECURITY INVOKER
Quando eu chamo essa função de um CTE, ele executa o comando SQL, mas não aciona a função, por exemplo:
WITH test AS
(SELECT * FROM __post_users_id_coin(10, 1))
SELECT
1 -- Select 1 but update not performed
Por outro lado, se eu chamar a função de um CTE e selecionar o resultado do CTE (ou chamar a função diretamente sem CTE), ele executará o comando SQL e acionará a função, por exemplo:
WITH test AS
(SELECT * FROM __post_users_id_coin(10, 1))
SELECT
*
FROM
test -- Select result and update performed
ou
SELECT * FROM __post_users_id_coin(10,1)
Como eu realmente não me importo com o resultado da função (só preciso executar a atualização), existe alguma maneira de fazer isso funcionar sem selecionar o resultado da CTE?
fonte
Isso é esperado, comportamento documentado.
Tom Lane explica aqui.
Documentado no manual aqui:
Negrito ênfase minha. "Data-modificando" são
INSERT
,UPDATE
eDELETE
consultas. (Ao contrário deSELECT
.). O manual mais uma vez:Função adequada
Larguei as cláusulas padrão (ruído) e
STRICT
é o sinônimo curto deRETURNS NULL ON NULL INPUT
.Certifique-se de alguma forma que os nomes dos parâmetros não entrem em conflito com os nomes das colunas. Eu comecei com
_
, mas essa é apenas a minha preferência pessoal.Se
coin
puder serNULL
, sugiro:Se
users.id
é a chave primária, entãoRETURNS TABLE
nemROWs 1000
faz sentido. Somente uma única linha pode ser atualizada / retornada. Mas isso não vem ao caso principal.Chamada adequada
Não faz sentido usar a
RETURNING
cláusula e retornar valores de sua função se você for ignorar os valores retornados na chamada. Também não faz sentido decompor as linhas retornadasSELECT * FROM ...
se você as ignorar de qualquer maneira.Apenas retorne uma constante escalar (
RETURNING 1
), defina a função comoRETURNS int
(ou solte-aRETURNING
completamente e faça-aRETURNS void
) e chame-a comSELECT my_function(...)
Solução
Desde que você ...
.. apenas
SELECT
uma forma constante do CTE. É garantido que será executado desde que seja referenciado no exteriorSELECT
(direta ou indiretamente).Se você realmente tem uma função de retorno de conjunto e ainda não se importa com a saída:
Não há necessidade de retornar mais de uma linha. A função ainda é chamada.
Por fim, não está claro por que você precisa do CTE para começar. Provavelmente apenas uma prova de conceito.
Intimamente relacionado:
Resposta relacionada no SO:
E considere:
fonte
INSERT
antes,UPDATE
dentro da mesma função de quebra automática - nenhuma transação disponível.test
noWITH test AS (SELECT * FROM __post_users_id_coin(10, 1)) SELECT ... LIMIT 1;
considerado um CTE modificando ou não?SELECT
não é "modificador de dados" de acordo com a terminologia CTE. Eu adicionei alguns esclarecimentos acima. É de responsabilidade do usuário se ele adicionar código a uma função que modifica os dados atrás das cortinas.