<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rodrigo Speller</title>
    <description>The latest articles on DEV Community by Rodrigo Speller (@rodrigo-speller).</description>
    <link>https://dev.to/rodrigo-speller</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2619957%2Ff2cb6266-09e3-4ef1-909c-744259e88e79.png</url>
      <title>DEV Community: Rodrigo Speller</title>
      <link>https://dev.to/rodrigo-speller</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rodrigo-speller"/>
    <language>en</language>
    <item>
      <title>O Padrão de Resiliência de Aplicações "Circuit Breaker"</title>
      <dc:creator>Rodrigo Speller</dc:creator>
      <pubDate>Wed, 16 Apr 2025 18:12:48 +0000</pubDate>
      <link>https://dev.to/rodrigo-speller/o-padrao-de-resiliencia-de-aplicacoes-circuit-breaker-7dj</link>
      <guid>https://dev.to/rodrigo-speller/o-padrao-de-resiliencia-de-aplicacoes-circuit-breaker-7dj</guid>
      <description>&lt;h2&gt;
  
  
  Prefácio
&lt;/h2&gt;

&lt;p&gt;Não há muito tempo atrás, quando a fiação elétrica estava sendo construída nas residências, muitas pessoas foram vítimas de choques elétricos. Os azarados ligavam muitos aparelhos em seu circuito e cada aparelho consumia uma certa quantidade de corrente elétrica. Quando a corrente é resistida, ela produz calor proporcional ao quadrado da corrente vezes a resistência (I²R). Como eles não tinham fiação doméstica supercondutora, esse acoplamento oculto entre aparelhos eletrônicos fazia com que os fios nas paredes ficassem quentes, às vezes quentes o suficiente para pegar fogo. &lt;em&gt;Puft. Não há mais casa.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A incipiente indústria de energia encontrou uma solução parcial para o problema do aquecimento resistivo, na forma de &lt;em&gt;fusíveis&lt;/em&gt;. Todo o propósito de um fusível elétrico é queimar antes da casa. É um componente projetado para falhar primeiro, controlando assim um modo de falha geral. Este dispositivo brilhante funcionou bem, exceto por dois problemas. Primeiro, um fusível é um item descartável de uso único; portanto, é possível que eles se egotem. Em segundo lugar, os fusíveis residenciais (nos Estados Unidos) tinham aproximadamente o mesmo diâmetro das moedas de cobre. Juntas, essas duas condições levaram muitas pessoas a realizar experimentos com fusíveis caseiros de alta corrente e baixa resistência (ou seja, um disco de cobre de 3/4"). &lt;em&gt;Puft. Não há mais casa.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Os fusíveis residenciais seguiram o caminho do telefone a disco. Agora, os disjuntores protegem os caçadores de engenhocas ansiosos para queimarem suas casas. O princípio é o mesmo: detecta o uso excessivo, falha primeiro, e abre o circuito. Mais abstratamente, o disjuntor existe para permitir que um subsistema (um circuito elétrico) falhe (consumo excessivo de corrente, possivelmente devido a um curto-circuito) sem destruir todo o sistema (a casa). Além disso, uma vez que o perigo tenha passado, o disjuntor pode ser reiniciado para restaurar a função completa do sistema. (NYGARD, 2007)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NYGARD, Michael T. Circuit Breaker. In: &lt;a href="https://amzn.to/3e1wzh5" rel="noopener noreferrer"&gt;RELEASE It! Design and Deploy Production-Ready Software&lt;/a&gt;. 1. ed. Raleigh, North Carolina Dallas, Texas, EUA: The Pragmatic Bookshelf, 2007. cap. 5.2, p. 115. ISBN 978-0-9787392-1-8.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;É comum que sistemas de software façam chamadas remotas para aplicações que estejam sendo executadas em diferentes processos, ou até mesmo, em diferentes máquinas atráves da rede. Uma das principais diferenças entre chamadas locais e chamadas remotas é que as remotas podem apresentar falhas de infraestrutura ou travar, sem retornar uma resposta até que um tempo limite seja atingido. Ou pior, se houver muitas chamadas a um serviço que não responde, pode ocorrer o esgotamento de recursos críticos, levando a falhas em cascata em vários sistemas. Em seu excelente livro &lt;em&gt;&lt;a href="https://amzn.to/3e1wzh5" rel="noopener noreferrer"&gt;Release It&lt;/a&gt;&lt;/em&gt;, Michael Nygard popularizou o padrão &lt;strong&gt;&lt;em&gt;Circuit Breaker&lt;/em&gt;&lt;/strong&gt; - "Disjuntor" - para evitar esse tipo de cascata catastrófica. (MARTIN, 2014)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://martinfowler.com/bliki/CircuitBreaker.html" rel="noopener noreferrer"&gt;CircuitBreaker&lt;/a&gt;. [S. l.], 6 mar. 2014. Acesso em: 2 out. 2022.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Um disjuntor protege um circuito elétrico para evitar que sobrecargas de corrente passem por este dispositivo de proteção e cause danos aos dispositivos, aparelhos e fiação (ou, até mesmo, pessoas) ligados ao circuito protegido. O disjuntor funciona como uma chave automática que, quando armado, fecha o circuito, permitindo a passagem de corrente elétrica através dele. Enquanto o circuito estiver fechado, a corrente elétrica passa pelo disjuntor, que "monitora" a intensidade de corrente que passa por ele. Se essa corrente elétrica se eleva além do limite de operação segura deste disjuntor, ele se desarma automaticamente, abrindo o circuito para impedir a passagem da corrente, protegendo todo o circuito protegido por ele.&lt;/p&gt;

&lt;p&gt;Assim como em um circuito elétrico, falhas de funcionamento em softwares também trazem riscos: operacionais, físicos, ao patrimônio, pessoais e, até mesmo, em alguns casos, risco de morte. A falha em uma operação de software pode resultar em operações parcialmente executadas, ou impedir a realização de transações por completo, a depender da implementação e dos requisitos funcionais do software. Quando uma operação falha, vários fatores podem ter influenciado esse resultado negativo, a falha pode ser consequência de uma instabilidade momentânea, indisponibilidade de um dos recursos da cadeia de dependências do sistema, ou, até mesmo, uma falha permanente que depende de intervenção para sua correção.&lt;/p&gt;

&lt;p&gt;Se uma operação falha, significa que algo deixou de ser feito, e provavelmente receberá uma retentativa em algum momento próximo, seja de forma automática ou por uma nova solicitação do usuário. O problema é que além do funcionamento da operação estar comprometido, cada nova chamada à operação consome recursos, sem garantias de que uma retentativa será suficiente para a conclusão exitosa da operação. Além disso, a causa raíz que motiva a falha pode não estar diretamente relacionada ao serviço da operação, mas em uma camada mais profunda da cadeia de dependências do sistema. &lt;/p&gt;

&lt;p&gt;Por exemplo: Em uma aplicação hipotética, uma operação depende da chamada de um serviço de API Web, que dependende de um serviço RPC que realiza a orquestração da operação entre alguns outros serviços; Um desses serviços realiza uma operação de persistência em um banco de dados. Se em algum momento, o espaço de armazenamento desse banco de dados se esgotar, o banco de dados não poderá mais guardar novos registros. Neste caso, as operações que necessitam guardar dados nesse banco, resultarão em uma falha, mas até que a falha ocorra, alguns recursos são alocados para a tentiva de executar a operação. Porém, até que haja a intervenção necessária no espaço de armazenamento do banco de dados, a falha continuará ocorrendo continuamente.&lt;/p&gt;

&lt;p&gt;No exemplo anterior, pode-se observar que as operações que tentarem persistir novos registros no banco de dados continuarão consumindo recursos e concorrendo com as demais operações do sistema e enquanto o problema do espaço de armazenamento do banco de dados não for resolvido, é tendência que outras operações em falha também se acumulem. Como medida paliativa, seria interessante que essas operações em falha deixassem de ocorrer, até que a causa raíz fosse resolvida para que os recursos dessas operações deixem de ser alocados desnecessariamente. Para isso existe o Padrão &lt;em&gt;"Circuit Breaker"&lt;/em&gt; (ou &lt;em&gt;"Disjuntor"&lt;/em&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Circuit Breaker
&lt;/h2&gt;

&lt;p&gt;Como uma analogia aos disjuntores elétricos, o &lt;em&gt;Circuit Breaker&lt;/em&gt; é um componente que intermedia as chamadas às operações que precisam ser protegidas contra falhas em um sistema. Este componente monitora as chamadas às operações protegidas e ao detectar falhas que podem comprometer o sistema, interrompe o fluxo de chamadas de forma controlada. Essa prática é conhecida como &lt;em&gt;fail-fast&lt;/em&gt; (falha rápida).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Isso é diferente de retentativas, pois os &lt;em&gt;circuit breakers&lt;/em&gt; existem para evitar operações, ao invés de reexecutá-las."&lt;/em&gt; (NYGARD, 2007)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr29e2165oip7iy5dplep.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr29e2165oip7iy5dplep.png" width="800" height="277"&gt;&lt;/a&gt;
  &lt;b&gt;Figura 1 - Fluxo de uma chamada protegida por um Circuit Breaker&lt;/b&gt;
&lt;/p&gt;

&lt;p&gt;O modelo geral do padrão &lt;em&gt;Circuit Breaker&lt;/em&gt; funciona a partir dessas 11 regras:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;O &lt;em&gt;circuit breaker&lt;/em&gt; encapsula a chamada para a operação a ser protegida;&lt;/li&gt;
&lt;li&gt;As chamadas protegidas para a operação, são realizadas através do &lt;em&gt;circuit breaker&lt;/em&gt;;&lt;/li&gt;
&lt;li&gt;O estado inicial do &lt;em&gt;circuit breaker&lt;/em&gt; mantém o circuito &lt;strong&gt;"fechado"&lt;/strong&gt;, encaminhando as chamadas;&lt;/li&gt;
&lt;li&gt;Enquanto as chamadas são realizadas, o &lt;em&gt;circuit breaker&lt;/em&gt; monitora e registra o resultado da operação;&lt;/li&gt;
&lt;li&gt;Enquanto as falhas ocorrem dentro do limite de operação aceitável do &lt;em&gt;circuit breaker&lt;/em&gt;, as chamadas continuam sendo encaminhadas;&lt;/li&gt;
&lt;li&gt;Quando uma falha ultrapassa o limite operacional aceitável do &lt;em&gt;circuit breaker&lt;/em&gt;, o circuito é &lt;strong&gt;"aberto"&lt;/strong&gt; e não encaminhará a próximas chamadas;&lt;/li&gt;
&lt;li&gt;As chamadas não encaminhadas pelo &lt;em&gt;cicuit breaker&lt;/em&gt; resultarão em falhas automaticamente;&lt;/li&gt;
&lt;li&gt;Quando o circuito é aberto, inicia-se um temporizador que determina por quanto tempo o circuito deve permanecer neste estado;&lt;/li&gt;
&lt;li&gt;Quando o temporizador se esgota, o circuito entra no estado &lt;strong&gt;"semiaberto"&lt;/strong&gt;, atípico dos disjuntores;&lt;/li&gt;
&lt;li&gt;O estado semiaberto indica que a próxima chamada recebida pelo &lt;em&gt;circuit breaker&lt;/em&gt; deve ser encaminhada;&lt;/li&gt;
&lt;li&gt;Estando no estado semiaberto, se a chamada for bem sucedida, o circuito volta ao estado fechado, senão, volta ao estado aberto.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Os três estados: fechado, aberto e semiaberto
&lt;/h3&gt;

&lt;p&gt;Um disjuntor elétrico possui apenas dois estados de operação: &lt;em&gt;armado&lt;/em&gt; e &lt;em&gt;desarmado&lt;/em&gt;. Enquanto o disjuntor está armado, significa que o circuito está &lt;em&gt;fechado&lt;/em&gt;, permitindo a passagem de corrente entre seus terminais para alimentar o cicuito protegido. Caso o disjuntor detecte alguma sobrecarga de corrente no circuito protegido, isto é, que ultrapasse o limite seguro de operação definido para este disjuntor, o mesmo se desarma automaticamente, impedindo a passagem de corrente e mantendo o circuito &lt;em&gt;aberto&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;O componente &lt;em&gt;Circuit Breaker&lt;/em&gt; se comporta de forma parecida a um disjuntor elétrico. Enquanto este recebe e encaminha as chamadas às operações protegidas normalmente, ou com falhas dentro de um limite aceitável, ele permite a continuidade da operação, mantendo-se em estado &lt;strong&gt;fechado&lt;/strong&gt;. Se em algum momento, a quantidade de falhas supera o limite de falhas aceitáveis, o &lt;em&gt;Cicuit Breaker&lt;/em&gt; deixa de encaminhar as próximas chamadas e opera em estado &lt;strong&gt;aberto&lt;/strong&gt;, falhando imediatamente pelo próprio &lt;em&gt;Circuit Breaker&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Apenas os estados &lt;em&gt;"fechado"&lt;/em&gt; e &lt;em&gt;"aberto"&lt;/em&gt; seriam suficientes para implementar um &lt;em&gt;Circuit Breaker&lt;/em&gt; que opera de forma análoga aos disjuntores elétricos, porém, os disjuntores necessitam de intervenção externa para redefinir o estado do circuito para ser rearmado novamente, em caso de desarme. Já para softwares, essa abordagem causaria um impacto negativo na disponibilidade do sistema. Sendo assim, o interessante é que o &lt;em&gt;Circuit Breaker&lt;/em&gt; seja capaz de redefinir seu estado automaticamente quando as coisas estiverem bem novamente, sem a necessidade de intervenção externa. Isso pode ser feito através de um temporizador que, após um intervalo de tempo definido, redefine o estado do &lt;em&gt;Circuit Breaker&lt;/em&gt; para &lt;em&gt;"semiaberto"&lt;/em&gt;. Assim, o &lt;em&gt;Circuit Breaker&lt;/em&gt; pode tentar encaminhar a próxima chamada à operação protegida, e dependendo do resultado dessa chamada, o circuito pode ser &lt;em&gt;fechado&lt;/em&gt; novamente ou permanecer &lt;em&gt;aberto&lt;/em&gt; até que o temporizador se esgote novamente. Sendo assim, diferente dos disjuntores elétricos, o componente &lt;em&gt;Circuit Breaker&lt;/em&gt; possui um terceiro estado para o circuito: &lt;strong&gt;semiaberto&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Quando o &lt;em&gt;Circuit Breaker&lt;/em&gt; detecta um volume inaceitável de falhas e abre o circuito, deve-se definir também um critério para reestabelecer o circuito automaticamente. O comportamento geral para essa transição, é definir um limite de tempo em que o &lt;em&gt;Circuit Breaker&lt;/em&gt; permaneça em estado &lt;em&gt;"aberto"&lt;/em&gt;, ea pós esse limite de tempo, o estado do circuito é alterado automaticamente para "semiaberto". Quando o circuito está &lt;em&gt;semiaberto&lt;/em&gt;, significa que a próxima chamada recebida será encaminhada e seu resultado definirá a transição para o próximo estado do circuito: se a chamada for bem sucedida, o circuito será &lt;em&gt;fechado&lt;/em&gt;; se falhar, o circuito será &lt;em&gt;aberto&lt;/em&gt; novamente.&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7qzayh65iog2lvmzu6sz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7qzayh65iog2lvmzu6sz.png" width="482" height="292"&gt;&lt;/a&gt;
  &lt;b&gt;Figura 2 - Transições de estados de um Circuit Breaker&lt;/b&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Os componentes básicos
&lt;/h3&gt;

&lt;p&gt;
  &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxtf9yxnx6fjqvbserbc6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxtf9yxnx6fjqvbserbc6.png" width="263" height="373"&gt;&lt;/a&gt;
  &lt;b&gt;Figura 3 - Componentes básicos de um Circuit Breaker&lt;/b&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  O algoritmo geral
&lt;/h3&gt;

&lt;p&gt;
  &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdcdqcamdv7q9icwpxq38.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdcdqcamdv7q9icwpxq38.png" width="612" height="682"&gt;&lt;/a&gt;
  &lt;b&gt;Figura 4 - Algoritmo de uma chamada a uma operação protegida por um Circuit Breaker&lt;/b&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4rrzcddp3kwfaw05lvqr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4rrzcddp3kwfaw05lvqr.png" width="462" height="292"&gt;&lt;/a&gt;
  &lt;b&gt;Figura 5 - Algoritmo do temporizador do estado aberto do Circuit Breaker&lt;/b&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0hot8nbhxt0dle0b5mt3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0hot8nbhxt0dle0b5mt3.png" width="752" height="512"&gt;&lt;/a&gt;
  &lt;b&gt;Figura 6 - Algoritmo de controle de operações do Circuit Breaker baseando na quantidade de falhas consecutivas&lt;/b&gt;
&lt;/p&gt;

</description>
      <category>performance</category>
      <category>circuitbreaker</category>
    </item>
    <item>
      <title>The Strange Behavior of The Empty Default Privileges on PostgreSQL</title>
      <dc:creator>Rodrigo Speller</dc:creator>
      <pubDate>Fri, 27 Dec 2024 04:37:43 +0000</pubDate>
      <link>https://dev.to/rodrigo-speller/the-strange-behavior-of-the-empty-default-privileges-on-postgresql-42dc</link>
      <guid>https://dev.to/rodrigo-speller/the-strange-behavior-of-the-empty-default-privileges-on-postgresql-42dc</guid>
      <description>&lt;p&gt;PostgreSQL grants privileges on some types of objects to &lt;strong&gt;PUBLIC&lt;/strong&gt; by default&lt;br&gt;
when the objects are created.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No privileges are granted to &lt;strong&gt;PUBLIC&lt;/strong&gt; by default on tables, table columns,
sequences, foreign data wrappers, foreign servers, large objects, schemas,
tablespaces, or configuration parameters.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For other types of objects, the default privileges granted to &lt;strong&gt;PUBLIC&lt;/strong&gt; are as&lt;br&gt;
follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CONNECT&lt;/code&gt; and &lt;code&gt;TEMPORARY&lt;/code&gt; (create temporary tables) privileges for databases;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;EXECUTE&lt;/code&gt; privilege for functions and procedures;&lt;/li&gt;
&lt;li&gt;and &lt;code&gt;USAGE&lt;/code&gt; privilege for languages and data types (including domains).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The object owner can, of course, &lt;code&gt;REVOKE&lt;/code&gt; both default and expressly granted&lt;br&gt;
privileges. Also, these default privilege settings can be overridden using the&lt;br&gt;
&lt;code&gt;ALTER DEFAULT PRIVILEGES&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/17/ddl-priv.html" rel="noopener noreferrer"&gt;&lt;em&gt;PostgreSQL - Privileges Documentation&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;This document illustrates a strange behavior where even after revoking all&lt;br&gt;
default privileges for functions, newly created functions still inherit the&lt;br&gt;
built-in &lt;code&gt;EXECUTE&lt;/code&gt; access to &lt;strong&gt;PUBLIC&lt;/strong&gt; (and to the function owner), contrary as&lt;br&gt;
the expectation.&lt;/p&gt;
&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;The catalog &lt;code&gt;pg_catalog.pg_proc&lt;/code&gt; stores information about functions, procedures,&lt;br&gt;
aggregate functions, and window functions (collectively also known as routines).&lt;br&gt;
This catalog contains the &lt;code&gt;proacl aclitem[]&lt;/code&gt; column that stores the access&lt;br&gt;
privileges of the object.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Each &lt;code&gt;aclitem&lt;/code&gt; lists all the permissions of one &lt;em&gt;grantee&lt;/em&gt; that have been&lt;br&gt;
granted by a particular &lt;em&gt;grantor&lt;/em&gt;. Specific privileges are represented by&lt;br&gt;
one-letter abbreviations from &lt;a href="https://www.postgresql.org/docs/17/ddl-priv.html#PRIVILEGE-ABBREVS-TABLE" rel="noopener noreferrer"&gt;Privileges - Table 5.1&lt;/a&gt;, with &lt;code&gt;*&lt;/code&gt; appended if the&lt;br&gt;
privilege was granted with &lt;em&gt;grant option&lt;/em&gt;. For example, &lt;code&gt;calvin=r*w/hobbes&lt;/code&gt;,&lt;br&gt;
specifies that the role &lt;strong&gt;calvin&lt;/strong&gt; has the privilege&lt;br&gt;
&lt;code&gt;SELECT&lt;/code&gt; &lt;strong&gt;(r)&lt;/strong&gt; &lt;code&gt;with grant option&lt;/code&gt; &lt;strong&gt;(*)&lt;/strong&gt; as well as the &lt;code&gt;non-grantable&lt;/code&gt;&lt;br&gt;
privilege &lt;code&gt;UPDATE&lt;/code&gt; &lt;strong&gt;(w)&lt;/strong&gt;, both granted by the role &lt;strong&gt;hobbes&lt;/strong&gt;. If calvin also&lt;br&gt;
has some privileges on the same object granted by a different grantor, those&lt;br&gt;
would appear as a separate &lt;code&gt;aclitem&lt;/code&gt; entry. An &lt;em&gt;empty grantee&lt;/em&gt; field in an&lt;br&gt;
&lt;code&gt;aclitem&lt;/code&gt; stands for &lt;strong&gt;PUBLIC&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The value of the &lt;code&gt;proacl aclitem[]&lt;/code&gt; column is set when the object is created,&lt;br&gt;
based on default access privileges set to the database or schema. That column&lt;br&gt;
value can be in one of three possible states:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;null&lt;/em&gt;&lt;/strong&gt;: The object's ACL was not defined. In this case, the built-in
default privileges are applied to the object. For functions, the built-in
default privileges are to grant &lt;code&gt;EXECUTE&lt;/code&gt; access to &lt;strong&gt;PUBLIC&lt;/strong&gt; and to the
object owner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;an empty value&lt;/em&gt;&lt;/strong&gt;: The object's privileges entry is non-null but empty.
This means that no privileges are granted at all, even to the object's owner
— a rare situation. The owner still has &lt;em&gt;implicit grant options&lt;/em&gt; in this
case, and so could re-grant her own privileges.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;the list of entries&lt;/em&gt;&lt;/strong&gt;: The object's ACL is defined with the entries of
&lt;em&gt;grantees&lt;/em&gt;, the privileges and the &lt;em&gt;grantor&lt;/em&gt; information.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;ALTER DEFAULT PRIVILEGES&lt;/code&gt; allows you to set the privileges that will be applied&lt;br&gt;
to objects created in the future. (It does not affect privileges assigned to&lt;br&gt;
already-existing objects.) Privileges can be set globally (i.e., for all objects&lt;br&gt;
created in the current database), or just for objects created in specified&lt;br&gt;
schemas.&lt;/p&gt;

&lt;p&gt;As before explained, the default privileges for any object type normally &lt;em&gt;grant&lt;br&gt;
all grantable permissions to the object owner&lt;/em&gt;, and may &lt;em&gt;grant some privileges&lt;br&gt;
to &lt;strong&gt;PUBLIC&lt;/strong&gt;&lt;/em&gt; as well. However, this behavior can be changed by altering the&lt;br&gt;
global default privileges with &lt;code&gt;ALTER DEFAULT PRIVILEGES&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't confuse &lt;em&gt;global/per-schema default privileges&lt;/em&gt; with &lt;em&gt;built-in default&lt;br&gt;
  privileges&lt;/em&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;built-in default privileges&lt;/em&gt;: The base rules of the default privileges.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;global/per-schema default privileges&lt;/em&gt;: The rules of the default privileges
after configured by &lt;code&gt;ALTER DEFAULT PRIVILEGES&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The Strange Behavior of The Empty Default Privileges
&lt;/h2&gt;

&lt;p&gt;Built-in default privileges of PostgreSQL automatically apply some grants&lt;br&gt;
privileges on some types of objects to &lt;strong&gt;PUBLIC&lt;/strong&gt; . In short, this default&lt;br&gt;
behavior does not have much security concerns, because the types of objects and&lt;br&gt;
the grants involved on this condition does not reprents a direct security risk,&lt;br&gt;
as they are protected by other layers of objects that encapsulate their usage.&lt;/p&gt;

&lt;p&gt;Must also be clear that &lt;strong&gt;PUBLIC&lt;/strong&gt; does not mean any unkonown access, but rather&lt;br&gt;
access from registered roles in the system. And, perhaps the intention of the&lt;br&gt;
PostgreSQL's engineering of this design is to simplify the model of access of&lt;br&gt;
the database resources.&lt;/p&gt;

&lt;p&gt;For example, the efficacy of an &lt;code&gt;EXECUTE&lt;/code&gt; grant to permits the operation of&lt;br&gt;
some function by a role, depends of the grantee to have the &lt;code&gt;USAGE&lt;/code&gt; privilege&lt;br&gt;
to access the function's scheme too. As well, the grantee must have privileges&lt;br&gt;
to operate other resources related to the function purpose during the function&lt;br&gt;
operation.&lt;/p&gt;

&lt;p&gt;Some architectures may need to address the principle of least privilege, so&lt;br&gt;
revoking default privileges to gradually provide these access to appropriate&lt;br&gt;
roles one by one. But even after revoking all default privileges for functions&lt;br&gt;
using &lt;code&gt;ALTER DEFAULT PRIVILEGES&lt;/code&gt;, newly created functions still inherit the&lt;br&gt;
built-in &lt;code&gt;EXECUTE&lt;/code&gt; privilege. This behavior goes against the expectation that&lt;br&gt;
revoking all default privileges should completely remove any access granted by&lt;br&gt;
default.&lt;/p&gt;
&lt;h3&gt;
  
  
  Suggestion to mitigate the strange behavior
&lt;/h3&gt;

&lt;p&gt;To address the issue where revoking default privileges does not completely&lt;br&gt;
remove the unintended access, the following solution provides a way to regain&lt;br&gt;
control over default privilege inheritance and prevent unwanted access:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a &lt;code&gt;nobody&lt;/code&gt; role (if it doesn't exists).&lt;/p&gt;

&lt;p&gt;This role is designed to act as a placeholder for access management,&lt;br&gt;
ensuring that no one receives unintended privileges automatically.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;ROLE&lt;/span&gt; &lt;span class="n"&gt;nobody&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;NOLOGIN&lt;/span&gt; &lt;span class="n"&gt;NOINHERIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Revoke all default privileges.&lt;/p&gt;

&lt;p&gt;By revoking all default privileges on functions, you ensure that no default&lt;br&gt;
access is granted to the &lt;code&gt;PUBLIC&lt;/code&gt; role or the &lt;code&gt;postgres&lt;/code&gt; superuser role.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;PRIVILEGES&lt;/span&gt;
    &lt;span class="k"&gt;REVOKE&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt;
    &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;FUNCTIONS&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="k"&gt;PUBLIC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Grant all default privileges to &lt;code&gt;nobody&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, you explicitly grant the default privileges for functions to the&lt;br&gt;
&lt;code&gt;nobody&lt;/code&gt; role. This step ensures that any new functions created will have&lt;br&gt;
their default privileges directed toward the this role, but does not have&lt;br&gt;
any practical effect, as this role does not have login or inheritance&lt;br&gt;
rights.&lt;/p&gt;

&lt;p&gt;This step effectively neutralizes the &lt;em&gt;strange behavior of the empty default&lt;br&gt;
privileges&lt;/em&gt; by confining it to a role that has no impact on actual database&lt;br&gt;
operations.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;PRIVILEGES&lt;/span&gt;
  &lt;span class="k"&gt;GRANT&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt;
  &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;FUNCTIONS&lt;/span&gt;
  &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;nobody&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;By implementing these steps, you can regain control over the default privilege&lt;br&gt;
behavior in PostgreSQL and prevent the automatic inheritance of privileges,&lt;br&gt;
which is important for maintaining a security-conscious environment.&lt;/p&gt;

&lt;p&gt;This solution can also be applied to other types of objects and privileges that&lt;br&gt;
are automatically granted by built-in default privileges.&lt;/p&gt;
&lt;h3&gt;
  
  
  How to reproduce the strange behavior
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;PostgreSQL 10+.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Create the database to test.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;example_db&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the database was created, reconnect on it &lt;code&gt;example_db&lt;/code&gt; database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Showing the initial state of the session.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;current_database&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;current_role&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;session_user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;current_database&lt;/th&gt;
&lt;th&gt;current_user&lt;/th&gt;
&lt;th&gt;current_role&lt;/th&gt;
&lt;th&gt;session_user&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;example_db&lt;/td&gt;
&lt;td&gt;postgres&lt;/td&gt;
&lt;td&gt;postgres&lt;/td&gt;
&lt;td&gt;postgres&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Result: 1 row&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check the initial state of default privileges.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_catalog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pg_default_acl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;oid&lt;/th&gt;
&lt;th&gt;defaclrole&lt;/th&gt;
&lt;th&gt;defaclnamespace&lt;/th&gt;
&lt;th&gt;defaclobjtype&lt;/th&gt;
&lt;th&gt;defaclacl&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Result: 0 rows&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Setup
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Revoke all default privileges for functions.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;PRIVILEGES&lt;/span&gt;
  &lt;span class="k"&gt;REVOKE&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt;
  &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;FUNCTIONS&lt;/span&gt;
  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="k"&gt;PUBLIC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Check default privileges definition.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_catalog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pg_default_acl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;oid&lt;/th&gt;
&lt;th&gt;defaclrole&lt;/th&gt;
&lt;th&gt;defaclnamespace&lt;/th&gt;
&lt;th&gt;defaclobjtype&lt;/th&gt;
&lt;th&gt;defaclacl&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;43772&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;f&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Result: 1 row&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Objects creation.
&lt;/h4&gt;

&lt;p&gt;At this example, we'll create a function to show as current default privileges&lt;br&gt;
will be appliend.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- An unprivileged role (not owner).&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;ROLE&lt;/span&gt; &lt;span class="n"&gt;example_role&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;NOLOGIN&lt;/span&gt; &lt;span class="n"&gt;NOINHERIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- An scheme to isolate the function.&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;SCHEMA&lt;/span&gt; &lt;span class="n"&gt;example_schema&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- Grants the USAGE privilege on the schema to allow example_role to access it.&lt;/span&gt;
&lt;span class="k"&gt;GRANT&lt;/span&gt; &lt;span class="k"&gt;USAGE&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;SCHEMA&lt;/span&gt; &lt;span class="n"&gt;example_schema&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;example_role&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- The target function.&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;example_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;example_function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;RETURNS&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;
  &lt;span class="k"&gt;LANGUAGE&lt;/span&gt; &lt;span class="k"&gt;SQL&lt;/span&gt;
  &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="s1"&gt;'Hello!'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="err"&gt;$$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Check the initial access privileges of the function.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's initially null, meaning the system default (grants &lt;code&gt;EXECUTE&lt;/code&gt; access to&lt;br&gt;
&lt;em&gt;PUBLIC&lt;/em&gt; and to the &lt;em&gt;owner&lt;/em&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;oid&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;regproc&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;proacl&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_catalog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pg_proc&lt;/span&gt;
  &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;proname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'example_function'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;THE STRANGE BEHAVIOR IS HERE:&lt;/em&gt;&lt;/strong&gt; At this moment the function's ACL value&lt;br&gt;
 must be inherited from defined &lt;em&gt;default privileges&lt;/em&gt;, &lt;strong&gt;empty&lt;/strong&gt; (no one entry),&lt;br&gt;
 but it's &lt;code&gt;null&lt;/code&gt; (built-in default privileges, that grants &lt;code&gt;EXECUTE&lt;/code&gt; access to&lt;br&gt;
 &lt;strong&gt;PUBLIC&lt;/strong&gt; and to the function's &lt;em&gt;owner&lt;/em&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;name&lt;/th&gt;
&lt;th&gt;proacl&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;example_schema.example_function&lt;/td&gt;
&lt;td&gt;&lt;em&gt;(NULL)&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Result: 1 row.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Callint to test
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Changes the current user.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;SESSION&lt;/span&gt; &lt;span class="k"&gt;AUTHORIZATION&lt;/span&gt; &lt;span class="n"&gt;example_role&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Check the current state of the session.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;current_role&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;session_user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;current_user&lt;/th&gt;
&lt;th&gt;current_role&lt;/th&gt;
&lt;th&gt;session_user&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;example_role&lt;/td&gt;
&lt;td&gt;example_role&lt;/td&gt;
&lt;td&gt;example_role&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Result: 1 row&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Execute the function (expects to fail).&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;example_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;example_function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;But not fail.&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;example_function&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hello!&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Result: 1 row&lt;/em&gt;&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>security</category>
    </item>
  </channel>
</rss>
