Monday, June 25, 2012

Informix making the world smarter...

This article is written only in English
Este artigo apenas está disponível em Inglês

Although I'm preparing some technical articles I'm happy to make a break to echo some good news...

Informix is helping an IBM Partner, Centric Solutions, in making the world smarter. Bank of China is using it for a SWIFT application, that also helps to save trees.

These are my words, but I think everyone agrees it must be robust, fast and trustworthy... and Informix is a perfect match for that!

Read all about it here:

http://www.prnewswire.com/news-releases/bank-of-china-in-the-uk-works-with-ibm-to-become-a-smarter-greener-bank-114573679.html

Sunday, June 24, 2012

UDRs: In transaction? / Em transacção?

This article is written in English and Portuguese
Este artigo está escrito em Inglês e Português

English version:

Introduction

I just checked... This will be post 100!!!... I've never been so active in the blog... We have Panther (full of features that I still haven't covered), I did some work with OAT and tasks that I want to share, and besides that I've been trying some new things... Yes... Although I've been working with Informix for nearly 20 years (it's scaring to say this but it's true...) there are aspects that I usually don't work with. I'd say the one I'm going to look into today is not used by the vast majority of the users. And that's a shame because:
  1. It can solve problems that we aren't able to solve in any other way
  2. If it was more used, it would be improved faster
Also, many people think that this is what marked the decline of the Informix company. You probably already figured out that I'm talking about extensibility. To recall a little bit of history, in 1995, Informix had the DSA architecture in version 7. And it acquired the Illustra company, founded by Michael Stonebraker and others. Mr. Stonebraker already had a long history of innovation (which he kept improving up to today) and he stayed with Informix for some years. All the technology around Datablades and extensibility in Informix comes from there... Informix critics say that the company got so absorbed in the extensibility features (that it believed would be the "next wave") that it loosed the market focus. Truth is that the extensibility never became a mainstream feature neither in Informix or in other databases, and all of them followed Informix launch of Universal Server (1996): Oracle, IBM DB2 etc.

But, this article will not focus on the whole extensibility concept. It would be impossible and tedious to try to cover it in one blog article. Instead I'll introduce one of it's aspects: User Defined Routines (UDRs), and in particular routines written using the C language.

There is a manual about UDRs, and I truly recommend that you read it. But here I'll follow another approach: We'll start with a very simple problem that without C UDRs would be impossible to solve, define a solution for it, and go all the way to implement it and use it with an example.


The problem

Have you ever faced a situation where you're writing a stored procedure in SPL, and you want to put some part of it inside a transaction, but you're afraid that the calling code is already in a transaction?
You could workaround this by initiating the transaction and catching the error (already in transaction) with an ON EXCEPTION block.
But this may have other implications (ON EXCEPTION blocks are tricky when the procedure is called from a trigger). So it would be nice to check if the session is already in a transaction. A natural way to do that would be a call to DBINFO(...), but unfortunately current versions (up to 11.7.xC1) don't allow that. Meaning there is no DBINFO() parameter that makes it return that information.


Solution search

