Uso de generadores python en Postgres

bases de datos y persistencia
Instrucciones

Siguiendo con la colección de recetas que combinan postgres y python, en esta recetas veremos como utilizar los generadores de python dentro de postgres. Por ejemplo, como un secuenciador.

Uno de los problemas que nos encontraremos es que la comunicación entre python y postgres es que se limita casi exclusivamente a los tipos básicos. Si queremos almacenar un "generador" no nos quedará más remedio que almacenarlo en memoria de modo que sea localizado por las diferentes ejecuciones del secuenciador. Para este cometido, en PL/Python tenemos dos diccionarios: SD (static data) y GD (global data). El GD está disponible en cualquier procedimiento python, y no conviene utilizado si no es necesario. Utilizaremos el SD para conservar nuestro generador entre llamadas a nuestra función. Este diccionario sólo existe durante la sessión en curso, con lo que siempre habrá que comprobar que tenemos el generador en memoria para crearlo si no fuera así. Una mejora sería guardar el generador en la propia base de datos como una cadena de texto, pero tal vez para otra ocasión.:

-- Creación del secuenciador
CREATE FUNCTION mysec()
  RETURNS SETOF text AS '
if not SD.has_key("genfun"):
  def genfun():
    i=0L
    while True:
      yield i
      i=2*i+1 #crear una progresión extraña
  SD["genfun"]=genfun()

f=SD["genfun"]

return str(f.next())' LANGUAGE 'plpythonu';

La secuencia enseguida sobrepasa los valores máximos que puede almacenarse en un dato entero de postgres. Para poder trabajar con el tipo 'longint' de python se debe devolver el valor como TEXT. Podemos probar el funcionamiento de este generador:

SELECT mysec() LIMIT 100;

             mysec
--------------------------------
 0
 1
 3
 7
 15
 31
 63
 127
 255
 511
 1023
 2047
  ...........
  ...........
 4951760157141521099596496895
 9903520314283042199192993791
 19807040628566084398385987583
 39614081257132168796771975167
 79228162514264337593543950335
 158456325028528675187087900671
 316912650057057350374175801343
 633825300114114700748351602687
(100 filas)