Este artigo está escrito em Inglês e Português
English version:
Introduction
This article focus on a little known aspect of stored procedures or functions. That probably explains why it was the less voted in a recent poll I've conducted. Nonetheless it's (from my point of view) a very interesting topic. During this article I'll be referring to procedures, but I could use the term functions.
If we take a look at the sysprocedures table we'll see a field called mode. This field is just one character and the values it can contain are:
- D or d
DBA - O or o
Owner - P or p
Protected - R or r
Restricted - T or t
Trigger
CREATE PROCEDURE test()You'll have an OWNER mode procedure, owned by informix user. But if instead you run:
END PROCEDURE
CREATE PROCEDURE myuser.test()You'll have a RESTRICTED mode procedure owned by myuser.
END PROCEDURE
You need to have DBA privilege to create a procedure on behalfwith another user name.
Why RESTRICTED?
The reasons why the restricted mode procedures/functions were created are based on security. Let's imagine the following scenario:
- You have two databases called db1 and db2
- You have a user myuser with connect privileges on db1 and db2 and another user mydba with DBA privileges on db1
- User myuser needs to be connected to db1 and run a distributed query to db2
- The db2's DBA grants the required privileges on db2 to user myuser
This is why the RESTRICTED mode was created. Every time we create a procedure on behalf of another user, it will be created as a RESTRICTED mode procedure. And as such any remote operation will be done using the currently logged user and not with the identity of the procedure owner (as it happens with OWNER mode procedures).
Other implications
So, the reasons for the creation of this new mode are explained and are good reasons. But there can be another implication. Note that I'll be referencing a product issue, but it's highly probable that you'd never notice it. But the fix for that bug introduced new limits and a new error so it can be interesting to dig a bit deeper on this.
Whenever we make a remote connection inside a statement we need to open a new database. And we need to keep a record of the current opened ones. The structure of the opened databases used to be an array of "only" 8 positions. And in certain conditions we could wrap around it without raising an error. And this could lead to a nasty situation where the "current" database was not the one it should be. I noticed this on a customer environment when we started to get error -674 (procedure not found) on a procedure called from a trigger. Why is this related to the restricted vs owner mode procedures? Because with the mixed use of restricted and owner mode procedures we raise the possibility of having the same database opened with different users (the owners and our current user).
Please don't be scared with this problem. The situation I got involved around 60 objects (tables and procedures) linked together by a complex sequence of triggers that called procedures, that made INSERTs/UPDATEs/DELETEs which in turn called other procedures etc..
This sequence was started by a simple INSERT. And it involved 5 databases. The array I mentioned earlier had 8 positions.
Since then, we fixed several things and now (11.50.xC9 and 11.70.xC3):
- The array was increased to 32 positions
- If we still achieve that limit a proper error will be raised (-26600)
- The documentation was improved (it didn't mention any limit and it still mentions 8, but it should be fixed soon)
Versão Portuguesa:
Introdução
Este artigo foca um aspecto pouco conhecido das stored procedures (ou funções). O facto de ser desconhecido deve ajudar a explicar porque foi o menos votado para artigos num inquérito que realizei há pouco tempo. Apesar disso, é um assunto interessante (do meu ponto de vista). Durante este artigo irei referir na maior parte das vezes "procedimentos". Mas podemos assumir "funções".
Se dermos uma vista de olhos à tabela sysprocedures podemos reparar que contém uma coluna com o nome mode. É apenas um caracter e os valores que pode conter são:
- D or d
DBA - O or o
Owner - P or p
Protected - R or r
Restricted - T or t
Trigger
CREATE PROCEDURE teste()Ficaremos com um procedimento em modo OWNER, cujo dono é o informix. Mas se em vez disso fizermos:
END PROCEDURE
CREATE PROCEDURE myuser.teste()Ficaremos com um procedimento em modo RESTRICTED cujo dono é o myuser.
END PROCEDURE
É necessário ter privilégios de DBA para criar procedimentos em nome de outro utilizador.
Porquê RESTRICTED?
As razões que levaram à criação do modo RESTRICTED para funções e procedimentos prendem-se com segurança. Vamos imaginar o seguinte cenário:
- Temos duas bases de dados chamadas bd1 e bd2
- Temos um utilizador myuser com privilégios de CONNECT em bd1 e bd2 e outro utilizador mydba com privilégios de DBA na bd1
- O utilizador myuser necessita de, estando conectado à bd1, correr uma query distribuída à bd2
- O DBA da bd2 faz o GRANT dos privilégios necessários na bd2 ao utilizador myuser
Esta foi a razão que levou à criação deste novo modo. Em termos práticos, um procedimento criado como RESTRICTED executa todas as operações remotas com a identidade do utilizador que a está a executar e não com a identidade do utilizador que está definido como dono (que pode ser diferente de quem a criou).
Outras implicações
Portanto, as razões para a introdução deste novo modo estão apresentadas e são boas razões. Mas podem existir outras implicações. De seguida irei referir um bug do produto, mas é altamente improvável que venha a encontrá-lo. Mas a correcção introduziu algumas alterações que são dignas de nota e que valerão a pena gastar algum tempo com elas.
Cada vez que fazemos uma conexão remota, dentro de uma instrução SQL, temos de abrir a base de dados remota. E necessitamos de manter um registo das bases de dados abertas em cada momento. A estrutura que mantém essa informação era um array de "apenas" 8 posições. E em determinadas situações poderíamos "dar a volta" sem despoletar um erro apropriado. E isto poderia dar origem a uma situação onde a base de dados "actual" não era a que deveria ser (devido à forma como eram abertas e fechadas as ligações durante a execução de uma instrução SQL). Deparei-me com isto num ambiente de um cliente onde começamos a obter o erro -674 (procedure not found) num procedimento despoletado por um trigger. Como é que isto se relaciona com o tema deste artigo? Porque o uso misto de procedimentos em modo RESTRICTED e OWNER potencia um maior número de bases de dados abertas em simultâneo (cada conexão tem um utilizador específico associado que conforme o modo pode ser o dono dos procedimentos ou o utilizador da sessão).
Não fique assustado com este problema. Para melhor enquadrar, na situação que encontrei existiam cerca de 60 objectos (tabelas e procedimentos) ligados por uma complexa teia de triggers e procedimentos (triggers que chamavam procedimentos que fazia INSERTs, UPDATEs e DELETEs, que por sua vez faziam disparar outros triggers e assim sucessivamente).
A sequência era despoletada por um simples INSERT e envolvia 5 bases de dados distintas. O array mencionado anteriormente tinha apenas 8 posições.
Isto levou a várias correcções e agora (11.50.xC9 e 11.70.xC3):
- O array foi incrementado para 32 posições
- Se alguma vez atingirmos este limite (espero sinceramente que não) um erro apropriado será retornado (-26600)
- A documentação foi melhorada (não mencionada qualquer limite, sendo que de momento ainda refere 8... Deve ser corrigido brevemente)
No comments:
Post a Comment