One important part of Informix extensibility is the so called Datablade API. It's a set of programmable interfaces that we can use inside Datablades code and also inside C UDRs. The fine infocenter has a reference manual for the Datablade API functions. A quick search there for "transaction" makes a specific function come up: mi_transaction_state()
The documentation states that when calling it (no parameters needed) it will return an mi_integer (let's assume integer for now) type with one of these values:
  • MI_NO_XACT
    meaning we don't have a transaction open
  • MI_IMPLICIT_XACT
    meaning we have an implicit transaction open (for example if we're connected to an ANSI mode database)
  • MI_EXPLICIT_XACT
    meaning we have an explicit transaction open
This is all we need conceptually.... Now we need to transform ideas into runnable code!

Starting the code

In order to implement a C UDR function we should proceed through several steps:
  1. Create the C code skeleton
  2. Create the C code function using the Datablade API
  3. Create a makefile that has all the needed instructions to generate the executable code in a format the engine can use
  4. Compile the code
  5. Use SQL to define the new function, telling the engine where it can find the function and the interface to call it, as well as the language and other function attributes
  6. Test it!



Create the C code skeleton

Informix provides a tool called DataBlade Developers Kit (DBDK) which includes several components: Blade Manager, Blade Pack and Bladesmith. Blade Manager allows us to register the datablades against the databases, the Blade Pack does the "packaging" of all the Datablades files (executable libraries, documentation files, SQL files etc.) that make up a datablade. Finally Bladesmith helps us to create the various components and source code files. It's a development tool that only runs on Windows but can also be used to prepare files for Unix/Linux. For complex projects it may be a good idea to use Bladesmith, but for this very simple example I'll do it by hand. Also note I'm just creating a C UDR. These tools are intended to deal with much more complex projects. A Datablade can include new datatypes, several functions etc.
So, for our example I took a peek at the recent Informix Developer's Handbook to copy the examples.

Having looked at the examples above, it was easy to create the C code:


/*
This simple function returns an integer to the calling SQL code with the following meaning:
0 - We're not within a transaction
1 - We're inside an implicit transaction
2 - We're inside an explicit (BEGIN WORK...) transaction
-1 - Something unexpected happened!
*/

#include <milib.h>

mi_integer get_transaction_state_c( MI_FPARAM *fp)
{
mi_integer i,ret;
i=mi_transaction_state();
switch(i)
{
case MI_NO_XACT:
ret=0;
break;
case MI_IMPLICIT_XACT:
ret=1;
break;
case MI_EXPLICIT_XACT:
ret=2;
break;
default:
ret=-1;
}
return (ret);
}

I've put the above code in a C source file called get_transaction_state_c.c

Create the makefile

Again, for the makefile I copied some examples and came up with the following. Please consider this as an example only. I'm not an expert on makefile building and this is just a small project.


include $(INFORMIXDIR)/incl/dbdk/makeinc.linux

MI_INCL = $(INFORMIXDIR)/incl
CFLAGS = -DMI_SERVBUILD $(CC_PIC) -I$(MI_INCL)/public $(COPTS)
LINKFLAGS = $(SHLIBLFLAG) $(SYMFLAG)


all: get_transaction_state.so

clean:
rm -f get_transaction_state.so get_transaction_state_c.o


get_transaction_state_c.o: get_transaction_state_c.c
$(CC) $(CFLAGS) -o $@ -c $?

get_transaction_state.so: get_transaction_state_c.o
$(SHLIBLOD) $(LINKFLAGS) -o $@ $?


Note that this is a GNU Make makefile. The first line includes a makefile that IBM supplies with Informix. It basically contains variables or macro definitions. You should adapt the include directive to your system (the name of the makefile can vary with the platform) and make sure that the variables I use are also defined in your system base makefile.
After that I define some more variables and I create the makefile targets. I just want it to build the get_transaction_state.so dynamically loadable library and for that I'm including the object (get_transaction_state_c.o) generated from my source code (get_transaction_state_c.c). Pretty simple if you have basic knowledge about makefiles

Compile the code

Once we have the makefile we just need to run a simple command to make it compile:


cheetah@pacman.onlinedomus.net:informix-> make
cc -DMI_SERVBUILD -fpic -I/usr/informix/srvr1150uc7/incl/public -g -o get_transaction_state_c.o -c get_transaction_state_c.c
gcc -shared -Bsymbolic -o get_transaction_state.so get_transaction_state_c.o
cheetah@pacman.onlinedomus.net:informix->
The two commands run are the translation of the macros/variables defined in the makefile(s) and they simply compile the source code (1st command) and then generate the dynamic loadable library. If all goes well (as it naturally happened in the output above), we'll have a library on this location, ready for usage by Informix:


cheetah@pacman.onlinedomus.net:informix-> ls -lia *.so
267913 -rwxrwxr-x 1 informix informix 5639 Nov 23 22:06 get_transaction_state.so
cheetah@pacman.onlinedomus.net:informix-> file *.so
get_transaction_state.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (GNU/Linux), dynamically linked, not stripped
cheetah@pacman.onlinedomus.net:informix->

Use SQL to define the function

Now that we have executable code, in the form of a dynamic loadable library, we need to instruct Informix to use it. For that we will create a new function, telling the engine that it's implemented in C language and the location where it's stored. For that I created a simple SQL file:


cheetah@pacman.onlinedomus.net:informix-> ls *.sql
get_transaction_state_c.sql
cheetah@pacman.onlinedomus.net:informix-> cat get_transaction_state_c.sql
DROP FUNCTION get_transaction_state_c;

CREATE FUNCTION get_transaction_state_c () RETURNING INTEGER
EXTERNAL NAME '/home/informix/udr_tests/get_transaction_state/get_transaction_state.so'
LANGUAGE C;
cheetah@pacman.onlinedomus.net:informix->


So, let's run it...:


cheetah@pacman.onlinedomus.net:informix-> dbaccess stores get_transaction_state_c.sql

Database selected.


674: Routine (get_transaction_state_c) can not be resolved.

111: ISAM error: no record found.
Error in line 1
Near character position 36

Routine created.


Database closed.

cheetah@pacman.onlinedomus.net:informix->


Note that the -674 error is expected, since my SQL includes a DROP FUNCTION. If I were using 11.7 (due to several tests I don't have it ready at this moment) I could have used the new syntax "DROP IF EXISTS...".

So, after this step I should have a function callable from the SQL interface with the name get_transaction_state_c(). It takes no arguments and returns an integer value.

Test it!

Now it's time to see it working. I've opened a session in stores database and did the following:
  1. Run the function. It returned "0", meaning no transaction was opened.
  2. Than I opened a transaction and run it again. It returned "2", meaning an explicit transaction was opened
  3. I closed the transaction and run the function by the third time. As expected it returned "0"
Here is the output:


cheetah@pacman.onlinedomus.net:informix-> dbaccess stores -

Database selected.

> EXECUTE FUNCTION get_transaction_state_c();


(expression)

0

1 row(s) retrieved.

> BEGIN WORK;

Started transaction.

> EXECUTE FUNCTION get_transaction_state_c();


(expression)

2

1 row(s) retrieved.

> ROLLBACK WORK;

Transaction rolled back.

> EXECUTE FUNCTION get_transaction_state_c();


(expression)

0

1 row(s) retrieved.

>

We haven't seen it returning "1". That happens when we're inside an implicit transaction. This situation can be seen if we use the function in an ANSI mode database. For that I'm going to use another database (stores_ansi), and naturally I need to create the function there (using the previous SQL statements). Then I repeat more or less the same steps and the result is interesting:


cheetah@pacman.onlinedomus.net:informix-> dbaccess stores_ansi -

Database selected.

> EXECUTE FUNCTION get_transaction_state_c();


(expression)

0

1 row(s) retrieved.

> SELECT COUNT(*) FROM systables;


(count(*))

83

1 row(s) retrieved.

> EXECUTE FUNCTION get_transaction_state_c();


(expression)

1

1 row(s) retrieved.

>
If you notice it, the first execution returns "0". Since I have not done any operations there is no transaction opened. But just after a simple SELECT, the return is "1", meaning an implicit transaction is opened. This has to do with the nature and behavior of ANSI mode databases.
If you use them and you intend to use this function you must take that into consideration. Or you could simply map the "1" and "2" output of the mi_transaction_state() function return into simply a "1". This would signal that a transaction is opened (omitting the distinction between implicit and explicit transactions).

Final considerations

Please keep in mind that this article serves more as a light introduction to the C language UDRs than to solve a real problem. If you need to know if you're already in transaction (inside a stored procedure for example) you can use this solution, but you could as well try to open a transaction and capture and deal with the error inside an ON EXCEPTION block.

Also note that if this is a real problem for your applications, even if you're inside an already opened transaction, you can make your procedure code work as a unit, by using the SAVEPOINT functionality introduced in 11.50. So, in simple pseudo-code it would be done like this:

  1. Call get_transaction_state_c()
  2. If we're inside a transaction then set TX="SVPOINT" and create a savepoint called "MYSVPOINT" and goto 4)
  3. If we're not inside a transaction than set TX="TX" and create one. Goto 4
  4. Run our procedure code
  5. If any error happens test TX variable. Else goto 8
  6. If TX=="TX" then ROLLBACK WORK. Return error
  7. Else, if TX=="SVPOINT" then ROLLBACK WORK TO SAVEPOINT 'MYSVPOINT'. Return error
  8. Return success
After this introduction, I hope to be able to write a few more articles related to this topic. The basic idea is that sometimes it's very easy to extend the functionality of Informix. And I feel that many customers don't take advantage of this.
Naturally, there are implications on writing C UDRs. The example above is terribly simple, and it will not harm the engine. But when you're writing code that will be run by the engine a lot of questions pop up.... Memory usage, memory leaks, security stability... But there are answers to this concerns. Hopefully some of them (problems and solutions) will be covered in future articles.


Versão Portuguesa:

Introdução

Acabei de verificar.... Este será o centésimo artigo!!! Nunca estive tão activo no blog... Temos a versão Panther (11.7) (cheia de funcionalidades sobre as quais ainda não escrevi), fiz algum trabalho com tarefas do OAT que quero partilhar, e para além disso tenho andado a testar coisas novas... Sim... Apesar de já trabalhar com Informix há perto de 20 anos (é assustador dizer isto, mas é verdade...) há áreas de funcionalidade com as quais não lido habitualmente. Diria que aquela sobre a qual vou debruçar-me hoje não é usada pela maioria dos utilizadores. E isso é uma pena porque:
  1. Permite resolver problemas que não têm outra solução
  2. Se fosse mais usada seria melhorada mais rapidamente
Adicionalmente, existe muita gente que pensa que isto foi o que marcou o declínio da empresa Informix. Possivelmente já percebeu que estou a falar da extensibilidade. Para relembrar um pouco de história, em 1995, a Informix tinha a arquitectura DSA (Dynamic Scalable Architecture) na versão 7. E adquiriu a empresa Illustra, fundada por Michael Stonebraker e outros. O senhor Stonebraker já tinha um longo passado de inovação (que prossegue ainda actualmente) e permaneceu na Informix durante alguns anos. Toda a tecnologia à volta dos datablades e extensibilidade teve aí a sua origem.... Os críticos da Informix dizem que a companhia ficou tão absorvida pelas funcionalidades de extensibilidade (que acreditava serem a próxima "vaga") que perdeu o foco do mercado. A verdade é que a extensibilidade nunca se tornou em algo generalizado nem no Informix nem em outras bases de dados, e todas elas seguiram o lançamento do Informix Universal Server (1996): Oracle, IBM DB2 etc.

Mas este artigo não irá focar todo o conceito de extensibilidade. Seria impossível e entediante tentar cobrir tudo isso num artigo de blog. Em vez disso vou apenas introduzir um dos seus aspectos: User Defined Routines (UDRs), e em particular rotinas escritas usando linguagem C.

Existe um manual que cobre os UDRs, e eu recomendo vivamente a sua leitura. Mas aqui seguirei outra abordagem: Começarei com um problema muito simples, que sem um UDR em C seria impossível de resolver, definirei uma solução para o mesmo, e prosseguirei até à implementação e utilização da solução com um exemplo.

O problema

Alguma vez esteve numa situação em que estivesse a escrever um procedimento em SPL, e quisesse colocar parte dele dentro de uma transacção, mas tivesse receio que o código que chama o procedimento já estivesse com uma transacção aberta?

Poderia contornar o problema iniciando uma transacção e apanhando o erro (already in transaction) com um bloco de ON EXCEPTION

Mas isto teria outras implicações (os blocos de ON EXCEPTION podem criar problemas se o procedimento for chamado de um trigger). Portanto seria bom poder verificar se a sessão já está no meio de uma transacção. Uma forma natural de o fazer seria recorrer à função DBINFO(...), mas infelizmente as versões actuais (até à 11.7.xC1) não permitem isso. Ou seja, não há nenhum parâmetro desta função que permita obter a informação que necessitamos.

Pesquisa da solução

Uma parte importante da extensibilidade no Informix é a chamada Datable API. É um conjunto de interfaces programáveis que podemos usar dentro de datablades e também dentro de UDRs em C. O infocenter tem um manual de referência das funções do Datablade API. Uma pesquisa rápida por "transaction" faz aparecer uma função: mi_transaction_state()

A documentação indica que quando a chamamos (não requer parâmetros) irá retornar um valor do tipo mi_integer (equivale a um inteiro) com um destes valores:
  • MI_NO_XACT
    significa que não temos uma transacção aberta
  • MI_IMPLICIT_XACT
    significa que temos uma transacção implícita aberta (por exemplo se estivermos conectados a uma base de dados em modo ANSI)
  • MI_EXPLICIT_XACT
    significa que temos uma transacção explícita aberta
Isto é tudo o que necessitamos conceptualmente.... Agora precisamos de transformar uma ideia em código executável!

Começando o código

Para implementarmos um UDR em C necessitamos de efectuar vários passos:
  1. Criar o esqueleto do código C
  2. Criar a função com código C usando o datablade API
  3. Criar um makefile que tenha todas as instruções necessárias para gerar o código executável num formato que possa ser usado pelo motor
  4. Compilar o código
  5. Usar SQL para definir uma nova função, indicando ao motor onde pode encontrar a função, o interface para a chamar bem como a linguagem usada e outros atributos da função
  6. Testar!

Criar o código em C

O Informix fornece uma ferramenta chamada DataBlade Developers Kit (DBDK) que incluí vários componentes: Blade Manager, Blade Pack e Bladesmith. O Blade Manager permite-nos registar datablades em bases de dados, o Blade Pack faz o "empacotamento" de todos os ficheiros de um datablade (bibliotecas executáveis, ficheiros de documentação, ficheiros SQL, etc.). Finalmente o Bladesmith ajuda-nos a criar vários componentes e código fonte. É uma ferramenta de desenvolvimento que apenas corre em Windows mas que pode ser usado para preparar ficheiros para Unix/Linux. Para projectos complexos será boa ideia usar o Bladesmith mas para este exemplo simples farei tudo à mão. Apenas estou a criar um UDR em C. Estas ferramentas destinam-se a lidar com projectos muito mais complexos. Um Datablade pode incluir novos tipos de dados, várias funções etc.
Assim, para o nosso exemplo dei uma espreitadela ao recente Informix Developer's Handbook para copiar alguns exemplos.

Depois de ver os exemplos referidos, foi fácil criar o código em C:
/*
This simple function returns an integer to the calling SQL code with the following meaning:
0 - We're not within a transaction
1 - We're inside an implicit transaction
2 - We're inside an explicit (BEGIN WORK...) transaction
-1 - Something unexpected happened!
*/

#include <milib.h>

mi_integer get_transaction_state_c( MI_FPARAM *fp)
{
mi_integer i,ret;
i=mi_transaction_state();
switch(i)
{
case MI_NO_XACT:
ret=0;
break;
case MI_IMPLICIT_XACT:
ret=1;
break;
case MI_EXPLICIT_XACT:
ret=2;
break;
default:
ret=-1;
}
return (ret);
}

Coloquei o código acima num ficheiro chamado get_transaction_state_c.c


Criar o makefile

Também para o makefile, limitei-me a copiar alguns exemplos e gerei o seguinte. Por favor considere isto apenas como um exemplo. Não sou especialista em construção de makefiles e isto é apenas um pequeno projecto.


include $(INFORMIXDIR)/incl/dbdk/makeinc.linux

MI_INCL = $(INFORMIXDIR)/incl
CFLAGS = -DMI_SERVBUILD $(CC_PIC) -I$(MI_INCL)/public $(COPTS)
LINKFLAGS = $(SHLIBLFLAG) $(SYMFLAG)


all: get_transaction_state.so

clean:
rm -f get_transaction_state.so get_transaction_state_c.o


get_transaction_state_c.o: get_transaction_state_c.c
$(CC) $(CFLAGS) -o $@ -c $?

get_transaction_state.so: get_transaction_state_c.o
$(SHLIBLOD) $(LINKFLAGS) -o $@ $?


Este makefile destina-se ao GNU Make. A primeira linha incluí um makefile fornecido pela IBM com o Informix. Este, basicamente, contém definições de variáveis e macros. Deve adaptar a directiva include ao seu sistema (o nome do makefile pode variar com a plataforma) e garanta que as variáveis que usei estão definidas no makefile base do seu sistema.
Depois disso defini mais algumas variáveis e criei os targets. Apenas quero que gere a biblioteca dinâmica get_transaction_state.so e para isso estou a incluir o objecto (get_transaction_state_c.o) gerado a partir do meu código fonte (get_transaction_state_c.c). Bastante simples se tiver conhecimentos básicos de makefiles.


Compilar o código

Depois de termos o makefile apenas necessitamos de um comando simples para executar a compilação:


cheetah@pacman.onlinedomus.net:informix-> make
cc -DMI_SERVBUILD -fpic -I/usr/informix/srvr1150uc7/incl/public -g -o get_transaction_state_c.o -c get_transaction_state_c.c
gcc -shared -Bsymbolic -o get_transaction_state.so get_transaction_state_c.o
cheetah@pacman.onlinedomus.net:informix->
Os dois comandos executados são a tradução dos macros/variáveis definidos no(s) makefiles(s), e apenas compilam o código fonte (primeiro comando) e depois geram a biblioteca dinâmica. Se tudo correr bem (como naturalmente aconteceu no output acima), teremos a biblioteca nesta localização, pronta a ser usada pelo Informix:
cheetah@pacman.onlinedomus.net:informix-> ls -lia *.so
267913 -rwxrwxr-x 1 informix informix 5639 Nov 23 22:06 get_transaction_state.so
cheetah@pacman.onlinedomus.net:informix-> file *.so
get_transaction_state.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (GNU/Linux), dynamically linked, not stripped
cheetah@pacman.onlinedomus.net:informix->

Usar SQL para definir a função

Agora que temos o código executável, na forma de uma biblioteca dinâmica, precisamos de instruir o Informix para usá-la. Para isso vamos criar uma nova função, dizendo ao motor que está implementada em linguagem C e qual a localização onde está guardada. Faremos isso com um script SQL simples:

cheetah@pacman.onlinedomus.net:informix-> ls *.sql
get_transaction_state_c.sql
cheetah@pacman.onlinedomus.net:informix-> cat get_transaction_state_c.sql
DROP FUNCTION get_transaction_state_c;

CREATE FUNCTION get_transaction_state_c () RETURNING INTEGER
EXTERNAL NAME '/home/informix/udr_tests/get_transaction_state/get_transaction_state.so'
LANGUAGE C;
cheetah@pacman.onlinedomus.net:informix->


Vamos executá-lo...:


cheetah@pacman.onlinedomus.net:informix-> dbaccess stores get_transaction_state_c.sql

Database selected.


674: Routine (get_transaction_state_c) can not be resolved.

111: ISAM error: no record found.
Error in line 1
Near character position 36

Routine created.


Database closed.

cheetah@pacman.onlinedomus.net:informix->


Repare que o erro -674 é expectável, dado que o meu SQL incluí a instrução DROP FUNCTION (e ela ainda não existe). Se estivesse a usar a versão 11.7 (devido a vários testes não a tenho operacional agora) podia ter usado a nova sintaxe "DROP IF EXISTS".

Portanto depois deste passo, devo ter uma função que pode ser chamada pela interface SQL com o nome get_transaction_state_c(). Não recebe argumentos e retorna um valor inteiro.


Testar!

Agora é tempo de a ver a trabalhar. Abri uma sessão na base de dados stores e fiz o seguinte:
  1. Corri a função. Retornou "0", o que significa que não havia transacção aberta
  2. Depois abri uma transacção e executei a função novamente. Retornou "2", o que significa que uma transacção explícita estava aberta
  3. Fechei a transacção e corri a função pela terceira vez. Como esperado retornou "0"
Aqui está o output:


cheetah@pacman.onlinedomus.net:informix-> dbaccess stores -

Database selected.

> EXECUTE FUNCTION get_transaction_state_c();


(expression)

0

1 row(s) retrieved.

> BEGIN WORK;

Started transaction.

> EXECUTE FUNCTION get_transaction_state_c();


(expression)

2

1 row(s) retrieved.

> ROLLBACK WORK;

Transaction rolled back.

> EXECUTE FUNCTION get_transaction_state_c();


(expression)

0

1 row(s) retrieved.

>

Não vimos o retorno "1". Isso acontece quando estamos dentro de uma transacção implícita. Esta situação pode ser vista se a função estiver a ser executada numa base de dados em modo ANSI. Para isso vou usar uma outra base de dados (stores_ansi), e naturalmente necessito de criar a função aqui (usando as instruções SQL anteriores). Depois repito mais ou menos os mesmos passos e o resultado é interessante:

cheetah@pacman.onlinedomus.net:informix-> dbaccess stores_ansi -

Database selected.

> EXECUTE FUNCTION get_transaction_state_c();


(expression)

0

1 row(s) retrieved.

> SELECT COUNT(*) FROM systables;


(count(*))

83

1 row(s) retrieved.

> EXECUTE FUNCTION get_transaction_state_c();


(expression)

1

1 row(s) retrieved.

>
Se reparar, a primeira execução retornou "0". Como ainda não tinha efectuado nenhuma operação não havia transacção aberta. Mas logo a seguir a um simples SELECT já retorna "1", o que significa que uma transacção implícita estava aberta. Isto prende-se com a natureza e comportamento das bases de dados em modo ANSI.
Se as usa e pretende usar esta função terá de ter isto em consideração. Ou poderá simplesmente mapear o retorno "1" e "2" da função mi_transaction_state() no retorno "1" da função criada por si. Isto sinalizaria que uma transacção estava aberta (omitindo a distinção entre transacção implícita e explícita).

Considerações finais

Relembro que este artigo serve mais como introdução aos UDRs na linguagem C que propriamente para resolver um problema real.
Se necessitar de saber se já está numa transacção (dentro de uma stored procedure por exemplo) pode usar esta solução, mas também podia tentar abrir uma transacção e capturar e gerir o erro dentro de um bloco ON EXCEPTION.

Chamo a atenção também para que se isto é um problema real das suas aplicações, mesmo que esteja já dentro de uma transacção, pode fazer com que o código da sua stored procedure trabalhe como uma unidade, usando a funcionalidade dos SAVEPOINTs, introduzida na versão 11.50. Em pseudo-código seria feito assim:

  1. Chamar a get_transaction_state_c()
  2. Se estamos dentro de uma transacção então estabelecer TX="SVPOINT" e criar um savepoint chamado "MYSVPOINT". Ir para 4)
  3. Se não estamos dentro de uma transacção então estabelecer TX="TX" e criar uma. Ir para 4)
  4. Correr o código da procedure
  5. Se ocorrer algum erro testat a variável TX. Ir para 8)
  6. Se TX =="TX" então ROLLBACK WORK. Retornar erro.
  7. Senão, SE TX=="SVPOINT" então ROLLBACK WORK TO SAVEPOINT 'MYSVPOINT'. Retornar erro
  8. Retornar sucesso
Depois desta introdução espero conseguir escrever mais alguns artigos relacionados com este tópico. A ideia base é que algumas vezes é muito fácil estender a funcionalidade base do Informix. E sinto que muitos clientes não tiram partido disto.
Naturalmente há implicações em escrever UDRs em C. O exemplo acima é terrivelmente simples, e não trará prejuízo ao motor. Mas quando escrevemos código que será executado pelo motor surgem uma série de questões... Utilização de memória, fugas de memória, segurança, estabilidade.... Mas existem respostas para estas preocupações. Espero que alguns (problema e soluções) sejam cobertos em artigos futuros.

Sunday, June 17, 2012

Informix Roadshow 2011 Lisboa (Agenda)

This article is only written in Portuguese due to it's local nature
Este artigo só está escrito em Português dada a sua natureza local


A agenda do evento Informix Roadshow 2011 a realizar no próximo dia 3 de Maio nas instalações da IBM é:


AGENDA:
  • 9:45 Registo e Boas Vindas
  • 10.00 – 10.15 Discover the Next Decade of Informix at IBM
    Juan Brogeras - SWG Information Management Sales Director SPGI
  • 10.15 – 10.45 Informix UltimateWarehouse.Transformational and Continuous Improvements for Your DataWarehouse.
    Steve Shoaf -WWSales Executive - Informix & solidDB
  • 10.45 – 11.15 Informix Genero: Broadening the Informix 4GL Portfolio.
    Manuel Jorge Sousa - Vice President 4Js for Iberia
  • 11.15 – 11.45 Café
  • 11.45 – 12.15 Informix 11.7 solutions, features, roadmap and evolution
    José Manuel Ruiz Gallud - Database Sales, Southwest IOT
  • 12.15 – 12.45 Upgrading Informix Dynamic Server / Case study.
  • 12.45 – 13.15 Testemunho de um Informix Business Partner
  • 13.15 – 13.30 Wrap up / Almoço

Faça a sua inscrição através do email ibmdm@pt.ibm.com
Estacionamento gratuito no parque do Hotel Vip Art’s (mesmo em frente ao Edf IBM no Parque das Nações em Lisboa)

Tuesday, June 12, 2012

Web applications.... Food for thought

This article is written in English and Portuguese
Este artigo está escrito em Inglês e Português

English version:
A very short article... Take it as food for thought... I was just using Facebook and noticed that I was getting notifications that I cannot really see if I click on them. What has this to do with Informix' Nothing.... But I can speculate that it has to do with mySQL used by Facebook. It's known that it uses a modified version of the original database with replication between the nodes and query balancing. So it's possible that you see something in a specific view that you cannot see in another view. This may look very strange for an OLTP "kind of guy". But it's perfectly acceptable (to a certain point) in a web application that doesn't support transactions, and as such can handle a bit of "data lagging". This could be implemented out of the box with Informix and it's Flexible Grid technology. So there's the Informix link :)


Versão Portuguesa:
Um artigo muito curto... Tome-o como um estimulador para o pensamento... Estava a usar o Facebook e reparei que estava a receber notificações que depois não consigo ver se clicar nelas. O que é que isto tem que ver com Informix? Nada... Mas posso especular que tem a ver com o mySQL usado pelo Facebook. É do conhecimento público que usa uma versão modificada da base de dados original com replicação entre os nós e balanceamento de querys. Por isso é possível que also seja visível numa determinada vista e não o seja noutra. Isto pode parecer muito estranho para as pessoas habituadas ao OLTP clássico. Mas é perfeitamente aceitável (até certo ponto) numa aplicação Web que não serve de suporte a transações, e que por isso pode suportar um pouco de "atraso nos dados". Isto poderia ser implementado em Informix tal como ele é fornecido, usando o Flexible Grid. Pronto, aqui está a ligação com o Informix

Monday, June 4, 2012

HP-UX: What now? / E agora?

This article is written in English and Portuguese
Este artigo está escrito em Inglês e Português

English version:

You know I usually stick to Informix related topics, but a few weeks ago something was announced that has to make us think... As we all know by now, Oracle announced that future versions of their software products will not support HP-UX running on Intel Itanium chips.
Why do we have to think about it? Well, from my personal perspective because it raises a lot of serious doubts/questions. Let's see:

  1. First you read in the announcement that Intel is not truly committed to Itanium. The exact words are "Intel management made it clear that their strategic focus is on their x86 microprocessor and that Itanium was nearing the end of its life". Intel denied this in the following days. Who do we believe? The company that owns the chip in question or another (now also) hardware supplier? Is it normal that a company discontinues it's products on a platform that has not announced it's end of life plans?

  2. The announcement was made just before an important HP shareholders meeting... We could of course believe this was just a coincidence

  3. In the last months a lot of news came up referring to personal wars between Oracle's and HP's executives (ex HP CEO is now a very important Oracle executive). Meanwhile ex SAP CEO has been appointed as HP CEO, and Oracle and SAP had an ongoing court trial started at the time he was SAP's CEO. All these an point 2) may lead us to the feeling that while personalities clash, customers suffer. There's nothing wrong with having strong personalities as leaders of large companies, on the contrary. But we would expect their egos not to cause harm to their customers (of course "harm" translates into costs, uncertainty, fear and doubts - typically FUD that competitors like to spread, but in this case competitors don't have to bother...)

  4. Oracle mentions that others (Microsoft and Red Hat) have previously discontinued support for Itanium. This is true, but there is a big difference: The market share that these two companies had in the Itanium market was considered irrelevant. Now, for Oracle, the situation is completely different. They have a large share of Itanium customers (accordingly to this blog, there are around 140.000 Oracle/Itanium customers)

  5. Some people argue that supporting a platform has it's costs. Of course this is true, but the costs are certainly well covered if the above number holds true. That's part of the business. In order to provide a product, you incur in certain costs. And also note that Oracle always said, wrote an publicized that their code base was the same independently of the platform. So using this as an argument is hardly acceptable...

  6. Many people think this is just a commercial move from Oracle. They're trying to weak a competitor position while at the same time they hope to raise their own hardware sales. We can accept that this is normal, but we should keep in mind a few things. First, just a while ago Oracle choose HP as an hardware partner (remember Exadata?). Secondly Oracle CEO has said that it would like to see Oracle becoming the IBM of the sixties (integrated stack where the margins would be bigger), but that it would keep its software running on competitor platforms. Well something has changed :)

  7. Will this be the only case, or will Oracle do the same in the future with other OS? The fact is that the number of OS and Hardware vendors for enterprise computing is shrinking. You currently have Microsof Windows on Intel x86, IBM AIX on System p, HP-UX on Itanium, Solaris Sparc, Linux on Intel x86, and Solaris on Intel (I'm explicitley forgeting other platforms like IBM System Z and HP NonStop). Oracle is doing it's best to eliminate HP-UX/Itanium. Will it stop there? Or will it proceed it's path to become "the IBM of the 1960s" (meaning the closed system that locked customers in)? Note that IBM still suffers with the image it created at the time.

The above are just a list of some important points. I may be missing a few. The announcement must had a significant impact on HP Itanium customers running Oracle software. Imagine that you wake up one morning and find out that the software vendor you choose gave up supporting your platform. Of course you'll have support for your existing products, but you'd really appreciate a roadmap... By the way, wasn't that the same company that 10 years ago accused IBM of not having a roadmap for Informix? It's funny when we put things into perspective...
So, assuming you're one of those customers what will you do? You have a few options:
  1. You jump on the Oracle train and buy a one way ticket... I mean you choose Sparc for your upcoming hardware renovation... You don't know where the train will take you... You don't even know how much it will cost you... Specially because you just bought a one way ticket... Once you're "there" you'll figure what what price the next ride will cost... One thing you know: You'll be traveling with the same company since no other operates in the same region...

  2. You choose another hardware platform, and you really hope the same trick will not be played again

  3. You change your software supplier
I'd say none of the options above looks particularly attractive. But in case you need another database (and you're able to get your application running against it), you should really consider Informix. Here's why:
  1. It's robust, easy to use, reliable, works well in virtualized environments etc., but you should already know that

  2. It has a roadmap and has just completed a decade of improvements after the IBM acquisition

  3. It belongs to a company that will try to sell you it's hardware, because it believes it's good, and not because it tends to be the only option to run it's software

  4. It's already very well integrated with many of the other IBM software portfolio, and this is assumed to be a continuous effort

  5. It has a long history of working well with HP-UX (traditionally on PA-RISC and now with Itanium). A search for "informix" in the HP site will show you several HP documents about integration between Informix and HP-UX
To wrap up this article, I'd like to put here a few links that relate to this topic. I hope they'll allow you to see what's being written about this Oracle announcement, and to form your own opinion about it.




Versão Portuguesa:

Normalmente restrinjo-me a assuntos exclusivamente relacionados com Informix, mas há algumas semanas atrás foi anunciado algo que nos tem de fazer pensar.... Como já todos deveremos saber nesta altura, a Oracle anunciou que futuras versões do seu software não irão suportar HP-UX a correr em chips Itanium.
Porque é que devemos reflectir sobre isto? Bom, na minha opinião pessoal porque isto levanta uma série de dúvidas e questões importantes. Vejamos:

  1. Começamos por ler no anúncio que a Intel não está verdadeiramente empenhada no Itanium. As palavras exactas (tradução pessoal) foram: "... a gestão da Intel deixou claro que o foco da sua estratégia é a linha de processadores x86 e que o Itanium se está a aproximar do fim de vida..." . A Intel negou isto nos dias seguintes. Em quem acreditamos? Na empresa que detém o processador em questão ou noutra empresa (agora também) fornecedora de hardware? Será normal que uma empresa anuncie o fim de desenvolvimento dos seus produtos numa plataforma cujo fim de vida não foi sequer anunciado?

  2. O anúncio foi feito imediatamente antes de um encontro de accionistas da HP.... Podemos claro acreditar que isto foi apenas uma coincidência

  3. Nos últimos meses vieram a público uma série de notícias referentes a guerras pessoais entre executivos da HP e Oracle (o ex CEO da HP é agora um quadro importante na Oracle - o número dois na verdade, logo abaixo do Larry Ellison). Entretanto o ex CEO da SAP foi nomeado CEO da HP, e a Oracle e HP tinham um processo em tribunal que remonta ao tempo em que o mesmo era CEO da SAP. Tudo isto e o ponto 2) podem levar-nos a pensar que enquanto as personalidades se chocam os clientes sofrem. Não há nada de errado em que grandes empresas tenham personalidades fortes na sua liderança, bem pelo contrário. Mas seria de esperar que os egos não prejudiquem os respectivos clientes. O "prejuízo" traduz-se em custos, incerteza, medos e dúvidas - o que em Inglês se chama "FUD - fear, uncertainty and doubt -", que normalmente é espalhado pela concorrência, mas que neste caso nem requer esforço da concorrência pois é feiro pelos próprios.

  4. A Oracle referiu que outros (Microsoft e Red Hat) já tinham previamente descontinuado o suporte para Itanium. Isto é verdade, mas há uma enorme diferença: A quota de mercado que estas duas empresas tinham em Itanium não é comparável à da Oracle. Esta tem uma grande percentagem dos clientes Itanium a usarem os seus produtos (de acordo com este blog, existem cerca de 140.000 clientes Oracle/Itanium)

  5. Algumas pessoas defendem que suportar uma plataforma tem os seus custos. Isto é uma verdade óbvia., mas esses custos são largamente cobertos se os números acima forem correctos. Isso faz parte do negócio. Para fornecer um produto as empresas (de qualquer tipo) incorrem em custos. Note-se ainda que a Oracle sempre disse, escreveu e publicitou que o seu código era o mesmo independente da plataforma. Por tudo isto, o argumento do custo de suportar uma plataforma não me parece aceiável...

  6. Muitas pessoas acreditam que isto é apenas uma manobra comercial da Oracle. Estão a tentar enfraquecer um concorrente ao mesmo tempo que tentam aumentar as suas p´roprias vendas de hardware. Podemos encarar isto como algo relativamente normal, mas devemos manter em mente uma série de factos. Primeiro, apenas há algum tempo atrás, a Oracle escolheu a HP como o seu parceiro de hardware (lembram-se do Exadata?). Segundo, o CEO da oracle disse que gostava de ver (tradução pessoal) A Oracle tornar-se a IBM dos anos sessenta (soluções integradas onde as margens são maiores), mas que manteria o seu software a correr nas plataformas da concorrência. Parece que algo mudou entretanto... :)

  7. Será este um caso único, ou irá a Oracle fazer os mesmo com outras plataformas? A verdade é que as plataformas (SO e hardware) para computação empresarial estão a diminuir. Actualmente temos Microsof Windows em Intel x86, IBM AIX em System p, HP-UX em Itanium, Solaris Sparc, Linux em Intel x86, e Solaris em Intel (estou a omitir outras plataformas como IBM System Z e HP NonStop) . A Oracle está a fazer o seu melhor para eliminar HP-UX em Itanium. Irá parar por aí? Ou irá prosseguir os seu caminho para se tornar a "IBM dos anos sessenta" (neste caso um sistema fechado que prende os clientes)? Note-se que a IBM ainda sofre com a imagem criada nessa altura.

Acima está uma lista de alguns pontos importantes. Posso ter esquecido alguns. O anúncio deve ter tido um impacto significativo nos clientes HP Itanium que utilizam software Oracle. Imagine que acorda uma manhã e descobre que o fornecedor de software que seleccionou, deixou de suportar a sua plataforma. Claro que terá suporte para os produtos que já existem, mas certamente apreciaria a existência de um roadmap... Aliás, não foi esta a mesma empresa que há 10 anos atrás acusou a IBM de não ter um roadmap para Informix? É engraçado quando se colocam as coisas em perspectiva...
Assim, assumindo que é um desses clientes, o que irá fazer? A meu ver tem algumas opções:
  1. Apanha o compboio da Oracle e compra um bilhete de ida... Ou seja, escolhe SPARC para a sua próxima renovação de hardware... Não sabe para onde o comboio o leva... Nem sequer sabe quanto lhe vai custar... Especialmente porque comprará apenas um bilhete de ida... Depois de "lá" chegar logo verá qual o preço da próxima "viagem"... Uma coisa será certa: Irá viajar com a mesma empresa, pois mais ninguém opera na mesma "região"...

  2. Escolhe outra plataforma de hardware e espera ardentemente que o mesmo truque não seja empregue novamente

  3. Muda de fornecedore de softtware
Diria que nenhuma das opções acima parece particularmente atractiva. Mas caso necessite de uma nova base de dados (e possa colocar a sua aplicação a correr nela), deveria considerar o Informix. Eis porquê:
  1. É robusto, confiável, corre bem em ambientes virtualizadoes etc.., mas isto já deverá saber

  2. Tem um roadmap e acabou de completar 10 anos de inovação após a aquisição pela IBMI

  3. Pertence a uma empresa que tentará vender-lhe o seu hardware porque acredita que é bom, e não apenas porque tende a ser a única plataforma onde pode correr o seu hardware

  4. Já está bastante bem integrado com muito do software IBM, e isto é assumidamente um esforço contínuo

  5. Tem uma longa história de bom desempenho em HP-UX (tradicionalmente em PA-RISC e actualmente em Itanium). Uma pesquisa por "informix" no site da HP irá mostrar-lhe vários documentos da HP sobre a integração entre Informix e HP-UX
Para fechar este artigo, gostaria de deixar alguns links relacionados com este assunto. Espero que lhe permitam ver o que tem sido escrito sobre este anúncio da Oracle, e que possa formar a sua p´ropria opinião sobre o tema.